-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: endpoints list for all available service clients
- Loading branch information
Ivan Zuev
committed
Dec 24, 2021
1 parent
b463cf8
commit 78c2355
Showing
7 changed files
with
487 additions
and
118 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,111 +1,2 @@ | ||
import grpc, { ChannelCredentials } from 'grpc'; | ||
import util from './lib/util'; | ||
import { EndpointResolver } from './lib/endpoint'; | ||
import metadata from './lib/metadata'; | ||
import iam from './api/iam/v1'; | ||
|
||
type TokenCreator = () => Promise<string>; | ||
|
||
interface ClientClass<T> { | ||
new(address: string, credentials: ChannelCredentials, options?: object, tokenCreator?: TokenCreator): T; | ||
__endpointId: string; | ||
} | ||
|
||
interface GenericConfig { | ||
pollInterval?: number; | ||
} | ||
|
||
export interface OAuthCredentialsConfig extends GenericConfig { | ||
oauthToken: string; | ||
} | ||
|
||
export interface IamTokenCredentialsConfig extends GenericConfig { | ||
iamToken: string; | ||
} | ||
|
||
export type SessionConfig = OAuthCredentialsConfig | IamTokenCredentialsConfig | GenericConfig; | ||
|
||
const createIamToken = async (iamEndpoint: string, req: unknown) => { | ||
const Ctor = iam.IamTokenService.makeGrpcConstructor(); | ||
let client = new Ctor(iamEndpoint, grpc.credentials.createSsl()); | ||
|
||
client = util.pimpServiceInstance(client); | ||
const resp = await client.create(req); | ||
|
||
return resp.iamToken; | ||
}; | ||
|
||
const newTokenCreator = (config: SessionConfig, iamEndpoint: string): TokenCreator => { | ||
if ('oauthToken' in config) { | ||
return () => createIamToken(iamEndpoint, { | ||
yandexPassportOauthToken: config.oauthToken, | ||
}); | ||
} | ||
|
||
if ('iamToken' in config) { | ||
return async () => config.iamToken; | ||
} | ||
|
||
const tokenService = new metadata.TokenService(); | ||
|
||
return async () => { | ||
await tokenService.initialize(); | ||
|
||
return tokenService.getToken(); | ||
}; | ||
}; | ||
|
||
const newChannelCredentials = (tokenCreator: TokenCreator) => grpc.credentials.combineChannelCredentials( | ||
grpc.credentials.createSsl(), | ||
grpc.credentials.createFromMetadataGenerator((params, callback) => { | ||
tokenCreator() | ||
.then((token) => { | ||
const md = new grpc.Metadata(); | ||
|
||
md.set('authorization', `Bearer ${token}`); | ||
|
||
return callback(null, md); | ||
}) | ||
.catch((error) => callback(error)); | ||
}), | ||
); | ||
|
||
export class Session { | ||
private static defaultConfig: Partial<SessionConfig> = { | ||
pollInterval: 1000, | ||
}; | ||
|
||
private readonly __config: SessionConfig; | ||
private readonly __endpointResolver: EndpointResolver; | ||
private readonly __tokenCreator: TokenCreator; | ||
private readonly __channelCredentials: ChannelCredentials; | ||
|
||
constructor(config: SessionConfig) { | ||
this.__config = { | ||
...Session.defaultConfig, | ||
...config, | ||
}; | ||
this.__endpointResolver = new EndpointResolver(); | ||
this.__tokenCreator = newTokenCreator( | ||
this.__config, | ||
this.__endpointResolver.resolve('iam'), | ||
); | ||
this.__channelCredentials = newChannelCredentials(this.__tokenCreator); | ||
} | ||
|
||
async setEndpoint(newEndpoint: string) { | ||
await this.__endpointResolver.updateEndpointList(newEndpoint); | ||
} | ||
|
||
client<T>(Cls: ClientClass<T>): T { | ||
return util.pimpServiceInstance( | ||
new Cls( | ||
// eslint-disable-next-line no-underscore-dangle | ||
this.__endpointResolver.resolve(Cls.__endpointId), | ||
this.__channelCredentials, | ||
undefined, | ||
this.__tokenCreator, | ||
), | ||
); | ||
} | ||
} | ||
export * as serviceClients from './generated/yandex/cloud/service_clients'; | ||
export * as cloudApi from './generated/yandex/cloud'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { ServiceClientConstructor } from '@grpc/grpc-js'; | ||
import { getServiceClientEndpoint } from './service-endpoints'; | ||
import { serviceClients } from '.'; | ||
|
||
describe('service endpoints', () => { | ||
it('each service in generated service_clients module should have endpoint declared in service-endpoints', () => { | ||
for (const [, ServiceClient] of Object.entries(serviceClients)) { | ||
// eslint-disable-next-line @typescript-eslint/no-loop-func | ||
expect(() => { | ||
const endpoint = getServiceClientEndpoint(ServiceClient); | ||
|
||
expect(endpoint).toBeTruthy(); | ||
}).not.toThrow(); | ||
} | ||
}); | ||
|
||
it('should throw exception if endpoint was not found', () => { | ||
const serviceName = 'myCustomService'; | ||
|
||
expect(() => { | ||
getServiceClientEndpoint({ options: { serviceName } } as unknown as ServiceClientConstructor); | ||
}).toThrow(`Endpoint for service ${serviceName} is no defined`); | ||
}); | ||
|
||
it('should throw exception if client class has no serviceName option', () => { | ||
expect(() => { | ||
getServiceClientEndpoint({ options: {} } as unknown as ServiceClientConstructor); | ||
}).toThrow('Unable to retrieve serviceName of provided service client class'); | ||
}); | ||
}); |
Oops, something went wrong.