Skip to content

Commit cdb3574

Browse files
committed
refactor: refaactor StaticCredentialsAuthService
change the way it waits until token request fulfils: use promises instead of sleep. also change constructor options to interface
1 parent a0ff3ea commit cdb3574

File tree

2 files changed

+52
-36
lines changed

2 files changed

+52
-36
lines changed

examples/auth/static-credentials/snippet.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import {Driver, StaticCredentialsAuthService, Logger} from 'ydb-sdk';
33
export async function run(logger: Logger, endpoint: string, database: string, args?: any) {
44
logger.info('Driver initializing...');
55
const {user, password} = args;
6-
const authService = new StaticCredentialsAuthService(user, password, endpoint)
6+
const authService = new StaticCredentialsAuthService(user, password, endpoint, {
7+
tokenExpirationTimeout: 20000,
8+
})
79
const driver = new Driver({endpoint, database, authService});
810
const timeout = 100000;
911
if (!await driver.ready(timeout)) {

src/credentials.ts

Lines changed: 49 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -40,37 +40,58 @@ export class AnonymousAuthService implements IAuthService {
4040
}
4141
}
4242

43+
interface StaticCredentialsAuthOptions {
44+
/** Custom ssl sertificates. If you use it in driver, you must use it here too */
45+
sslCredentials?: ISslCredentials;
46+
/**
47+
* Timeout for token request in milliseconds
48+
* @default 10 * 1000
49+
*/
50+
tokenRequestTimeout?: number;
51+
/** Expiration time for token in milliseconds
52+
* @default 6 * 60 * 60 * 1000
53+
*/
54+
tokenExpirationTimeout?: number
55+
}
4356

4457
export class StaticCredentialsAuthService implements IAuthService {
45-
private tokenExpirationTimeout = 30 * 60 * 1000;
46-
private tokenRequestTimeout = 10 * 1000;
47-
private tokenTimestamp: DateTime|null;
48-
private token: string = '';
49-
private tokenUpdateInProgress: Boolean = false;
58+
private readonly tokenRequestTimeout = 10 * 1000;
59+
private readonly tokenExpirationTimeout = 6 * 60 * 60 * 1000;
60+
private tokenTimestamp: DateTime | null;
61+
private token: string = "";
62+
private tokenUpdatePromise: Promise<any> | null = null;
5063
private user: string;
5164
private password: string;
52-
private endpoint: string
53-
private sslCredentials: ISslCredentials | undefined
65+
private endpoint: string;
66+
private sslCredentials: ISslCredentials | undefined;
5467

5568
private readonly GrpcService = class extends GrpcService<Ydb.Auth.V1.AuthService> {
5669
constructor(endpoint: string, sslCredentials?: ISslCredentials) {
57-
super(endpoint, 'Ydb.Auth.V1.AuthService', Ydb.Auth.V1.AuthService, sslCredentials)
70+
super(endpoint, "Ydb.Auth.V1.AuthService", Ydb.Auth.V1.AuthService, sslCredentials);
5871
}
5972

6073
login(request: Ydb.Auth.ILoginRequest) {
61-
return this.api.login(request)
74+
return this.api.login(request);
6275
}
6376

64-
destroy() { this.api.end() }
65-
66-
}
77+
destroy() {
78+
this.api.end();
79+
}
80+
};
6781

68-
constructor(user: string, password: string, endpoint: string, sslCredentials?: ISslCredentials) {
82+
constructor(
83+
user: string,
84+
password: string,
85+
endpoint: string,
86+
options?: StaticCredentialsAuthOptions
87+
) {
88+
this.tokenTimestamp = null;
6989
this.user = user;
7090
this.password = password;
7191
this.endpoint = endpoint;
72-
this.sslCredentials = sslCredentials
73-
this.tokenTimestamp = null;
92+
this.sslCredentials = options?.sslCredentials;
93+
if (options?.tokenRequestTimeout) this.tokenRequestTimeout = options.tokenRequestTimeout;
94+
if (options?.tokenExpirationTimeout) this.tokenExpirationTimeout = options.tokenExpirationTimeout;
7495
}
7596

7697
private get expired() {
@@ -80,45 +101,38 @@ export class StaticCredentialsAuthService implements IAuthService {
80101
}
81102

82103
private async sendTokenRequest(): Promise<AuthServiceResult> {
83-
let runtimeAuthService = new this.GrpcService(this.endpoint, this.sslCredentials)
104+
let runtimeAuthService = new this.GrpcService(this.endpoint, this.sslCredentials);
84105
try {
85106
const tokenPromise = runtimeAuthService.login({
86107
user: this.user,
87-
password: this.password
108+
password: this.password,
88109
});
89110
const response = await withTimeout<Ydb.Auth.LoginResponse>(tokenPromise, this.tokenRequestTimeout);
90111
const result = AuthServiceResult.decode(getOperationPayload(response));
91-
runtimeAuthService.destroy()
92-
return result
112+
runtimeAuthService.destroy();
113+
return result;
93114
} catch (error) {
94-
throw new Error("Can't login by user and password " + String(error))
115+
throw new Error("Can't login by user and password " + String(error));
95116
}
96-
97117
}
98118

99119
private async updateToken() {
100-
this.tokenUpdateInProgress = true
101-
const {token} = await this.sendTokenRequest();
120+
const { token } = await this.sendTokenRequest();
102121
if (token) {
103122
this.token = token;
104123
this.tokenTimestamp = DateTime.utc();
105-
this.tokenUpdateInProgress = false
106124
} else {
107-
this.tokenUpdateInProgress = false
108-
throw new Error('Received empty token from credentials!');
125+
throw new Error("Received empty token from credentials!");
109126
}
110127
}
111128

112-
private async waitUntilTokenUpdated() {
113-
while (this.tokenUpdateInProgress) { await sleep(1) }
114-
return
115-
}
116-
117129
public async getAuthMetadata(): Promise<grpc.Metadata> {
118-
if (this.expired) {
119-
// block updateToken calls while token updating
120-
if(this.tokenUpdateInProgress) await this.waitUntilTokenUpdated()
121-
else await this.updateToken();
130+
if (this.expired || this.tokenUpdatePromise) {
131+
if (!this.tokenUpdatePromise) {
132+
this.tokenUpdatePromise = this.updateToken();
133+
}
134+
await this.tokenUpdatePromise;
135+
this.tokenUpdatePromise = null;
122136
}
123137
return makeCredentialsMetadata(this.token);
124138
}

0 commit comments

Comments
 (0)