1
- import { AxiosInstance } from 'axios' ;
1
+ import axios , { AxiosInstance } from 'axios' ;
2
2
import { plainToClass } from 'class-transformer' ;
3
+ import { decode } from 'jsonwebtoken' ;
3
4
4
5
import { RdiClient } from 'src/modules/rdi/client/rdi.client' ;
5
- import { RdiUrl } from 'src/modules/rdi/constants' ;
6
- import { RdiDryRunJobDto , RdiDryRunJobResponseDto , RdiTestConnectionResult } from 'src/modules/rdi/dto' ;
7
- import { RdiPipelineDeployFailedException } from 'src/modules/rdi/exceptions' ;
8
6
import {
9
- RdiJob ,
7
+ RdiUrl ,
8
+ RDI_TIMEOUT ,
9
+ TOKEN_TRESHOLD ,
10
+ POLLING_INTERVAL ,
11
+ MAX_POLLING_TIME ,
12
+ } from 'src/modules/rdi/constants' ;
13
+ import {
14
+ RdiDryRunJobDto ,
15
+ RdiDryRunJobResponseDto ,
16
+ RdiTestConnectionsResponseDto ,
17
+ } from 'src/modules/rdi/dto' ;
18
+ import {
19
+ RdiPipelineDeployFailedException ,
20
+ RdiPipelineInternalServerErrorException ,
21
+ wrapRdiPipelineError ,
22
+ } from 'src/modules/rdi/exceptions' ;
23
+ import {
10
24
RdiPipeline ,
11
25
RdiStatisticsResult ,
12
- RdiType ,
13
- RdiDryRunJobResult ,
14
- RdiDyRunJobStatus ,
15
26
RdiStatisticsStatus ,
16
- RdiStatisticsData ,
27
+ RdiStatisticsData , RdiClientMetadata , Rdi ,
17
28
} from 'src/modules/rdi/models' ;
18
29
import { convertKeysToCamelCase } from 'src/utils/base.helper' ;
30
+ import { RdiPipelineTimeoutException } from 'src/modules/rdi/exceptions/rdi-pipeline.timeout-error.exception' ;
19
31
20
32
const RDI_DEPLOY_FAILED_STATUS = 'failed' ;
21
33
22
34
export class ApiRdiClient extends RdiClient {
23
- public type = RdiType . API ;
24
-
25
35
protected readonly client : AxiosInstance ;
26
36
27
- async isConnected ( ) : Promise < boolean > {
28
- // todo: check if needed and possible
29
- return true ;
37
+ private auth : { jwt : string , exp : number } ;
38
+
39
+ constructor ( clientMetadata : RdiClientMetadata , rdi : Rdi ) {
40
+ super ( clientMetadata , rdi ) ;
41
+ this . client = axios . create ( {
42
+ baseURL : rdi . url ,
43
+ timeout : RDI_TIMEOUT ,
44
+ } ) ;
30
45
}
31
46
32
47
async getSchema ( ) : Promise < object > {
33
- const response = await this . client . get ( RdiUrl . GetSchema ) ;
34
- return response . data ;
48
+ try {
49
+ const response = await this . client . get ( RdiUrl . GetSchema ) ;
50
+ return response . data ;
51
+ } catch ( e ) {
52
+ throw wrapRdiPipelineError ( e ) ;
53
+ }
35
54
}
36
55
37
56
async getPipeline ( ) : Promise < RdiPipeline > {
38
- const response = await this . client . get ( RdiUrl . GetPipeline ) ;
39
- return response . data ;
57
+ try {
58
+ const response = await this . client . get ( RdiUrl . GetPipeline ) ;
59
+ return response . data ;
60
+ } catch ( e ) {
61
+ throw wrapRdiPipelineError ( e ) ;
62
+ }
40
63
}
41
64
42
65
async getStrategies ( ) : Promise < object > {
43
- const response = await this . client . get ( RdiUrl . GetStrategies ) ;
44
- return response . data ;
66
+ try {
67
+ const response = await this . client . get ( RdiUrl . GetStrategies ) ;
68
+ return response . data ;
69
+ } catch ( e ) {
70
+ throw wrapRdiPipelineError ( e ) ;
71
+ }
45
72
}
46
73
47
74
async getTemplate ( options : object ) : Promise < object > {
48
- const response = await this . client . get ( RdiUrl . GetTemplate , { params : options } ) ;
49
- return response . data ;
75
+ try {
76
+ const response = await this . client . get ( RdiUrl . GetTemplate , { params : options } ) ;
77
+ return response . data ;
78
+ } catch ( error ) {
79
+ throw wrapRdiPipelineError ( error ) ;
80
+ }
50
81
}
51
82
52
83
async deploy ( pipeline : RdiPipeline ) : Promise < void > {
53
- const response = await this . client . post ( RdiUrl . Deploy , { ...pipeline } ) ;
84
+ let response ;
85
+ try {
86
+ response = await this . client . post ( RdiUrl . Deploy , { ...pipeline } ) ;
87
+ } catch ( error ) {
88
+ throw wrapRdiPipelineError ( error , error . response . data . message ) ;
89
+ }
54
90
55
91
if ( response . data ?. status === RDI_DEPLOY_FAILED_STATUS ) {
56
92
throw new RdiPipelineDeployFailedException ( undefined , { error : response . data ?. error } ) ;
57
93
}
58
94
}
59
95
60
- async deployJob ( job : RdiJob ) : Promise < RdiJob > {
61
- return null ;
62
- }
63
-
64
96
async dryRunJob ( data : RdiDryRunJobDto ) : Promise < RdiDryRunJobResponseDto > {
65
- const response = await this . client . post ( RdiUrl . DryRunJob , data ) ;
66
- return response . data ;
97
+ try {
98
+ const response = await this . client . post ( RdiUrl . DryRunJob , data ) ;
99
+ return response . data ;
100
+ } catch ( e ) {
101
+ throw wrapRdiPipelineError ( e ) ;
102
+ }
67
103
}
68
104
69
- async testConnections ( config : string ) : Promise < RdiTestConnectionResult > {
70
- const response = await this . client . post ( RdiUrl . TestConnections , config ) ;
105
+ async testConnections ( config : string ) : Promise < RdiTestConnectionsResponseDto > {
106
+ try {
107
+ const response = await this . client . post ( RdiUrl . TestConnections , config ) ;
108
+
109
+ const actionId = response . data . action_id ;
71
110
72
- return response . data ;
111
+ return this . pollActionStatus ( actionId ) ;
112
+ } catch ( e ) {
113
+ throw wrapRdiPipelineError ( e ) ;
114
+ }
73
115
}
74
116
75
117
async getPipelineStatus ( ) : Promise < any > {
76
- const response = await this . client . get ( RdiUrl . GetPipelineStatus ) ;
118
+ try {
119
+ const response = await this . client . get ( RdiUrl . GetPipelineStatus ) ;
77
120
78
- return response . data ;
121
+ return response . data ;
122
+ } catch ( e ) {
123
+ throw wrapRdiPipelineError ( e ) ;
124
+ }
79
125
}
80
126
81
127
async getStatistics ( sections ?: string ) : Promise < RdiStatisticsResult > {
@@ -91,11 +137,61 @@ export class ApiRdiClient extends RdiClient {
91
137
}
92
138
93
139
async getJobFunctions ( ) : Promise < object > {
94
- const response = await this . client . post ( RdiUrl . JobFunctions ) ;
95
- return response . data ;
140
+ try {
141
+ const response = await this . client . post ( RdiUrl . JobFunctions ) ;
142
+ return response . data ;
143
+ } catch ( e ) {
144
+ throw wrapRdiPipelineError ( e ) ;
145
+ }
96
146
}
97
147
98
- async disconnect ( ) : Promise < void > {
99
- return undefined ;
148
+ async connect ( ) : Promise < void > {
149
+ try {
150
+ const response = await this . client . post (
151
+ RdiUrl . Login ,
152
+ { username : this . rdi . username , password : this . rdi . password } ,
153
+ ) ;
154
+ const accessToken = response . data . access_token ;
155
+ const decodedJwt = decode ( accessToken ) ;
156
+
157
+ this . auth = { jwt : accessToken , exp : decodedJwt . exp } ;
158
+ this . client . defaults . headers . common [ 'Authorization' ] = `Bearer ${ accessToken } ` ;
159
+ } catch ( e ) {
160
+ throw wrapRdiPipelineError ( e ) ;
161
+ }
162
+ }
163
+
164
+ async ensureAuth ( ) : Promise < void > {
165
+ const expiresIn = this . auth . exp * 1_000 - Date . now ( ) ;
166
+
167
+ if ( expiresIn < TOKEN_TRESHOLD ) {
168
+ await this . connect ( ) ;
169
+ }
170
+ }
171
+
172
+ private async pollActionStatus ( actionId : string ) : Promise < any > {
173
+ const startTime = Date . now ( ) ;
174
+ while ( true ) {
175
+ if ( Date . now ( ) - startTime > MAX_POLLING_TIME ) {
176
+ throw new RdiPipelineTimeoutException ( ) ;
177
+ }
178
+
179
+ try {
180
+ const response = await this . client . get ( `${ RdiUrl . Action } /${ actionId } ` ) ;
181
+ const { status, data, error } = response . data ;
182
+
183
+ if ( status === 'failed' ) {
184
+ throw new RdiPipelineInternalServerErrorException ( error ) ;
185
+ }
186
+
187
+ if ( status === 'completed' ) {
188
+ return data ;
189
+ }
190
+ } catch ( e ) {
191
+ throw wrapRdiPipelineError ( e ) ;
192
+ }
193
+
194
+ await new Promise ( ( resolve ) => setTimeout ( resolve , POLLING_INTERVAL ) ) ;
195
+ }
100
196
}
101
197
}
0 commit comments