From 4dbcbd05921f24ba5d387df62664a880004b4f92 Mon Sep 17 00:00:00 2001 From: Lawrence Forooghian Date: Fri, 5 Jan 2024 16:53:53 +0000 Subject: [PATCH] Convert Resource.do to use promises Resolves #1528. --- src/common/lib/client/resource.ts | 237 ++++++++++++++---------------- 1 file changed, 113 insertions(+), 124 deletions(-) diff --git a/src/common/lib/client/resource.ts b/src/common/lib/client/resource.ts index b32be834c8..71ed587579 100644 --- a/src/common/lib/client/resource.ts +++ b/src/common/lib/client/resource.ts @@ -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( client: BaseClient, headers: RequestCallbackHeaders | undefined, params: Record, - errCallback: Function, opCallback: Function -) { +): Promise> { if (client.http.supportsAuthHeaders) { - Utils.whenPromiseSettles( - client.auth.getAuthHeaders(), - function (err: Error | null, authHeaders?: Record) { - 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) { - 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( - callback: ResourceCallback, + result: ResourceResult, MsgPack: MsgPack | null, format: Utils.Format | null -): ResourceCallback { - return (err, body, outerHeaders, unpacked, outerStatusCode) => { - if (err && !body) { - callback(err); - return; - } +): ResourceResult { + 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; + const { statusCode: wrappedStatusCode, response, headers: wrappedHeaders } = body as Record; - 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) { @@ -100,37 +85,27 @@ function urlFromPathAndParams(path: string, params: Record) { return path + (params ? '?' : '') + paramString(params); } -function logResponseHandler( - callback: ResourceCallback, - method: HttpMethods, - path: string, - params: Record -): 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) + - '; StatusCode: ' + - statusCode + - '; Body: ' + - (Platform.BufferUtils.isBuffer(body) ? body.toString() : body) - ); - } - if (callback) { - callback(err, body as T, headers, unpacked, statusCode); - } - }; +function logResult(result: ResourceResult, method: HttpMethods, path: string, params: Record) { + 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) + + '; StatusCode: ' + + result.statusCode + + '; Body: ' + + (Platform.BufferUtils.isBuffer(result.body) ? result.body.toString() : result.body) + ); + } } export type ResourceCallback = ( @@ -335,32 +310,15 @@ class Resource { envelope: Utils.Format | null, throwError: boolean ): Promise | ResourceResult> { - let callback: ResourceCallback; - - const promise = new Promise | ResourceResult>((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, params: Record) { + async function doRequest( + this: any, + headers: Record, + params: Record + ): Promise> { if (Logger.shouldLog(Logger.LOG_MICRO)) { Logger.logAction( Logger.LOG_MICRO, @@ -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((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(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, 'err'> & Pick>, 'err'> = { ...result }; + delete response.err; + return response; + } + } - return promise; + return result; } }