chore: pass validator into validator context (#34810)

This commit is contained in:
Pavel Feldman 2025-02-15 08:28:28 -08:00 committed by GitHub
parent 024a52821a
commit 3606a434fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 49 additions and 22 deletions

View File

@ -141,6 +141,14 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
};
}
private _validatorToWireContext(): ValidatorContext {
return {
tChannelImpl: tChannelImplToWire,
binary: this._connection.rawBuffers() ? 'buffer' : 'toBase64',
isUnderTest: () => this._platform.isUnderTest(),
};
}
private _createChannel(base: Object): T {
const channel = new Proxy(base, {
get: (obj: any, prop: string | symbol) => {
@ -149,7 +157,7 @@ export abstract class ChannelOwner<T extends channels.Channel = channels.Channel
if (validator) {
return async (params: any) => {
return await this._wrapApiCall(async apiZone => {
const validatedParams = validator(params, '', { tChannelImpl: tChannelImplToWire, binary: this._connection.rawBuffers() ? 'buffer' : 'toBase64' });
const validatedParams = validator(params, '', this._validatorToWireContext());
if (!apiZone.isInternal && !apiZone.reported) {
// Reporting/tracing/logging this api call for the first time.
apiZone.params = params;

View File

@ -16,12 +16,10 @@
import { Connection } from './connection';
import { setPlatformForSelectors } from './selectors';
import { setIsUnderTestForValidator } from '../protocol/validatorPrimitives';
import type { Platform } from './platform';
export function createConnectionFactory(platform: Platform): () => Connection {
setPlatformForSelectors(platform);
setIsUnderTestForValidator(() => platform.isUnderTest());
return () => new Connection(platform);
}

View File

@ -148,6 +148,14 @@ export class Connection extends EventEmitter {
return await new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject, apiName, type, method }));
}
private _validatorFromWireContext(): ValidatorContext {
return {
tChannelImpl: this._tChannelImplFromWire.bind(this),
binary: this._rawBuffers ? 'buffer' : 'fromBase64',
isUnderTest: () => this._platform.isUnderTest(),
};
}
dispatch(message: object) {
if (this._closedError)
return;
@ -166,7 +174,7 @@ export class Connection extends EventEmitter {
callback.reject(parsedError);
} else {
const validator = findValidator(callback.type, callback.method, 'Result');
callback.resolve(validator(result, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._rawBuffers ? 'buffer' : 'fromBase64' }));
callback.resolve(validator(result, '', this._validatorFromWireContext()));
}
return;
}
@ -196,7 +204,7 @@ export class Connection extends EventEmitter {
}
const validator = findValidator(object._type, method, 'Event');
(object._channel as any).emit(method, validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._rawBuffers ? 'buffer' : 'fromBase64' }));
(object._channel as any).emit(method, validator(params, '', this._validatorFromWireContext()));
}
close(cause?: string) {
@ -227,7 +235,7 @@ export class Connection extends EventEmitter {
throw new Error(`Cannot find parent object ${parentGuid} to create ${guid}`);
let result: ChannelOwner<any>;
const validator = findValidator(type, '', 'Initializer');
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._rawBuffers ? 'buffer' : 'fromBase64' });
initializer = validator(initializer, '', this._validatorFromWireContext());
switch (type) {
case 'Android':
result = new Android(parent, type, guid, initializer);

View File

@ -14,17 +14,12 @@
* limitations under the License.
*/
let isUnderTest = () => false;
export function setIsUnderTestForValidator(getter: () => boolean) {
isUnderTest = getter;
}
export class ValidationError extends Error {}
export type Validator = (arg: any, path: string, context: ValidatorContext) => any;
export type ValidatorContext = {
tChannelImpl: (names: '*' | string[], arg: any, path: string, context: ValidatorContext) => any,
binary: 'toBase64' | 'fromBase64' | 'buffer',
tChannelImpl: (names: '*' | string[], arg: any, path: string, context: ValidatorContext) => any;
binary: 'toBase64' | 'fromBase64' | 'buffer';
isUnderTest: () => boolean;
};
export const scheme: { [key: string]: Validator } = {};
@ -117,7 +112,7 @@ export const tObject = (s: { [key: string]: Validator }): Validator => {
if (!Object.is(value, undefined))
result[key] = value;
}
if (isUnderTest()) {
if (context.isUnderTest()) {
for (const [key, value] of Object.entries(arg)) {
if (key.startsWith('__testHook'))
result[key] = value;

View File

@ -200,13 +200,13 @@ export class DispatcherConnection {
sendEvent(dispatcher: DispatcherScope, event: string, params: any) {
const validator = findValidator(dispatcher._type, event, 'Event');
params = validator(params, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
params = validator(params, '', this._validatorToWireContext());
this.onmessage({ guid: dispatcher._guid, method: event, params });
}
sendCreate(parent: DispatcherScope, type: string, guid: string, initializer: any) {
const validator = findValidator(type, '', 'Initializer');
initializer = validator(initializer, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
initializer = validator(initializer, '', this._validatorToWireContext());
this.onmessage({ guid: parent._guid, method: '__create__', params: { type, initializer, guid } });
}
@ -218,6 +218,22 @@ export class DispatcherConnection {
this.onmessage({ guid: dispatcher._guid, method: '__dispose__', params: { reason } });
}
private _validatorToWireContext(): ValidatorContext {
return {
tChannelImpl: this._tChannelImplToWire.bind(this),
binary: this._isLocal ? 'buffer' : 'toBase64',
isUnderTest,
};
}
private _validatorFromWireContext(): ValidatorContext {
return {
tChannelImpl: this._tChannelImplFromWire.bind(this),
binary: this._isLocal ? 'buffer' : 'fromBase64',
isUnderTest,
};
}
private _tChannelImplFromWire(names: '*' | string[], arg: any, path: string, context: ValidatorContext): any {
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
const guid = arg.guid;
@ -279,8 +295,9 @@ export class DispatcherConnection {
let validMetadata: channels.Metadata;
try {
const validator = findValidator(dispatcher._type, method, 'Params');
validParams = validator(params, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._isLocal ? 'buffer' : 'fromBase64' });
validMetadata = metadataValidator(metadata, '', { tChannelImpl: this._tChannelImplFromWire.bind(this), binary: this._isLocal ? 'buffer' : 'fromBase64' });
const validatorContext = this._validatorFromWireContext();
validParams = validator(params, '', validatorContext);
validMetadata = metadataValidator(metadata, '', validatorContext);
if (typeof (dispatcher as any)[method] !== 'function')
throw new Error(`Mismatching dispatcher: "${dispatcher._type}" does not implement "${method}"`);
} catch (e) {
@ -338,7 +355,7 @@ export class DispatcherConnection {
try {
const result = await dispatcher._handleCommand(callMetadata, method, validParams);
const validator = findValidator(dispatcher._type, method, 'Result');
response.result = validator(result, '', { tChannelImpl: this._tChannelImplToWire.bind(this), binary: this._isLocal ? 'buffer' : 'toBase64' });
response.result = validator(result, '', this._validatorToWireContext());
callMetadata.result = result;
} catch (e) {
if (isTargetClosedError(e) && sdkObject) {

View File

@ -18,6 +18,7 @@ import EventEmitter from 'events';
import * as socks from './utils/socksProxy';
import { ValidationError, findValidator } from '../protocol/validator';
import { isUnderTest } from './utils/debug';
import type { WebSocketTransport } from './transport';
import type { ValidatorContext } from '../protocol/validator';
@ -42,7 +43,7 @@ export class SocksInterceptor {
const id = --lastId;
this._ids.add(id);
const validator = findValidator('SocksSupport', prop, 'Params');
params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64' });
params = validator(params, '', { tChannelImpl: tChannelForSocks, binary: 'toBase64', isUnderTest });
transport.send({ id, guid: this._socksSupportObjectGuid, method: prop, params, metadata: { stack: [], apiName: '', internal: true } } as any);
} catch (e) {
}
@ -74,7 +75,7 @@ export class SocksInterceptor {
}
if (this._socksSupportObjectGuid && message.guid === this._socksSupportObjectGuid) {
const validator = findValidator('SocksSupport', message.method, 'Event');
const params = validator(message.params, '', { tChannelImpl: tChannelForSocks, binary: 'fromBase64' });
const params = validator(message.params, '', { tChannelImpl: tChannelForSocks, binary: 'fromBase64', isUnderTest });
this._channel.emit(message.method, params);
return true;
}