3 Commits
Author SHA1 Message Date
ntr c99b148e15 sample wip 2022-11-26 18:22:13 +11:00
ntr ffc023f419 Merge branch 'master' into sample-offers 2022-11-26 17:31:14 +11:00
ntr a0cd49b411 discogs and offers inferred types 2022-11-24 09:35:05 +11:00
10 changed files with 116 additions and 36 deletions

No files matched your search

+41
View File
@@ -29,6 +29,7 @@
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/bluebird": "^3.5.36", "@types/bluebird": "^3.5.36",
"@types/koa": "^2.13.5", "@types/koa": "^2.13.5",
"@types/koa-websocket": "^5.0.7",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.182",
"@types/mocha": "^9.1.1", "@types/mocha": "^9.1.1",
"axios": "^0.27.2", "axios": "^0.27.2",
@@ -325,6 +326,17 @@
"@types/koa": "*" "@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": { "node_modules/@types/lodash": {
"version": "4.14.182", "version": "4.14.182",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
@@ -382,6 +394,15 @@
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
"dev": true "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": { "node_modules/@ungap/promise-all-settled": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
@@ -3961,6 +3982,17 @@
"@types/koa": "*" "@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": { "@types/lodash": {
"version": "4.14.182", "version": "4.14.182",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz",
@@ -4018,6 +4050,15 @@
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
"dev": true "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": { "@ungap/promise-all-settled": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+1
View File
@@ -16,6 +16,7 @@
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/bluebird": "^3.5.36", "@types/bluebird": "^3.5.36",
"@types/koa": "^2.13.5", "@types/koa": "^2.13.5",
"@types/koa-websocket": "^5.0.7",
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.182",
"@types/mocha": "^9.1.1", "@types/mocha": "^9.1.1",
"axios": "^0.27.2", "axios": "^0.27.2",
+29 -22
View File
@@ -14,11 +14,13 @@ import type Log from 'bunyan';
import type { Listing, User, Want, Prisma } from '@prisma/client'; import type { Listing, User, Want, Prisma } from '@prisma/client';
import { Pg } from './pg'; import { Pg } from './pg';
import { Discogs } from './discogs';
import { Offers } from './offers';
import routerAuth from './routers/router.auth'; import routerAuth from './routers/router.auth';
import { Events } from './events'; import { Events } from './events';
import createRpc, { RpcMessageType } from './rpc'; 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 PORT = 41337;
const WS_PORT = 40055; const WS_PORT = 40055;
const SECRET = 'ohja4Eif9eidah3aj5ta2haa4iemooth'; 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.initialize());
app.ws.use(passport.session()); app.ws.use(passport.session());
app.ws.use(async (ctx, next) => { 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 ws = ctx.websocket;
const rpc = createRpc(log, pg, ctx.state.user, ws, discogs, offers); 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 }); if (ctx.state.user) events.emit(Events.Connection, { ws, id: ctx.state.user.id });
ws.on('message', async function incoming(message) { ws.on('message', async function incoming(message) {
try { try {
const parsed = JSON.parse(message.toString()); const parsed = JSON.parse(message.toString());
const response = await rpc.receive(parsed); const response = await rpc.receive(parsed);
rpc.send(response); rpc.send(response);
} catch (e) { } catch (e) {
log.warn(e); log.warn(e);
log.warn(message.toString()); log.warn(message.toString());
rpc.send([RpcMessageType.Error, e.message || e.msg]); rpc.send([RpcMessageType.Error, e.message || e.msg]);
} }
return true; return true;
}); });
ws.on('close', function onClose() { ws.on('close', function onClose() {
log.info('ws disconnected', { user: ctx.state.user }); log.info('ws disconnected', { user: ctx.state.user });
}); });
await rpc.onConnection(); await rpc.onConnection();
} catch (e) {
log.error(e);
}
}); });
return { return {
+3 -1
View File
@@ -111,4 +111,6 @@ export default function createDiscogs(log: Log, pg: Pg) {
release, release,
search, search,
}; };
} }
export type Discogs = ReturnType<typeof createDiscogs>;
+9
View File
@@ -131,11 +131,20 @@ export default function createOffers(log: Log, pg: Pg) {
return groups; return groups;
} }
async function samples() {
const user = await pg.userFindEmail('ntr@mnml.gg');
const offerGroups = await userOffers(user);
return offerGroups.slice(0, 1);
}
return { return {
generate, generate,
accept, accept,
statusSet, statusSet,
acpOffers, acpOffers,
userOffers, userOffers,
samples,
}; };
} }
export type Offers = ReturnType<typeof createOffers>;
+16 -2
View File
@@ -6,7 +6,10 @@ import type Log from 'bunyan';
import type { Want, Offer, User } from '@prisma/client'; 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 { Status } from './offers';
import { isAdmin } from './utils'; import { isAdmin } from './utils';
@@ -18,7 +21,7 @@ function checkMsgType(msgType: RpcMessageType): msgType is RpcMessageType {
} }
// rpc is created per connection from the api // 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<PongMessage> { async function ping(): Promise<PongMessage> {
return [RpcMessageType.Pong, []]; return [RpcMessageType.Pong, []];
} }
@@ -109,7 +112,15 @@ export default function createRpc(log: Log, pg: Pg, user: User, ws, discogs, off
throw new Error(`Invalid parameters for message type ${msgType}: ${JSON.stringify(message)}`); throw new Error(`Invalid parameters for message type ${msgType}: ${JSON.stringify(message)}`);
} }
async function anonConnection() {
const samples = await offers.samples();
const sampleMsg: OfferSamplesMessage = [RpcMessageType.OfferSamples, samples];
send(sampleMsg);
}
async function onConnection() { async function onConnection() {
if (!user) return anonConnection();
const userMsg: UserMessage = [RpcMessageType.User, user]; const userMsg: UserMessage = [RpcMessageType.User, user];
send(userMsg); send(userMsg);
@@ -148,6 +159,7 @@ export enum RpcMessageType {
Error = 'Error', Error = 'Error',
OfferSamples = 'OfferSamples',
OfferStatusSet = 'OfferStatusSet', OfferStatusSet = 'OfferStatusSet',
AcpOfferStatusSet = 'AcpOfferStatusSet', AcpOfferStatusSet = 'AcpOfferStatusSet',
@@ -164,6 +176,7 @@ type UserMessage = [RpcMessageType.User, User];
type WantsMessage = [RpcMessageType.Wants, Want[]]; type WantsMessage = [RpcMessageType.Wants, Want[]];
type OffersMessage = [RpcMessageType.Offers, Offer[]]; type OffersMessage = [RpcMessageType.Offers, Offer[]];
type OfferStatusSetMessage = [RpcMessageType.OfferStatusSet, Offer[]]; type OfferStatusSetMessage = [RpcMessageType.OfferStatusSet, Offer[]];
type OfferSamplesMessage = [RpcMessageType.OfferSamples, Offer[]];
type AcpOfferStatusSetMessage = [RpcMessageType.AcpOfferStatusSet, Offer[]]; type AcpOfferStatusSetMessage = [RpcMessageType.AcpOfferStatusSet, Offer[]];
type AcpOffersMessage = [RpcMessageType.AcpOffers, Offer[]]; type AcpOffersMessage = [RpcMessageType.AcpOffers, Offer[]];
@@ -178,6 +191,7 @@ export type RpcMessage =
WantsMessage | WantsMessage |
OffersMessage | OffersMessage |
OfferSamplesMessage |
OfferStatusSetMessage | OfferStatusSetMessage |
AcpOfferStatusSetMessage | AcpOfferStatusSetMessage |
+12 -5
View File
@@ -6,6 +6,7 @@ import { useSelector, useDispatch } from 'react-redux'
import http from './../http'; import http from './../http';
import { State, userState } from './../store'; import { State, userState } from './../store';
import Swirl from './../components/swirl'; import Swirl from './../components/swirl';
import OfferGroup from './../components/offer.group';
const Login = ({ mode }) => { const Login = ({ mode }) => {
const dispatch = useDispatch() const dispatch = useDispatch()
@@ -94,14 +95,20 @@ const Login = ({ mode }) => {
}; };
function LoginPage({ mode }) { function LoginPage({ mode }) {
const offers = useSelector((state: State) => state.offers);
return ( return (
<div class="landing"> <div class="landing">
<Login mode={mode} /> <Login mode={mode} />
<Swirl /> <div class='offers'>
<div class='words'> {offers.map(OfferGroup)}
<p>Mates Crates is a record importing service.</p> <div>
<p>We bundle orders together from thousands of online stores to reduce the cost of shipping vinyl.</p> <Swirl />
<p>Based in Preston.</p> <div class='words'>
<p>We bundle orders together from thousands of online stores to reduce the cost of shipping vinyl.</p>
<p>Based in Preston.</p>
</div>
</div>
</div> </div>
</div> </div>
) )
+1 -1
View File
@@ -11,7 +11,7 @@ export const userState = createSlice({
export const offersState = createSlice({ export const offersState = createSlice({
name: 'offers', name: 'offers',
initialState: null, initialState: [],
reducers: { reducers: {
set: (state, action) => action.payload set: (state, action) => action.payload
}, },
+3 -5
View File
@@ -217,6 +217,7 @@ button, [type=submit] {
grid-gap: calc(var(--spacing-double) * 2); grid-gap: calc(var(--spacing-double) * 2);
grid-template-areas: grid-template-areas:
"login swirl" "login swirl"
"login sample"
"login words"; "login words";
.login { .login {
@@ -227,8 +228,8 @@ button, [type=submit] {
} }
.swirl { .swirl {
grid-area: swirl; // grid-area: swirl;
height: 15rem; height: 5rem;
} }
.words { .words {
@@ -344,8 +345,6 @@ article {
} }
form { form {
margin-bottom: var(--spacing);
label, input { label, input {
display: block; display: block;
} }
@@ -365,7 +364,6 @@ form {
text-transform: uppercase; text-transform: uppercase;
margin-bottom: var(--spacing-half); margin-bottom: var(--spacing-half);
} }
} }
a { a {
+1
View File
@@ -84,6 +84,7 @@ export default function createSocket(dispatch) {
Offers: onOffers, Offers: onOffers,
User: onUser, User: onUser,
OfferSamples: onOffers,
AcpOffers: onAcpOffers, AcpOffers: onAcpOffers,
Pong: onPong, Pong: onPong,