Skip to content

Commit

Permalink
feat: endpoints list for all available service clients
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Zuev committed Dec 24, 2021
1 parent b463cf8 commit 78c2355
Show file tree
Hide file tree
Showing 7 changed files with 487 additions and 118 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"homepage": "https://github.com/yandex-cloud/nodejs-sdk#readme",
"dependencies": {
"@grpc/grpc-js": "^1.4.4",
"@grpc/grpc-js": "https://gitpkg.now.sh/DavyJohnes/grpc-node/packages/grpc-js?fix-class-options-issue-with-dist",
"aws-sdk": ">= 2.0.9",
"lodash": "^4.17.21",
"log4js": "^6.3.0",
Expand Down
113 changes: 2 additions & 111 deletions src/index.ts
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';
30 changes: 30 additions & 0 deletions src/service-endpoints.test.ts
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');
});
});
Loading

0 comments on commit 78c2355

Please sign in to comment.