Skip to content

Commit

Permalink
Convert Resource.do to use promises
Browse files Browse the repository at this point in the history
Resolves #1528.
  • Loading branch information
lawrence-forooghian committed Jan 15, 2024
1 parent 3c5e282 commit 4dbcbd0
Showing 1 changed file with 113 additions and 124 deletions.
237 changes: 113 additions & 124 deletions src/common/lib/client/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,83 +7,68 @@ import ErrorInfo, { IPartialErrorInfo, PartialErrorInfo } from '../types/errorin
import BaseClient from './baseclient';
import { MsgPack } from 'common/types/msgpack';
import { RequestCallbackHeaders } from 'common/types/http';
import { ErrnoException } from '../../types/http';

function withAuthDetails(
async function withAuthDetails<T>(
client: BaseClient,
headers: RequestCallbackHeaders | undefined,
params: Record<string, any>,
errCallback: Function,
opCallback: Function
) {
): Promise<ResourceResult<T>> {
if (client.http.supportsAuthHeaders) {
Utils.whenPromiseSettles(
client.auth.getAuthHeaders(),
function (err: Error | null, authHeaders?: Record<string, string>) {
if (err) errCallback(err);
else opCallback(Utils.mixin(authHeaders!, headers), params);
}
);
const authHeaders = await client.auth.getAuthHeaders();
return opCallback(Utils.mixin(authHeaders!, headers), params);
} else {
Utils.whenPromiseSettles(
client.auth.getAuthParams(),
function (err: Error | null, authParams?: Record<string, string>) {
if (err) errCallback(err);
else opCallback(headers, Utils.mixin(authParams!, params));
}
);
const authParams = await client.auth.getAuthParams();
return opCallback(headers, Utils.mixin(authParams!, params));
}
}

function unenvelope<T>(
callback: ResourceCallback<T>,
result: ResourceResult<T>,
MsgPack: MsgPack | null,
format: Utils.Format | null
): ResourceCallback<T> {
return (err, body, outerHeaders, unpacked, outerStatusCode) => {
if (err && !body) {
callback(err);
return;
}
): ResourceResult<T> {
if (result.err && !result.body) {
return { err: result.err };
}

if (!unpacked) {
try {
body = Utils.decodeBody(body, MsgPack, format);
} catch (e) {
if (Utils.isErrorInfoOrPartialErrorInfo(e)) {
callback(e);
} else {
callback(new PartialErrorInfo(Utils.inspectError(e), null));
}
return;
let body = result.body;

if (!result.unpacked) {
try {
body = Utils.decodeBody(body, MsgPack, format);
} catch (e) {
if (Utils.isErrorInfoOrPartialErrorInfo(e)) {
return { err: e };
} else {
return { err: new PartialErrorInfo(Utils.inspectError(e), null) };
}
}
}

if (!body) {
callback(new PartialErrorInfo('unenvelope(): Response body is missing', null));
return;
}
if (!body) {
return { err: new PartialErrorInfo('unenvelope(): Response body is missing', null) };
}

const { statusCode: wrappedStatusCode, response, headers: wrappedHeaders } = body as Record<string, any>;
const { statusCode: wrappedStatusCode, response, headers: wrappedHeaders } = body as Record<string, any>;

if (wrappedStatusCode === undefined) {
/* Envelope already unwrapped by the transport */
callback(err, body, outerHeaders, true, outerStatusCode);
return;
}
if (wrappedStatusCode === undefined) {
/* Envelope already unwrapped by the transport */
return { ...result, body, unpacked: true };
}

if (wrappedStatusCode < 200 || wrappedStatusCode >= 300) {
/* handle wrapped errors */
let wrappedErr = (response && response.error) || err;
if (!wrappedErr) {
wrappedErr = new Error('Error in unenveloping ' + body);
wrappedErr.statusCode = wrappedStatusCode;
}
callback(wrappedErr, response, wrappedHeaders, true, wrappedStatusCode);
return;
if (wrappedStatusCode < 200 || wrappedStatusCode >= 300) {
/* handle wrapped errors */
let wrappedErr = (response && response.error) || result.err;
if (!wrappedErr) {
wrappedErr = new Error('Error in unenveloping ' + body);
wrappedErr.statusCode = wrappedStatusCode;
}
return { err: wrappedErr, body: response, headers: wrappedHeaders, unpacked: true, statusCode: wrappedStatusCode };
}

callback(err, response, wrappedHeaders, true, wrappedStatusCode);
};
return { err: result.err, body: response, headers: wrappedHeaders, unpacked: true, statusCode: wrappedStatusCode };
}

function paramString(params: Record<string, any>) {
Expand All @@ -100,37 +85,27 @@ function urlFromPathAndParams(path: string, params: Record<string, any>) {
return path + (params ? '?' : '') + paramString(params);
}

function logResponseHandler<T>(
callback: ResourceCallback<T>,
method: HttpMethods,
path: string,
params: Record<string, string>
): ResourceCallback {
return (err, body, headers, unpacked, statusCode) => {
if (err) {
Logger.logAction(
Logger.LOG_MICRO,
'Resource.' + method + '()',
'Received Error; ' + urlFromPathAndParams(path, params) + '; Error: ' + Utils.inspectError(err)
);
} else {
Logger.logAction(
Logger.LOG_MICRO,
'Resource.' + method + '()',
'Received; ' +
urlFromPathAndParams(path, params) +
'; Headers: ' +
paramString(headers as Record<string, any>) +
'; StatusCode: ' +
statusCode +
'; Body: ' +
(Platform.BufferUtils.isBuffer(body) ? body.toString() : body)
);
}
if (callback) {
callback(err, body as T, headers, unpacked, statusCode);
}
};
function logResult<T>(result: ResourceResult<T>, method: HttpMethods, path: string, params: Record<string, string>) {
if (result.err) {
Logger.logAction(
Logger.LOG_MICRO,
'Resource.' + method + '()',
'Received Error; ' + urlFromPathAndParams(path, params) + '; Error: ' + Utils.inspectError(result.err)
);
} else {
Logger.logAction(
Logger.LOG_MICRO,
'Resource.' + method + '()',
'Received; ' +
urlFromPathAndParams(path, params) +
'; Headers: ' +
paramString(result.headers as Record<string, any>) +
'; StatusCode: ' +
result.statusCode +
'; Body: ' +
(Platform.BufferUtils.isBuffer(result.body) ? result.body.toString() : result.body)
);
}
}

export type ResourceCallback<T = unknown> = (
Expand Down Expand Up @@ -335,32 +310,15 @@ class Resource {
envelope: Utils.Format | null,
throwError: boolean
): Promise<ResourceResponse<T> | ResourceResult<T>> {
let callback: ResourceCallback<T>;

const promise = new Promise<ResourceResponse<T> | ResourceResult<T>>((resolve, reject) => {
callback = (err, body, headers, unpacked, statusCode) => {
if (throwError) {
if (err) {
reject(err);
} else {
resolve({ body, headers, unpacked, statusCode });
}
} else {
resolve({ err, body, headers, unpacked, statusCode });
}
};
});

if (Logger.shouldLog(Logger.LOG_MICRO)) {
callback = logResponseHandler(callback!, method, path, params);
}

if (envelope) {
callback = unenvelope(callback!, client._MsgPack, envelope);
(params = params || {})['envelope'] = envelope;
}

function doRequest(this: any, headers: Record<string, string>, params: Record<string, any>) {
async function doRequest(
this: any,
headers: Record<string, string>,
params: Record<string, any>
): Promise<ResourceResult<T>> {
if (Logger.shouldLog(Logger.LOG_MICRO)) {
Logger.logAction(
Logger.LOG_MICRO,
Expand Down Expand Up @@ -392,26 +350,57 @@ class Resource {
);
}

client.http.do(method, path, headers, body, params, function (err, res, resHeaders, unpacked, statusCode) {
if (err && Auth.isTokenErr(err as ErrorInfo)) {
/* token has expired, so get a new one */
Utils.whenPromiseSettles(client.auth.authorize(null, null), function (err: ErrorInfo | null) {
if (err) {
callback(err);
return;
}
/* retry ... */
withAuthDetails(client, headers, params, callback, doRequest);
});
return;
}
callback(err as ErrorInfo, res as T | undefined, resHeaders, unpacked, statusCode);
type HttpResult = {
error?: ErrnoException | IPartialErrorInfo | null;
body?: unknown;
headers?: RequestCallbackHeaders;
unpacked?: boolean;
statusCode?: number;
};

const httpResult = await new Promise<HttpResult>((resolve) => {
client.http.do(method, path, headers, body, params, function (error, body, headers, unpacked, statusCode) {
resolve({ error, body, headers, unpacked, statusCode });
});
});

if (httpResult.error && Auth.isTokenErr(httpResult.error as ErrorInfo)) {
/* token has expired, so get a new one */
await client.auth.authorize(null, null);
/* retry ... */
return withAuthDetails(client, headers, params, doRequest);
}

return {
err: httpResult.error as ErrorInfo,
body: httpResult.body as T | undefined,
headers: httpResult.headers,
unpacked: httpResult.unpacked,
statusCode: httpResult.statusCode,
};
}

let result = await withAuthDetails<T>(client, headers, params, doRequest);

if (envelope) {
result = unenvelope(result, client._MsgPack, envelope);
}

withAuthDetails(client, headers, params, callback!, doRequest);
if (Logger.shouldLog(Logger.LOG_MICRO)) {
logResult(result, method, path, params);
}

if (throwError) {
if (result.err) {
throw result.err;
} else {
const response: Omit<ResourceResult<T>, 'err'> & Pick<Partial<ResourceResult<T>>, 'err'> = { ...result };
delete response.err;
return response;
}
}

return promise;
return result;
}
}

Expand Down

0 comments on commit 4dbcbd0

Please sign in to comment.