1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | import { Metadata } from './metadata';
|
19 |
|
20 | export interface CallMetadataOptions {
|
21 | service_url: string;
|
22 | }
|
23 |
|
24 | export type CallMetadataGenerator = (
|
25 | options: CallMetadataOptions,
|
26 | cb: (err: Error | null, metadata?: Metadata) => void
|
27 | ) => void;
|
28 |
|
29 |
|
30 |
|
31 | export interface OldOAuth2Client {
|
32 | getRequestMetadata: (
|
33 | url: string,
|
34 | callback: (
|
35 | err: Error | null,
|
36 | headers?: {
|
37 | [index: string]: string;
|
38 | }
|
39 | ) => void
|
40 | ) => void;
|
41 | }
|
42 |
|
43 | export interface CurrentOAuth2Client {
|
44 | getRequestHeaders: (url?: string) => Promise<{ [index: string]: string }>;
|
45 | }
|
46 |
|
47 | export type OAuth2Client = OldOAuth2Client | CurrentOAuth2Client;
|
48 |
|
49 | function isCurrentOauth2Client(
|
50 | client: OAuth2Client
|
51 | ): client is CurrentOAuth2Client {
|
52 | return (
|
53 | 'getRequestHeaders' in client &&
|
54 | typeof client.getRequestHeaders === 'function'
|
55 | );
|
56 | }
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | export abstract class CallCredentials {
|
63 | |
64 |
|
65 |
|
66 |
|
67 | abstract generateMetadata(options: CallMetadataOptions): Promise<Metadata>;
|
68 | |
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | abstract compose(callCredentials: CallCredentials): CallCredentials;
|
75 |
|
76 | |
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | abstract _equals(other: CallCredentials): boolean;
|
83 |
|
84 | |
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | static createFromMetadataGenerator(
|
92 | metadataGenerator: CallMetadataGenerator
|
93 | ): CallCredentials {
|
94 | return new SingleCallCredentials(metadataGenerator);
|
95 | }
|
96 |
|
97 | |
98 |
|
99 |
|
100 |
|
101 |
|
102 | static createFromGoogleCredential(
|
103 | googleCredentials: OAuth2Client
|
104 | ): CallCredentials {
|
105 | return CallCredentials.createFromMetadataGenerator((options, callback) => {
|
106 | let getHeaders: Promise<{ [index: string]: string }>;
|
107 | if (isCurrentOauth2Client(googleCredentials)) {
|
108 | getHeaders = googleCredentials.getRequestHeaders(options.service_url);
|
109 | } else {
|
110 | getHeaders = new Promise((resolve, reject) => {
|
111 | googleCredentials.getRequestMetadata(
|
112 | options.service_url,
|
113 | (err, headers) => {
|
114 | if (err) {
|
115 | reject(err);
|
116 | return;
|
117 | }
|
118 | if (!headers) {
|
119 | reject(new Error('Headers not set by metadata plugin'));
|
120 | return;
|
121 | }
|
122 | resolve(headers);
|
123 | }
|
124 | );
|
125 | });
|
126 | }
|
127 | getHeaders.then(
|
128 | (headers) => {
|
129 | const metadata = new Metadata();
|
130 | for (const key of Object.keys(headers)) {
|
131 | metadata.add(key, headers[key]);
|
132 | }
|
133 | callback(null, metadata);
|
134 | },
|
135 | (err) => {
|
136 | callback(err);
|
137 | }
|
138 | );
|
139 | });
|
140 | }
|
141 |
|
142 | static createEmpty(): CallCredentials {
|
143 | return new EmptyCallCredentials();
|
144 | }
|
145 | }
|
146 |
|
147 | class ComposedCallCredentials extends CallCredentials {
|
148 | constructor(private creds: CallCredentials[]) {
|
149 | super();
|
150 | }
|
151 |
|
152 | async generateMetadata(options: CallMetadataOptions): Promise<Metadata> {
|
153 | const base: Metadata = new Metadata();
|
154 | const generated: Metadata[] = await Promise.all(
|
155 | this.creds.map((cred) => cred.generateMetadata(options))
|
156 | );
|
157 | for (const gen of generated) {
|
158 | base.merge(gen);
|
159 | }
|
160 | return base;
|
161 | }
|
162 |
|
163 | compose(other: CallCredentials): CallCredentials {
|
164 | return new ComposedCallCredentials(this.creds.concat([other]));
|
165 | }
|
166 |
|
167 | _equals(other: CallCredentials): boolean {
|
168 | if (this === other) {
|
169 | return true;
|
170 | }
|
171 | if (other instanceof ComposedCallCredentials) {
|
172 | return this.creds.every((value, index) =>
|
173 | value._equals(other.creds[index])
|
174 | );
|
175 | } else {
|
176 | return false;
|
177 | }
|
178 | }
|
179 | }
|
180 |
|
181 | class SingleCallCredentials extends CallCredentials {
|
182 | constructor(private metadataGenerator: CallMetadataGenerator) {
|
183 | super();
|
184 | }
|
185 |
|
186 | generateMetadata(options: CallMetadataOptions): Promise<Metadata> {
|
187 | return new Promise<Metadata>((resolve, reject) => {
|
188 | this.metadataGenerator(options, (err, metadata) => {
|
189 | if (metadata !== undefined) {
|
190 | resolve(metadata);
|
191 | } else {
|
192 | reject(err);
|
193 | }
|
194 | });
|
195 | });
|
196 | }
|
197 |
|
198 | compose(other: CallCredentials): CallCredentials {
|
199 | return new ComposedCallCredentials([this, other]);
|
200 | }
|
201 |
|
202 | _equals(other: CallCredentials): boolean {
|
203 | if (this === other) {
|
204 | return true;
|
205 | }
|
206 | if (other instanceof SingleCallCredentials) {
|
207 | return this.metadataGenerator === other.metadataGenerator;
|
208 | } else {
|
209 | return false;
|
210 | }
|
211 | }
|
212 | }
|
213 |
|
214 | class EmptyCallCredentials extends CallCredentials {
|
215 | generateMetadata(options: CallMetadataOptions): Promise<Metadata> {
|
216 | return Promise.resolve(new Metadata());
|
217 | }
|
218 |
|
219 | compose(other: CallCredentials): CallCredentials {
|
220 | return other;
|
221 | }
|
222 |
|
223 | _equals(other: CallCredentials): boolean {
|
224 | return other instanceof EmptyCallCredentials;
|
225 | }
|
226 | }
|
227 |
|
\ | No newline at end of file |