Skip to content

Commit

Permalink
feat: handlers implementations are now abstract arrow functions
Browse files Browse the repository at this point in the history
* Fixes #5

[ci skip]
  • Loading branch information
addievo committed Sep 13, 2023
1 parent 2468889 commit 45ac70e
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 122 deletions.
12 changes: 6 additions & 6 deletions src/RPCServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,47 +138,47 @@ class RPCServer extends EventTarget {
if (manifestItem instanceof RawHandler) {
this.registerRawStreamHandler(
key,
manifestItem.handle.bind(manifestItem),
manifestItem.handle,
manifestItem.timeout,
);
continue;
}
if (manifestItem instanceof DuplexHandler) {
this.registerDuplexStreamHandler(
key,
manifestItem.handle.bind(manifestItem),
manifestItem.handle,
manifestItem.timeout,
);
continue;
}
if (manifestItem instanceof ServerHandler) {
this.registerServerStreamHandler(
key,
manifestItem.handle.bind(manifestItem),
manifestItem.handle,
manifestItem.timeout,
);
continue;
}
if (manifestItem instanceof ClientHandler) {
this.registerClientStreamHandler(
key,
manifestItem.handle.bind(manifestItem),
manifestItem.handle,
manifestItem.timeout,
);
continue;
}
if (manifestItem instanceof ClientHandler) {
this.registerClientStreamHandler(
key,
manifestItem.handle.bind(manifestItem),
manifestItem.handle,
manifestItem.timeout,
);
continue;
}
if (manifestItem instanceof UnaryHandler) {
this.registerUnaryHandler(
key,
manifestItem.handle.bind(manifestItem),
manifestItem.handle,
manifestItem.timeout,
);
continue;
Expand Down
11 changes: 11 additions & 0 deletions src/errors/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ export function never(): never {
throw new ErrorRPC('This function should never be called');
}

class ErrorRPCMethodNotImplemented<T> extends ErrorRPC<T> {
constructor(message?: string) {
super(message || 'This method must be overridden'); // Default message if none provided
this.name = 'ErrorRPCMethodNotImplemented';
this.description =
'This abstract method must be implemented in a derived class';
this.exitCode = sysexits.USAGE; // Or another suitable exit code
}
}

export {
ErrorRPC,
ErrorRPCDestroyed,
Expand All @@ -200,4 +210,5 @@ export {
ErrorRPCStreamEnded,
ErrorRPCTimedOut,
ErrorUtilsUndefinedBehaviour,
ErrorRPCMethodNotImplemented,
};
11 changes: 6 additions & 5 deletions src/handlers/clientHandler.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import type { ContainerType, JSONValue } from '../types';
import type { ContextTimed } from '@matrixai/contexts';
import { Handler } from './handler';
import { ErrorRPCMethodNotImplemented } from '../errors';

abstract class ClientHandler<
export abstract class ClientHandler<
Container extends ContainerType = ContainerType,
Input extends JSONValue = JSONValue,
Output extends JSONValue = JSONValue,
> extends Handler<Container, Input, Output> {
abstract handle(
public handle = async (
input: AsyncIterableIterator<Input>,
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): Promise<Output>;
): Promise<Output> => {
throw new ErrorRPCMethodNotImplemented();
};
}

export { ClientHandler };
11 changes: 6 additions & 5 deletions src/handlers/duplexHandler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { ContainerType, JSONValue } from '../types';
import type { ContextTimed } from '@matrixai/contexts';
import { Handler } from './handler';
import { ErrorRPCMethodNotImplemented } from '../errors';

abstract class DuplexHandler<
export abstract class DuplexHandler<
Container extends ContainerType = ContainerType,
Input extends JSONValue = JSONValue,
Output extends JSONValue = JSONValue,
Expand All @@ -12,12 +13,12 @@ abstract class DuplexHandler<
* error. If you need to handle any clean up it should be handled in a
* `finally` block and check the abort signal for potential errors.
*/
abstract handle(
public handle = async function* (
input: AsyncIterableIterator<Input>,
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): AsyncIterableIterator<Output>;
): AsyncIterableIterator<Output> {
throw new ErrorRPCMethodNotImplemented('This method must be overwrtitten.');
};
}

export { DuplexHandler };
4 changes: 1 addition & 3 deletions src/handlers/handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ContainerType, JSONValue } from '../types';

abstract class Handler<
export abstract class Handler<
Container extends ContainerType = ContainerType,
Input extends JSONValue = JSONValue,
Output extends JSONValue = JSONValue,
Expand All @@ -17,5 +17,3 @@ abstract class Handler<

constructor(protected container: Container) {}
}

export { Handler };
11 changes: 6 additions & 5 deletions src/handlers/rawHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import type { ContextTimed } from '@matrixai/contexts';
import type { ReadableStream } from 'stream/web';
import type { ContainerType, JSONRPCRequest, JSONValue } from '../types';
import { Handler } from './handler';
import { ErrorRPCMethodNotImplemented } from '../errors';

abstract class RawHandler<
export abstract class RawHandler<
Container extends ContainerType = ContainerType,
> extends Handler<Container> {
abstract handle(
public handle = async (
input: [JSONRPCRequest, ReadableStream<Uint8Array>],
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): Promise<[JSONValue, ReadableStream<Uint8Array>]>;
): Promise<[JSONValue, ReadableStream<Uint8Array>]> => {
throw new ErrorRPCMethodNotImplemented('This method must be overridden');
};
}

export { RawHandler };
11 changes: 6 additions & 5 deletions src/handlers/serverHandler.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import type { ContextTimed } from '@matrixai/contexts';
import type { ContainerType, JSONValue } from '../types';
import { Handler } from '@/handlers/handler';
import { ErrorRPCMethodNotImplemented } from '../errors';

abstract class ServerHandler<
export abstract class ServerHandler<
Container extends ContainerType = ContainerType,
Input extends JSONValue = JSONValue,
Output extends JSONValue = JSONValue,
> extends Handler<Container, Input, Output> {
abstract handle(
public handle = async function* (
input: Input,
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): AsyncIterableIterator<Output>;
): AsyncIterableIterator<Output> {
throw new ErrorRPCMethodNotImplemented('This method must be overridden');
};
}

export { ServerHandler };
11 changes: 6 additions & 5 deletions src/handlers/unaryHandler.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import type { ContextTimed } from '@matrixai/contexts';
import type { ContainerType, JSONValue } from '../types';
import { Handler } from './handler';
import { ErrorRPCMethodNotImplemented } from '../errors';

abstract class UnaryHandler<
export abstract class UnaryHandler<
Container extends ContainerType = ContainerType,
Input extends JSONValue = JSONValue,
Output extends JSONValue = JSONValue,
> extends Handler<Container, Input, Output> {
abstract handle(
public handle = async (
input: Input,
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): Promise<Output>;
): Promise<Output> => {
throw new ErrorRPCMethodNotImplemented('This method must be overridden');
};
}

export { UnaryHandler };
71 changes: 49 additions & 22 deletions tests/rpc/RPC.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ContainerType, JSONRPCRequest } from '../../src/types';
import type { ReadableStream } from 'stream/web';
import type { JSONValue } from '../../src/types';
import type { ContextTimed } from '@matrixai/contexts';
import { TransformStream } from 'stream/web';
import { fc, testProp } from '@fast-check/jest';
import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
Expand Down Expand Up @@ -39,17 +40,17 @@ describe('RPC', () => {
let header: JSONRPCRequest | undefined;

class TestMethod extends RawHandler<ContainerType> {
public async handle(
public handle = async (
input: [JSONRPCRequest<JSONValue>, ReadableStream<Uint8Array>],
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue> | undefined,
): Promise<[JSONValue, ReadableStream<Uint8Array>]> {
): Promise<[JSONValue, ReadableStream<Uint8Array>]> => {
return new Promise((resolve) => {
const [header_, stream] = input;
header = header_;
resolve(['some leading data', stream]);
});
}
};
}
const rpcServer = await RPCServer.createRPCServer({
manifest: {
Expand Down Expand Up @@ -139,12 +140,16 @@ describe('RPC', () => {
>();

class TestMethod extends RawHandler<ContainerType> {
public async handle(): Promise<
[JSONRPCRequest<JSONValue>, ReadableStream<Uint8Array>]
> {
throw Error('some error');
}
public handle = async (
input: [JSONRPCRequest<JSONValue>, ReadableStream<Uint8Array>],
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): Promise<[JSONValue, ReadableStream<Uint8Array>]> => {
throw new Error('some error');
};
}

const rpcServer = await RPCServer.createRPCServer({
manifest: {
testMethod: new TestMethod({}),
Expand Down Expand Up @@ -187,11 +192,14 @@ describe('RPC', () => {
Uint8Array
>();
class TestMethod extends DuplexHandler {
public async *handle(
public handle = async function* (
input: AsyncGenerator<JSONValue>,
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): AsyncGenerator<JSONValue> {
yield* input;
}
};
}
const rpcServer = await RPCServer.createRPCServer({
manifest: {
Expand Down Expand Up @@ -242,11 +250,13 @@ describe('RPC', () => {
>();

class TestMethod extends ServerHandler<ContainerType, number, number> {
public async *handle(input: number): AsyncGenerator<number> {
public handle = async function* (
input: number,
): AsyncGenerator<number> {
for (let i = 0; i < input; i++) {
yield i;
}
}
};
}

const rpcServer = await RPCServer.createRPCServer({
Expand Down Expand Up @@ -294,14 +304,17 @@ describe('RPC', () => {
>();

class TestMethod extends ClientHandler<ContainerType, number, number> {
public async handle(input: AsyncIterable<number>): Promise<number> {
public handle = async (
input: AsyncIterable<number>,
): Promise<number> => {
let acc = 0;
for await (const number of input) {
acc += number;
}
return acc;
}
};
}

const rpcServer = await RPCServer.createRPCServer({
manifest: {
testMethod: new TestMethod({}),
Expand Down Expand Up @@ -348,9 +361,9 @@ describe('RPC', () => {
>();

class TestMethod extends UnaryHandler {
public async handle(input: JSONValue): Promise<JSONValue> {
public handle = async (input: JSONValue): Promise<JSONValue> => {
return input;
}
};
}
const rpcServer = await RPCServer.createRPCServer({
manifest: {
Expand Down Expand Up @@ -395,9 +408,14 @@ describe('RPC', () => {
>();

class TestMethod extends UnaryHandler {
public async handle(): Promise<JSONValue> {
public handle = async (
_input: JSONValue,
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue> | undefined,
_ctx: ContextTimed,
): Promise<JSONValue> => {
throw error;
}
};
}

const rpcServer = await RPCServer.createRPCServer({
Expand Down Expand Up @@ -447,9 +465,14 @@ describe('RPC', () => {
>();

class TestMethod extends UnaryHandler {
public async handle(): Promise<JSONValue> {
public handle = async (
_input: JSONValue,
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue> | undefined,
_ctx: ContextTimed,
): Promise<JSONValue> => {
throw error;
}
};
}

const rpcServer = await RPCServer.createRPCServer({
Expand Down Expand Up @@ -488,12 +511,16 @@ describe('RPC', () => {
Uint8Array
>();
class TestMethod extends DuplexHandler {
public async *handle(
public handle = async function* (
input: AsyncIterableIterator<JSONValue>,
cancel: (reason?: any) => void,
meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): AsyncIterableIterator<JSONValue> {
yield* input;
}
};
}

const middleware = rpcUtilsMiddleware.defaultServerMiddlewareWrapper(() => {
return {
forward: new TransformStream({
Expand Down
Loading

0 comments on commit 45ac70e

Please sign in to comment.