101 lines
2.8 KiB
TypeScript
101 lines
2.8 KiB
TypeScript
import { EventEmitter } from 'node:events';
|
|
import { setTimeout } from 'timers/promises';
|
|
import assert from 'assert/strict';
|
|
|
|
import type Log from 'bunyan';
|
|
|
|
import type { Want, Offer, User } from '@prisma/client';
|
|
|
|
import { Pg } from './pg';
|
|
import { Status } from './offers';
|
|
|
|
function checkMsgType(msgType: RpcMessageType): msgType is RpcMessageType {
|
|
if (RpcMessageType[msgType]) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// rpc is created per connection from the api
|
|
export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, offers) {
|
|
async function ping(): Promise<PongMessage> {
|
|
return [RpcMessageType.Pong, []];
|
|
}
|
|
|
|
async function offerStatusSet(params: OfferStatusSetParams): Promise<OffersMessage> {
|
|
log.info(params);
|
|
const { id, status } = params;
|
|
assert(id, 'no id supplied');
|
|
assert(Status[status], 'unknown status');
|
|
|
|
const offer = await offers.statusSet(user, id, status);
|
|
return [RpcMessageType.Offers, []]
|
|
}
|
|
|
|
async function receive(message: any): Promise<RpcMessage> {
|
|
const [msgType, params] = message;
|
|
|
|
if (msgType !== RpcMessageType.Ping) log.info({ msgType, params }, 'rpc message');
|
|
|
|
// // this sucks but can't figure out how to convince typescript to agree yet
|
|
if (checkMsgType(msgType)) {
|
|
switch (msgType) {
|
|
case RpcMessageType.Ping:
|
|
return ping();
|
|
case RpcMessageType.OfferStatusSet:
|
|
return offerStatusSet(params);
|
|
default:
|
|
throw new Error(`Message type ${msgType} is known but unhandled`);
|
|
}
|
|
} else {
|
|
throw new Error(`Unknown message type ${msgType}`);
|
|
}
|
|
|
|
throw new Error(`Invalid parameters for message type ${msgType}: ${JSON.stringify(message)}`);
|
|
}
|
|
|
|
function send(msg: RpcMessage) {
|
|
ws.send(JSON.stringify(msg, (key, value) =>
|
|
typeof value === 'bigint'
|
|
? value.toString()
|
|
: value // return everything else unchanged
|
|
))
|
|
}
|
|
|
|
return {
|
|
receive,
|
|
send,
|
|
}
|
|
}
|
|
|
|
export enum RpcMessageType {
|
|
Ping = 'Ping',
|
|
Pong = 'Pong',
|
|
|
|
Bundles = 'Bundles',
|
|
Offers = 'Offers',
|
|
List = 'List',
|
|
Error = 'Error',
|
|
|
|
OfferStatusSet = 'OfferStatusSet',
|
|
}
|
|
|
|
type ErrorMessage = [RpcMessageType.Error, string];
|
|
type PongMessage = [RpcMessageType.Pong, []];
|
|
type PingMessage = [RpcMessageType.Ping, []];
|
|
type OffersMessage = [RpcMessageType.Offers, Offer[]];
|
|
type OfferStatusSetMessage = [RpcMessageType.OfferStatusSet, Offer[]];
|
|
|
|
export type RpcMessage =
|
|
PingMessage |
|
|
PongMessage |
|
|
OffersMessage |
|
|
OfferStatusSetMessage |
|
|
ErrorMessage;
|
|
|
|
|
|
type OfferStatusSetParams = {
|
|
id: UUID,
|
|
status: Status,
|
|
};
|