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 { return [RpcMessageType.Pong, []]; } async function offerStatusSet(params: OfferStatusSetParams): Promise { 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 { 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, };