socio 0.1.0 working demo

This commit is contained in:
Rolands 2022-11-27 21:41:35 +02:00
parent e05b435e96
commit be349bb228
10 changed files with 87 additions and 70 deletions

View file

@ -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 receivedand the latter lies outside his control." /Epictetus/
export class SocioClient {
// private:

View file

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

View file

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

View file

@ -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
View 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()) || []
}

View file

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

View file

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

View file

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

View file

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

View file

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