Skip to content

Commit 823ec6e

Browse files
committed
add progress event and session proxy
1 parent f444170 commit 823ec6e

File tree

2 files changed

+274
-41
lines changed

2 files changed

+274
-41
lines changed

src/proxy.ts

Lines changed: 145 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,67 @@
1+
import { AWSError, CredentialProviderChain, Request, Service } from 'aws-sdk';
12
import { ConfigurationOptions } from 'aws-sdk/lib/config';
2-
import { CredentialsOptions } from 'aws-sdk/lib/credentials';
3+
import { Credentials, CredentialsOptions } from 'aws-sdk/lib/credentials';
4+
import { ServiceConfigurationOptions } from 'aws-sdk/lib/service';
35
import * as Aws from 'aws-sdk/clients/all';
46
import { NextToken } from 'aws-sdk/clients/cloudformation';
5-
import { allArgsConstructor, builder } from 'tombok';
7+
import { allArgsConstructor, builder, IBuilder} from 'tombok';
68

79
import {
10+
BaseResourceHandlerRequest,
811
BaseResourceModel,
12+
Callable,
913
HandlerErrorCode,
14+
Newable,
1015
OperationStatus,
1116
} from './interface';
1217

1318

1419
type ClientMap = typeof Aws;
1520
type Client = InstanceType<ClientMap[keyof ClientMap]>;
21+
type ClientType<T = ClientMap> = T[keyof T] extends Service ? never : T[keyof T];
22+
23+
// type Async<T> = T extends AsyncGenerator<infer R> ? AsyncGenerator<R> : T extends Generator<infer R> ? AsyncGenerator<R> : T extends Promise<infer R> ? Promise<R> : Promise<T>;
24+
25+
// type ProxyModule<M> = {
26+
// [K in keyof M]: M[K] extends (...args: infer A) => infer R ? (...args: A) => Async<R> : never;
27+
// };
28+
29+
// type Callback<D> = (err: AWSError | undefined, data: D) => void;
30+
31+
// interface AWSRequestMethod<P, D> {
32+
// (params: P, callback?: Callback<D>): Request<D, AWSError>;
33+
// (callback?: Callback<D>): Request<D, AWSError>;
34+
// }
35+
36+
// export type CapturedAWSClient<C extends AWSClient> = {
37+
// [K in keyof C]: C[K] extends AWSRequestMethod<infer P, infer D>
38+
// ? AWSRequestMethod<P, D>
39+
// : C[K];
40+
// };
41+
42+
// export type CapturedAWS<T = ClientMap> = {
43+
// [K in keyof T]: T[K] extends AWSClient ? CapturedAWSClient<T[K]> : T[K];
44+
// };
45+
46+
// export function captureAWSClient<C extends AWSClient>(
47+
// client: C
48+
// ): CapturedAWSClient<C>;
49+
// export function captureAWS(awssdk: ClientMap): CapturedAWS;
50+
51+
// type Clients = { [K in keyof AwsClientMap]?: AwsClientMap[K] extends Service ? never : AwsClientMap[K] };
52+
53+
class SessionCredentialsProvider {
54+
55+
private awsSessionCredentials: Credentials;
56+
57+
public get(): Credentials {
58+
return this.awsSessionCredentials;
59+
}
60+
61+
public setCredentials(credentials: CredentialsOptions): void {
62+
this.awsSessionCredentials = new Credentials(credentials);
63+
}
64+
}
1665

1766
export class SessionProxy {
1867

@@ -26,7 +75,37 @@ export class SessionProxy {
2675
...this.options,
2776
...options,
2877
});
29-
return service;
78+
return service; //this.promisifyReturn(service);
79+
}
80+
81+
// private createService<T extends ClientMap, K extends keyof T>(client: Newable<T[K]>, options: ServiceConfigurationOptions): InstanceType<ClientType> {
82+
// // const clients: { [K in keyof ClientMap]?: ClientMap[K] } = Aws;
83+
// // const name: T;
84+
85+
// return new client();
86+
// }
87+
88+
// Wraps an Aws endpoint instance so that you don’t always have to chain `.promise()` onto every function
89+
public promisifyReturn(obj: any): ProxyConstructor {
90+
return new Proxy(obj, {
91+
get(target, propertyKey) {
92+
const property = target[propertyKey];
93+
94+
if (typeof property === "function") {
95+
return function (...args: any[]) {
96+
const result = property.apply(this, args);
97+
98+
if (result instanceof Request) {
99+
return result.promise();
100+
} else {
101+
return result;
102+
}
103+
}
104+
} else {
105+
return property;
106+
}
107+
},
108+
});
30109
}
31110

32111
public static getSession(credentials?: CredentialsOptions, region?: string): SessionProxy | null {
@@ -42,70 +121,100 @@ export class SessionProxy {
42121

43122
@allArgsConstructor
44123
@builder
45-
export class ProgressEvent<R = BaseResourceModel, T = Map<string, any>> {
124+
export class ProgressEvent<R extends BaseResourceModel = BaseResourceModel, T = Map<string, any>> {
46125
/**
47126
* The status indicates whether the handler has reached a terminal state or is
48127
* still computing and requires more time to complete
49128
*/
50-
private status: OperationStatus;
129+
public status: OperationStatus;
51130

52131
/**
53132
* If OperationStatus is FAILED or IN_PROGRESS, an error code should be provided
54133
*/
55-
private errorCode?: HandlerErrorCode;
134+
public errorCode?: HandlerErrorCode;
56135

57136
/**
58137
* The handler can (and should) specify a contextual information message which
59138
* can be shown to callers to indicate the nature of a progress transition or
60139
* callback delay; for example a message indicating "propagating to edge"
61140
*/
62-
private message: string = '';
141+
public message: string = '';
63142

64143
/**
65144
* The callback context is an arbitrary datum which the handler can return in an
66145
* IN_PROGRESS event to allow the passing through of additional state or
67146
* metadata between subsequent retries; for example to pass through a Resource
68147
* identifier which can be used to continue polling for stabilization
69148
*/
70-
private callbackContext?: T;
149+
public callbackContext?: T;
71150

72151
/**
73152
* A callback will be scheduled with an initial delay of no less than the number
74153
* of seconds specified in the progress event.
75154
*/
76-
private callbackDelaySeconds: number;
155+
public callbackDelaySeconds: number;
77156

78157
/**
79158
* The output resource instance populated by a READ for synchronous results and
80159
* by CREATE/UPDATE/DELETE for final response validation/confirmation
81160
*/
82-
private resourceModel?: R;
161+
public resourceModel?: R;
83162

84163
/**
85164
* The output resource instances populated by a LIST for synchronous results
86165
*/
87-
private resourceModels?: Array<R>;
166+
public resourceModels?: Array<R>;
88167

89168
/**
90169
* The token used to request additional pages of resources for a LIST operation
91170
*/
92-
private nextToken?: NextToken;
171+
public nextToken?: NextToken;
172+
173+
// TODO: remove workaround when decorator mutation implemented: https://github.com/microsoft/TypeScript/issues/4881
174+
constructor(...args: any[]) {}
175+
public static builder(template?: Partial<ProgressEvent>): IBuilder<ProgressEvent> {return null}
93176

94177
public serialize(
95178
toTesponse: boolean = false, bearerToken?: string
179+
// ): Record<string, any> {
96180
): Map<string, any> {
97-
// to match Java serialization, which drops `null` values, and the
98-
// contract tests currently expect this also
99-
let ser: Map<string, any> = JSON.parse(JSON.stringify(this));
100-
101-
return ser;
181+
// To match Java serialization, which drops `null` values, and the
182+
// contract tests currently expect this also.
183+
const json: Map<string, any> = new Map<string, any>(Object.entries(this));//JSON.parse(JSON.stringify(this)));
184+
json.forEach((value: any, key: string) => {
185+
if (value == null) {
186+
json.delete(key);
187+
}
188+
});
189+
// Object.keys(json).forEach((key) => (json[key] == null) && delete json[key]);
190+
// Mutate to what's expected in the response.
191+
if (toTesponse) {
192+
json.set('bearerToken', bearerToken);
193+
json.set('operationStatus', json.get('status'));
194+
json.delete('status');
195+
if (this.resourceModel) {
196+
json.set('resourceModel', this.resourceModel.toObject());
197+
}
198+
if (this.resourceModels) {
199+
const models = this.resourceModels.map((resource: R) => resource.toObject());
200+
json.set('resourceModels', models);
201+
}
202+
json.delete('callbackDelaySeconds');
203+
if (json.has('callbackContext')) {
204+
json.delete('callbackContext');
205+
}
206+
if (this.errorCode) {
207+
json.set('errorCode', this.errorCode);
208+
}
209+
}
210+
return json;
211+
// return new Map(Object.entries(jsonData));
102212
}
103213

104214
/**
105-
* Convenience method for constructing a FAILED response
215+
* Convenience method for constructing FAILED response
106216
*/
107217
public static failed(errorCode: HandlerErrorCode, message: string): ProgressEvent {
108-
// @ts-ignore
109218
const event = ProgressEvent.builder()
110219
.status(OperationStatus.Failed)
111220
.errorCode(errorCode)
@@ -115,10 +224,9 @@ export class ProgressEvent<R = BaseResourceModel, T = Map<string, any>> {
115224
}
116225

117226
/**
118-
* Convenience method for constructing a IN_PROGRESS response
227+
* Convenience method for constructing IN_PROGRESS response
119228
*/
120229
public static progress(model: any, cxt: any): ProgressEvent {
121-
// @ts-ignore
122230
const event = ProgressEvent.builder()
123231
.callbackContext(cxt)
124232
.resourceModel(model)
@@ -137,15 +245,20 @@ export class ProgressEvent<R = BaseResourceModel, T = Map<string, any>> {
137245
*/
138246
@allArgsConstructor
139247
@builder
140-
export class ResourceHandlerRequest<T> {
141-
private clientRequestToken: string;
142-
private desiredResourceState: T;
143-
private previousResourceState: T;
144-
private desiredResourceTags: Map<string, string>;
145-
private systemTags: Map<string, string>;
146-
private awsAccountId: string;
147-
private awsPartition: string;
148-
private logicalResourceIdentifier: string;
149-
private nextToken: string;
150-
private region: string;
248+
export class ResourceHandlerRequest<T extends BaseResourceModel> extends BaseResourceHandlerRequest<T> {
249+
public clientRequestToken: string;
250+
public desiredResourceState: T;
251+
public previousResourceState: T;
252+
public desiredResourceTags: Map<string, string>;
253+
public systemTags: Map<string, string>;
254+
public awsAccountId: string;
255+
public awsPartition: string;
256+
public logicalResourceIdentifier: string;
257+
public nextToken: string;
258+
public region: string;
259+
260+
constructor(...args: any[]) {super()}
261+
public static builder(template?: Partial<ResourceHandlerRequest<any>>): IBuilder<ResourceHandlerRequest<any>> {
262+
return null
263+
}
151264
}

0 commit comments

Comments
 (0)