channels and router fix
parent
c81f19e700
commit
a212169022
|
|
@ -2,20 +2,10 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
|||
import TimeAgo from 'react-timeago';
|
||||
import { v4 } from 'uuid';
|
||||
import { registerRouter, router, send, unregisterRouter } from '../lib/api';
|
||||
import type { IMessage} from './Message';
|
||||
import { Message } from './Message';
|
||||
|
||||
const firstLineIndent = '10px';
|
||||
const multiLineIndent = '16px';
|
||||
const rightMessagePagging = '16px';
|
||||
|
||||
interface Message {
|
||||
text: string;
|
||||
from: string;
|
||||
timestamp: number;
|
||||
// nid: number;
|
||||
uid: string;
|
||||
}
|
||||
|
||||
function createMessage(from: string, text: string, t = 0): Message {
|
||||
function createMessage(from: string, text: string, t = 0): IMessage {
|
||||
return {
|
||||
text,
|
||||
from,
|
||||
|
|
@ -24,33 +14,18 @@ function createMessage(from: string, text: string, t = 0): Message {
|
|||
};
|
||||
}
|
||||
|
||||
const mockMessages: Message[] = [
|
||||
// createMessage('Bob', 'Hey', 55),
|
||||
// createMessage('Alice', 'Hello', 50),
|
||||
// createMessage('Bob', 'What up', 45),
|
||||
// createMessage('Alice', 'nm UUU', 40),
|
||||
// createMessage('Bob', 'Hey', 35),
|
||||
// createMessage('Alice', 'Hello', 30),
|
||||
// createMessage('Bob', 'What up', 25),
|
||||
// createMessage('Alice', 'nm UUU', 20),
|
||||
// createMessage('Bob', 'Hey', 15),
|
||||
// createMessage('Alice', 'Hello', 10),
|
||||
// createMessage('Bob', 'What up', 5),
|
||||
// createMessage('Alice', 'This is what a really long message could possibly look like, if a person decided to write a really long essay. This is what a really long message could possibly look like, if a person decided to write a really long essay. This is what a really long message could possibly look like, if a person decided to write a really long essay. This is what a really long message could possibly look like, if a person decided to write a really long essay.'),
|
||||
];
|
||||
|
||||
export default () => {
|
||||
const [messages, setMessages] = useState<Message[]>(mockMessages);
|
||||
const [messages, setMessages] = useState<IMessage[]>([]);
|
||||
const [hist, setHist] = useState(false);
|
||||
|
||||
const textBoxRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const actions = router({
|
||||
message(data: Message) {
|
||||
message(data: IMessage) {
|
||||
setMessages([...messages, data]);
|
||||
},
|
||||
recent(data: { messages: Message[] }) {
|
||||
'message:recent'(data: { messages: IMessage[] }) {
|
||||
setMessages([...data.messages, ...messages]);
|
||||
},
|
||||
});
|
||||
|
|
@ -63,14 +38,14 @@ export default () => {
|
|||
useEffect(() => {
|
||||
if(!hist) {
|
||||
console.log('sending recents request');
|
||||
send('recent');
|
||||
send('message:recent');
|
||||
setHist(true);
|
||||
}
|
||||
}, [hist]);
|
||||
|
||||
const sendMessage = useCallback(() => {
|
||||
if(textBoxRef.current === null) return;
|
||||
send('message', createMessage('Val', textBoxRef.current.innerText));
|
||||
send('message:message', createMessage('Val', textBoxRef.current.innerText));
|
||||
textBoxRef.current.innerText = '';
|
||||
}, []);
|
||||
|
||||
|
|
@ -105,46 +80,7 @@ export default () => {
|
|||
width: '100%',
|
||||
}}>
|
||||
{messages.map(message => (
|
||||
<div key={message.uid} style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '128px 1fr',
|
||||
width: '100%',
|
||||
padding: '1px 0px',
|
||||
}}>
|
||||
<span style={{
|
||||
fontStyle: 'italic',
|
||||
color: '#596793',
|
||||
textAlign: 'right',
|
||||
userSelect: 'none',
|
||||
marginRight: '16px',
|
||||
}}>
|
||||
<TimeAgo
|
||||
date={message.timestamp}
|
||||
formatter={(t, u) => u === 'second' ? 'Just Now' : ('' + t + u[0])}
|
||||
></TimeAgo>
|
||||
</span>
|
||||
<span style={{
|
||||
}}>
|
||||
<div style={{
|
||||
fontWeight: 'bold',
|
||||
float: 'left',
|
||||
paddingRight: firstLineIndent,
|
||||
// marginRight: '16px',
|
||||
// height: '100%'
|
||||
// borderBottom: '1px solid white'
|
||||
}}>
|
||||
{message.from}
|
||||
</div>
|
||||
<div style={{
|
||||
marginRight: rightMessagePagging,
|
||||
paddingLeft: multiLineIndent,
|
||||
boxSizing: 'border-box',
|
||||
position: 'relative',
|
||||
}}>
|
||||
{message.text}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<Message message={message}></Message>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
import TimeAgo from 'react-timeago';
|
||||
|
||||
export interface IMessage {
|
||||
uid: string;
|
||||
timestamp: number;
|
||||
from: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface MessageProps {
|
||||
message: IMessage
|
||||
}
|
||||
|
||||
const firstLineIndent = '10px';
|
||||
const multiLineIndent = '16px';
|
||||
const rightMessagePagging = '16px';
|
||||
|
||||
export function Message({
|
||||
message,
|
||||
}: MessageProps) {
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div key={message.uid} style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '128px 1fr',
|
||||
width: '100%',
|
||||
padding: '1px 0px',
|
||||
}}>
|
||||
<span style={{
|
||||
fontStyle: 'italic',
|
||||
color: '#596793',
|
||||
textAlign: 'right',
|
||||
userSelect: 'none',
|
||||
marginRight: '16px',
|
||||
}}>
|
||||
<TimeAgo
|
||||
date={message.timestamp}
|
||||
formatter={(t, u) => u === 'second' ? 'Just Now' : ('' + t + u[0])}
|
||||
></TimeAgo>
|
||||
</span>
|
||||
<span style={{
|
||||
}}>
|
||||
<div style={{
|
||||
fontWeight: 'bold',
|
||||
float: 'left',
|
||||
paddingRight: firstLineIndent,
|
||||
// marginRight: '16px',
|
||||
// height: '100%'
|
||||
// borderBottom: '1px solid white'
|
||||
}}>
|
||||
{message.from}
|
||||
</div>
|
||||
<div style={{
|
||||
marginRight: rightMessagePagging,
|
||||
paddingLeft: multiLineIndent,
|
||||
boxSizing: 'border-box',
|
||||
position: 'relative',
|
||||
}}>
|
||||
{message.text}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
CREATE TABLE `channels` (`id` int(11) NOT NULL AUTO_INCREMENT, `name` TINYTEXT NOT NULL, `uid` TINYTEXT NOT NULL UNIQUE, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
INSERT INTO channels (name, uid) VALUES ('General', UUID());
|
||||
|
||||
ALTER TABLE `messages` ADD COLUMN `channel_uid` TINYTEXT NOT NULL AFTER `t_sent`;
|
||||
|
||||
UPDATE messages SET channel_uid = (SELECT uid FROM channels) where messages.channel_uid = '';
|
||||
|
||||
ALTER TABLE `messages` CHANGE `channel_uid` `channel_uid` varchar(36) COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `t_sent`;
|
||||
|
||||
ALTER TABLE `channels` CHANGE `uid` `uid` varchar(36) COLLATE 'utf8mb4_general_ci' NOT NULL AFTER `name`;
|
||||
|
||||
ALTER TABLE messages ADD CONSTRAINT fk_channel_uid FOREIGN KEY (channel_uid) REFERENCES channels(uid);
|
||||
|
|
@ -96,7 +96,7 @@ export async function update() {
|
|||
console.log('database up to date!');
|
||||
} else {
|
||||
const difference = expectedVersion - currentVersion;
|
||||
process.stdout.write(`database ${difference} version${difference !== 1 ? 's' : ''} behind`);
|
||||
console.log(`database ${difference} version${difference !== 1 ? 's' : ''} behind`);
|
||||
// console.log(`${currentVersion} >>> ${expectedVersion}`);
|
||||
const neededMigrations = migrations.filter(m => m.version > currentVersion);
|
||||
let completedMigrations = 0;
|
||||
|
|
|
|||
|
|
@ -3,14 +3,20 @@ import { connection } from './migrate';
|
|||
|
||||
|
||||
|
||||
export default async function(a: any, ...opts: any[]): Promise<any[]> {
|
||||
export default async function(a: any, ...opts: any[]): Promise<any[] | null> {
|
||||
const b64 = a.split('base64,')[1];
|
||||
const text = Buffer.from(b64, 'base64').toString();
|
||||
return await new Promise((resolve, reject) => {
|
||||
connection.query(text, [...opts], (err, results) => {
|
||||
if(!err) return resolve(results);
|
||||
console.error(err);
|
||||
try {
|
||||
return await new Promise((resolve, reject) => {
|
||||
connection.query(text, [...opts], (err, results) => {
|
||||
if(!err) return resolve(results);
|
||||
console.error(err.errno, err.sqlMessage);
|
||||
console.error(err.sql);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch(e) {
|
||||
return null;
|
||||
}
|
||||
// console.log(...opts)
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
SELECT (name, uid) FROM channels;
|
||||
|
|
@ -17,7 +17,9 @@ wss.on('connection', (ws) => {
|
|||
}
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,26 @@
|
|||
export default function router(routes: any) {
|
||||
|
||||
for(const routeName in routes) {
|
||||
const route = routes[routeName];
|
||||
if(typeof route === 'object') {
|
||||
for(const suffix in route) {
|
||||
if('routes' in route) {
|
||||
for(const suffix of route.routes) {
|
||||
const combinedRouteName = routeName + ':' + suffix;
|
||||
routes[combinedRouteName] = route[suffix];
|
||||
routes[combinedRouteName] = (_: never, ...args: any[]) => route(suffix, args);
|
||||
}
|
||||
delete routes[routeName];
|
||||
}
|
||||
}
|
||||
return function(route: any, data: any) {
|
||||
|
||||
const sendFn = function(route: any, data: any) {
|
||||
console.log(routes);
|
||||
if(route in routes) {
|
||||
return routes[route](data);
|
||||
} else {
|
||||
console.warn(`route <${route}> not found`);
|
||||
console.trace();
|
||||
}
|
||||
};
|
||||
|
||||
sendFn.routes = Object.keys(routes);
|
||||
return sendFn;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { broadcast } from '..';
|
||||
import query from '../db/query';
|
||||
import router from '../router';
|
||||
import newMessage from '../db/snippets/message/new.sql';
|
||||
import recentMessages from '../db/snippets/message/recent.sql';
|
||||
|
||||
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);
|
||||
},
|
||||
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,
|
||||
})),
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
@ -1,30 +1,9 @@
|
|||
import router from '../router';
|
||||
import { broadcast } from '../index';
|
||||
import query from '../db/query';
|
||||
import newMessage from '../db/snippets/message/new.sql';
|
||||
import recentMessages from '../db/snippets/message/recent.sql';
|
||||
import message from './message';
|
||||
|
||||
export default router({
|
||||
up() {
|
||||
console.log(Date.now());
|
||||
},
|
||||
message(data: any) {
|
||||
query(newMessage, data.text, data.from, data.uid, data.timestamp);
|
||||
broadcast('message', data);
|
||||
},
|
||||
async recent() {
|
||||
console.log('got recents request');
|
||||
const messages = await query(recentMessages);
|
||||
return {
|
||||
action: 'recent',
|
||||
data: {
|
||||
messages: messages.map(v => ({
|
||||
from: v.from,
|
||||
uid: v.uid,
|
||||
timestamp: v.t_sent * 1000,
|
||||
text: v.text,
|
||||
})),
|
||||
},
|
||||
};
|
||||
},
|
||||
message: message,
|
||||
});
|
||||
|
|
@ -66,7 +66,7 @@ const setupServerPackageWatcher = () => {
|
|||
if (!data) return;
|
||||
const mayIgnore = stderrFilterPatterns.some((r) => r.test(data));
|
||||
if (mayIgnore) return;
|
||||
logger.error(data, {timestamp: true});
|
||||
data.split('\n').forEach(d => logger.error(d, {timestamp: true}));
|
||||
});
|
||||
|
||||
/** Stops the watch script when the application has been quit */
|
||||
|
|
|
|||
Reference in New Issue