Skip to content

Commit

Permalink
fix: Add idResolvers support. Add export of Integrated Resolvers. A…
Browse files Browse the repository at this point in the history
…dd `PureBrotliCompressionResolver` and `WasmBrotliCompressionResolver` (for different env support)
  • Loading branch information
yeskiy committed Mar 24, 2023
1 parent 3633713 commit 7e7a933
Show file tree
Hide file tree
Showing 19 changed files with 355 additions and 60 deletions.
47 changes: 47 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"url": "git+https://github.com/yeskiy/prpcow.git"
},
"dependencies": {
"brotli": "^1.3.3",
"brotli-wasm": "^1.3.1",
"buffer": "^6.0.3",
"events": "^3.3.0",
"pure-uuid": "^1.6.3",
Expand All @@ -38,6 +40,7 @@
"ws": "^8.5.0 || ^7.5.0"
},
"devDependencies": {
"@types/brotli": "^1.3.1",
"@types/uuid": "^9.0.1",
"@types/ws": "^8.5.4",
"@typescript-eslint/eslint-plugin": "^5.51.0",
Expand Down
64 changes: 46 additions & 18 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import NoCompressionResolver from "./compressResolvers/noCompression.compression
import { ICompressResolver } from "./compressResolvers";
import { IFunctionResolver } from "./functionResolvers";
import { IModelResolver } from "./modelResolvers";
import { IIdResolver } from "./idResolvers";
import UuidIdResolver from "./idResolvers/uuid.idResolver";

interface WebsocketProto {
prototype: WebSocket;
Expand All @@ -27,6 +29,7 @@ export type ClientOptions = {
FunctionResolver?: IFunctionResolver;
ModelResolver?: IModelResolver;
CompressResolver?: ICompressResolver;
IdResolver?: IIdResolver;
};
logger?: LoggerOptions | boolean;
};
Expand All @@ -37,6 +40,7 @@ type ClientInnerOptions = ClientOptions & {
FunctionResolver: IFunctionResolver;
ModelResolver: IModelResolver;
CompressResolver: ICompressResolver;
IdResolver: IIdResolver;
};
version: string;
};
Expand Down Expand Up @@ -69,6 +73,7 @@ export class Client {
FunctionResolver: WeakFunctionPool,
ModelResolver: DefaultResolver,
CompressResolver: NoCompressionResolver,
IdResolver: UuidIdResolver,
...finalOptions.universalRPC,
},
version: packageJson.version,
Expand Down Expand Up @@ -122,13 +127,19 @@ export class Client {
semver.eq(
this.options.version,
clientRequest.data.version
) ||
clientRequest.data.functionResolver ===
this.options.universalRPC.FunctionResolver.typeName() ||
clientRequest.data.modelResolver ===
this.options.universalRPC.ModelResolver.typeName() ||
clientRequest.data.CompressResolver ===
this.options.universalRPC.CompressResolver.typeName()
) &&
this.options.universalRPC.FunctionResolver.isCompatibleWith(
clientRequest.data.functionResolver
) &&
this.options.universalRPC.ModelResolver.isCompatibleWith(
clientRequest.data.modelResolver
) &&
this.options.universalRPC.CompressResolver.isCompatibleWith(
clientRequest.data.compressResolver
) &&
this.options.universalRPC.IdResolver.isCompatibleWith(
clientRequest.data.idResolver
)
)
) {
this.logger.silly(
Expand All @@ -143,7 +154,10 @@ export class Client {
clientRequest.data.modelResolver
}`,
`Client compressResolver: ${this.options.universalRPC.CompressResolver.typeName()}, Server compressResolver: ${
clientRequest.data.CompressResolver
clientRequest.data.compressResolver
}`,
`Client idResolver: ${this.options.universalRPC.IdResolver.typeName()}, Server idResolver: ${
clientRequest.data.idResolver
}`
);
throw new RuntimeError(
Expand All @@ -155,30 +169,42 @@ export class Client {
? ""
: `Client version: ${this.options.version}, Server version: ${clientRequest.data.version}`
} ${
clientRequest.data
.functionResolver !==
this.options.universalRPC.FunctionResolver.typeName()
!this.options.universalRPC.FunctionResolver.isCompatibleWith(
clientRequest.data
.functionResolver
)
? ""
: `Client functionResolver: ${this.options.universalRPC.FunctionResolver.typeName()}, Server functionResolver: ${
clientRequest.data
.functionResolver
}`
} ${
clientRequest.data.modelResolver !==
this.options.universalRPC.ModelResolver.typeName()
!this.options.universalRPC.ModelResolver.isCompatibleWith(
clientRequest.data.modelResolver
)
? ""
: `Client modelResolver: ${this.options.universalRPC.ModelResolver.typeName()}, Server modelResolver: ${
clientRequest.data
.modelResolver
}`
} ${
clientRequest.data
.CompressResolver !==
this.options.universalRPC.CompressResolver.typeName()
!this.options.universalRPC.CompressResolver.isCompatibleWith(
clientRequest.data
.compressResolver
)
? ""
: `Client compressResolver: ${this.options.universalRPC.CompressResolver.typeName()}, Server compressResolver: ${
clientRequest.data
.CompressResolver
.compressResolver
}`
} ${
!this.options.universalRPC.IdResolver.isCompatibleWith(
clientRequest.data.idResolver
)
? ""
: `Client idResolver: ${this.options.universalRPC.IdResolver.typeName()}, Server idResolver: ${
clientRequest.data
.idResolver
}`
}`,
400,
Expand All @@ -191,14 +217,16 @@ export class Client {
);

const initPayload = {
key: this.key,
version: this.options.version,
functionResolver:
this.options.universalRPC.FunctionResolver.typeName(),
modelResolver:
this.options.universalRPC.ModelResolver.typeName(),
compressResolver:
this.options.universalRPC.CompressResolver.typeName(),
key: this.key,
idResolver:
this.options.universalRPC.IdResolver.typeName(),
};

this.logger.debug(
Expand Down
11 changes: 4 additions & 7 deletions src/compressResolvers/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import WebSocket from "ws";
import { BufferLike, ModifiedWebSocket } from "../utils/websocketModifier.util";
import { Logger, LoggerOptions } from "../utils/logger.util";
import { IResolverStatic, Resolver } from "../types";

export abstract class CompressResolver {
export abstract class CompressResolver extends Resolver {
options: {
session: ModifiedWebSocket;
logger: LoggerOptions | boolean;
Expand All @@ -14,6 +15,7 @@ export abstract class CompressResolver {
session: ModifiedWebSocket;
logger: LoggerOptions | boolean;
}) {
super();
this.options = options;
if (typeof this.options.logger !== "boolean") {
this.logger = new Logger({
Expand All @@ -28,20 +30,15 @@ export abstract class CompressResolver {
this.logger = new Logger();
}
}

static typeName(): string {
throw new Error("typeName() implementation is required");
}
public abstract compress(messageEvent: object): Promise<BufferLike>;
public abstract decompress(
messageEvent: WebSocket.MessageEvent
): Promise<object>;
}

export interface ICompressResolver {
export interface ICompressResolver extends IResolverStatic {
new (options: {
session: ModifiedWebSocket;
logger: LoggerOptions | boolean;
}): CompressResolver;
typeName(): string;
}
29 changes: 29 additions & 0 deletions src/compressResolvers/pureBrotli.compressionResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { MessageEvent } from "ws";
import brotli from "brotli";
import { Buffer } from "buffer";
import { BufferLike } from "../utils/websocketModifier.util";
import { CompressResolver } from "./index";

export default class PureBrotliCompressionResolver extends CompressResolver {
public static typeName(): string {
return "PureBrotli";
}

public static isCompatibleWith(type: string): boolean {
return [this.typeName(), "WasmBrotli"].indexOf(type) !== -1;
}

// eslint-disable-next-line class-methods-use-this
public async compress(messageEvent: object): Promise<BufferLike> {
return brotli.compress(Buffer.from(JSON.stringify(messageEvent)), {
quality: 0,
});
}

// eslint-disable-next-line class-methods-use-this
public async decompress(messageEvent: MessageEvent): Promise<object> {
return JSON.parse(
brotli.decompress(<Buffer>messageEvent.data).toString()
);
}
}
31 changes: 31 additions & 0 deletions src/compressResolvers/wasmBrotli.compressionResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import WebSocket from "ws";
import * as brotli from "brotli-wasm";
import { Buffer } from "buffer";
import { CompressResolver } from "./index";
import { BufferLike } from "../utils/websocketModifier.util";

export default class WasmBrotliCompressionResolver extends CompressResolver {
public static typeName(): string {
return "WasmBrotli";
}

public static isCompatibleWith(type: string): boolean {
return [this.typeName(), "PureBrotli"].indexOf(type) !== -1;
}

// eslint-disable-next-line class-methods-use-this
public async compress(messageEvent: object): Promise<BufferLike> {
return brotli.compress(Buffer.from(JSON.stringify(messageEvent)), {
quality: 0,
});
}

// eslint-disable-next-line class-methods-use-this
public async decompress(
messageEvent: WebSocket.MessageEvent
): Promise<object> {
return JSON.parse(
brotli.decompress(<Uint8Array>messageEvent.data).toString()
);
}
}
13 changes: 8 additions & 5 deletions src/functionResolvers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { DataObject } from "../utils/typeAssert.util";
import { ModifiedWebSocket } from "../utils/websocketModifier.util";
import { Logger, LoggerOptions } from "../utils/logger.util";
import { ModelResolver } from "../modelResolvers";
import { FunctionResolverFunction } from "../types";
import { FunctionResolverFunction, IResolverStatic, Resolver } from "../types";
import { IdResolver } from "../idResolvers";

export abstract class FunctionResolver {
export abstract class FunctionResolver extends Resolver {
protected options: {
session: ModifiedWebSocket;
sendMessage: (message: any) => Promise<void>;
deSerializeObject: ModelResolver["deserialize"];
serializeObject: ModelResolver["serialize"];
uuid: IdResolver["gen"];
logger: LoggerOptions | boolean;
};

Expand All @@ -20,8 +22,10 @@ export abstract class FunctionResolver {
sendMessage: (message: any) => Promise<void>;
deSerializeObject: ModelResolver["deserialize"];
serializeObject: ModelResolver["serialize"];
uuid: IdResolver["gen"];
logger: LoggerOptions | boolean;
}) {
super();
this.options = options;
if (typeof this.options.logger !== "boolean") {
this.logger = new Logger({
Expand Down Expand Up @@ -49,14 +53,13 @@ export abstract class FunctionResolver {
public abstract close(): void;
}

export interface IFunctionResolver {
export interface IFunctionResolver extends IResolverStatic {
new (options: {
session: ModifiedWebSocket;
sendMessage: (message: any) => Promise<void>;
deSerializeObject: ModelResolver["deserialize"];
serializeObject: ModelResolver["serialize"];
uuid: IdResolver["gen"];
logger: LoggerOptions | boolean;
}): FunctionResolver;

typeName(): string;
}
Loading

0 comments on commit 7e7a933

Please sign in to comment.