Skip to content

Commit 6dee6bb

Browse files
authored
Merge pull request #24 from jsonjoy-com/cleanup
Cleanup
2 parents 3af3de2 + cfbbbed commit 6dee6bb

File tree

17 files changed

+74
-126
lines changed

17 files changed

+74
-126
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,15 @@
7979
"@jsonjoy.com/json-pack": "^1.1.0",
8080
"@jsonjoy.com/util": "^1.4.0",
8181
"abstract-level": "^2.0.0",
82+
"classic-level": "^1.4.1",
8283
"fs-zoo": "^1.1.0",
8384
"memory-level": "^1.0.0",
85+
"rpc-error": "^1.1.0",
8486
"rx-use": "^1.8.1",
8587
"sonic-forest": "^1.0.3",
86-
"thingies": "^2.4.0",
87-
"classic-level": "^1.4.1"
88+
"thingies": "^2.4.0"
8889
},
8990
"devDependencies": {
90-
"json-joy": "^17.0.0",
9191
"@biomejs/biome": "^1.9.3",
9292
"@types/benchmark": "^2.1.5",
9393
"@types/jest": "^29.5.12",
@@ -96,6 +96,7 @@
9696
"@types/ws": "^8.5.10",
9797
"benchmark": "^2.1.4",
9898
"jest": "^29.7.0",
99+
"json-joy": "^17.0.0",
99100
"rimraf": "^5.0.5",
100101
"rxjs": "^7.8.1",
101102
"ts-jest": "^29.1.2",

src/README.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,30 @@
11
# Reactive-RPC
22

3-
Implements [Reactive-RPC](https://onp4.com/@vadim/p/qgzwgi42cz) protocol.
3+
Implements [Reactive-RPC](https://onp4.com/@vadim/p/qgzwgi42cz) protocol. A fast
4+
and type-safe HTTP and WebSocket server and client.
45

6+
7+
## Features
8+
9+
- Very fast.
10+
- Type-safe. Write types using JSON Type, TypeScript types are automatically
11+
inferred on the server and client.
12+
- Supports Reactive-RPC protocol.
13+
- Supports JSON-RPC 2.0 protocol.
14+
- Supports binary data.
15+
- Supports HTTP/1.1 and WebSocket.
16+
- Ships with a client and server
17+
- Specify RPC methods using JSON Type.
18+
- Supports TLS with automatic certificate reloading.
19+
20+
21+
## Installation
22+
23+
```bash
24+
npm install reactive-rpc rxjs
25+
```
26+
27+
28+
## Usage
29+
30+
See `/src/__demos__` for examples.

src/__demos__/json-crdt-server/services/blocks/BlocksServices.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ export class BlocksServices {
111111
public async get(id: string) {
112112
const {store} = this;
113113
const result = await store.get(id);
114-
if (!result) throw RpcError.fromCode(RpcErrorCodes.NOT_FOUND);
114+
if (!result) throw RpcError.notFound();
115115
return result;
116116
}
117117

118118
public async view(id: string) {
119119
const {store} = this;
120120
const result = await store.get(id);
121-
if (!result) throw RpcError.fromCode(RpcErrorCodes.NOT_FOUND);
121+
if (!result) throw RpcError.notFound();
122122
const model = Model.load(result.block.snapshot.blob);
123123
return model.view();
124124
}
@@ -141,7 +141,7 @@ export class BlocksServices {
141141
) {
142142
const {store} = this;
143143
if (typeof offset !== 'number') offset = await store.seq(id);
144-
if (typeof offset !== 'number') throw RpcError.fromCode(RpcErrorCodes.NOT_FOUND);
144+
if (typeof offset !== 'number') throw RpcError.notFound();
145145
let min = 0,
146146
max = 0;
147147
if (!limit || Math.round(limit) !== limit) throw RpcError.badRequest('INVALID_LIMIT');

src/__tests__/json-crdt-server/block.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ export const runBlockTests = (_setup: ApiTestSetup, params: {staticOnly?: true}
690690
const {call, stop} = await setup();
691691
const id = getId();
692692
const get1 = await of(call('block.get', {id}));
693-
expect(get1[1]).toMatchObject({message: 'NOT_FOUND'});
693+
expect(get1[1]).toMatchObject({code: 'NOT_FOUND'});
694694
const result = await call('block.pull', {
695695
id,
696696
seq: -1,

src/common/codec/compact/CompactRpcMessageCodec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type * as types from './types';
1111
import type {TlvBinaryJsonEncoder} from '@jsonjoy.com/json-pack';
1212

1313
const fromJson = (arr: unknown | unknown[] | types.CompactMessage): msg.ReactiveRpcMessage => {
14-
if (!(arr instanceof Array)) throw RpcError.fromCode(RpcErrorCodes.BAD_REQUEST);
14+
if (!(arr instanceof Array)) throw RpcError.badRequest();
1515
const type = arr[0];
1616
switch (type) {
1717
case CompactMessageType.RequestComplete: {

src/common/rpc/RpcMessageBatchProcessor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as msg from '../messages';
2-
import type {RpcErrorValue} from './caller';
32
import {validateId, validateMethod} from './validation';
43
import {TypedRpcError} from './caller/error/typed';
54
import type {RpcCaller} from './caller/RpcCaller';
5+
import type {RpcErrorValue} from './caller/error/types';
66

77
export type IncomingBatchMessage =
88
| msg.RequestDataMessage

src/common/rpc/RpcMessageStreamProcessor.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as msg from '../messages';
22
import {TimedQueue} from '../util/TimedQueue';
33
import {RpcErrorCodes, RpcError} from './caller/error/RpcError';
4-
import type {RpcValue} from '../messages/Value';
54
import {subscribeCompleteObserver} from '../util/subscribeCompleteObserver';
5+
import {TypedRpcError} from './caller/error/typed';
6+
import type {RpcValue} from '../messages/Value';
67
import type {RpcCaller} from './caller/RpcCaller';
78
import type {Call, RpcApiMap} from './caller/types';
8-
import {TypedRpcError} from './caller/error/typed';
99

1010
type Send = (messages: (msg.ReactiveRpcServerMessage | msg.NotificationMessage)[]) => void;
1111

@@ -182,12 +182,12 @@ export class RpcMessageStreamProcessor<Ctx = unknown> {
182182
let call = this.activeStreamCalls.get(id);
183183
if (!call) {
184184
if (!method) {
185-
this.sendError(id, RpcErrorCodes.NO_METHOD_SPECIFIED);
185+
this.sendError(id, RpcErrorCodes.METHOD_INV);
186186
return;
187187
}
188188
const info = this.caller.info(method);
189189
if (!info) {
190-
this.sendError(id, RpcErrorCodes.METHOD_NOT_FOUND);
190+
this.sendError(id, RpcErrorCodes.METHOD_UNK);
191191
return;
192192
}
193193
if (info.isStreaming) {
@@ -216,12 +216,12 @@ export class RpcMessageStreamProcessor<Ctx = unknown> {
216216
return;
217217
}
218218
if (!method) {
219-
this.sendError(id, RpcErrorCodes.NO_METHOD_SPECIFIED);
219+
this.sendError(id, RpcErrorCodes.METHOD_INV);
220220
return;
221221
}
222222
const caller = this.caller;
223223
if (!caller.exists(method)) {
224-
this.sendError(id, RpcErrorCodes.METHOD_NOT_FOUND);
224+
this.sendError(id, RpcErrorCodes.METHOD_UNK);
225225
return;
226226
}
227227
const {isStreaming} = caller.info(method);
@@ -245,16 +245,16 @@ export class RpcMessageStreamProcessor<Ctx = unknown> {
245245
return;
246246
}
247247
if (!method) {
248-
this.sendError(id, RpcErrorCodes.NO_METHOD_SPECIFIED);
248+
this.sendError(id, RpcErrorCodes.METHOD_INV);
249249
return;
250250
}
251251
if (!this.caller.exists(method)) {
252-
this.sendError(id, RpcErrorCodes.METHOD_NOT_FOUND);
252+
this.sendError(id, RpcErrorCodes.METHOD_UNK);
253253
return;
254254
}
255255
const {isStreaming} = this.caller.info(method);
256256
if (!isStreaming) {
257-
void this.sendError(id, RpcErrorCodes.INVALID_METHOD);
257+
void this.sendError(id, RpcErrorCodes.METHOD_UNK);
258258
return;
259259
}
260260
const streamCall = this.createStreamCall(id, method, ctx);
@@ -272,7 +272,7 @@ export class RpcMessageStreamProcessor<Ctx = unknown> {
272272

273273
public onNotificationMessage(message: msg.NotificationMessage, ctx: Ctx): void {
274274
const {method, value} = message;
275-
if (!method || method.length > 128) throw RpcError.fromCode(RpcErrorCodes.INVALID_METHOD);
275+
if (!method || method.length > 128) throw RpcError.fromErrno(RpcErrorCodes.METHOD_INV);
276276
const request = value && typeof value === 'object' ? value?.data : undefined;
277277
this.caller.notification(method, request, ctx).catch(() => {});
278278
}

src/common/rpc/__tests__/RpcMessageStreamProcessor.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ describe('pre-call checks', () => {
730730
expect(send).toHaveBeenCalledTimes(1);
731731
const errorValue = send.mock.calls[0][0][0];
732732
expect(errorValue).toBeInstanceOf(ResponseErrorMessage);
733-
expect(errorValue.value.data.message).toBe('BUFFER_OVERFLOW');
733+
expect(errorValue.value.data.message).toBe('OVERFLOW');
734734
});
735735

736736
test('buffer size can be set to 5 for the whole server', async () => {
@@ -766,7 +766,7 @@ describe('pre-call checks', () => {
766766
await new Promise((r) => setTimeout(r, 1));
767767
expect(send).toHaveBeenCalledTimes(1);
768768
expect(send.mock.calls[0][0][0]).toBeInstanceOf(ResponseErrorMessage);
769-
expect(send.mock.calls[0][0][0].value.data.message).toBe('BUFFER_OVERFLOW');
769+
expect(send.mock.calls[0][0][0].value.data.message).toBe('OVERFLOW');
770770
});
771771

772772
test('buffer size can be set to 5 per method', async () => {
@@ -802,7 +802,7 @@ describe('pre-call checks', () => {
802802
await new Promise((r) => setTimeout(r, 1));
803803
expect(send).toHaveBeenCalledTimes(1);
804804
expect(send.mock.calls[0][0][0]).toBeInstanceOf(ResponseErrorMessage);
805-
expect(send.mock.calls[0][0][0].value.data.message).toBe('BUFFER_OVERFLOW');
805+
expect(send.mock.calls[0][0][0].value.data.message).toBe('OVERFLOW');
806806
});
807807

808808
test('when pre-call checks finish just before buffer is full, can receive more request data', async () => {
@@ -929,9 +929,9 @@ describe('buffering', () => {
929929
await new Promise((r) => setTimeout(r, 10));
930930
expect(send).toHaveBeenCalledTimes(1);
931931
expect(send.mock.calls[0][0][0]).toBeInstanceOf(ResponseErrorMessage);
932-
expect(send.mock.calls[0][0][0].value.data.message).toBe('METHOD_NOT_FOUND');
932+
expect(send.mock.calls[0][0][0].value.data.message).toBe('METHOD_UNK');
933933
expect(send.mock.calls[0][0][1]).toBeInstanceOf(ResponseErrorMessage);
934-
expect(send.mock.calls[0][0][1].value.data.message).toBe('METHOD_NOT_FOUND');
934+
expect(send.mock.calls[0][0][1].value.data.message).toBe('METHOD_UNK');
935935
expect(send.mock.calls[0][0][0]).toBeInstanceOf(ResponseErrorMessage);
936936
expect(send.mock.calls[0][0][1]).toBeInstanceOf(ResponseErrorMessage);
937937
});

src/common/rpc/caller/RpcCaller.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import {firstValueFrom, from, type Observable, Subject} from 'rxjs';
22
import {catchError, finalize, first, map, mergeWith, share, switchMap, take, takeUntil, tap} from 'rxjs/operators';
3-
import {RpcError, RpcErrorCodes, type RpcErrorValue} from './error/RpcError';
3+
import {RpcError, RpcErrorCodes} from 'rpc-error';
44
import {TypedRpcError} from './error/typed';
55
import {RpcValue} from '../../messages/Value';
66
import {StaticRpcMethod} from '../methods/StaticRpcMethod';
77
import {BufferSubject} from '../../../util/rx/BufferSubject';
88
import type {Call} from './types';
99
import type {RpcMethod} from '../types';
1010
import type {StreamingRpcMethod} from '../methods/StreamingRpcMethod';
11+
import type {RpcErrorValue} from './error/types';
1112

1213
export interface RpcApiCallerOptions<Ctx = unknown> {
1314
getMethod: (name: string) => undefined | StaticRpcMethod<Ctx> | StreamingRpcMethod<Ctx>;
@@ -51,7 +52,7 @@ export class RpcCaller<Ctx = unknown> {
5152

5253
public getMethodStrict(name: string): StaticRpcMethod<Ctx> | StreamingRpcMethod<Ctx> {
5354
const method = this.getMethod(name);
54-
if (!method) throw TypedRpcError.valueFromCode(RpcErrorCodes.METHOD_NOT_FOUND);
55+
if (!method) throw TypedRpcError.valueFromCode(RpcErrorCodes.METHOD_UNK);
5556
return method;
5657
}
5758

src/common/rpc/caller/TypedApiCaller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {RpcErrorCodes} from './error/RpcError';
1+
import {RpcErrorCodes} from 'rpc-error';
22
import {TypedRpcError} from './error/typed';
33
import {RpcCaller, type RpcApiCallerOptions} from './RpcCaller';
44
import {FunctionStreamingType, FunctionType} from '@jsonjoy.com/json-type/lib/type/classes';
@@ -85,7 +85,7 @@ export class TypedApiCaller<Types extends TypeMap, Ctx = unknown> extends RpcCal
8585

8686
public get<K extends keyof Types>(id: K): MethodDefinition<Ctx, Types[K]> {
8787
const method = this.methods.get(id as string) as any;
88-
if (!method) throw TypedRpcError.valueFromCode(RpcErrorCodes.METHOD_NOT_FOUND);
88+
if (!method) throw TypedRpcError.valueFromCode(RpcErrorCodes.METHOD_UNK);
8989
return method;
9090
}
9191
}

0 commit comments

Comments
 (0)