chat persistence
parent
7d49867b14
commit
d50029146c
|
|
@ -1,12 +1,14 @@
|
|||
version: '3.1'
|
||||
|
||||
services:
|
||||
|
||||
db:
|
||||
image: mariadb
|
||||
restart: always
|
||||
environment:
|
||||
MARIADB_ROOT_PASSWORD: example
|
||||
MARIADB_ROOT_HOST: '127.0.0.1'
|
||||
ports:
|
||||
- 3306:3306
|
||||
|
||||
adminer:
|
||||
image: adminer
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"name": "vite-electron-builder",
|
||||
"name": "viscord",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vite-electron-builder",
|
||||
"name": "viscord",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@types/mysql": "^2.15.21",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-timeago": "^4.1.3",
|
||||
|
|
@ -17,6 +18,7 @@
|
|||
"eslint-plugin-react": "^7.30.1",
|
||||
"express": "^4.18.1",
|
||||
"get-port": "^6.1.2",
|
||||
"mysql": "^2.18.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-time-ago": "^7.2.1",
|
||||
|
|
@ -914,6 +916,14 @@
|
|||
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mysql": {
|
||||
"version": "2.15.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz",
|
||||
"integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.11.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz",
|
||||
|
|
@ -1883,6 +1893,14 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
|
||||
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
|
|
@ -2599,8 +2617,7 @@
|
|||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"node_modules/crc": {
|
||||
"version": "3.8.0",
|
||||
|
|
@ -5203,8 +5220,7 @@
|
|||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"node_modules/isbinaryfile": {
|
||||
"version": "4.0.10",
|
||||
|
|
@ -5672,6 +5688,20 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/mysql": {
|
||||
"version": "2.18.1",
|
||||
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
|
||||
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
|
||||
"dependencies": {
|
||||
"bignumber.js": "9.0.0",
|
||||
"readable-stream": "2.3.7",
|
||||
"safe-buffer": "5.1.2",
|
||||
"sqlstring": "2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/nano-staged": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/nano-staged/-/nano-staged-0.8.0.tgz",
|
||||
|
|
@ -6187,8 +6217,7 @@
|
|||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
|
|
@ -6436,7 +6465,6 @@
|
|||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
|
|
@ -6950,6 +6978,14 @@
|
|||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/sqlstring": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
|
||||
"integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/stat-mode": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz",
|
||||
|
|
@ -6971,7 +7007,6 @@
|
|||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
|
|
@ -7694,8 +7729,7 @@
|
|||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
|
|
@ -8823,6 +8857,14 @@
|
|||
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mysql": {
|
||||
"version": "2.15.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz",
|
||||
"integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.11.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.39.tgz",
|
||||
|
|
@ -9544,6 +9586,11 @@
|
|||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true
|
||||
},
|
||||
"bignumber.js": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
|
||||
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A=="
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
|
|
@ -10082,8 +10129,7 @@
|
|||
"core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||
},
|
||||
"crc": {
|
||||
"version": "3.8.0",
|
||||
|
|
@ -11940,8 +11986,7 @@
|
|||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"isbinaryfile": {
|
||||
"version": "4.0.10",
|
||||
|
|
@ -12309,6 +12354,17 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"mysql": {
|
||||
"version": "2.18.1",
|
||||
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
|
||||
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
|
||||
"requires": {
|
||||
"bignumber.js": "9.0.0",
|
||||
"readable-stream": "2.3.7",
|
||||
"safe-buffer": "5.1.2",
|
||||
"sqlstring": "2.3.1"
|
||||
}
|
||||
},
|
||||
"nano-staged": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/nano-staged/-/nano-staged-0.8.0.tgz",
|
||||
|
|
@ -12684,8 +12740,7 @@
|
|||
"process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"progress": {
|
||||
"version": "2.0.3",
|
||||
|
|
@ -12871,7 +12926,6 @@
|
|||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
|
|
@ -13259,6 +13313,11 @@
|
|||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"sqlstring": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
|
||||
"integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ=="
|
||||
},
|
||||
"stat-mode": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz",
|
||||
|
|
@ -13274,7 +13333,6 @@
|
|||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
|
|
@ -13813,8 +13871,7 @@
|
|||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.1",
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
"vue-tsc": "0.38.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/mysql": "^2.15.21",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@types/react-timeago": "^4.1.3",
|
||||
|
|
@ -65,6 +66,7 @@
|
|||
"eslint-plugin-react": "^7.30.1",
|
||||
"express": "^4.18.1",
|
||||
"get-port": "^6.1.2",
|
||||
"mysql": "^2.18.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-time-ago": "^7.2.1",
|
||||
|
|
|
|||
|
|
@ -48,8 +48,19 @@ const connect = async () => {
|
|||
|
||||
connect();
|
||||
|
||||
export function send(action: string, data?: any) {
|
||||
export async function send(action: string, data?: any) {
|
||||
if(socket === null) return;
|
||||
if(socket && socket.readyState === socket.CONNECTING) {
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
socket?.addEventListener('open', resolve);
|
||||
socket?.addEventListener('close', reject);
|
||||
});
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
if(socket.readyState !== socket.OPEN) return;
|
||||
}
|
||||
const message = JSON.stringify({ action, data });
|
||||
socket.send(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ export default () => {
|
|||
message(data: Message) {
|
||||
setMessages([...messages, data]);
|
||||
},
|
||||
recent(data: { messages: Message[] }) {
|
||||
setMessages(data.messages);
|
||||
},
|
||||
});
|
||||
registerRouter(actions);
|
||||
return () => {
|
||||
|
|
@ -56,9 +59,16 @@ export default () => {
|
|||
};
|
||||
}, [messages]);
|
||||
|
||||
useEffect(() => {
|
||||
if(messages.length === 0) {
|
||||
console.log('sending recents request');
|
||||
send('recent');
|
||||
}
|
||||
}, [messages]);
|
||||
|
||||
const sendMessage = useCallback(() => {
|
||||
if(textBoxRef.current === null) return;
|
||||
send('message', createMessage('Version 3', textBoxRef.current.innerText));
|
||||
send('message', createMessage('Val', textBoxRef.current.innerText));
|
||||
textBoxRef.current.innerText = '';
|
||||
}, []);
|
||||
|
||||
|
|
@ -93,7 +103,7 @@ export default () => {
|
|||
width: '100%',
|
||||
}}>
|
||||
{messages.map(message => (
|
||||
<div style={{
|
||||
<div key={message.uid} style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '128px 1fr',
|
||||
width: '100%',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
DB_HOST=localhost
|
||||
DB_USER=root
|
||||
DB_PASSWORD=example
|
||||
DB_DB=viscord
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
SET NAMES utf8;
|
||||
SET time_zone = '+00:00';
|
||||
SET foreign_key_checks = 0;
|
||||
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE DATABASE `viscord` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
|
||||
USE `viscord`;
|
||||
|
||||
CREATE TABLE `messages` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`uid` tinytext NOT NULL,
|
||||
`from` tinytext NOT NULL,
|
||||
`text` longtext NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `migrations` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
INSERT INTO `migrations` ()
|
||||
VALUES ();
|
||||
|
||||
-- 2022-07-21 01:27:49
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
USE `viscord`;
|
||||
|
||||
ALTER TABLE `messages`
|
||||
ADD COLUMN `t_sent` BIGINT UNSIGNED AFTER `text`;
|
||||
|
||||
INSERT INTO `migrations` ()
|
||||
VALUES ();
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// import migration from './migrations/1-chat-persistence.sql';
|
||||
|
||||
import { createConnection } from 'mysql';
|
||||
import { readdirSync, readFileSync } from 'fs';
|
||||
import { dirname, resolve } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const host = 'localhost';
|
||||
const user = 'root';
|
||||
const password = 'example';
|
||||
|
||||
interface Migration {
|
||||
sql: string;
|
||||
version: number;
|
||||
}
|
||||
|
||||
const migrations: Migration[] =
|
||||
readdirSync(resolve(__dirname, 'migrations'))
|
||||
.sort((a, b) => {
|
||||
const an = Number(a.split('-')[0]);
|
||||
const bn = Number(b.split('-')[0]);
|
||||
return an > bn ? 1 : an < bn ? -1 : 0;
|
||||
})
|
||||
.map(path => {
|
||||
const fullpath = resolve(__dirname, 'migrations', path);
|
||||
const n = Number(path.split('-')[0]);
|
||||
return {
|
||||
sql: readFileSync(fullpath).toString(),
|
||||
version: n,
|
||||
};
|
||||
});
|
||||
|
||||
export const connection = createConnection({
|
||||
host,
|
||||
user,
|
||||
password,
|
||||
});
|
||||
const migrationConnection = createConnection({
|
||||
host,
|
||||
user,
|
||||
password,
|
||||
multipleStatements: true,
|
||||
});
|
||||
|
||||
const connected: Promise<null> = new Promise((res, rej) => {
|
||||
connection.connect((err) => {
|
||||
if(err === null) {
|
||||
console.log('connected to database!');
|
||||
res(null);
|
||||
} else {
|
||||
console.error(err);
|
||||
rej(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export async function update() {
|
||||
// console.log(migrations);
|
||||
console.log('waiting for connection...');
|
||||
await connected;
|
||||
// determine version
|
||||
const currentVersion: number = await new Promise((resolve, rej) => {
|
||||
connection.query(`
|
||||
SELECT SCHEMA_NAME
|
||||
FROM INFORMATION_SCHEMA.SCHEMATA
|
||||
WHERE SCHEMA_NAME = 'viscord'
|
||||
`, async (err, res, fields) => {
|
||||
if(res.length === 0) {
|
||||
resolve(0);
|
||||
} else {
|
||||
const version: number = await new Promise((resolve, reject) => {
|
||||
connection.query(`
|
||||
SELECT max(id) as 'version' FROM viscord.migrations;
|
||||
`, function (err, results, fields) {
|
||||
resolve(results[0].version);
|
||||
});
|
||||
});
|
||||
resolve(version);
|
||||
// check the version table!
|
||||
}
|
||||
});
|
||||
});
|
||||
const expectedVersion = migrations.length;
|
||||
|
||||
if(currentVersion >= expectedVersion) {
|
||||
console.log('database up to date!');
|
||||
} else {
|
||||
const difference = expectedVersion - currentVersion;
|
||||
console.log(`database ${difference} version${difference !== 1 ? 's' : ''} behind`);
|
||||
// console.log(`${currentVersion} >>> ${expectedVersion}`);
|
||||
const neededMigrations = migrations.filter(m => m.version > currentVersion);
|
||||
for(const migration of neededMigrations) {
|
||||
console.log(`${currentVersion} >>> ${migration.version}`);
|
||||
await new Promise((resolve, reject) => {
|
||||
migrationConnection.query(migration.sql, (err, res) => {
|
||||
if(err !== null) return reject(err);
|
||||
console.log(`executed ${res.length} statement${res.length !== 0 ? 's' : ''}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
// console.log('database version:', currentVersion)
|
||||
|
||||
// console.log(response);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { connection } from './migrate';
|
||||
|
||||
|
||||
|
||||
|
||||
export default async function(a: any, ...opts: any[]): Promise<any[]> {
|
||||
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);
|
||||
});
|
||||
});
|
||||
// console.log(...opts)
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
INSERT INTO viscord.messages
|
||||
(`text`, `from`, `uid`, `t_sent`)
|
||||
VALUES (
|
||||
?,
|
||||
?,
|
||||
?,
|
||||
UNIX_TIMESTAMP()
|
||||
)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SELECT * FROM viscord.messages
|
||||
ORDER BY t_sent
|
||||
LIMIT 100;
|
||||
|
|
@ -8,7 +8,7 @@ const wss = new WebSocketServer({
|
|||
});
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
ws.on('message', (str) => {
|
||||
ws.on('message', async (str) => {
|
||||
try {
|
||||
const message = JSON.parse(str.toString());
|
||||
if(typeof message.action !== 'string') {
|
||||
|
|
@ -17,7 +17,10 @@ wss.on('connection', (ws) => {
|
|||
}
|
||||
const {action, data} = message;
|
||||
try {
|
||||
router(action, data);
|
||||
const _return = await (router(action, data) as unknown as Promise<any>);
|
||||
if(_return) {
|
||||
ws.send(JSON.stringify(_return));
|
||||
}
|
||||
} catch(e) {
|
||||
console.warn(`error in action ${action}`);
|
||||
console.error(e);
|
||||
|
|
@ -39,4 +42,14 @@ export function broadcast(action: string, data?: any) {
|
|||
}
|
||||
}
|
||||
|
||||
export default wss;
|
||||
export default wss;
|
||||
|
||||
// -------------
|
||||
|
||||
import { update } from './db/migrate';
|
||||
|
||||
try {
|
||||
update();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ export default function router(routes: any) {
|
|||
}
|
||||
return function(route: any, data: any) {
|
||||
if(route in routes) {
|
||||
routes[route](data);
|
||||
return routes[route](data);
|
||||
} else {
|
||||
console.warn(`route <${route}> not found`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,30 @@
|
|||
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';
|
||||
|
||||
export default router({
|
||||
up() {
|
||||
console.log(Date.now());
|
||||
},
|
||||
message(data: string) {
|
||||
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,
|
||||
})),
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
@ -3,7 +3,6 @@ import {join} from 'path';
|
|||
|
||||
const PACKAGE_ROOT = __dirname;
|
||||
|
||||
|
||||
/**
|
||||
* @type {import('vite').UserConfig}
|
||||
* @see https://vitejs.dev/config/
|
||||
|
|
@ -17,6 +16,9 @@ const config = {
|
|||
'/@/': join(PACKAGE_ROOT, 'src') + '/',
|
||||
},
|
||||
},
|
||||
assetsInclude: [
|
||||
'**/*.sql',
|
||||
],
|
||||
build: {
|
||||
ssr: true,
|
||||
sourcemap: 'inline',
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ const setupServerPackageWatcher = () => {
|
|||
});
|
||||
|
||||
/** Proxy all logs */
|
||||
spawnProcess.stdout.on('data', d => d.toString().trim() && logger.warn(d.toString(), {timestamp: true}));
|
||||
spawnProcess.stdout.on('data', d => d.toString().trim() && logger.info(d.toString().trim(), {timestamp: true}));
|
||||
|
||||
/** Proxy error logs but stripe some noisy messages. See {@link stderrFilterPatterns} */
|
||||
spawnProcess.stderr.on('data', d => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
declare module '*.sql';
|
||||
Reference in New Issue