channel list
parent
0159cfde99
commit
bf6d521963
|
|
@ -56,3 +56,6 @@ thumbs.db
|
|||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
/.idea/csv-plugin.xml
|
||||
|
||||
# docker data
|
||||
docker-volume
|
||||
|
|
|
|||
|
|
@ -6,12 +6,16 @@ services:
|
|||
restart: always
|
||||
environment:
|
||||
MARIADB_ROOT_PASSWORD: example
|
||||
MARIADB_ROOT_HOST: '127.0.0.1'
|
||||
MARIADB_DATABASE: corner
|
||||
MARIADB_USER: corner
|
||||
MARIADB_PASSWORD: corner
|
||||
ports:
|
||||
- 3306:3306
|
||||
# volumes:
|
||||
# - ./docker-volume:/var/lib/mysql
|
||||
|
||||
adminer:
|
||||
image: adminer
|
||||
restart: always
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 8080:8080
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/ban-types": "off"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<title>Vite App</title>
|
||||
</head>
|
||||
<body style="margin: 0px; overflow: hidden; color: #f8f8f2; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif">
|
||||
<div id="app" style="width: 100vw; height: 100vh"></div>
|
||||
<div id="app" style="width: 100vw; height: 100vh; background: #282a36"></div>
|
||||
<script src="./src/index.tsx" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Channels from './pages/Channels';
|
||||
import Chat from './pages/Chat';
|
||||
|
||||
ReactDOM.render(
|
||||
(
|
||||
<>
|
||||
<Chat
|
||||
{/* <Chat
|
||||
|
||||
></Chat>
|
||||
></Chat> */}
|
||||
<Channels
|
||||
|
||||
></Channels>
|
||||
</>
|
||||
),
|
||||
document.getElementById('app'),
|
||||
|
|
|
|||
|
|
@ -27,21 +27,18 @@ const connect = async () => {
|
|||
if(socket === null) return;
|
||||
connectionAttempts = 0;
|
||||
// socket.send('Hello Server!');
|
||||
console.log('API Connected');
|
||||
});
|
||||
|
||||
socket.addEventListener('message', (event) => {
|
||||
console.log('API Broadcasted', event.data);
|
||||
const {action, data} = JSON.parse(event.data);
|
||||
console.log('[IN]', action, data);
|
||||
for(const router of routers) {
|
||||
// debugger;
|
||||
router(action, data);
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener('close', () => {
|
||||
socket = null;
|
||||
console.log('API Closed');
|
||||
connect();
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { registerRouter, router, send, unregisterRouter } from '../lib/api';
|
||||
|
||||
function useRouter(actions: Function | object, deps: any[]) {
|
||||
const _router = typeof actions === 'object' ? router(actions) : actions;
|
||||
useEffect(() => {
|
||||
registerRouter(_router);
|
||||
return () => {
|
||||
unregisterRouter(_router);
|
||||
};
|
||||
}, deps);
|
||||
|
||||
return {
|
||||
send: send,
|
||||
};
|
||||
}
|
||||
|
||||
interface IChannel {
|
||||
uid: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default function Channels() {
|
||||
|
||||
const [channels, setChannels] = useState<IChannel[]>([]);
|
||||
|
||||
const { send } = useRouter({
|
||||
'channels:list'(data: any) {
|
||||
// console.log(data)
|
||||
setChannels(data);
|
||||
},
|
||||
}, [channels]);
|
||||
|
||||
useEffect(() => {
|
||||
if(channels.length === 0) {
|
||||
send('channels:list');
|
||||
}
|
||||
}, [channels]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{channels.map(channel => (
|
||||
<div key={channel.uid}>
|
||||
<span style={{
|
||||
fontWeight: 'bold',
|
||||
}}>#</span>{channel.name}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -60,7 +60,6 @@ export default () => {
|
|||
<>
|
||||
<div
|
||||
style={{
|
||||
background: '#282a36',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
display: 'grid',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
DB_HOST=localhost
|
||||
DB_USER=root
|
||||
DB_PASSWORD=example
|
||||
DB_USER=corner
|
||||
DB_PASSWORD=corner
|
||||
DB_DB=corner
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/ban-types": "off"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,17 +65,17 @@ export async function update() {
|
|||
// determine version
|
||||
const currentVersion: number = await new Promise((resolve, rej) => {
|
||||
migrationConnection.query(`
|
||||
SELECT SCHEMA_NAME
|
||||
FROM INFORMATION_SCHEMA.SCHEMATA
|
||||
WHERE SCHEMA_NAME = '${database}';
|
||||
SELECT COUNT(*) as tables
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = '${database}';
|
||||
`, async (err, res, fields) => {
|
||||
if(res.length === 0) {
|
||||
await new Promise((resolve, reject) => {
|
||||
migrationConnection.query(`CREATE DATABASE \`${database}\` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;`, (err, res) => {
|
||||
if(err) return reject(err);
|
||||
return resolve(res);
|
||||
});
|
||||
});
|
||||
if(res[0].tables === 0) {
|
||||
// await new Promise((resolve, reject) => {
|
||||
// migrationConnection.query(`CREATE DATABASE \`${database}\` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;`, (err, res) => {
|
||||
// if(err) return reject(err);
|
||||
// return resolve(res);
|
||||
// });
|
||||
// });
|
||||
resolve(0);
|
||||
} else {
|
||||
const version: number = await new Promise((resolve, reject) => {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
SELECT (name, uid) FROM channels;
|
||||
SELECT name, uid FROM channels;
|
||||
|
|
@ -1,54 +1,23 @@
|
|||
import { WebSocketServer } from 'ws';
|
||||
import router from './routers/root';
|
||||
import router from './lib/router';
|
||||
import message from './routers/message';
|
||||
import { expose } from './lib/WebSocketServer';
|
||||
|
||||
const wss = new WebSocketServer({
|
||||
port: 3000,
|
||||
}, () => {
|
||||
console.log('ws chat server started on dev.valnet.xyz');
|
||||
const api = router({
|
||||
up() {
|
||||
console.log(Date.now());
|
||||
},
|
||||
message: message,
|
||||
messages: message,
|
||||
channel: channel,
|
||||
channels: channel,
|
||||
});
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
ws.on('message', async (str) => {
|
||||
try {
|
||||
const message = JSON.parse(str.toString());
|
||||
if(typeof message.action !== 'string') {
|
||||
console.warn('invalid JSON message');
|
||||
return;
|
||||
}
|
||||
const {action, data} = message;
|
||||
try {
|
||||
console.log(action, data);
|
||||
const _return = await (router(action, data) as unknown as Promise<any>);
|
||||
console.log(_return);
|
||||
if(_return) {
|
||||
ws.send(JSON.stringify(_return));
|
||||
}
|
||||
} catch(e) {
|
||||
console.warn(`error in action ${action}`);
|
||||
console.error(e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('JSON parse failed on message');
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export function send(client: any, action: string, data?: any) {
|
||||
client.send(JSON.stringify({action, data}));
|
||||
}
|
||||
|
||||
export function broadcast(action: string, data?: any) {
|
||||
for(const client of wss.clients) {
|
||||
send(client, action, data);
|
||||
}
|
||||
}
|
||||
|
||||
export default wss;
|
||||
expose(api, 3000);
|
||||
|
||||
// -------------
|
||||
|
||||
import { update } from './db/migrate';
|
||||
import channel from './routers/channel';
|
||||
|
||||
try {
|
||||
update();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
import { WebSocketServer } from 'ws';
|
||||
|
||||
export function expose(router: Function, port: number) {
|
||||
const wss = new WebSocketServer({
|
||||
port: 3000,
|
||||
}, () => {
|
||||
console.log('ws chat server started on dev.valnet.xyz');
|
||||
});
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
ws.on('message', async (str) => {
|
||||
try {
|
||||
const message = JSON.parse(str.toString());
|
||||
if(typeof message.action !== 'string') {
|
||||
console.warn('invalid JSON message');
|
||||
return;
|
||||
}
|
||||
const {action, data} = message;
|
||||
try {
|
||||
console.log('[IN]', action, data);
|
||||
const _return = await (router(action, data) as unknown as Promise<any>);
|
||||
console.log(_return);
|
||||
if(_return) {
|
||||
try {
|
||||
switch(_return.type) {
|
||||
case ResponseType.BROADCAST: {
|
||||
console.log('[OUT_BROADCAST]', action, _return.data);
|
||||
for(const client of wss.clients) {
|
||||
send(client, action, _return.data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ResponseType.REPLY: {
|
||||
console.log('[OUT]', action, _return.data);
|
||||
send(ws, action, _return.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
console.warn(`error in action ${action}`);
|
||||
console.error(e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('JSON parse failed on message');
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
enum ResponseType {
|
||||
BROADCAST,
|
||||
REPLY
|
||||
}
|
||||
|
||||
function send(client: any, action: string, data?: any) {
|
||||
client.send(JSON.stringify({action, data}));
|
||||
}
|
||||
|
||||
export function broadcast(data: any) {
|
||||
return {
|
||||
type: ResponseType.BROADCAST,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
export function reply(data: any) {
|
||||
return {
|
||||
type: ResponseType.REPLY,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
// export default wss;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
export default function router(routes: any) {
|
||||
|
||||
|
||||
export default function router(routes: any) {
|
||||
for(const routeName in routes) {
|
||||
const route = routes[routeName];
|
||||
if('routes' in route) {
|
||||
|
|
@ -12,7 +13,6 @@ export default function router(routes: any) {
|
|||
}
|
||||
|
||||
const sendFn = function(route: any, data: any) {
|
||||
console.log(routes);
|
||||
if(route in routes) {
|
||||
return routes[route](data);
|
||||
} else {
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import query from '../db/query';
|
||||
import router from '../lib/router';
|
||||
import list from '../db/snippets/channel/list.sql';
|
||||
import { reply } from '../lib/WebSocketServer';
|
||||
|
||||
export default router({
|
||||
async list() {
|
||||
const res = await query(list);
|
||||
return reply(res ?? undefined);
|
||||
},
|
||||
});
|
||||
|
|
@ -1,29 +1,26 @@
|
|||
import { broadcast } from '..';
|
||||
import query from '../db/query';
|
||||
import router from '../router';
|
||||
import router from '../lib/router';
|
||||
import newMessage from '../db/snippets/message/new.sql';
|
||||
import recentMessages from '../db/snippets/message/recent.sql';
|
||||
import { broadcast, reply } from '../lib/WebSocketServer';
|
||||
|
||||
export default router({
|
||||
async message(data: any) {
|
||||
const failed = null === await query(newMessage, data.text, data.from, data.uid, data.timestamp);
|
||||
if(failed) return;
|
||||
broadcast('message:message', data);
|
||||
return broadcast(data);
|
||||
},
|
||||
async recent() {
|
||||
console.log('got recents request');
|
||||
const messages = await query(recentMessages);
|
||||
if(messages === null) return;
|
||||
return {
|
||||
action: 'message:recent',
|
||||
data: {
|
||||
messages: messages.map(v => ({
|
||||
from: v.from,
|
||||
uid: v.uid,
|
||||
timestamp: v.t_sent * 1000,
|
||||
text: v.text,
|
||||
})),
|
||||
},
|
||||
};
|
||||
return reply({
|
||||
messages: messages.map(v => ({
|
||||
from: v.from,
|
||||
uid: v.uid,
|
||||
timestamp: v.t_sent * 1000,
|
||||
text: v.text,
|
||||
})),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import router from '../router';
|
||||
import message from './message';
|
||||
|
||||
export default router({
|
||||
up() {
|
||||
console.log(Date.now());
|
||||
},
|
||||
message: message,
|
||||
});
|
||||
Reference in New Issue