mirror of
https://github.com/Rolands-Laucis/Socio.git
synced 2026-05-15 14:15:57 -06:00
socio 0.1.0 working demo
This commit is contained in:
parent
e05b435e96
commit
be349bb228
10 changed files with 87 additions and 70 deletions
|
|
@ -1,16 +1,23 @@
|
|||
//https://stackoverflow.com/questions/38946112/es6-import-error-handling
|
||||
try { //for my logger
|
||||
var { info, log, error, done, soft_error, setPrefix, setShowTime } = await import('@rolands/log')
|
||||
setPrefix('Socio Client')
|
||||
setShowTime(false)
|
||||
var { info, log, error, done, soft_error, setPrefix, setShowTime } = await import('@rolands/log'); setPrefix('Socio Client'); setShowTime(false);
|
||||
} catch (e) {
|
||||
console.log('[Socio Client ERROR]', e)
|
||||
var info = (...objs) => console.log('[Socio Client]', ...objs)
|
||||
var done = (...objs) => console.log('[Socio Client]', ...objs)
|
||||
var log = (...objs) => console.log('[Socio Client]', ...objs)
|
||||
var soft_error = (...objs) => console.log('[Socio Client]', ...objs)
|
||||
console.log('[Socio Client ERROR] IMPORT:', e)
|
||||
var info = (...objs) => console.log('[Socio Client]', ...objs),
|
||||
done = (...objs) => console.log('[Socio Client]', ...objs),
|
||||
log = (...objs) => console.log('[Socio Client]', ...objs),
|
||||
soft_error = (...objs) => console.log('[Socio Client]', ...objs)
|
||||
}
|
||||
|
||||
// import { QueryIsSelect, ParseSQLForTables } from 'socio/utils'
|
||||
import { QueryIsSelect, ParseSQLForTables } from './utils.js'
|
||||
|
||||
// try{
|
||||
// const { QueryIsSelect, ParseSQLForTables } = await import('./utils.js')
|
||||
// }catch(e){
|
||||
// const { QueryIsSelect, ParseSQLForTables } = await import('socio/utils')
|
||||
// }
|
||||
|
||||
//"Because he not only wants to perform well, he wants to be well received — and the latter lies outside his control." /Epictetus/
|
||||
export class SocioClient {
|
||||
// private:
|
||||
|
|
|
|||
67
core/core.js
67
core/core.js
|
|
@ -1,10 +1,12 @@
|
|||
//Nullum magnum ingenium sine mixture dementia fuit. - There has been no great wisdom without an element of madness.
|
||||
|
||||
import { log, soft_error, info, setPrefix, setShowTime } from '@rolands/log'; setPrefix('Socio'); setShowTime(false); //for my logger
|
||||
import { UUID } from './secure.js';
|
||||
//libs
|
||||
import { WebSocketServer } from 'ws'; //https://github.com/websockets/ws https://github.com/websockets/ws/blob/master/doc/ws.md
|
||||
import { sql_string_regex } from './secure.js'
|
||||
//https://stackoverflow.com/questions/16280747/sending-message-to-a-specific-connected-users-using-websocket
|
||||
|
||||
//mine
|
||||
import { log, soft_error, info, setPrefix, setShowTime } from '@rolands/log'; setPrefix('Socio'); setShowTime(false); //for my logger
|
||||
import { QueryIsSelect, ParseSQLForTables } from './utils.js'
|
||||
import { sql_string_regex, UUID } from './secure.js'
|
||||
|
||||
//NB! some fields in these variables are private for safety reasons, but also bcs u shouldnt be altering them, only if through my defined ways. They are mostly expected to be constants.
|
||||
//whereas public variables are free for you to alter freely at any time during runtime.
|
||||
|
|
@ -56,7 +58,7 @@ export class SessionManager{
|
|||
this.#lifecycle_hooks.con(this.#sessions[client_id], req)
|
||||
|
||||
//notify the client of their ID
|
||||
this.#sessions[client_id].Send({ kind: 'CON', data:client_id });
|
||||
this.#sessions[client_id].Send('CON', { data:client_id });
|
||||
this.#HandleInfo('CON', client_id)
|
||||
|
||||
//set this client websockets event handlers
|
||||
|
|
@ -98,8 +100,7 @@ export class SessionManager{
|
|||
switch (kind) {
|
||||
case 'REG':
|
||||
if (client_id in this.#sessions)
|
||||
this.#sessions[client_id].Send({
|
||||
kind:'UPD',
|
||||
this.#sessions[client_id].Send('UPD',{
|
||||
data:{
|
||||
id: data.id,
|
||||
result: await this.Query({
|
||||
|
|
@ -110,30 +111,30 @@ export class SessionManager{
|
|||
})
|
||||
|
||||
//set up hook
|
||||
if (QueryUtils.QueryIsSelect(data.sql))
|
||||
QueryUtils.ParseSQLForTables(data.sql).forEach(t => this.#sessions[client_id].RegisterHook(t, data.id, data.sql, data.params));
|
||||
if (QueryIsSelect(data.sql))
|
||||
ParseSQLForTables(data.sql).forEach(t => this.#sessions[client_id].RegisterHook(t, data.id, data.sql, data.params));
|
||||
|
||||
break;
|
||||
case 'SQL':
|
||||
const is_select = QueryUtils.QueryIsSelect(data.sql)
|
||||
const is_select = QueryIsSelect(data.sql)
|
||||
if (client_id in this.#sessions) {
|
||||
//have to do the query in every case
|
||||
const res = this.Query({ ...data, ses_id: this.#sessions[client_id].ses_id })
|
||||
if (is_select) //wait for result, if a result is expected, and send it back
|
||||
this.#sessions[client_id].Send({ kind:'SQL', data:{ id: data.id, result: await res } })
|
||||
this.#sessions[client_id].Send('SQL',{data:{ id: data.id, result: await res } })
|
||||
}
|
||||
|
||||
//if the sql wasnt a SELECT, but altered some resource, then need to propogate that to other connection hooks
|
||||
if (!is_select)
|
||||
this.Update(QueryUtils.ParseSQLForTables(data.sql))
|
||||
this.Update(ParseSQLForTables(data.sql))
|
||||
|
||||
break;
|
||||
case 'PING': this.#sessions[client_id].Send({kind:'PONG', data:{ id: data?.id }}); break;
|
||||
case 'PING': this.#sessions[client_id].Send('PONG',{data:{ id: data?.id }}); break;
|
||||
case 'AUTH':
|
||||
if (this.#lifecycle_hooks.auth)
|
||||
this.#sessions[client_id].Send({ kind:'AUTH', data:{ id: data.id, result: await this.#lifecycle_hooks.auth(client_id, data.params) } })
|
||||
this.#sessions[client_id].Send('AUTH',{data:{ id: data.id, result: await this.#lifecycle_hooks.auth(client_id, data.params) } })
|
||||
else
|
||||
this.#sessions[client_id].Send({ kind:'AUTH', data:{ id: data.id, result: false } })
|
||||
this.#sessions[client_id].Send('AUTH', {data:{ id: data.id, result: false } })
|
||||
break;
|
||||
// case '': break;
|
||||
default: throw (`Unrecognized message kind! [${kind}] with data:`, data);
|
||||
|
|
@ -153,7 +154,18 @@ export class SessionManager{
|
|||
tables.forEach(async (t) => {
|
||||
if (s.hook_tables.includes(t)) {
|
||||
for await (const hook of s.GetHookObjs(t)) {
|
||||
s.Send(['UPD', { id: hook.id, result: (await this.Query({ id: hook.id, ses_id: s.ses_id, query: hook.sql, params: hook.params })) }])
|
||||
s.Send('UPD', {
|
||||
data:
|
||||
{
|
||||
id: hook.id,
|
||||
result: (await this.Query(
|
||||
{
|
||||
ses_id: s.ses_id,
|
||||
...hook
|
||||
}))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -165,7 +177,7 @@ export class SessionManager{
|
|||
SendTo(client_id='', data={}){
|
||||
try{
|
||||
if (client_id in this.#sessions)
|
||||
this.#sessions[client_id].Send({ kind:'PUSH', data:data })
|
||||
this.#sessions[client_id].Send('PUSH', {data:data })
|
||||
else throw `The provided session ID [${client_id}] was not found in the tracked web socket connections!`
|
||||
} catch (e) { this.#HandleError(e) }
|
||||
}
|
||||
|
|
@ -232,9 +244,9 @@ class Session{
|
|||
// log('reg hook', table, this.#hooks[table])
|
||||
}
|
||||
|
||||
Send(data={}){
|
||||
this.#ws.send(JSON.stringify(data))
|
||||
if (this.verbose) info('sent:', data)
|
||||
Send(kind='',data={}){
|
||||
this.#ws.send(JSON.stringify({ kind: kind, ...data }))
|
||||
if (this.verbose) info('sent:',kind, data)
|
||||
}
|
||||
|
||||
get hook_tables(){return Object.keys(this.#hooks)}
|
||||
|
|
@ -243,18 +255,3 @@ class Session{
|
|||
|
||||
get authenticated(){return this.#authenticated}
|
||||
}
|
||||
|
||||
|
||||
class QueryUtils{
|
||||
static QueryIsSelect(sql = '') {
|
||||
return /^SELECT/im.test(sql)
|
||||
}
|
||||
|
||||
static ParseSQLForTables(sql = '') {
|
||||
return sql
|
||||
.match(/(?:FROM|INTO)[\s\n\t](?<tables>[\w,\s\n\t]+?)[\s\n\t]?(?:WHERE|VALUES|;|LIMIT|GROUP|ORDER)/mi)
|
||||
?.groups?.tables
|
||||
.split(/,[\s\n\t\r]*/mig)
|
||||
.map((t) => t.split(/[\s\n\t\r]/mi)[0].trim()) || []
|
||||
}
|
||||
}
|
||||
4
core/package-lock.json
generated
4
core/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "socio",
|
||||
"version": "0.0.7",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "socio",
|
||||
"version": "0.0.7",
|
||||
"version": "0.1.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@rolands/log": "^1.1.1",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "socio",
|
||||
"version": "0.0.7",
|
||||
"version": "0.1.0",
|
||||
"description": "a websocket based live and synced front and back end",
|
||||
"main": "core.js",
|
||||
"type": "module",
|
||||
|
|
|
|||
11
core/utils.js
Normal file
11
core/utils.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export function QueryIsSelect(sql = '') {
|
||||
return /^SELECT/im.test(sql)
|
||||
}
|
||||
|
||||
export function ParseSQLForTables(sql = '') {
|
||||
return sql
|
||||
.match(/(?:FROM|INTO)[\s\n\t](?<tables>[\w,\s\n\t]+?)[\s\n\t]?(?:WHERE|VALUES|;|LIMIT|GROUP|ORDER)/mi)
|
||||
?.groups?.tables
|
||||
.split(/,[\s\n\t\r]*/mig)
|
||||
.map((t) => t.split(/[\s\n\t\r]/mi)[0].trim()) || []
|
||||
}
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
//Errare humanum est, perseverare diabolicum. - To err is human; to persist in it - diabolial. /Lucius Annaeus Seneca/
|
||||
|
||||
import { SocioClient } from '/core-client.js'
|
||||
// import { SocioClient } from "../../core/core-client"
|
||||
//import the socio lib. NB! here i am doing it as a dynamic import, bcs i also develop the lib here and its automatic this way and demo always works. You should do a regular import at the top level like other imports.
|
||||
try {
|
||||
const { SocioClient } = await import("../../core/core-client")
|
||||
} catch (e) {
|
||||
const { SocioClient } = await import('/core-client.js')
|
||||
}
|
||||
|
||||
//instantiate the Socio Client from lib on the expected websocket port and wait for it to connect
|
||||
//NB! use wss secure socket protocol and use the ./core/Secure class to encrypt these queries in PROD!
|
||||
|
|
|
|||
28
demos/framework/package-lock.json
generated
28
demos/framework/package-lock.json
generated
|
|
@ -10,7 +10,7 @@
|
|||
"dependencies": {
|
||||
"@rolands/log": "^1.1.1",
|
||||
"sequelize": "^6.25.3",
|
||||
"socio": "^0.0.1",
|
||||
"socio": "^0.1.0",
|
||||
"sqlite3": "^5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -1009,7 +1009,6 @@
|
|||
"version": "0.26.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz",
|
||||
"integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
},
|
||||
|
|
@ -1642,11 +1641,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/socio": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/socio/-/socio-0.0.1.tgz",
|
||||
"integrity": "sha512-YjOk596DV092CL1mIsS3moKUQ0W7Ge4RM5L2NT/PbimcuuWYQy3ZcjIlaAIMIcxlwA7Dm9nwyXD26wadKvNrWA==",
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/socio/-/socio-0.1.0.tgz",
|
||||
"integrity": "sha512-yzrDkfo4zhwIcXQmo0Y39piTS9/ZqhYVdpBGkfm/s4uVsVgcAtmWV39coX9QU6GAEiKiVsEcn2nzrqb9nIyDEg==",
|
||||
"dependencies": {
|
||||
"@rolands/log": "^1.0.1",
|
||||
"@rolands/log": "^1.1.1",
|
||||
"magic-string": "^0.26.7",
|
||||
"ws": "^8.9.0"
|
||||
}
|
||||
},
|
||||
|
|
@ -1690,8 +1690,7 @@
|
|||
"node_modules/sourcemap-codec": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
|
||||
},
|
||||
"node_modules/sqlite3": {
|
||||
"version": "5.1.2",
|
||||
|
|
@ -2647,7 +2646,6 @@
|
|||
"version": "0.26.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz",
|
||||
"integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
}
|
||||
|
|
@ -3073,11 +3071,12 @@
|
|||
"optional": true
|
||||
},
|
||||
"socio": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/socio/-/socio-0.0.1.tgz",
|
||||
"integrity": "sha512-YjOk596DV092CL1mIsS3moKUQ0W7Ge4RM5L2NT/PbimcuuWYQy3ZcjIlaAIMIcxlwA7Dm9nwyXD26wadKvNrWA==",
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/socio/-/socio-0.1.0.tgz",
|
||||
"integrity": "sha512-yzrDkfo4zhwIcXQmo0Y39piTS9/ZqhYVdpBGkfm/s4uVsVgcAtmWV39coX9QU6GAEiKiVsEcn2nzrqb9nIyDEg==",
|
||||
"requires": {
|
||||
"@rolands/log": "^1.0.1",
|
||||
"@rolands/log": "^1.1.1",
|
||||
"magic-string": "^0.26.7",
|
||||
"ws": "^8.9.0"
|
||||
}
|
||||
},
|
||||
|
|
@ -3111,8 +3110,7 @@
|
|||
"sourcemap-codec": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "5.1.2",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
"dependencies": {
|
||||
"@rolands/log": "^1.1.1",
|
||||
"sequelize": "^6.25.3",
|
||||
"socio": "^0.0.1",
|
||||
"socio": "^0.1.0",
|
||||
"sqlite3": "^5.1.2"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// import { SessionManager } from '../../core/core.js' //i use this locally
|
||||
// import { SocioSecurity } from '../../core/secure.js' //i use this locally
|
||||
import {SessionManager} from 'socio/core.js' //for using the lib as a download from npm
|
||||
import { SocioSecurity } from 'socio/secure.js' //for using the lib as a download from npm
|
||||
import { SessionManager } from '../../core/core.js' //i use this locally
|
||||
import { SocioSecurity } from '../../core/secure.js' //i use this locally
|
||||
// import {SessionManager} from 'socio/core.js' //for using the lib as a download from npm
|
||||
// import { SocioSecurity } from 'socio/secure.js' //for using the lib as a download from npm
|
||||
|
||||
import { Sequelize } from 'sequelize';
|
||||
import { log, done, setPrefix, setShowTime } from '@rolands/log'; setPrefix('SERVER'); setShowTime(false);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
//imports:
|
||||
import { SocioClient } from 'socio/core-client.js'
|
||||
// import { SocioClient } from '../../../core/core-client.js'
|
||||
import { SocioClient } from '../../../core/core-client.js' //for local lib dev testing
|
||||
// import { SocioClient } from 'socio/core-client.js' //use the lib in a project as downloaded from npm
|
||||
import {onMount} from 'svelte'
|
||||
import {slide} from 'svelte/transition'
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue