diff --git a/api/package-lock.json b/api/package-lock.json index eabc415..0564ae8 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -29,6 +29,7 @@ "@types/bcrypt": "^5.0.0", "@types/bluebird": "^3.5.36", "@types/koa": "^2.13.5", + "@types/koa-websocket": "^5.0.7", "@types/lodash": "^4.14.182", "@types/mocha": "^9.1.1", "axios": "^0.27.2", @@ -325,6 +326,17 @@ "@types/koa": "*" } }, + "node_modules/@types/koa-websocket": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/koa-websocket/-/koa-websocket-5.0.7.tgz", + "integrity": "sha512-zv5F0iaV9zk3iXLzvskUZKgX35RW7F7UNX3tK1FNQUn2nierQWlY2aM0dBTYs0kLVLRtBhsxcUdiKzDp9JPOAw==", + "dev": true, + "dependencies": { + "@types/koa": "*", + "@types/koa-compose": "*", + "@types/ws": "*" + } + }, "node_modules/@types/lodash": { "version": "4.14.182", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", @@ -382,6 +394,15 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -3961,6 +3982,17 @@ "@types/koa": "*" } }, + "@types/koa-websocket": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/koa-websocket/-/koa-websocket-5.0.7.tgz", + "integrity": "sha512-zv5F0iaV9zk3iXLzvskUZKgX35RW7F7UNX3tK1FNQUn2nierQWlY2aM0dBTYs0kLVLRtBhsxcUdiKzDp9JPOAw==", + "dev": true, + "requires": { + "@types/koa": "*", + "@types/koa-compose": "*", + "@types/ws": "*" + } + }, "@types/lodash": { "version": "4.14.182", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", @@ -4018,6 +4050,15 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", diff --git a/api/package.json b/api/package.json index 3786f54..8030a83 100644 --- a/api/package.json +++ b/api/package.json @@ -16,6 +16,7 @@ "@types/bcrypt": "^5.0.0", "@types/bluebird": "^3.5.36", "@types/koa": "^2.13.5", + "@types/koa-websocket": "^5.0.7", "@types/lodash": "^4.14.182", "@types/mocha": "^9.1.1", "axios": "^0.27.2", diff --git a/api/src/api.ts b/api/src/api.ts index af4de29..a78e075 100644 --- a/api/src/api.ts +++ b/api/src/api.ts @@ -14,11 +14,13 @@ import type Log from 'bunyan'; import type { Listing, User, Want, Prisma } from '@prisma/client'; import { Pg } from './pg'; +import { Discogs } from './discogs'; +import { Offers } from './offers'; import routerAuth from './routers/router.auth'; import { Events } from './events'; import createRpc, { RpcMessageType } from './rpc'; -export default function createApi(log: Log, pg: Pg, discogs, offers, events) { +export default function createApi(log: Log, pg: Pg, discogs: Discogs, offers: Offers, events) { const PORT = 41337; const WS_PORT = 40055; const SECRET = 'ohja4Eif9eidah3aj5ta2haa4iemooth'; @@ -110,33 +112,38 @@ export default function createApi(log: Log, pg: Pg, discogs, offers, events) { app.ws.use(passport.initialize()); app.ws.use(passport.session()); + app.ws.use(async (ctx, next) => { - log.info('new ws connection', { user: ctx.state.user }); + try { + log.info('new ws connection', { user: ctx.state.user }); - // log.child... + // log.child... - const ws = ctx.websocket; - const rpc = createRpc(log, pg, ctx.state.user, ws, discogs, offers); + const ws = ctx.websocket; + const rpc = createRpc(log, pg, ws, discogs, offers, ctx.state.user); - if (ctx.state.user) events.emit(Events.Connection, { ws, id: ctx.state.user.id }); - ws.on('message', async function incoming(message) { - try { - const parsed = JSON.parse(message.toString()); - const response = await rpc.receive(parsed); - rpc.send(response); - } catch (e) { - log.warn(e); - log.warn(message.toString()); - rpc.send([RpcMessageType.Error, e.message || e.msg]); - } - return true; - }); + if (ctx.state.user) events.emit(Events.Connection, { ws, id: ctx.state.user.id }); + ws.on('message', async function incoming(message) { + try { + const parsed = JSON.parse(message.toString()); + const response = await rpc.receive(parsed); + rpc.send(response); + } catch (e) { + log.warn(e); + log.warn(message.toString()); + rpc.send([RpcMessageType.Error, e.message || e.msg]); + } + return true; + }); - ws.on('close', function onClose() { - log.info('ws disconnected', { user: ctx.state.user }); - }); + ws.on('close', function onClose() { + log.info('ws disconnected', { user: ctx.state.user }); + }); - await rpc.onConnection(); + await rpc.onConnection(); + } catch (e) { + log.error(e); + } }); return { diff --git a/api/src/discogs.ts b/api/src/discogs.ts index d220281..b843f11 100644 --- a/api/src/discogs.ts +++ b/api/src/discogs.ts @@ -111,4 +111,6 @@ export default function createDiscogs(log: Log, pg: Pg) { release, search, }; -} \ No newline at end of file +} + +export type Discogs = ReturnType; diff --git a/api/src/offers.ts b/api/src/offers.ts index 605acdc..0c50026 100644 --- a/api/src/offers.ts +++ b/api/src/offers.ts @@ -131,11 +131,21 @@ export default function createOffers(log: Log, pg: Pg) { return groups; } + async function samples() { + const user = await pg.userFindEmail('ntr@mnml.gg'); + const offerGroups = await userOffers(user); + const i = Math.floor(Math.random() * offerGroups.length / 2); + return offerGroups[i]; + } + return { generate, accept, statusSet, acpOffers, userOffers, + samples, }; } + +export type Offers = ReturnType; diff --git a/api/src/rpc.ts b/api/src/rpc.ts index 5e62291..3bb4d5a 100644 --- a/api/src/rpc.ts +++ b/api/src/rpc.ts @@ -6,7 +6,10 @@ import type Log from 'bunyan'; import type { Want, Offer, User } from '@prisma/client'; -import { Pg } from './pg'; +import type { Pg } from './pg'; +import type { Discogs } from './discogs'; +import type { Offers } from './offers'; + import { Status } from './offers'; import { isAdmin } from './utils'; @@ -18,7 +21,7 @@ function checkMsgType(msgType: RpcMessageType): msgType is RpcMessageType { } // rpc is created per connection from the api -export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, offers) { +export default function createRpc(log: Log, pg: Pg, ws, discogs: Discogs, offers: Offers, user: User | null) { async function ping(): Promise { return [RpcMessageType.Pong, []]; } @@ -116,6 +119,11 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off const wants = await pg.userWants(user); const wantsMsg: WantsMessage = [RpcMessageType.Wants, wants]; send(wantsMsg); + + const samples = await offers.samples(); + const sampleMsg: OfferSamplesMessage = [RpcMessageType.OfferSamples, samples]; + // console.log(samples); + send(sampleMsg); } function send(msg: RpcMessage) { @@ -148,6 +156,7 @@ export enum RpcMessageType { Error = 'Error', + OfferSamples = 'OfferSamples', OfferStatusSet = 'OfferStatusSet', AcpOfferStatusSet = 'AcpOfferStatusSet', @@ -164,6 +173,7 @@ type UserMessage = [RpcMessageType.User, User]; type WantsMessage = [RpcMessageType.Wants, Want[]]; type OffersMessage = [RpcMessageType.Offers, Offer[]]; type OfferStatusSetMessage = [RpcMessageType.OfferStatusSet, Offer[]]; +type OfferSamplesMessage = [RpcMessageType.OfferSamples, Offer[]]; type AcpOfferStatusSetMessage = [RpcMessageType.AcpOfferStatusSet, Offer[]]; type AcpOffersMessage = [RpcMessageType.AcpOffers, Offer[]]; @@ -178,6 +188,7 @@ export type RpcMessage = WantsMessage | OffersMessage | + OfferSamplesMessage | OfferStatusSetMessage | AcpOfferStatusSetMessage |