Mates Crates is a record importing service.
diff --git a/client/src/routes/search.tsx b/client/src/routes/search.tsx
index 7ab5fa1..92305fa 100644
--- a/client/src/routes/search.tsx
+++ b/client/src/routes/search.tsx
@@ -2,13 +2,13 @@ import { h } from 'preact';
import { useState, useRef, useEffect } from 'preact/hooks';
import { ExternalLink, Check } from 'react-feather';
-import actions from '../actions';
+import http from '../http';
function Result(r) {
const [added, setAdded] = useState(false)
async function onClick() {
- const [error, want] = await actions.postWant(r.id);
+ const [error, want] = await http.postWant(r.id);
if (error) return false;
setAdded(true);
}
@@ -40,7 +40,7 @@ const User = () => {
const [infoText, setInfoText] = useState('');
async function fetchResults() {
- const [error, results] = await actions.postWantSearch(artist, title);
+ const [error, results] = await http.postWantSearch(artist, title);
if (results.length === 0) {
setResults([]);
@@ -52,7 +52,7 @@ const User = () => {
}
async function submitWantlist() {
- const [error, wants] = await actions.postDiscogs(username);
+ const [error, wants] = await http.postDiscogs(username);
if (wants.length === 0) {
setResults([]);
return setInfoText('No new additions');
diff --git a/client/src/store.tsx b/client/src/store.tsx
index 5764d03..ef0da81 100644
--- a/client/src/store.tsx
+++ b/client/src/store.tsx
@@ -1,9 +1,29 @@
-import createStore from 'unistore'
+import { route } from 'preact-router';
+import unistore from 'unistore'
-export default function mcratesStore() {
- return createStore({
- bundles: [],
- offers: []
- });
+import http from './http';
+
+export function createStore() {
+ return unistore({
+ bundles: [],
+ offers: [],
+ user: null,
+ });
}
+export const actions = store => ({
+ setUser: async function setUser(state, user, dest) {
+ route(dest);
+ return { user };
+ },
+
+ setOffers: async function setOffers(state, offers) {
+ return { offers };
+ },
+
+ logout: async function logout(store, e) {
+ await http.postLogout();
+ route('/login');
+ return { user: null };
+ },
+});
diff --git a/client/src/ws.ts b/client/src/ws.ts
new file mode 100644
index 0000000..ac03115
--- /dev/null
+++ b/client/src/ws.ts
@@ -0,0 +1,115 @@
+const SOCKET_URL = (window.location.host.includes('localhost') || window.location.host === '' || window.location.host.includes('192.168.0'))
+ ? `ws://${window.location.hostname}:40080`
+ : `${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`;
+
+export default function createSocket(store) {
+ let ws;
+
+ // -------------
+ // Outgoing
+ // -------------
+ function send(msg) {
+ if (msg[0] !== 'Ping') console.log('outgoing msg', msg);
+ if (ws.readyState !== 1) return false;
+ try {
+ ws.send(JSON.stringify(msg));
+ } catch (e) {
+ console.warn(e);
+ }
+ }
+
+ // let ping;
+ function sendPing() {
+ // ping = Date.now();
+ send(['Ping', {}]);
+
+ // setTimeout(sendPing, 50);
+ }
+
+ function sendSourcesAvailable() {
+ send(['SourcesAvailable', {}]);
+ }
+
+ let pongTimeout;
+ function onPong() {
+ pongTimeout = setTimeout(sendPing, 1000);
+ }
+
+ // -------------
+ // Incoming
+ // -------------
+ function onSourcesAvailable(clouds) {
+ // store.dispatch(http.LIBRARY_RECEIVE_POINTCLOUDS, clouds);
+ }
+
+ // -------------
+ // Setup
+ // -------------
+ // when the server sends a reply it will have one of these message types
+ // this object wraps the reply types to a function
+ const handlers = {
+ SourcesAvailable: onSourcesAvailable,
+
+ Pong: onPong,
+ Error: errHandler,
+ };
+
+ function errHandler(error) {
+ // store.dispatch(http.LIBRARY_EVENT, { level: 'error', log: error });
+ console.error(error);
+ }
+
+ function onMessage(event) {
+ const res = event.data;
+ const [msgType, params] = JSON.parse(res);
+ if (msgType !== 'Pong') {
+ console.log(msgType, params);
+ }
+
+ // check for error and split into response type and data
+ if (!handlers[msgType]) return console.error(`${msgType} handler missing`);
+ return handlers[msgType](params);
+ }
+
+ // Connection opened
+ function onOpen() {
+ sendPing();
+ }
+
+ function onError(event) {
+ console.error('WebSocket error', event);
+ }
+
+ function onClose(event) {
+ console.error('WebSocket closed', event);
+ return setTimeout(connect, 2000);
+ }
+
+ function connect() {
+ if (ws) {
+ clearTimeout(pongTimeout);
+ ws.removeEventListener('open', onOpen);
+ ws.removeEventListener('message', onMessage);
+ ws.removeEventListener('error', onError);
+ ws.removeEventListener('close', onClose);
+ ws = null;
+ }
+
+ console.log('connecting to websocket', SOCKET_URL);
+ ws = new WebSocket(SOCKET_URL);
+
+ // Listen for messages
+ ws.addEventListener('open', onOpen);
+ ws.addEventListener('message', onMessage);
+ ws.addEventListener('error', onError);
+ ws.addEventListener('close', onClose);
+
+ return ws;
+ }
+
+ return {
+ connect,
+
+ sendSourcesAvailable,
+ };
+}