455 lines
8.2 KiB
JavaScript
455 lines
8.2 KiB
JavaScript
/*
|
|
|
|
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);
|
|
});
|