Skip to content

Commit

Permalink
type fix && add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
YieldRay committed Dec 19, 2023
1 parent dd7851d commit dfc9684
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 11 deletions.
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ A strictly typed json-rpc(2.0) implemention, zero dependency, minimal abstractio
```ts
const methodSet = {
upper: (str: string) => str.toUpperCase(),
} as const
lower: (str: string) => str.toLowerCase(),
plus: ([a, b]: [number, number]) => a + b,
minus: ([a, b]: [number, number]) => a - b,
}

const server = new JSONRPCServer(methodSet)

Expand All @@ -22,8 +25,10 @@ assertEquals(await client.request('upper', 'hello'), 'HELLO')
assertEquals(
await client.batch(
client.createRequest('upper', 'nihao'),
// notifaction does not have response, even when response errors
client.createNotifaction('upper'),
client.createRequest('upper', 'shijie'),
client.createRequest('plus', [1, 1]),
),
[
{
Expand All @@ -34,10 +39,16 @@ assertEquals(
status: 'fulfilled',
value: 'SHIJIE',
},
{
status: 'fulfilled',
value: 2,
},
],
)
```

Example to use the client

```ts
const client = new JSONRPCClient((json) =>
fetch('http://localhost:6800/jsonrpc', {
Expand All @@ -48,3 +59,29 @@ const client = new JSONRPCClient((json) =>

const aria2cMethods = await client.request('system.listMethods')
```

Example to use the server

```ts
const server = new JSONRPCServer()

server.setMethod('trim', (str: string) => str.trim())
server.setMethod('trimStart', (str: string) => str.trimStart())
server.setMethod('trimEnd', (str: string) => str.trimEnd())

const httpServer = Deno.serve(
async (request) => {
const url = new URL(request.url)
if (url.pathname === '/jsonrpc') {
return new Response(
// server.process() accept string and returns Promise<string>
await server.process(await request.text()),
{
headers: { 'content-type': 'application/json' },
},
)
}
return new Response('404', { status: 404 })
},
)
```
4 changes: 2 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@ export class JSONRPCClient<MethodSet extends JSONRPCMethodSet> {

/**
* You should use the `createRequest()` or `createNotifaction()` method to
* create the requests array.
* create the requests array. Response order is always matched by id.
*
* Throws `JSONRPCClientParseError` if server response cannot be parsed,
* note that it does not throws for any `JSONRPCErrorResponse`, in this
* note that it does not throws for any `JSONRPCErrorResponse`, in this
* case it will be a single object: `{ status: 'rejected', reason: {...} }`
*
* Usually it returns be like (same as the `Promise.allSettled()` method):
Expand Down
73 changes: 71 additions & 2 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,44 @@ Deno.test('JSONRPCClient/JSONRPCServer', async () => {
assertObjectMatch(
await client.request(
'plus',
{ $: 'not an array, so it should throw' } as any,
{ error_test: 'not an array, so it should throw' } as any,
).catch((e) => e),
{
code: -32603,
message: 'Internal error',
},
)

assertObjectMatch(
await client.request(
'no_such_method' as any,
).catch((e) => e),
{
code: -32601,
message: 'Method not found',
},
)

assertEquals(
await client.batch(
client.createRequest('upper', 'nihao'),
client.createNotifaction('upper', 'anything'),
client.createNotifaction('lower', 'anything'),
client.createRequest('upper', 'shijie'),
client.createRequest('plus', [1, 2]),
client.createRequest('minus', [1, 2]),
),
[{
status: 'fulfilled',
value: 'NIHAO',
}, {
status: 'fulfilled',
value: 'SHIJIE',
}, {
status: 'fulfilled',
value: 3,
}, {
status: 'fulfilled',
value: -1,
}],
)
})
Expand All @@ -61,6 +79,14 @@ Deno.test({
.state !==
'granted',
fn: async () => {
const ok = await fetch('http://localhost:6800/jsonrpc', {
signal: AbortSignal.timeout(500),
}).then((res) => res.ok).catch(() => false)
if (!ok) {
// skip when no aria2c jsonrpc is running
return
}

const client = new JSONRPCClient((json) =>
fetch('http://localhost:6800/jsonrpc', {
method: 'POST',
Expand All @@ -81,3 +107,46 @@ Deno.test({
assertObjectMatch(r2, { status: 'fulfilled' })
},
})

Deno.test({
name: 'JSONRPCServer/Deno.serve()',
ignore: Deno.permissions.querySync({ name: 'net' })
.state !==
'granted',
fn: async () => {
const server = new JSONRPCServer()

server.setMethod('trim', (str: string) => str.trim())
server.setMethod('trimStart', (str: string) => str.trimStart())
server.setMethod('trimEnd', (str: string) => str.trimEnd())

const httpServer = Deno.serve(
{ port: 8888, onListen() {} },
async (request) => {
const url = new URL(request.url)
if (url.pathname === '/jsonrpc') {
return new Response(
await server.process(await request.text()),
{
headers: { 'content-type': 'application/json' },
},
)
}
return new Response('404', { status: 404 })
},
)

const client = new JSONRPCClient((json) =>
fetch('http://localhost:8888/jsonrpc', {
method: 'POST',
body: json,
}).then((res) => res.text())
)

assertEquals(await client.request('trim', ' trim '), 'trim')
assertEquals(await client.request('trimStart', ' trim '), 'trim ')
assertEquals(await client.request('trimEnd', ' trim '), ' trim')

await httpServer.shutdown()
},
})
17 changes: 11 additions & 6 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,17 @@ import type { JSONRPCMethodSet, JSONRPCValue } from './types.ts'
*
* See `JSONRPCMethodSet` for how method in method set should be.
*/
export class JSONRPCServer<MethodSet extends JSONRPCMethodSet> {
export class JSONRPCServer<
MethodSet extends JSONRPCMethodSet = JSONRPCMethodSet,
> {
private methodSet: MethodSet

constructor()
constructor(methodSet: MethodSet)
constructor(methodSet?: MethodSet) {
this.methodSet = methodSet || ({} as MethodSet)
}

/**
* Override this function, to customize the behavior
* when method is not in methodSet.
Expand Down Expand Up @@ -60,12 +68,9 @@ export class JSONRPCServer<MethodSet extends JSONRPCMethodSet> {
public setMethod<T extends keyof MethodSet>(
method: T,
fn: MethodSet[T],
): void {
) {
Reflect.set(this.methodSet, method, fn)
}

constructor(methodSet: MethodSet) {
this.methodSet = methodSet
return this
}

/**
Expand Down

0 comments on commit dfc9684

Please sign in to comment.