First commit
This commit is contained in:
454
framework/sync/syncServer.js
Normal file
454
framework/sync/syncServer.js
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2020, 2023, The Unified Company.
|
||||
|
||||
This code is part of Unify.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the ESA Software Community License - Strong Copyleft,
|
||||
|
||||
https://unifyjs.org
|
||||
|
||||
*/
|
||||
|
||||
import { WebSocketServer } from 'ws';
|
||||
|
||||
import http from 'http';
|
||||
|
||||
import https from 'https';
|
||||
|
||||
import fs from 'fs';
|
||||
|
||||
import objectManager from '../server/objectManager.js';
|
||||
|
||||
import Console from '../server/console.js';
|
||||
|
||||
import webConsole from '../unify/console.js';
|
||||
|
||||
import socketMessage from '../unify/socketMessage.js';
|
||||
|
||||
import querySQL from '../unify/querySQL.js';
|
||||
|
||||
import database from '../server/database.js';
|
||||
|
||||
import sqlite from '../server/sqlite.js';
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import sqlite3 from 'better-sqlite3';
|
||||
|
||||
|
||||
database.createTable( "sync_server" );
|
||||
|
||||
|
||||
database.addColumn( "original_id", "INTEGER", "sync_server" );
|
||||
|
||||
database.addColumn( "queryString", "TEXT", "sync_server" );
|
||||
|
||||
database.addColumn( "columnValues", "TEXT", "sync_server" );
|
||||
|
||||
database.addColumn( "operation", "TEXT", "sync_server" );
|
||||
|
||||
database.addColumn( "clusterClientID", "INTEGER", "sync_server" );
|
||||
|
||||
|
||||
|
||||
database.createTable( "sync_client" );
|
||||
|
||||
|
||||
database.addColumn( "original_id", "INTEGER", "sync_client" );
|
||||
|
||||
database.addColumn( "server_id", "INTEGER", "sync_client" );
|
||||
|
||||
database.addColumn( "queryString", "TEXT", "sync_client" );
|
||||
|
||||
database.addColumn( "columnValues", "TEXT", "sync_client" );
|
||||
|
||||
database.addColumn( "operation", "TEXT", "sync_client" );
|
||||
|
||||
database.addColumn( "clusterClientID", "INTEGER", "sync_client" );
|
||||
|
||||
database.addColumn( "synced", "BOOLEAN", "sync_client" );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class socketClient{
|
||||
|
||||
socket;
|
||||
|
||||
userID = 0;
|
||||
|
||||
async createSocket( ) {
|
||||
|
||||
this.createEventListeners();
|
||||
|
||||
var messageID = 0;
|
||||
|
||||
var message = new socketMessage();
|
||||
|
||||
message.id = messageID;
|
||||
message.name = "connected";
|
||||
message.type = "promise";
|
||||
message.clientID = this.userID;
|
||||
|
||||
this.send( message );
|
||||
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
console.log( "client disconnected ", this.userID );
|
||||
|
||||
this.socketManager.removeClient( this.userID );
|
||||
|
||||
}
|
||||
|
||||
createEventListeners() {
|
||||
|
||||
var client = this;
|
||||
|
||||
this.socket.on('message', async function( json ){ await client.message( json, client ) });
|
||||
this.socket.on('close', function( json ){ client.destroy(); });
|
||||
|
||||
}
|
||||
|
||||
send( socketMessage ) {
|
||||
|
||||
this.socket.send( JSON.stringify( socketMessage ) );
|
||||
|
||||
}
|
||||
|
||||
getRowsAfterDatetime( datetime, tablename ) {
|
||||
|
||||
var query = new querySQL( );
|
||||
|
||||
query.type = "select";
|
||||
query.table = "sync_server";
|
||||
query.order = ["datetime"];
|
||||
|
||||
query.find( "table_name", tablename );
|
||||
|
||||
query.find( "datetime", datetime, ">" );
|
||||
|
||||
var result = database.query( query );
|
||||
|
||||
}
|
||||
|
||||
getRowsFromIDTilNow( fromID, excludeClusterClientID ) {
|
||||
|
||||
//console.log( "Get rows id > ", fromID, " and ClusterClientID != ", excludeClusterClientID );
|
||||
|
||||
var query = new querySQL( );
|
||||
|
||||
query.type = "select";
|
||||
query.table = "sync_server";
|
||||
//query.order = ["id"];
|
||||
|
||||
query.find( "id", fromID, ">" );
|
||||
|
||||
query.find( "clusterClientID", excludeClusterClientID, "!=" );
|
||||
|
||||
|
||||
return database.query( query );
|
||||
|
||||
}
|
||||
|
||||
async message( json ) {
|
||||
|
||||
var object = JSON.parse( json );
|
||||
|
||||
switch( object.type ) {
|
||||
|
||||
case "add_sqlite_operation":
|
||||
|
||||
var unsynced = object.unsynced;
|
||||
|
||||
if(unsynced.length > 0) {
|
||||
|
||||
console.log("recieved unsynced", unsynced.length);
|
||||
|
||||
console.log("add row with object.clusterClientID: ", object.clusterClientID);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// todo : feature - implement insertMany - better-sqlite3 make sql query static
|
||||
// So database doesnt have to generate query for every row.
|
||||
|
||||
// Better is to make an database.js cache that does this for all query's in unify
|
||||
// that are alike so everything in unify will get an Significant speedup
|
||||
|
||||
for (var i = 0; i < unsynced.length; i++) {
|
||||
|
||||
var newRow = unsynced[i];
|
||||
|
||||
var query = new querySQL( );
|
||||
|
||||
query.type = "insert";
|
||||
|
||||
query.table = "sync_server";
|
||||
|
||||
|
||||
query.setValue( "original_id", newRow.original_id );
|
||||
|
||||
query.setValue( "queryString", newRow.queryString );
|
||||
|
||||
query.setValue( "columnValues", newRow.columnValues );
|
||||
|
||||
query.setValue( "operation", newRow.operation );
|
||||
|
||||
query.setValue( "clusterClientID", newRow.clusterClientID );
|
||||
|
||||
|
||||
var result = database.query( query );
|
||||
|
||||
|
||||
/*
|
||||
// perform real query here
|
||||
|
||||
var columnArray = JSON.parse( newRow.columnValues );
|
||||
|
||||
var query = new querySQL( );
|
||||
|
||||
query.type = newRow.operation;
|
||||
|
||||
for (var a = 0; a < columnArray.length; a++) {
|
||||
|
||||
var column = new Array();
|
||||
|
||||
column.name = false;
|
||||
column.value = columnArray[a];
|
||||
|
||||
query.values.push( column );
|
||||
|
||||
}
|
||||
|
||||
query.sync = false;
|
||||
|
||||
database.executeQuery( newRow.queryString, query );
|
||||
|
||||
|
||||
// ---
|
||||
|
||||
var query = new querySQL( );
|
||||
|
||||
query.type = "insert";
|
||||
|
||||
query.table = "sync_client";
|
||||
|
||||
query.setValue( "original_id", newRow.original_id );
|
||||
|
||||
query.setValue( "queryString", newRow.queryString );
|
||||
|
||||
query.setValue( "columnValues", newRow.columnValues );
|
||||
|
||||
query.setValue( "operation", newRow.operation );
|
||||
|
||||
query.setValue( "clusterClientID", 555 ); // prevent loading when new db is apperent
|
||||
|
||||
query.setValue( "server_id", newRow.id );
|
||||
|
||||
|
||||
query.setValue( "synced", true );
|
||||
|
||||
query.sync = false;
|
||||
|
||||
|
||||
|
||||
var result = database.query( query );
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
var message = new socketMessage();
|
||||
|
||||
message.name = "updateSyncClient";
|
||||
|
||||
message.clientID = this.userID;
|
||||
|
||||
|
||||
|
||||
message.rows = this.getRowsFromIDTilNow( object.lastID, object.clusterClientID );
|
||||
//console.log("get all rows not of clusterID: ", object.clusterClientID);
|
||||
|
||||
//message.rows = [];
|
||||
|
||||
message.synced = unsynced;
|
||||
|
||||
//console.log("rows found", message.rows.length);
|
||||
|
||||
this.send( message );
|
||||
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case "download_database":
|
||||
|
||||
console.log("download_database");
|
||||
|
||||
var message = new socketMessage();
|
||||
|
||||
message.name = "upload_database";
|
||||
|
||||
message.binary = fs.readFileSync("./framework/db/syncServer.sqlite")
|
||||
|
||||
this.send( message );
|
||||
|
||||
//console.log(databaseBinary);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class socketManager{
|
||||
|
||||
socket;
|
||||
|
||||
core;
|
||||
|
||||
userID = 0;
|
||||
|
||||
port = 4422;
|
||||
|
||||
host = "localhost";
|
||||
|
||||
clients = new Array();
|
||||
|
||||
|
||||
constructor( port ){
|
||||
|
||||
if( port ) {
|
||||
|
||||
this.port = port;
|
||||
//Console.log("start server at port:", port );
|
||||
|
||||
}
|
||||
|
||||
global.socketManager = this;
|
||||
|
||||
}
|
||||
|
||||
emptyTable() {
|
||||
|
||||
database.database.prepare( "DELETE from sync_server" ).run()
|
||||
|
||||
}
|
||||
|
||||
|
||||
create() {
|
||||
|
||||
console.log("create socket server after this");
|
||||
|
||||
if( !global.ssl ) {
|
||||
|
||||
this.socket = new WebSocketServer({ port: this.port });
|
||||
|
||||
console.log("socket server started on port: " , this.port );
|
||||
|
||||
} else {
|
||||
|
||||
this.socket = new WebSocketServer({ server: this.httpsServer });
|
||||
|
||||
console.log("started Secure socket server ", this.port);
|
||||
|
||||
}
|
||||
|
||||
this.createEventListeners();
|
||||
|
||||
}
|
||||
|
||||
createEventListeners() {
|
||||
|
||||
var socketManager = this;
|
||||
|
||||
this.socket.on('connection', function( socket ){ socketManager.connection( socket ) });
|
||||
|
||||
}
|
||||
|
||||
addClient( id, socket ) {
|
||||
|
||||
var newClient = new socketClient( this.port );
|
||||
|
||||
newClient.userID = id;
|
||||
|
||||
newClient.socket = socket;
|
||||
|
||||
newClient.socketManager = this;
|
||||
|
||||
newClient.createSocket();
|
||||
|
||||
this.clients.push( newClient );
|
||||
|
||||
}
|
||||
|
||||
removeClient( userID ) {
|
||||
|
||||
var clients = this.clients;
|
||||
|
||||
//this.objectManager.removeObjectsByClientID( userID );
|
||||
|
||||
for(var c = 0; c<clients.length;c++ ) {
|
||||
|
||||
var client = clients[c];
|
||||
|
||||
if( client.userID == userID ) {
|
||||
|
||||
clients.splice( c, 1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
connection( socket ) {
|
||||
|
||||
const userID = this.userID++;
|
||||
|
||||
this.addClient( userID, socket );
|
||||
|
||||
console.log( "client connected : ", userID );
|
||||
|
||||
console.log( "number connected clients ", this.clients.length );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var socketManagerServer = new socketManager();
|
||||
|
||||
socketManagerServer.create();
|
||||
|
||||
|
||||
// just in case some user like using "kill"
|
||||
process.on("SIGTERM", (signal) => {
|
||||
console.log(`Process ${process.pid} received a SIGTERM signal`);
|
||||
|
||||
socketManagerServer.emptyTable();
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// catch ctrl-c, so that event 'exit' always works
|
||||
process.on("SIGINT", (signal) => {
|
||||
console.log(`Process ${process.pid} has been interrupted`);
|
||||
|
||||
socketManagerServer.emptyTable();
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
Reference in New Issue
Block a user