channel list

cordova
Valerie 2022-07-21 23:45:52 -04:00
parent 0159cfde99
commit bf6d521963
18 changed files with 200 additions and 94 deletions

3
.gitignore vendored
View File

@ -56,3 +56,6 @@ thumbs.db
# Editor-based Rest Client
.idea/httpRequests
/.idea/csv-plugin.xml
# docker data
docker-volume

View File

@ -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

View File

@ -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"
}
}

View File

@ -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>

View File

@ -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'),

View File

@ -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();
});
};

View File

@ -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>
))}
</>
);
}

View File

@ -60,7 +60,6 @@ export default () => {
<>
<div
style={{
background: '#282a36',
height: '100%',
width: '100%',
display: 'grid',

View File

@ -1,4 +1,4 @@
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=example
DB_USER=corner
DB_PASSWORD=corner
DB_DB=corner

View File

@ -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"
}
}

View File

@ -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) => {

View File

@ -1 +1 @@
SELECT (name, uid) FROM channels;
SELECT name, uid FROM channels;

View File

@ -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();

View File

@ -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;

View File

@ -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 {

View File

@ -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);
},
});

View File

@ -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,
})),
});
},
});

View File

@ -1,9 +0,0 @@
import router from '../router';
import message from './message';
export default router({
up() {
console.log(Date.now());
},
message: message,
});