@milaboratories/pl-client 2.16.0 → 2.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.cjs +61 -0
- package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.cjs.map +1 -0
- package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.js +58 -0
- package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.js.map +1 -0
- package/dist/core/PromiseTracker.cjs +39 -0
- package/dist/core/PromiseTracker.cjs.map +1 -0
- package/dist/core/PromiseTracker.d.ts +14 -0
- package/dist/core/PromiseTracker.d.ts.map +1 -0
- package/dist/core/PromiseTracker.js +37 -0
- package/dist/core/PromiseTracker.js.map +1 -0
- package/dist/core/StatefulPromise.cjs +65 -0
- package/dist/core/StatefulPromise.cjs.map +1 -0
- package/dist/core/StatefulPromise.d.ts +39 -0
- package/dist/core/StatefulPromise.d.ts.map +1 -0
- package/dist/core/StatefulPromise.js +63 -0
- package/dist/core/StatefulPromise.js.map +1 -0
- package/dist/core/ll_transaction.cjs +3 -2
- package/dist/core/ll_transaction.cjs.map +1 -1
- package/dist/core/ll_transaction.d.ts.map +1 -1
- package/dist/core/ll_transaction.js +3 -2
- package/dist/core/ll_transaction.js.map +1 -1
- package/dist/core/transaction.cjs +577 -515
- package/dist/core/transaction.cjs.map +1 -1
- package/dist/core/transaction.d.ts +6 -4
- package/dist/core/transaction.d.ts.map +1 -1
- package/dist/core/transaction.js +578 -516
- package/dist/core/transaction.js.map +1 -1
- package/dist/test/tcp-proxy.cjs +129 -0
- package/dist/test/tcp-proxy.cjs.map +1 -0
- package/dist/test/tcp-proxy.d.ts +17 -0
- package/dist/test/tcp-proxy.d.ts.map +1 -0
- package/dist/test/tcp-proxy.js +107 -0
- package/dist/test/tcp-proxy.js.map +1 -0
- package/dist/test/test_config.cjs +54 -7
- package/dist/test/test_config.cjs.map +1 -1
- package/dist/test/test_config.d.ts +18 -2
- package/dist/test/test_config.d.ts.map +1 -1
- package/dist/test/test_config.js +54 -7
- package/dist/test/test_config.js.map +1 -1
- package/package.json +8 -9
- package/src/core/PromiseTracker.ts +39 -0
- package/src/core/StatefulPromise.ts +92 -0
- package/src/core/client.test.ts +1 -1
- package/src/core/config.test.ts +1 -1
- package/src/core/connectivity.test.ts +70 -0
- package/src/core/error.test.ts +1 -1
- package/src/core/ll_client.test.ts +1 -1
- package/src/core/ll_transaction.test.ts +1 -1
- package/src/core/ll_transaction.ts +3 -2
- package/src/core/transaction.test.ts +6 -1
- package/src/core/transaction.ts +91 -48
- package/src/core/types.test.ts +1 -1
- package/src/core/unauth_client.test.ts +1 -1
- package/src/helpers/rich_resource_types.test.ts +1 -1
- package/src/test/tcp-proxy.ts +126 -0
- package/src/test/test_config.test.ts +1 -1
- package/src/test/test_config.ts +82 -7
- package/src/util/util.test.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.js","sources":["../../src/core/transaction.ts"],"sourcesContent":["// TODO: fix this\n/* eslint-disable no-prototype-builtins */\nimport type {\n AnyResourceId,\n LocalResourceId,\n OptionalResourceId,\n BasicResourceData,\n FieldData,\n FieldType,\n ResourceData,\n ResourceId,\n ResourceType,\n FutureFieldType } from './types';\nimport {\n createLocalResourceId,\n ensureResourceIdNotNull,\n MaxTxId,\n isLocalResourceId,\n extractBasicResourceData,\n isNullResourceId,\n} from './types';\nimport type {\n ClientMessageRequest,\n LLPlTransaction,\n OneOfKind,\n ServerMessageResponse,\n} from './ll_transaction';\nimport { TxAPI_Open_Request_WritableTx } from '../proto/github.com/milaboratory/pl/plapi/plapiproto/api';\nimport type { NonUndefined } from 'utility-types';\nimport { toBytes } from '../util/util';\nimport { fieldTypeToProto, protoToField, protoToResource } from './type_conversion';\nimport { canonicalJsonBytes, canonicalJsonGzBytes, deepFreeze, notEmpty } from '@milaboratories/ts-helpers';\nimport { isNotFoundError } from './errors';\nimport type { FinalResourceDataPredicate } from './final';\nimport type { LRUCache } from 'lru-cache';\nimport type { ResourceDataCacheRecord } from './cache';\nimport type { TxStat } from './stat';\nimport { initialTxStatWithoutTime } from './stat';\nimport type { ErrorResourceData } from './error_resource';\nimport { ErrorResourceType } from './error_resource';\nimport { JsonGzObject, JsonObject } from '../helpers/pl';\n\n/** Reference to resource, used only within transaction */\nexport interface ResourceRef {\n /** Global resource id of newly created resources, become available only\n * after response for the corresponding creation request is received. */\n readonly globalId: Promise<ResourceId>;\n\n /** Transaction-local resource id is assigned right after resource creation\n * request is sent, and can be used right away */\n readonly localId: LocalResourceId;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValue {\n key: string;\n value: Uint8Array;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValueString {\n key: string;\n value: string;\n}\n\ninterface _FieldId<RId> {\n /** Parent resource id */\n resourceId: RId;\n /** Field name */\n fieldName: string;\n}\n\nexport type FieldId = _FieldId<ResourceId>;\nexport type FieldRef = _FieldId<ResourceRef>;\nexport type LocalFieldId = _FieldId<LocalResourceId>;\nexport type AnyFieldId = FieldId | LocalFieldId;\n\nexport type AnyResourceRef = ResourceRef | ResourceId;\nexport type AnyFieldRef = _FieldId<AnyResourceRef>; // FieldRef | FieldId\nexport type AnyRef = AnyResourceRef | AnyFieldRef;\n\nexport function isField(ref: AnyRef): ref is AnyFieldRef {\n return ref.hasOwnProperty('resourceId') && ref.hasOwnProperty('fieldName');\n}\n\nexport function isResource(ref: AnyRef): ref is AnyResourceRef {\n return (\n typeof ref === 'bigint' || (ref.hasOwnProperty('globalId') && ref.hasOwnProperty('localId'))\n );\n}\n\nexport function isResourceId(ref: AnyRef): ref is ResourceId {\n return typeof ref === 'bigint' && !isLocalResourceId(ref) && !isNullResourceId(ref);\n}\n\nexport function isFieldRef(ref: AnyFieldRef): ref is FieldRef {\n return isResourceRef(ref.resourceId);\n}\n\nexport function isResourceRef(ref: AnyResourceRef): ref is ResourceRef {\n return ref.hasOwnProperty('globalId') && ref.hasOwnProperty('localId');\n}\n\nexport function toFieldId(ref: AnyFieldRef): AnyFieldId {\n if (isFieldRef(ref)) return { resourceId: ref.resourceId.localId, fieldName: ref.fieldName };\n else return ref as FieldId;\n}\n\nexport async function toGlobalFieldId(ref: AnyFieldRef): Promise<FieldId> {\n if (isFieldRef(ref))\n return { resourceId: await ref.resourceId.globalId, fieldName: ref.fieldName };\n else return ref as FieldId;\n}\n\nexport function toResourceId(ref: AnyResourceRef): AnyResourceId {\n if (isResourceRef(ref)) return ref.localId;\n else return ref;\n}\n\nexport async function toGlobalResourceId(ref: AnyResourceRef): Promise<ResourceId> {\n if (isResourceRef(ref)) return await ref.globalId;\n else return ref;\n}\n\nexport function field(resourceId: AnyResourceRef, fieldName: string): AnyFieldRef {\n return { resourceId, fieldName };\n}\n\n/** If transaction commit failed due to write conflicts */\nexport class TxCommitConflict extends Error {\n name = 'TxCommitConflict';\n}\n\nasync function notFoundToUndefined<T>(cb: () => Promise<T>): Promise<T | undefined> {\n try {\n return await cb();\n } catch (e) {\n if (isNotFoundError(e)) return undefined;\n throw e;\n }\n}\n\n/**\n * Each platform transaction has 3 stages:\n * - initialization (txOpen message -> txInfo response)\n * - communication (create resources, fields, references and so on)\n * - finalization (txCommit or txDiscard message)\n *\n * This class encapsulates finalization stage and provides ready-to-communication transaction object.\n * */\nexport class PlTransaction {\n private readonly globalTxId: Promise<bigint>;\n private readonly localTxId: number = PlTransaction.nextLocalTxId();\n\n /** Used in caching */\n private readonly txOpenTimestamp = Date.now();\n\n private localResourceIdCounter = 0;\n\n /** Store logical tx open / closed state to prevent invalid sequence of requests.\n * True means output stream was completed.\n * Contract: there must be no async operations between setting this field to true and sending complete signal to stream. */\n private _completed = false;\n\n /** Void operation futures are placed into this pool, and corresponding method return immediately.\n * This is done to save number of round-trips. Next operation producing result will also await those\n * pending ops, to throw any pending errors. */\n private pendingVoidOps: Promise<void>[] = [];\n\n private globalTxIdWasAwaited: boolean = false;\n\n private readonly _startTime = Date.now();\n private readonly _stat = initialTxStatWithoutTime();\n public get stat(): TxStat {\n return {\n ...this._stat,\n timeMs: Date.now() - this._startTime,\n };\n }\n\n constructor(\n private readonly ll: LLPlTransaction,\n public readonly name: string,\n public readonly writable: boolean,\n private readonly _clientRoot: OptionalResourceId,\n private readonly finalPredicate: FinalResourceDataPredicate,\n private readonly sharedResourceDataCache: LRUCache<ResourceId, ResourceDataCacheRecord>,\n private readonly enableFormattedErrors: boolean = false,\n ) {\n // initiating transaction\n this.globalTxId = this.sendSingleAndParse(\n {\n oneofKind: 'txOpen',\n txOpen: {\n name,\n enableFormattedErrors,\n writable: writable\n ? TxAPI_Open_Request_WritableTx.WRITABLE\n : TxAPI_Open_Request_WritableTx.NOT_WRITABLE,\n },\n },\n (r) => notEmpty(r.txOpen.tx?.id),\n );\n\n // To avoid floating promise\n this.globalTxId.catch((err) => {\n if (!this.globalTxIdWasAwaited) {\n console.warn(err);\n }\n });\n\n // Adding stats\n this._stat.txCount++;\n }\n\n private async drainAndAwaitPendingOps(): Promise<void> {\n if (this.pendingVoidOps.length === 0) return;\n\n // drain pending operations into temp array\n const pending = this.pendingVoidOps;\n this.pendingVoidOps = [];\n // awaiting these pending operations first, to catch any errors\n await Promise.all(pending);\n }\n\n private async sendSingleAndParse<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => T,\n ): Promise<T> {\n // pushing operation packet to server\n const rawResponsePromise = this.ll.send(r, false);\n\n await this.drainAndAwaitPendingOps();\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n }\n\n private async sendMultiAndParse<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>[]) => T,\n ): Promise<T> {\n // pushing operation packet to server\n const rawResponsePromise = this.ll.send(r, true);\n\n await this.drainAndAwaitPendingOps();\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n }\n\n private async sendVoidSync<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): Promise<void> {\n await this.ll.send(r, false);\n }\n\n /** Requests sent with this method should never produce recoverable errors */\n private sendVoidAsync<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): void {\n this.pendingVoidOps.push(this.sendVoidSync(r));\n }\n\n private checkTxOpen() {\n if (this._completed) throw new Error('Transaction already closed');\n }\n\n public get completed() {\n return this._completed;\n }\n\n /** Commit & closes transaction. {@link TxCommitConflict} is thrown on\n * commit conflicts. */\n public async commit() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n if (!this.writable) {\n // no need to explicitly commit or reject read-only tx\n const completeResult = this.ll.complete();\n await this.drainAndAwaitPendingOps();\n await completeResult;\n await this.ll.await();\n } else {\n // @TODO, also floating promises\n const commitResponse = this.sendSingleAndParse(\n { oneofKind: 'txCommit', txCommit: {} },\n (r) => r.txCommit.success,\n );\n\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.ll.complete();\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n if (!(await commitResponse)) throw new TxCommitConflict();\n\n await completeResult;\n\n // await event-loop completion\n await this.ll.await();\n }\n }\n\n public async discard() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n const discardResponse = this.sendVoidSync({ oneofKind: 'txDiscard', txDiscard: {} });\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.ll.complete();\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n await discardResponse;\n await completeResult;\n await this.ll.await();\n }\n\n //\n // Main tx methods\n //\n\n public get clientRoot(): ResourceId {\n return ensureResourceIdNotNull(this._clientRoot);\n }\n\n //\n // Resources\n //\n\n public createSingleton(\n name: string,\n type: ResourceType,\n errorIfExists: boolean = false,\n ): ResourceRef {\n const localId = this.nextLocalResourceId(false);\n\n const globalId = this.sendSingleAndParse(\n {\n oneofKind: 'resourceCreateSingleton',\n resourceCreateSingleton: {\n type,\n id: localId,\n data: Buffer.from(name),\n errorIfExists,\n },\n },\n (r) => r.resourceCreateSingleton.resourceId as ResourceId,\n );\n\n return { globalId, localId };\n }\n\n public async getSingleton(name: string, loadFields: true): Promise<ResourceData>;\n public async getSingleton(name: string, loadFields: false): Promise<BasicResourceData>;\n public async getSingleton(\n name: string,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData> {\n return await this.sendSingleAndParse(\n {\n oneofKind: 'resourceGetSingleton',\n resourceGetSingleton: {\n data: Buffer.from(name),\n loadFields,\n },\n },\n (r) => protoToResource(notEmpty(r.resourceGetSingleton.resource)),\n );\n }\n\n private createResource<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>>(\n root: boolean,\n req: (localId: LocalResourceId) => OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => bigint,\n ): ResourceRef {\n const localId = this.nextLocalResourceId(root);\n\n const globalId = this.sendSingleAndParse(req(localId), (r) => parser(r) as ResourceId);\n\n return { globalId, localId };\n }\n\n public createRoot(type: ResourceType): ResourceRef {\n this._stat.rootsCreated++;\n return this.createResource(\n true,\n (localId) => ({ oneofKind: 'resourceCreateRoot', resourceCreateRoot: { type, id: localId } }),\n (r) => r.resourceCreateRoot.resourceId,\n );\n }\n\n public createStruct(type: ResourceType, data?: Uint8Array | string): ResourceRef {\n this._stat.structsCreated++;\n this._stat.structsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: 'resourceCreateStruct',\n resourceCreateStruct: {\n type,\n id: localId,\n data: data === undefined ? undefined : typeof data === 'string' ? Buffer.from(data) : data,\n },\n }),\n (r) => r.resourceCreateStruct.resourceId,\n );\n }\n\n public createEphemeral(type: ResourceType, data?: Uint8Array | string): ResourceRef {\n this._stat.ephemeralsCreated++;\n this._stat.ephemeralsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: 'resourceCreateEphemeral',\n resourceCreateEphemeral: {\n type,\n id: localId,\n data: data === undefined ? undefined : typeof data === 'string' ? Buffer.from(data) : data,\n },\n }),\n (r) => r.resourceCreateEphemeral.resourceId,\n );\n }\n\n public createValue(\n type: ResourceType,\n data: Uint8Array | string,\n errorIfExists: boolean = false,\n ): ResourceRef {\n this._stat.valuesCreated++;\n this._stat.valuesCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: 'resourceCreateValue',\n resourceCreateValue: {\n type,\n id: localId,\n data: typeof data === 'string' ? Buffer.from(data) : data,\n errorIfExists,\n },\n }),\n (r) => r.resourceCreateValue.resourceId,\n );\n }\n\n public createJsonValue(data: unknown): ResourceRef {\n const jsonData = canonicalJsonBytes(data);\n return this.createValue(JsonObject, jsonData, false);\n }\n\n public createJsonGzValue(data: unknown, minSizeToGzip: number | undefined = 16_384): ResourceRef {\n const { data: jsonData, isGzipped } = canonicalJsonGzBytes(data, minSizeToGzip);\n return this.createValue(isGzipped ? JsonGzObject : JsonObject, jsonData, false);\n }\n\n public createError(message: string): ResourceRef {\n return this.createValue(ErrorResourceType, JSON.stringify({ message } satisfies ErrorResourceData));\n }\n\n public setResourceName(name: string, rId: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: 'resourceNameSet',\n resourceNameSet: { resourceId: toResourceId(rId), name },\n });\n }\n\n public deleteResourceName(name: string): void {\n this.sendVoidAsync({ oneofKind: 'resourceNameDelete', resourceNameDelete: { name } });\n }\n\n public async getResourceByName(name: string): Promise<ResourceId> {\n return await this.sendSingleAndParse(\n { oneofKind: 'resourceNameGet', resourceNameGet: { name } },\n (r) => ensureResourceIdNotNull(r.resourceNameGet.resourceId as OptionalResourceId),\n );\n }\n\n public async checkResourceNameExists(name: string): Promise<boolean> {\n return await this.sendSingleAndParse(\n { oneofKind: 'resourceNameExists', resourceNameExists: { name } },\n (r) => r.resourceNameExists.exists,\n );\n }\n\n public removeResource(rId: ResourceId): void {\n this.sendVoidAsync({ oneofKind: 'resourceRemove', resourceRemove: { id: rId } });\n }\n\n public async resourceExists(rId: ResourceId): Promise<boolean> {\n return await this.sendSingleAndParse(\n { oneofKind: 'resourceExists', resourceExists: { resourceId: rId } },\n (r) => r.resourceExists.exists,\n );\n }\n\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: true): Promise<ResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: false): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean\n ): Promise<BasicResourceData | ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: true,\n ignoreCache: boolean\n ): Promise<ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: false,\n ignoreCache: boolean\n ): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean,\n ignoreCache: boolean\n ): Promise<BasicResourceData | ResourceData>;\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ignoreCache: boolean = false,\n ): Promise<BasicResourceData | ResourceData> {\n if (!ignoreCache && !isResourceRef(rId) && !isLocalResourceId(rId)) {\n // checking if we can return result from cache\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache && fromCache.cacheTxOpenTimestamp < this.txOpenTimestamp) {\n if (!loadFields) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n return fromCache.basicData;\n } else if (fromCache.data) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n this._stat.rGetDataCacheFields += fromCache.data.fields.length;\n return fromCache.data;\n }\n }\n }\n\n const result = await this.sendSingleAndParse(\n {\n oneofKind: 'resourceGet',\n resourceGet: { resourceId: toResourceId(rId), loadFields: loadFields },\n },\n (r) => protoToResource(notEmpty(r.resourceGet.resource)),\n );\n\n this._stat.rGetDataNetRequests++;\n this._stat.rGetDataNetBytes += result.data?.length ?? 0;\n this._stat.rGetDataNetFields += result.fields.length;\n\n // we will cache only final resource data states\n // caching result even if we were ignore the cache\n if (!isResourceRef(rId) && !isLocalResourceId(rId) && this.finalPredicate(result)) {\n deepFreeze(result);\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache) {\n if (loadFields && !fromCache.data) {\n fromCache.data = result;\n // updating timestamp becuse we updated the record\n fromCache.cacheTxOpenTimestamp = this.txOpenTimestamp;\n }\n } else {\n const basicData = extractBasicResourceData(result);\n deepFreeze(basicData);\n if (loadFields)\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: result,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n else\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: undefined,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n }\n }\n\n return result;\n }\n\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: true\n ): Promise<ResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: false\n ): Promise<BasicResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean\n ): Promise<BasicResourceData | ResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData | undefined> {\n // calling this mehtod will ignore cache, because user intention is to detect resource absence\n // which cache will prevent\n const result = await notFoundToUndefined(\n async () => await this.getResourceData(rId, loadFields, true),\n );\n\n // cleaning cache record if resorce was removed from the db\n if (result === undefined && !isResourceRef(rId) && !isLocalResourceId(rId))\n this.sharedResourceDataCache.delete(rId);\n\n return result;\n }\n\n /**\n * Inform platform that resource will not get any new input fields.\n * This is required, when client creates resource without schema and wants\n * controller to start calculations.\n * Most controllers will not start calculations even when all inputs\n * have their values, if inputs list is not locked.\n */\n public lockInputs(rId: AnyResourceRef): void {\n this._stat.inputsLocked++;\n this.sendVoidAsync({\n oneofKind: 'resourceLockInputs',\n resourceLockInputs: { resourceId: toResourceId(rId) },\n });\n }\n\n /**\n * Inform platform that resource will not get any new output fields.\n * This is required for resource to pass deduplication.\n */\n public lockOutputs(rId: AnyResourceRef): void {\n this._stat.outputsLocked++;\n this.sendVoidAsync({\n oneofKind: 'resourceLockOutputs',\n resourceLockOutputs: { resourceId: toResourceId(rId) },\n });\n }\n\n public lock(rID: AnyResourceRef): void {\n this.lockInputs(rID);\n this.lockOutputs(rID);\n }\n\n public setResourceError(rId: AnyResourceRef, ref: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: 'resourceSetError',\n resourceSetError: { resourceId: toResourceId(rId), errorResourceId: toResourceId(ref) },\n });\n }\n\n //\n // Fields\n //\n\n public createField(fId: AnyFieldRef, fieldType: FieldType, value?: AnyRef): void {\n this._stat.fieldsCreated++;\n this.sendVoidAsync({\n oneofKind: 'fieldCreate',\n fieldCreate: { type: fieldTypeToProto(fieldType), id: toFieldId(fId) },\n });\n if (value !== undefined) this.setField(fId, value);\n }\n\n public async fieldExists(fId: AnyFieldRef): Promise<boolean> {\n return await this.sendSingleAndParse(\n {\n oneofKind: 'fieldExists',\n fieldExists: { field: toFieldId(fId) },\n },\n (r) => r.fieldExists.exists,\n );\n }\n\n public setField(fId: AnyFieldRef, ref: AnyRef): void {\n this._stat.fieldsSet++;\n if (isResource(ref))\n this.sendVoidAsync({\n oneofKind: 'fieldSet',\n fieldSet: {\n field: toFieldId(fId),\n value: {\n resourceId: toResourceId(ref),\n fieldName: '', // default value, read as undefined\n },\n },\n });\n else\n this.sendVoidAsync({\n oneofKind: 'fieldSet',\n fieldSet: {\n field: toFieldId(fId),\n value: toFieldId(ref),\n },\n });\n }\n\n public setFieldError(fId: AnyFieldRef, ref: AnyResourceRef): void {\n this._stat.fieldsSet++;\n this.sendVoidAsync({\n oneofKind: 'fieldSetError',\n fieldSetError: { field: toFieldId(fId), errResourceId: toResourceId(ref) },\n });\n }\n\n public async getField(fId: AnyFieldRef): Promise<FieldData> {\n this._stat.fieldsGet++;\n return await this.sendSingleAndParse(\n { oneofKind: 'fieldGet', fieldGet: { field: toFieldId(fId) } },\n (r) => protoToField(notEmpty(r.fieldGet.field)),\n );\n }\n\n public async getFieldIfExists(fId: AnyFieldRef): Promise<FieldData | undefined> {\n return notFoundToUndefined(async () => await this.getField(fId));\n }\n\n public resetField(fId: AnyFieldRef): void {\n this.sendVoidAsync({ oneofKind: 'fieldReset', fieldReset: { field: toFieldId(fId) } });\n }\n\n public removeField(fId: AnyFieldRef): void {\n this.sendVoidAsync({ oneofKind: 'fieldRemove', fieldRemove: { field: toFieldId(fId) } });\n }\n\n //\n // KV\n //\n\n public async listKeyValues(rId: AnyResourceRef): Promise<KeyValue[]> {\n const result = await this.sendMultiAndParse(\n {\n oneofKind: 'resourceKeyValueList',\n resourceKeyValueList: { resourceId: toResourceId(rId), startFrom: '', limit: 0 },\n },\n (r) => r.map((e) => e.resourceKeyValueList.record!),\n );\n\n this._stat.kvListRequests++;\n this._stat.kvListEntries += result.length;\n for (const kv of result) this._stat.kvListBytes += kv.key.length + kv.value.length;\n\n return result;\n }\n\n public async listKeyValuesString(rId: AnyResourceRef): Promise<KeyValueString[]> {\n return (await this.listKeyValues(rId)).map(({ key, value }) => ({\n key,\n value: Buffer.from(value).toString(),\n }));\n }\n\n public async listKeyValuesIfResourceExists(rId: AnyResourceRef): Promise<KeyValue[] | undefined> {\n return notFoundToUndefined(async () => await this.listKeyValues(rId));\n }\n\n public async listKeyValuesStringIfResourceExists(\n rId: AnyResourceRef,\n ): Promise<KeyValueString[] | undefined> {\n return notFoundToUndefined(async () => await this.listKeyValuesString(rId));\n }\n\n public setKValue(rId: AnyResourceRef, key: string, value: Uint8Array | string): void {\n this._stat.kvSetRequests++;\n this._stat.kvSetBytes++;\n this.sendVoidAsync({\n oneofKind: 'resourceKeyValueSet',\n resourceKeyValueSet: {\n resourceId: toResourceId(rId),\n key,\n value: toBytes(value),\n },\n });\n }\n\n public deleteKValue(rId: AnyResourceRef, key: string): void {\n this.sendVoidAsync({\n oneofKind: 'resourceKeyValueDelete',\n resourceKeyValueDelete: {\n resourceId: toResourceId(rId),\n key,\n },\n });\n }\n\n public async getKValue(rId: AnyResourceRef, key: string): Promise<Uint8Array> {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: 'resourceKeyValueGet',\n resourceKeyValueGet: { resourceId: toResourceId(rId), key },\n },\n (r) => r.resourceKeyValueGet.value,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result.length;\n\n return result;\n }\n\n public async getKValueString(rId: AnyResourceRef, key: string): Promise<string> {\n return Buffer.from(await this.getKValue(rId, key)).toString();\n }\n\n public async getKValueJson<T>(rId: AnyResourceRef, key: string): Promise<T> {\n return JSON.parse(await this.getKValueString(rId, key)) as T;\n }\n\n public async getKValueIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<Uint8Array | undefined> {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: 'resourceKeyValueGetIfExists',\n resourceKeyValueGetIfExists: { resourceId: toResourceId(rId), key },\n },\n (r) =>\n r.resourceKeyValueGetIfExists.exists ? r.resourceKeyValueGetIfExists.value : undefined,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result?.length ?? 0;\n\n return result;\n }\n\n public async getKValueStringIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<string | undefined> {\n const data = await this.getKValueIfExists(rId, key);\n return data === undefined ? undefined : Buffer.from(data).toString();\n }\n\n public async getKValueJsonIfExists<T>(rId: AnyResourceRef, key: string): Promise<T | undefined> {\n const str = await this.getKValueString(rId, key);\n if (str === undefined) return undefined;\n return JSON.parse(str) as T;\n }\n\n //\n // Cache\n //\n // TODO\n\n //\n // High level ops\n //\n\n /** Resolves existing or create first level resource from */\n public getFutureFieldValue(rId: AnyRef, fieldName: string, fieldType: FutureFieldType): FieldRef {\n const data = Buffer.from(JSON.stringify({ fieldName, fieldType }));\n const getFieldResource = this.createEphemeral({ name: 'json/getField', version: '1' }, data);\n this.setField({ resourceId: getFieldResource, fieldName: 'resource' }, rId);\n return { resourceId: getFieldResource, fieldName: 'result' };\n }\n\n //\n // Technical\n //\n\n public async getGlobalTxId() {\n this.globalTxIdWasAwaited = true;\n return await this.globalTxId;\n }\n\n /** Closes output event stream */\n public async complete() {\n if (this._completed) return;\n this._completed = true;\n const completeResult = this.ll.complete();\n await this.drainAndAwaitPendingOps();\n await completeResult;\n }\n\n /** Await incoming message loop termination and throw\n * any leftover errors if it was unsuccessful */\n public async await() {\n await this.ll.await();\n }\n\n //\n // Helpers\n //\n\n private nextLocalResourceId(root: boolean): LocalResourceId {\n return createLocalResourceId(root, ++this.localResourceIdCounter, this.localTxId);\n }\n\n private static localTxIdCounter = 0;\n\n private static nextLocalTxId() {\n PlTransaction.localTxIdCounter++;\n if (PlTransaction.localTxIdCounter === MaxTxId) PlTransaction.localTxIdCounter = 1;\n return PlTransaction.localTxIdCounter;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transaction.js","sources":["../../src/core/transaction.ts"],"sourcesContent":["// TODO: fix this\n/* eslint-disable no-prototype-builtins */\nimport type {\n AnyResourceId,\n LocalResourceId,\n OptionalResourceId,\n BasicResourceData,\n FieldData,\n FieldType,\n ResourceData,\n ResourceId,\n ResourceType,\n FutureFieldType } from './types';\nimport {\n createLocalResourceId,\n ensureResourceIdNotNull,\n MaxTxId,\n isLocalResourceId,\n extractBasicResourceData,\n isNullResourceId,\n} from './types';\nimport type {\n ClientMessageRequest,\n LLPlTransaction,\n OneOfKind,\n ServerMessageResponse,\n} from './ll_transaction';\nimport { TxAPI_Open_Request_WritableTx } from '../proto/github.com/milaboratory/pl/plapi/plapiproto/api';\nimport type { NonUndefined } from 'utility-types';\nimport { toBytes } from '../util/util';\nimport { fieldTypeToProto, protoToField, protoToResource } from './type_conversion';\nimport { canonicalJsonBytes, canonicalJsonGzBytes, deepFreeze, notEmpty } from '@milaboratories/ts-helpers';\nimport { isNotFoundError } from './errors';\nimport type { FinalResourceDataPredicate } from './final';\nimport type { LRUCache } from 'lru-cache';\nimport type { ResourceDataCacheRecord } from './cache';\nimport type { TxStat } from './stat';\nimport { initialTxStatWithoutTime } from './stat';\nimport type { ErrorResourceData } from './error_resource';\nimport { ErrorResourceType } from './error_resource';\nimport { JsonGzObject, JsonObject } from '../helpers/pl';\nimport { PromiseTracker } from './PromiseTracker';\n\n/** Reference to resource, used only within transaction */\nexport interface ResourceRef {\n /** Global resource id of newly created resources, become available only\n * after response for the corresponding creation request is received. */\n readonly globalId: Promise<ResourceId>;\n\n /** Transaction-local resource id is assigned right after resource creation\n * request is sent, and can be used right away */\n readonly localId: LocalResourceId;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValue {\n key: string;\n value: Uint8Array;\n}\n\n/** Key-Value pair from resource-attached KV storage */\nexport interface KeyValueString {\n key: string;\n value: string;\n}\n\ninterface _FieldId<RId> {\n /** Parent resource id */\n resourceId: RId;\n /** Field name */\n fieldName: string;\n}\n\nexport type FieldId = _FieldId<ResourceId>;\nexport type FieldRef = _FieldId<ResourceRef>;\nexport type LocalFieldId = _FieldId<LocalResourceId>;\nexport type AnyFieldId = FieldId | LocalFieldId;\n\nexport type AnyResourceRef = ResourceRef | ResourceId;\nexport type AnyFieldRef = _FieldId<AnyResourceRef>; // FieldRef | FieldId\nexport type AnyRef = AnyResourceRef | AnyFieldRef;\n\nexport function isField(ref: AnyRef): ref is AnyFieldRef {\n return ref.hasOwnProperty('resourceId') && ref.hasOwnProperty('fieldName');\n}\n\nexport function isResource(ref: AnyRef): ref is AnyResourceRef {\n return (\n typeof ref === 'bigint' || (ref.hasOwnProperty('globalId') && ref.hasOwnProperty('localId'))\n );\n}\n\nexport function isResourceId(ref: AnyRef): ref is ResourceId {\n return typeof ref === 'bigint' && !isLocalResourceId(ref) && !isNullResourceId(ref);\n}\n\nexport function isFieldRef(ref: AnyFieldRef): ref is FieldRef {\n return isResourceRef(ref.resourceId);\n}\n\nexport function isResourceRef(ref: AnyResourceRef): ref is ResourceRef {\n return ref.hasOwnProperty('globalId') && ref.hasOwnProperty('localId');\n}\n\nexport function toFieldId(ref: AnyFieldRef): AnyFieldId {\n if (isFieldRef(ref)) return { resourceId: ref.resourceId.localId, fieldName: ref.fieldName };\n else return ref as FieldId;\n}\n\nexport async function toGlobalFieldId(ref: AnyFieldRef): Promise<FieldId> {\n if (isFieldRef(ref))\n return { resourceId: await ref.resourceId.globalId, fieldName: ref.fieldName };\n else return ref as FieldId;\n}\n\nexport function toResourceId(ref: AnyResourceRef): AnyResourceId {\n if (isResourceRef(ref)) return ref.localId;\n else return ref;\n}\n\nexport async function toGlobalResourceId(ref: AnyResourceRef): Promise<ResourceId> {\n if (isResourceRef(ref)) return await ref.globalId;\n else return ref;\n}\n\nexport function field(resourceId: AnyResourceRef, fieldName: string): AnyFieldRef {\n return { resourceId, fieldName };\n}\n\n/** If transaction commit failed due to write conflicts */\nexport class TxCommitConflict extends Error {\n name = 'TxCommitConflict';\n}\n\nasync function notFoundToUndefined<T>(cb: () => Promise<T>): Promise<T | undefined> {\n try {\n return await cb();\n } catch (e) {\n if (isNotFoundError(e)) return undefined;\n throw e;\n }\n}\n\n/**\n * Decorator that wraps the method's returned promise with this.track()\n * This ensures that the promise will be awaited before the transaction is completed.\n */\nfunction tracked<T extends (this: PlTransaction, ...a: any[]) => Promise<any>>(\n value: T,\n _context: ClassMethodDecoratorContext,\n) {\n return function (\n this: PlTransaction,\n ...args: Parameters<T>\n ): ReturnType<T> {\n return this.track(value.apply(this, args)) as ReturnType<T>;\n } as unknown as T;\n}\n\n/**\n * Each platform transaction has 3 stages:\n * - initialization (txOpen message -> txInfo response)\n * - communication (create resources, fields, references and so on)\n * - finalization (txCommit or txDiscard message)\n *\n * This class encapsulates finalization stage and provides ready-to-communication transaction object.\n * */\nexport class PlTransaction {\n private readonly globalTxId: Promise<bigint>;\n private readonly localTxId: number = PlTransaction.nextLocalTxId();\n\n /** Used in caching */\n private readonly txOpenTimestamp = Date.now();\n\n private localResourceIdCounter = 0;\n\n /** Store logical tx open / closed state to prevent invalid sequence of requests.\n * True means output stream was completed.\n * Contract: there must be no async operations between setting this field to true and sending complete signal to stream. */\n private _completed = false;\n\n private globalTxIdWasAwaited: boolean = false;\n\n public readonly pending = new PromiseTracker();\n\n private readonly _startTime = Date.now();\n private readonly _stat = initialTxStatWithoutTime();\n public get stat(): TxStat {\n return {\n ...this._stat,\n timeMs: Date.now() - this._startTime,\n };\n }\n\n constructor(\n private readonly ll: LLPlTransaction,\n public readonly name: string,\n public readonly writable: boolean,\n private readonly _clientRoot: OptionalResourceId,\n private readonly finalPredicate: FinalResourceDataPredicate,\n private readonly sharedResourceDataCache: LRUCache<ResourceId, ResourceDataCacheRecord>,\n private readonly enableFormattedErrors: boolean = false,\n ) {\n // initiating transaction\n this.globalTxId = this.sendSingleAndParse(\n {\n oneofKind: 'txOpen',\n txOpen: {\n name,\n enableFormattedErrors,\n writable: writable\n ? TxAPI_Open_Request_WritableTx.WRITABLE\n : TxAPI_Open_Request_WritableTx.NOT_WRITABLE,\n },\n },\n (r) => notEmpty(r.txOpen.tx?.id),\n );\n\n void this.track(this.globalTxId);\n\n // To avoid floating promise\n this.globalTxId.catch((err) => {\n if (!this.globalTxIdWasAwaited) {\n console.warn(err);\n }\n });\n\n // Adding stats\n this._stat.txCount++;\n }\n\n /**\n * Collect all pending promises for the transaction finalization.\n */\n public track<T>(promiseOrCallback: Promise<T> | (() => Promise<T>)): Promise<T> {\n return this.pending.track(promiseOrCallback);\n }\n\n private async drainAndAwaitPendingOps(): Promise<void> {\n // awaiting these pending operations first, to catch any errors\n await this.pending.awaitAll();\n }\n\n private sendSingleAndParse<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => T,\n ): Promise<T> {\n return this.pending.track(async () => {\n const rawResponsePromise = this.ll.send(r, false);\n\n void this.pending.track(rawResponsePromise);\n\n await this.drainAndAwaitPendingOps();\n\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n });\n }\n\n private sendMultiAndParse<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>, T>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>[]) => T,\n ): Promise<T> {\n return this.pending.track(async () => {\n const rawResponsePromise = this.ll.send(r, true);\n\n void this.pending.track(rawResponsePromise);\n\n await this.drainAndAwaitPendingOps();\n\n // awaiting our result, and parsing the response\n return parser(await rawResponsePromise);\n });\n }\n\n private async sendVoidSync<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): Promise<void> {\n await this.ll.send(r, false);\n }\n\n /** Requests sent with this method should never produce recoverable errors */\n private sendVoidAsync<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>>(\n r: OneOfKind<ClientMessageRequest, Kind>,\n ): void {\n void this.track(this.sendVoidSync(r));\n }\n\n private checkTxOpen() {\n if (this._completed) throw new Error('Transaction already closed');\n }\n\n public get completed() {\n return this._completed;\n }\n\n /** Commit & closes transaction. {@link TxCommitConflict} is thrown on\n * commit conflicts. */\n public async commit() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n if (!this.writable) {\n // no need to explicitly commit or reject read-only tx\n const completeResult = this.track(this.ll.complete());\n await this.drainAndAwaitPendingOps();\n await completeResult;\n await this.ll.await();\n } else {\n const commitResponse = this.track(this.sendSingleAndParse(\n { oneofKind: 'txCommit', txCommit: {} },\n (r) => r.txCommit.success,\n ));\n\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.track(this.ll.complete());\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n if (!(await commitResponse)) throw new TxCommitConflict();\n\n await completeResult;\n\n // await event-loop completion\n await this.ll.await();\n }\n }\n\n public async discard() {\n this.checkTxOpen();\n\n // tx will accept no requests after this one\n this._completed = true;\n\n const discardResponse = this.sendVoidSync({ oneofKind: 'txDiscard', txDiscard: {} });\n void this.track(discardResponse);\n // send closing frame right after commit to save some time on round-trips\n const completeResult = this.track(this.ll.complete());\n\n // now when we pushed all packets into the stream, we should wait for any\n // pending void operations from before, to catch any errors\n await this.drainAndAwaitPendingOps();\n\n await discardResponse;\n await completeResult;\n await this.ll.await();\n }\n\n //\n // Main tx methods\n //\n\n public get clientRoot(): ResourceId {\n return ensureResourceIdNotNull(this._clientRoot);\n }\n\n //\n // Resources\n //\n\n public createSingleton(\n name: string,\n type: ResourceType,\n errorIfExists: boolean = false,\n ): ResourceRef {\n const localId = this.nextLocalResourceId(false);\n\n const globalId = this.sendSingleAndParse(\n {\n oneofKind: 'resourceCreateSingleton',\n resourceCreateSingleton: {\n type,\n id: localId,\n data: Buffer.from(name),\n errorIfExists,\n },\n },\n (r) => r.resourceCreateSingleton.resourceId as ResourceId,\n );\n\n void this.track(globalId);\n\n return { globalId, localId };\n }\n\n public getSingleton(name: string, loadFields: true): Promise<ResourceData>;\n public getSingleton(name: string, loadFields: false): Promise<BasicResourceData>;\n public getSingleton(\n name: string,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData> {\n return this.sendSingleAndParse(\n {\n oneofKind: 'resourceGetSingleton',\n resourceGetSingleton: {\n data: Buffer.from(name),\n loadFields,\n },\n },\n (r) => protoToResource(notEmpty(r.resourceGetSingleton.resource)),\n );\n }\n\n private createResource<Kind extends NonUndefined<ClientMessageRequest['oneofKind']>>(\n root: boolean,\n req: (localId: LocalResourceId) => OneOfKind<ClientMessageRequest, Kind>,\n parser: (resp: OneOfKind<ServerMessageResponse, Kind>) => bigint,\n ): ResourceRef {\n const localId = this.nextLocalResourceId(root);\n\n const globalId = this.sendSingleAndParse(req(localId), (r) => parser(r) as ResourceId);\n\n void this.track(globalId);\n\n return { globalId, localId };\n }\n\n public createRoot(type: ResourceType): ResourceRef {\n this._stat.rootsCreated++;\n return this.createResource(\n true,\n (localId) => ({ oneofKind: 'resourceCreateRoot', resourceCreateRoot: { type, id: localId } }),\n (r) => r.resourceCreateRoot.resourceId,\n );\n }\n\n public createStruct(type: ResourceType, data?: Uint8Array | string): ResourceRef {\n this._stat.structsCreated++;\n this._stat.structsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: 'resourceCreateStruct',\n resourceCreateStruct: {\n type,\n id: localId,\n data: data === undefined ? undefined : typeof data === 'string' ? Buffer.from(data) : data,\n },\n }),\n (r) => r.resourceCreateStruct.resourceId,\n );\n }\n\n public createEphemeral(type: ResourceType, data?: Uint8Array | string): ResourceRef {\n this._stat.ephemeralsCreated++;\n this._stat.ephemeralsCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: 'resourceCreateEphemeral',\n resourceCreateEphemeral: {\n type,\n id: localId,\n data: data === undefined ? undefined : typeof data === 'string' ? Buffer.from(data) : data,\n },\n }),\n (r) => r.resourceCreateEphemeral.resourceId,\n );\n }\n\n public createValue(\n type: ResourceType,\n data: Uint8Array | string,\n errorIfExists: boolean = false,\n ): ResourceRef {\n this._stat.valuesCreated++;\n this._stat.valuesCreatedDataBytes += data?.length ?? 0;\n return this.createResource(\n false,\n (localId) => ({\n oneofKind: 'resourceCreateValue',\n resourceCreateValue: {\n type,\n id: localId,\n data: typeof data === 'string' ? Buffer.from(data) : data,\n errorIfExists,\n },\n }),\n (r) => r.resourceCreateValue.resourceId,\n );\n }\n\n public createJsonValue(data: unknown): ResourceRef {\n const jsonData = canonicalJsonBytes(data);\n return this.createValue(JsonObject, jsonData, false);\n }\n\n public createJsonGzValue(data: unknown, minSizeToGzip: number | undefined = 16_384): ResourceRef {\n const { data: jsonData, isGzipped } = canonicalJsonGzBytes(data, minSizeToGzip);\n return this.createValue(isGzipped ? JsonGzObject : JsonObject, jsonData, false);\n }\n\n public createError(message: string): ResourceRef {\n return this.createValue(ErrorResourceType, JSON.stringify({ message } satisfies ErrorResourceData));\n }\n\n public setResourceName(name: string, rId: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: 'resourceNameSet',\n resourceNameSet: { resourceId: toResourceId(rId), name },\n });\n }\n\n public deleteResourceName(name: string): void {\n this.sendVoidAsync({ oneofKind: 'resourceNameDelete', resourceNameDelete: { name } });\n }\n\n public getResourceByName(name: string): Promise<ResourceId> {\n return this.sendSingleAndParse(\n { oneofKind: 'resourceNameGet', resourceNameGet: { name } },\n (r) => ensureResourceIdNotNull(r.resourceNameGet.resourceId as OptionalResourceId),\n );\n }\n\n public checkResourceNameExists(name: string): Promise<boolean> {\n return this.sendSingleAndParse(\n { oneofKind: 'resourceNameExists', resourceNameExists: { name } },\n (r) => r.resourceNameExists.exists,\n );\n }\n\n public removeResource(rId: ResourceId): void {\n this.sendVoidAsync({ oneofKind: 'resourceRemove', resourceRemove: { id: rId } });\n }\n\n public resourceExists(rId: ResourceId): Promise<boolean> {\n return this.sendSingleAndParse(\n { oneofKind: 'resourceExists', resourceExists: { resourceId: rId } },\n (r) => r.resourceExists.exists,\n );\n }\n\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: true): Promise<ResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(rId: AnyResourceRef, loadFields: false): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean\n ): Promise<BasicResourceData | ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: true,\n ignoreCache: boolean\n ): Promise<ResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: false,\n ignoreCache: boolean\n ): Promise<BasicResourceData>;\n /** This method may return stale resource state from cache if ignoreCache == false if resource was removed */\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean,\n ignoreCache: boolean\n ): Promise<BasicResourceData | ResourceData>;\n @tracked\n public async getResourceData(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ignoreCache: boolean = false,\n ): Promise<BasicResourceData | ResourceData> {\n if (!ignoreCache && !isResourceRef(rId) && !isLocalResourceId(rId)) {\n // checking if we can return result from cache\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache && fromCache.cacheTxOpenTimestamp < this.txOpenTimestamp) {\n if (!loadFields) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n return fromCache.basicData;\n } else if (fromCache.data) {\n this._stat.rGetDataCacheHits++;\n this._stat.rGetDataCacheBytes += fromCache.basicData.data?.length ?? 0;\n this._stat.rGetDataCacheFields += fromCache.data.fields.length;\n return fromCache.data;\n }\n }\n }\n\n const result = await this.sendSingleAndParse(\n {\n oneofKind: 'resourceGet',\n resourceGet: { resourceId: toResourceId(rId), loadFields: loadFields },\n },\n (r) => protoToResource(notEmpty(r.resourceGet.resource)),\n );\n\n this._stat.rGetDataNetRequests++;\n this._stat.rGetDataNetBytes += result.data?.length ?? 0;\n this._stat.rGetDataNetFields += result.fields.length;\n\n // we will cache only final resource data states\n // caching result even if we were ignore the cache\n if (!isResourceRef(rId) && !isLocalResourceId(rId) && this.finalPredicate(result)) {\n deepFreeze(result);\n const fromCache = this.sharedResourceDataCache.get(rId);\n if (fromCache) {\n if (loadFields && !fromCache.data) {\n fromCache.data = result;\n // updating timestamp because we updated the record\n fromCache.cacheTxOpenTimestamp = this.txOpenTimestamp;\n }\n } else {\n const basicData = extractBasicResourceData(result);\n deepFreeze(basicData);\n if (loadFields)\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: result,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n else\n this.sharedResourceDataCache.set(rId, {\n basicData,\n data: undefined,\n cacheTxOpenTimestamp: this.txOpenTimestamp,\n });\n }\n }\n\n return result;\n }\n\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: true\n ): Promise<ResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: false\n ): Promise<BasicResourceData | undefined>;\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean\n ): Promise<BasicResourceData | ResourceData | undefined>;\n @tracked\n public async getResourceDataIfExists(\n rId: AnyResourceRef,\n loadFields: boolean = true,\n ): Promise<BasicResourceData | ResourceData | undefined> {\n // calling this method will ignore cache, because user intention is to detect resource absence\n // which cache will prevent\n const result = await notFoundToUndefined(\n async () => await this.getResourceData(rId, loadFields, true),\n );\n\n // cleaning cache record if resource was removed from the db\n if (result === undefined && !isResourceRef(rId) && !isLocalResourceId(rId))\n this.sharedResourceDataCache.delete(rId);\n\n return result;\n }\n\n /**\n * Inform platform that resource will not get any new input fields.\n * This is required, when client creates resource without schema and wants\n * controller to start calculations.\n * Most controllers will not start calculations even when all inputs\n * have their values, if inputs list is not locked.\n */\n public lockInputs(rId: AnyResourceRef): void {\n this._stat.inputsLocked++;\n this.sendVoidAsync({\n oneofKind: 'resourceLockInputs',\n resourceLockInputs: { resourceId: toResourceId(rId) },\n });\n }\n\n /**\n * Inform platform that resource will not get any new output fields.\n * This is required for resource to pass deduplication.\n */\n public lockOutputs(rId: AnyResourceRef): void {\n this._stat.outputsLocked++;\n this.sendVoidAsync({\n oneofKind: 'resourceLockOutputs',\n resourceLockOutputs: { resourceId: toResourceId(rId) },\n });\n }\n\n public lock(rID: AnyResourceRef): void {\n this.lockInputs(rID);\n this.lockOutputs(rID);\n }\n\n public setResourceError(rId: AnyResourceRef, ref: AnyResourceRef): void {\n this.sendVoidAsync({\n oneofKind: 'resourceSetError',\n resourceSetError: { resourceId: toResourceId(rId), errorResourceId: toResourceId(ref) },\n });\n }\n\n //\n // Fields\n //\n\n public createField(fId: AnyFieldRef, fieldType: FieldType, value?: AnyRef): void {\n this._stat.fieldsCreated++;\n this.sendVoidAsync({\n oneofKind: 'fieldCreate',\n fieldCreate: { type: fieldTypeToProto(fieldType), id: toFieldId(fId) },\n });\n if (value !== undefined) this.setField(fId, value);\n }\n\n public fieldExists(fId: AnyFieldRef): Promise<boolean> {\n return this.sendSingleAndParse(\n {\n oneofKind: 'fieldExists',\n fieldExists: { field: toFieldId(fId) },\n },\n (r) => r.fieldExists.exists,\n );\n }\n\n public setField(fId: AnyFieldRef, ref: AnyRef): void {\n this._stat.fieldsSet++;\n if (isResource(ref))\n this.sendVoidAsync({\n oneofKind: 'fieldSet',\n fieldSet: {\n field: toFieldId(fId),\n value: {\n resourceId: toResourceId(ref),\n fieldName: '', // default value, read as undefined\n },\n },\n });\n else\n this.sendVoidAsync({\n oneofKind: 'fieldSet',\n fieldSet: {\n field: toFieldId(fId),\n value: toFieldId(ref),\n },\n });\n }\n\n public setFieldError(fId: AnyFieldRef, ref: AnyResourceRef): void {\n this._stat.fieldsSet++;\n this.sendVoidAsync({\n oneofKind: 'fieldSetError',\n fieldSetError: { field: toFieldId(fId), errResourceId: toResourceId(ref) },\n });\n }\n\n public getField(fId: AnyFieldRef): Promise<FieldData> {\n this._stat.fieldsGet++;\n return this.sendSingleAndParse(\n { oneofKind: 'fieldGet', fieldGet: { field: toFieldId(fId) } },\n (r) => protoToField(notEmpty(r.fieldGet.field)),\n );\n }\n\n @tracked\n public async getFieldIfExists(fId: AnyFieldRef): Promise<FieldData | undefined> {\n return notFoundToUndefined(async () => await this.getField(fId));\n }\n\n public resetField(fId: AnyFieldRef): void {\n this.sendVoidAsync({ oneofKind: 'fieldReset', fieldReset: { field: toFieldId(fId) } });\n }\n\n public removeField(fId: AnyFieldRef): void {\n this.sendVoidAsync({ oneofKind: 'fieldRemove', fieldRemove: { field: toFieldId(fId) } });\n }\n\n //\n // KV\n //\n\n @tracked\n public async listKeyValues(rId: AnyResourceRef): Promise<KeyValue[]> {\n const result = await this.sendMultiAndParse(\n {\n oneofKind: 'resourceKeyValueList',\n resourceKeyValueList: { resourceId: toResourceId(rId), startFrom: '', limit: 0 },\n },\n (r) => r.map((e) => e.resourceKeyValueList.record!),\n );\n\n this._stat.kvListRequests++;\n this._stat.kvListEntries += result.length;\n for (const kv of result) this._stat.kvListBytes += kv.key.length + kv.value.length;\n\n return result;\n }\n\n @tracked\n public async listKeyValuesString(rId: AnyResourceRef): Promise<KeyValueString[]> {\n return (await this.listKeyValues(rId)).map(({ key, value }) => ({\n key,\n value: Buffer.from(value).toString(),\n }));\n }\n\n @tracked\n public async listKeyValuesIfResourceExists(rId: AnyResourceRef): Promise<KeyValue[] | undefined> {\n return notFoundToUndefined(async () => await this.listKeyValues(rId));\n }\n\n @tracked\n public async listKeyValuesStringIfResourceExists(\n rId: AnyResourceRef,\n ): Promise<KeyValueString[] | undefined> {\n return notFoundToUndefined(async () => await this.listKeyValuesString(rId));\n }\n\n public setKValue(rId: AnyResourceRef, key: string, value: Uint8Array | string): void {\n this._stat.kvSetRequests++;\n this._stat.kvSetBytes++;\n this.sendVoidAsync({\n oneofKind: 'resourceKeyValueSet',\n resourceKeyValueSet: {\n resourceId: toResourceId(rId),\n key,\n value: toBytes(value),\n },\n });\n }\n\n public deleteKValue(rId: AnyResourceRef, key: string): void {\n this.sendVoidAsync({\n oneofKind: 'resourceKeyValueDelete',\n resourceKeyValueDelete: {\n resourceId: toResourceId(rId),\n key,\n },\n });\n }\n\n @tracked\n public async getKValue(rId: AnyResourceRef, key: string): Promise<Uint8Array> {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: 'resourceKeyValueGet',\n resourceKeyValueGet: { resourceId: toResourceId(rId), key },\n },\n (r) => r.resourceKeyValueGet.value,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result.length;\n\n return result;\n }\n\n @tracked\n public async getKValueString(rId: AnyResourceRef, key: string): Promise<string> {\n return Buffer.from(await this.getKValue(rId, key)).toString();\n }\n\n @tracked\n public async getKValueJson<T>(rId: AnyResourceRef, key: string): Promise<T> {\n return JSON.parse(await this.getKValueString(rId, key)) as T;\n }\n\n @tracked\n public async getKValueIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<Uint8Array | undefined> {\n const result = await this.sendSingleAndParse(\n {\n oneofKind: 'resourceKeyValueGetIfExists',\n resourceKeyValueGetIfExists: { resourceId: toResourceId(rId), key },\n },\n (r) =>\n r.resourceKeyValueGetIfExists.exists ? r.resourceKeyValueGetIfExists.value : undefined,\n );\n\n this._stat.kvGetRequests++;\n this._stat.kvGetBytes += result?.length ?? 0;\n\n return result;\n }\n\n @tracked\n public async getKValueStringIfExists(\n rId: AnyResourceRef,\n key: string,\n ): Promise<string | undefined> {\n const data = await this.getKValueIfExists(rId, key);\n return data === undefined ? undefined : Buffer.from(data).toString();\n }\n\n @tracked\n public async getKValueJsonIfExists<T>(rId: AnyResourceRef, key: string): Promise<T | undefined> {\n const str = await this.getKValueString(rId, key);\n if (str === undefined) return undefined;\n return JSON.parse(str) as T;\n }\n\n //\n // Cache\n //\n // TODO\n\n //\n // High level ops\n //\n\n /** Resolves existing or create first level resource from */\n public getFutureFieldValue(rId: AnyRef, fieldName: string, fieldType: FutureFieldType): FieldRef {\n const data = Buffer.from(JSON.stringify({ fieldName, fieldType }));\n const getFieldResource = this.createEphemeral({ name: 'json/getField', version: '1' }, data);\n this.setField({ resourceId: getFieldResource, fieldName: 'resource' }, rId);\n return { resourceId: getFieldResource, fieldName: 'result' };\n }\n\n //\n // Technical\n //\n\n public async getGlobalTxId() {\n this.globalTxIdWasAwaited = true;\n return await this.globalTxId;\n }\n\n /** Closes output event stream */\n public async complete() {\n if (this._completed) return;\n this._completed = true;\n const completeResult = this.track(this.ll.complete());\n await this.drainAndAwaitPendingOps();\n await completeResult;\n }\n\n /** Await incoming message loop termination and throw\n * any leftover errors if it was unsuccessful */\n public async await() {\n await this.ll.await();\n }\n\n //\n // Helpers\n //\n\n private nextLocalResourceId(root: boolean): LocalResourceId {\n return createLocalResourceId(root, ++this.localResourceIdCounter, this.localTxId);\n }\n\n private static localTxIdCounter = 0;\n\n private static nextLocalTxId() {\n PlTransaction.localTxIdCounter++;\n if (PlTransaction.localTxIdCounter === MaxTxId) PlTransaction.localTxIdCounter = 1;\n return PlTransaction.localTxIdCounter;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var net = require('node:net');
|
|
4
|
+
var node_stream = require('node:stream');
|
|
5
|
+
var promises = require('node:stream/promises');
|
|
6
|
+
var tp = require('node:timers/promises');
|
|
7
|
+
|
|
8
|
+
function _interopNamespaceDefault(e) {
|
|
9
|
+
var n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
Object.keys(e).forEach(function (k) {
|
|
12
|
+
if (k !== 'default') {
|
|
13
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return e[k]; }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var net__namespace = /*#__PURE__*/_interopNamespaceDefault(net);
|
|
26
|
+
var tp__namespace = /*#__PURE__*/_interopNamespaceDefault(tp);
|
|
27
|
+
|
|
28
|
+
async function startTcpProxy(options) {
|
|
29
|
+
const { port, targetPort } = options;
|
|
30
|
+
const state = {
|
|
31
|
+
latency: options.latency,
|
|
32
|
+
};
|
|
33
|
+
const setLatency = (latency) => {
|
|
34
|
+
state.latency = latency;
|
|
35
|
+
};
|
|
36
|
+
const getLatency = () => {
|
|
37
|
+
return state.latency;
|
|
38
|
+
};
|
|
39
|
+
const connections = new Set();
|
|
40
|
+
async function disconnectAll() {
|
|
41
|
+
const kill = () => {
|
|
42
|
+
for (const { socket, client } of connections) {
|
|
43
|
+
if (!socket.destroyed)
|
|
44
|
+
socket.destroy();
|
|
45
|
+
if (!client.destroyed)
|
|
46
|
+
client.destroy();
|
|
47
|
+
}
|
|
48
|
+
connections.clear();
|
|
49
|
+
};
|
|
50
|
+
await tp__namespace.setTimeout(1);
|
|
51
|
+
kill();
|
|
52
|
+
}
|
|
53
|
+
const server = net__namespace
|
|
54
|
+
.createServer((socket) => {
|
|
55
|
+
const client = net__namespace.createConnection({ port: targetPort }, () => {
|
|
56
|
+
if (options.verbose)
|
|
57
|
+
console.log(`connected to ${targetPort}`);
|
|
58
|
+
});
|
|
59
|
+
const pair = { socket, client };
|
|
60
|
+
connections.add(pair);
|
|
61
|
+
const onClose = () => connections.delete(pair);
|
|
62
|
+
socket.on('close', onClose);
|
|
63
|
+
client.on('close', onClose);
|
|
64
|
+
class LatencyTransform extends node_stream.Transform {
|
|
65
|
+
pendingTimer;
|
|
66
|
+
constructor() {
|
|
67
|
+
super();
|
|
68
|
+
}
|
|
69
|
+
_transform(chunk, _enc, callback) {
|
|
70
|
+
// Backpressure is respected by delaying the callback until after push
|
|
71
|
+
this.pendingTimer = setTimeout(() => {
|
|
72
|
+
this.pendingTimer = undefined;
|
|
73
|
+
this.push(chunk);
|
|
74
|
+
callback();
|
|
75
|
+
}, state.latency);
|
|
76
|
+
}
|
|
77
|
+
_destroy(err, cb) {
|
|
78
|
+
if (this.pendingTimer)
|
|
79
|
+
clearTimeout(this.pendingTimer);
|
|
80
|
+
this.pendingTimer = undefined;
|
|
81
|
+
cb(err);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const toClientLatency = new LatencyTransform();
|
|
85
|
+
const toTargetLatency = new LatencyTransform();
|
|
86
|
+
// Bidirectional pipelines with latency and error propagation
|
|
87
|
+
promises.pipeline(socket, toTargetLatency, client).catch((err) => {
|
|
88
|
+
socket.destroy(err);
|
|
89
|
+
client.destroy(err);
|
|
90
|
+
});
|
|
91
|
+
promises.pipeline(client, toClientLatency, socket).catch((err) => {
|
|
92
|
+
socket.destroy(err);
|
|
93
|
+
client.destroy(err);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
server.listen({ port: port ?? 0 }, () => {
|
|
97
|
+
console.log('opened server on', server.address());
|
|
98
|
+
});
|
|
99
|
+
// Wait for proxy to be ready
|
|
100
|
+
await new Promise((resolve, reject) => {
|
|
101
|
+
if (server.listening)
|
|
102
|
+
return resolve();
|
|
103
|
+
const onError = (err) => {
|
|
104
|
+
server.off('listening', onListening);
|
|
105
|
+
reject(err);
|
|
106
|
+
};
|
|
107
|
+
const onListening = () => {
|
|
108
|
+
server.off('error', onError);
|
|
109
|
+
resolve();
|
|
110
|
+
};
|
|
111
|
+
server.once('error', onError);
|
|
112
|
+
server.once('listening', onListening);
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
server,
|
|
116
|
+
get port() { return server.address()?.port; },
|
|
117
|
+
setLatency,
|
|
118
|
+
getLatency,
|
|
119
|
+
disconnectAll,
|
|
120
|
+
close: async () => {
|
|
121
|
+
await new Promise((resolve) => {
|
|
122
|
+
server.close(() => resolve());
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
exports.startTcpProxy = startTcpProxy;
|
|
129
|
+
//# sourceMappingURL=tcp-proxy.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp-proxy.cjs","sources":["../../src/test/tcp-proxy.ts"],"sourcesContent":["import * as net from 'node:net';\nimport type { AddressInfo } from 'node:net';\nimport { Transform } from 'node:stream';\nimport type { TransformCallback } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport * as timers from 'node:timers/promises';\n\nexport type TcpProxyOptions = {\n port?: number;\n targetPort: number;\n latency: number;\n verbose?: boolean;\n};\n\nexport async function startTcpProxy(options: TcpProxyOptions) {\n const { port, targetPort } = options;\n\n const state = {\n latency: options.latency,\n };\n\n const setLatency = (latency: number) => {\n state.latency = latency;\n };\n\n const getLatency = () => {\n return state.latency;\n };\n\n const connections = new Set<{ socket: net.Socket; client: net.Socket }>();\n\n async function disconnectAll() {\n const kill = () => {\n for (const { socket, client } of connections) {\n if (!socket.destroyed) socket.destroy();\n if (!client.destroyed) client.destroy();\n }\n connections.clear();\n };\n await timers.setTimeout(1);\n kill();\n };\n\n const server = net\n .createServer((socket: net.Socket) => {\n const client = net.createConnection({ port: targetPort }, () => {\n if (options.verbose) console.log(`connected to ${targetPort}`);\n });\n\n const pair = { socket, client };\n connections.add(pair);\n const onClose = () => connections.delete(pair);\n socket.on('close', onClose);\n client.on('close', onClose);\n\n class LatencyTransform extends Transform {\n private pendingTimer?: NodeJS.Timeout;\n constructor() {\n super();\n }\n\n _transform(chunk: Buffer, _enc: BufferEncoding, callback: TransformCallback) {\n // Backpressure is respected by delaying the callback until after push\n this.pendingTimer = setTimeout(() => {\n this.pendingTimer = undefined;\n this.push(chunk);\n callback();\n }, state.latency);\n }\n\n _destroy(err: Error | null, cb: (error?: Error | null) => void) {\n if (this.pendingTimer) clearTimeout(this.pendingTimer);\n this.pendingTimer = undefined;\n cb(err);\n }\n }\n\n const toClientLatency = new LatencyTransform();\n const toTargetLatency = new LatencyTransform();\n\n // Bidirectional pipelines with latency and error propagation\n pipeline(socket, toTargetLatency, client).catch((err) => {\n socket.destroy(err);\n client.destroy(err);\n });\n\n pipeline(client, toClientLatency, socket).catch((err) => {\n socket.destroy(err);\n client.destroy(err);\n });\n });\n\n server.listen({ port: port ?? 0 }, () => {\n console.log('opened server on', server.address());\n });\n\n // Wait for proxy to be ready\n await new Promise<void>((resolve, reject) => {\n if (server.listening) return resolve();\n const onError = (err: Error) => {\n server.off('listening', onListening);\n reject(err);\n };\n const onListening = () => {\n server.off('error', onError);\n resolve();\n };\n server.once('error', onError);\n server.once('listening', onListening);\n });\n\n return {\n server,\n get port() { return (server.address() as AddressInfo)?.port; },\n setLatency,\n getLatency,\n disconnectAll,\n close: async () => {\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n });\n },\n };\n}\n\nexport type TestTcpProxy = Awaited<ReturnType<typeof startTcpProxy>>;\n"],"names":["timers","net","Transform","pipeline"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as net from 'node:net';
|
|
2
|
+
export type TcpProxyOptions = {
|
|
3
|
+
port?: number;
|
|
4
|
+
targetPort: number;
|
|
5
|
+
latency: number;
|
|
6
|
+
verbose?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function startTcpProxy(options: TcpProxyOptions): Promise<{
|
|
9
|
+
server: net.Server;
|
|
10
|
+
readonly port: number;
|
|
11
|
+
setLatency: (latency: number) => void;
|
|
12
|
+
getLatency: () => number;
|
|
13
|
+
disconnectAll: () => Promise<void>;
|
|
14
|
+
close: () => Promise<void>;
|
|
15
|
+
}>;
|
|
16
|
+
export type TestTcpProxy = Awaited<ReturnType<typeof startTcpProxy>>;
|
|
17
|
+
//# sourceMappingURL=tcp-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp-proxy.d.ts","sourceRoot":"","sources":["../../src/test/tcp-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAOhC,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe;;;0BAO7B,MAAM;;;;GAsGpC;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as net from 'node:net';
|
|
2
|
+
import { Transform } from 'node:stream';
|
|
3
|
+
import { pipeline } from 'node:stream/promises';
|
|
4
|
+
import * as tp from 'node:timers/promises';
|
|
5
|
+
|
|
6
|
+
async function startTcpProxy(options) {
|
|
7
|
+
const { port, targetPort } = options;
|
|
8
|
+
const state = {
|
|
9
|
+
latency: options.latency,
|
|
10
|
+
};
|
|
11
|
+
const setLatency = (latency) => {
|
|
12
|
+
state.latency = latency;
|
|
13
|
+
};
|
|
14
|
+
const getLatency = () => {
|
|
15
|
+
return state.latency;
|
|
16
|
+
};
|
|
17
|
+
const connections = new Set();
|
|
18
|
+
async function disconnectAll() {
|
|
19
|
+
const kill = () => {
|
|
20
|
+
for (const { socket, client } of connections) {
|
|
21
|
+
if (!socket.destroyed)
|
|
22
|
+
socket.destroy();
|
|
23
|
+
if (!client.destroyed)
|
|
24
|
+
client.destroy();
|
|
25
|
+
}
|
|
26
|
+
connections.clear();
|
|
27
|
+
};
|
|
28
|
+
await tp.setTimeout(1);
|
|
29
|
+
kill();
|
|
30
|
+
}
|
|
31
|
+
const server = net
|
|
32
|
+
.createServer((socket) => {
|
|
33
|
+
const client = net.createConnection({ port: targetPort }, () => {
|
|
34
|
+
if (options.verbose)
|
|
35
|
+
console.log(`connected to ${targetPort}`);
|
|
36
|
+
});
|
|
37
|
+
const pair = { socket, client };
|
|
38
|
+
connections.add(pair);
|
|
39
|
+
const onClose = () => connections.delete(pair);
|
|
40
|
+
socket.on('close', onClose);
|
|
41
|
+
client.on('close', onClose);
|
|
42
|
+
class LatencyTransform extends Transform {
|
|
43
|
+
pendingTimer;
|
|
44
|
+
constructor() {
|
|
45
|
+
super();
|
|
46
|
+
}
|
|
47
|
+
_transform(chunk, _enc, callback) {
|
|
48
|
+
// Backpressure is respected by delaying the callback until after push
|
|
49
|
+
this.pendingTimer = setTimeout(() => {
|
|
50
|
+
this.pendingTimer = undefined;
|
|
51
|
+
this.push(chunk);
|
|
52
|
+
callback();
|
|
53
|
+
}, state.latency);
|
|
54
|
+
}
|
|
55
|
+
_destroy(err, cb) {
|
|
56
|
+
if (this.pendingTimer)
|
|
57
|
+
clearTimeout(this.pendingTimer);
|
|
58
|
+
this.pendingTimer = undefined;
|
|
59
|
+
cb(err);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const toClientLatency = new LatencyTransform();
|
|
63
|
+
const toTargetLatency = new LatencyTransform();
|
|
64
|
+
// Bidirectional pipelines with latency and error propagation
|
|
65
|
+
pipeline(socket, toTargetLatency, client).catch((err) => {
|
|
66
|
+
socket.destroy(err);
|
|
67
|
+
client.destroy(err);
|
|
68
|
+
});
|
|
69
|
+
pipeline(client, toClientLatency, socket).catch((err) => {
|
|
70
|
+
socket.destroy(err);
|
|
71
|
+
client.destroy(err);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
server.listen({ port: port ?? 0 }, () => {
|
|
75
|
+
console.log('opened server on', server.address());
|
|
76
|
+
});
|
|
77
|
+
// Wait for proxy to be ready
|
|
78
|
+
await new Promise((resolve, reject) => {
|
|
79
|
+
if (server.listening)
|
|
80
|
+
return resolve();
|
|
81
|
+
const onError = (err) => {
|
|
82
|
+
server.off('listening', onListening);
|
|
83
|
+
reject(err);
|
|
84
|
+
};
|
|
85
|
+
const onListening = () => {
|
|
86
|
+
server.off('error', onError);
|
|
87
|
+
resolve();
|
|
88
|
+
};
|
|
89
|
+
server.once('error', onError);
|
|
90
|
+
server.once('listening', onListening);
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
server,
|
|
94
|
+
get port() { return server.address()?.port; },
|
|
95
|
+
setLatency,
|
|
96
|
+
getLatency,
|
|
97
|
+
disconnectAll,
|
|
98
|
+
close: async () => {
|
|
99
|
+
await new Promise((resolve) => {
|
|
100
|
+
server.close(() => resolve());
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { startTcpProxy };
|
|
107
|
+
//# sourceMappingURL=tcp-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tcp-proxy.js","sources":["../../src/test/tcp-proxy.ts"],"sourcesContent":["import * as net from 'node:net';\nimport type { AddressInfo } from 'node:net';\nimport { Transform } from 'node:stream';\nimport type { TransformCallback } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport * as timers from 'node:timers/promises';\n\nexport type TcpProxyOptions = {\n port?: number;\n targetPort: number;\n latency: number;\n verbose?: boolean;\n};\n\nexport async function startTcpProxy(options: TcpProxyOptions) {\n const { port, targetPort } = options;\n\n const state = {\n latency: options.latency,\n };\n\n const setLatency = (latency: number) => {\n state.latency = latency;\n };\n\n const getLatency = () => {\n return state.latency;\n };\n\n const connections = new Set<{ socket: net.Socket; client: net.Socket }>();\n\n async function disconnectAll() {\n const kill = () => {\n for (const { socket, client } of connections) {\n if (!socket.destroyed) socket.destroy();\n if (!client.destroyed) client.destroy();\n }\n connections.clear();\n };\n await timers.setTimeout(1);\n kill();\n };\n\n const server = net\n .createServer((socket: net.Socket) => {\n const client = net.createConnection({ port: targetPort }, () => {\n if (options.verbose) console.log(`connected to ${targetPort}`);\n });\n\n const pair = { socket, client };\n connections.add(pair);\n const onClose = () => connections.delete(pair);\n socket.on('close', onClose);\n client.on('close', onClose);\n\n class LatencyTransform extends Transform {\n private pendingTimer?: NodeJS.Timeout;\n constructor() {\n super();\n }\n\n _transform(chunk: Buffer, _enc: BufferEncoding, callback: TransformCallback) {\n // Backpressure is respected by delaying the callback until after push\n this.pendingTimer = setTimeout(() => {\n this.pendingTimer = undefined;\n this.push(chunk);\n callback();\n }, state.latency);\n }\n\n _destroy(err: Error | null, cb: (error?: Error | null) => void) {\n if (this.pendingTimer) clearTimeout(this.pendingTimer);\n this.pendingTimer = undefined;\n cb(err);\n }\n }\n\n const toClientLatency = new LatencyTransform();\n const toTargetLatency = new LatencyTransform();\n\n // Bidirectional pipelines with latency and error propagation\n pipeline(socket, toTargetLatency, client).catch((err) => {\n socket.destroy(err);\n client.destroy(err);\n });\n\n pipeline(client, toClientLatency, socket).catch((err) => {\n socket.destroy(err);\n client.destroy(err);\n });\n });\n\n server.listen({ port: port ?? 0 }, () => {\n console.log('opened server on', server.address());\n });\n\n // Wait for proxy to be ready\n await new Promise<void>((resolve, reject) => {\n if (server.listening) return resolve();\n const onError = (err: Error) => {\n server.off('listening', onListening);\n reject(err);\n };\n const onListening = () => {\n server.off('error', onError);\n resolve();\n };\n server.once('error', onError);\n server.once('listening', onListening);\n });\n\n return {\n server,\n get port() { return (server.address() as AddressInfo)?.port; },\n setLatency,\n getLatency,\n disconnectAll,\n close: async () => {\n await new Promise<void>((resolve) => {\n server.close(() => resolve());\n });\n },\n };\n}\n\nexport type TestTcpProxy = Awaited<ReturnType<typeof startTcpProxy>>;\n"],"names":["timers"],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ var node_crypto = require('node:crypto');
|
|
|
9
9
|
var types = require('../core/types.cjs');
|
|
10
10
|
var auth = require('../core/auth.cjs');
|
|
11
11
|
var path = require('node:path');
|
|
12
|
+
var tcpProxy = require('./tcp-proxy.cjs');
|
|
12
13
|
|
|
13
14
|
function _interopNamespaceDefault(e) {
|
|
14
15
|
var n = Object.create(null);
|
|
@@ -118,26 +119,72 @@ async function getTestLLClient(confOverrides = {}) {
|
|
|
118
119
|
const { conf, auth } = await getTestClientConf();
|
|
119
120
|
return new ll_client.LLPlClient({ ...conf, ...confOverrides }, { auth });
|
|
120
121
|
}
|
|
121
|
-
async function getTestClient(alternativeRoot) {
|
|
122
|
+
async function getTestClient(alternativeRoot, confOverrides = {}) {
|
|
122
123
|
const { conf, auth } = await getTestClientConf();
|
|
123
124
|
if (alternativeRoot !== undefined && conf.alternativeRoot !== undefined)
|
|
124
125
|
throw new Error('test pl address configured with alternative root');
|
|
125
|
-
return await client.PlClient.init({ ...conf, alternativeRoot }, auth);
|
|
126
|
+
return await client.PlClient.init({ ...conf, ...confOverrides, alternativeRoot }, auth);
|
|
126
127
|
}
|
|
127
|
-
async function withTempRoot(body) {
|
|
128
|
+
async function withTempRoot(body, options = {}) {
|
|
128
129
|
const alternativeRoot = `test_${Date.now()}_${node_crypto.randomUUID()}`;
|
|
129
130
|
let altRootId = types.NullResourceId;
|
|
131
|
+
// Proxy management
|
|
132
|
+
let proxy;
|
|
133
|
+
let confOverrides = {};
|
|
130
134
|
try {
|
|
131
|
-
|
|
135
|
+
// Optionally start TCP proxy and rewrite PL_ADDRESS to point to proxy
|
|
136
|
+
if (options.viaTcpProxy === true && process.env.PL_ADDRESS) {
|
|
137
|
+
try {
|
|
138
|
+
const url = new URL(process.env.PL_ADDRESS);
|
|
139
|
+
const isHttp = url.protocol === 'http:';
|
|
140
|
+
const isLocal = url.hostname === '127.0.0.1' || url.hostname === 'localhost';
|
|
141
|
+
const port = parseInt(url.port);
|
|
142
|
+
if (isHttp && isLocal && Number.isFinite(port)) {
|
|
143
|
+
proxy = await tcpProxy.startTcpProxy({ targetPort: port, latency: options.proxyLatencyMs ?? 0 });
|
|
144
|
+
// Override client connection host:port to proxy
|
|
145
|
+
confOverrides = { hostAndPort: `127.0.0.1:${proxy.port}` };
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.warn('*** skipping proxy-based test, PL_ADDRESS is not localhost', process.env.PL_ADDRESS);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (_e) {
|
|
153
|
+
// ignore proxy setup errors; tests will run against original address
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const client = await getTestClient(alternativeRoot, confOverrides);
|
|
132
157
|
altRootId = client.clientRoot;
|
|
133
|
-
|
|
158
|
+
console.log('altRootId', altRootId, altRootId.toString(16));
|
|
159
|
+
const value = await body(client, proxy);
|
|
134
160
|
const rawClient = await getTestClient();
|
|
135
|
-
|
|
161
|
+
try {
|
|
162
|
+
await rawClient.deleteAlternativeRoot(alternativeRoot);
|
|
163
|
+
}
|
|
164
|
+
catch (cleanupErr) {
|
|
165
|
+
// Cleanup may fail if test intentionally deleted resources
|
|
166
|
+
console.warn(`Failed to clean up alternative root ${alternativeRoot}:`, cleanupErr.message);
|
|
167
|
+
}
|
|
136
168
|
return value;
|
|
137
169
|
}
|
|
138
170
|
catch (err) {
|
|
171
|
+
console.log('ERROR stack trace:', err.stack);
|
|
139
172
|
console.log(`ALTERNATIVE ROOT: ${alternativeRoot} (${types.resourceIdToString(altRootId)})`);
|
|
140
|
-
throw
|
|
173
|
+
throw err;
|
|
174
|
+
// throw new Error('withTempRoot error: ' + err.message, { cause: err });
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
// Stop proxy if started
|
|
178
|
+
if (proxy) {
|
|
179
|
+
try {
|
|
180
|
+
await proxy.disconnectAll();
|
|
181
|
+
}
|
|
182
|
+
catch (_e) { /* ignore */ }
|
|
183
|
+
try {
|
|
184
|
+
await new Promise((resolve) => proxy.server.close(() => resolve()));
|
|
185
|
+
}
|
|
186
|
+
catch (_e) { /* ignore */ }
|
|
187
|
+
}
|
|
141
188
|
}
|
|
142
189
|
}
|
|
143
190
|
|