aotrautils 0.0.45 → 0.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
aotrautils/README.md CHANGED
@@ -1,12 +1,12 @@
1
- Aotrautils library client
1
+ Aotrautils library client-side
2
2
  =========
3
3
 
4
- The aotrautils library to be used in plain javascript or nodejs projects. Provides use fule functions like foreach, the aotest automated testing framework, and the flat map to json and json to flap map converter utils.
5
-
4
+ The aotrautils library to be used in plain javascript or nodejs projects. Provides useful functions like foreach, the aotest automated testing framework, and the flat map to json and json to flap map converter utils.
5
+ Plus some useful client-side exclusive functions and methods.
6
6
 
7
7
  #Project license text : see doc/HGPL_LICENSE.txt file
8
8
 
9
- # Author name : Jérémie Ratomposon (massively helped by its programming egos legions)
9
+ # Author name : Jérémie Ratomposon (massively helped by his native country free education system)
10
10
  # Author email : info@alqemia.com
11
11
  # Organization name : Alqemia
12
12
  # Organization email : info@alqemia.com
@@ -1,6 +1,6 @@
1
1
 
2
2
 
3
- /*utils CLIENT library associated with aotra version : «1.0.0.000 (11/07/2022-00:48:13)»*/
3
+ /*utils CLIENT library associated with aotra version : «1.0.0.000 (11/07/2022-21:05:49)»*/
4
4
  /*-----------------------------------------------------------------------------*/
5
5
  /* ## Utility global methods in a browser (htmljs) client environment.
6
6
  *
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * # Library name : «aotrautils»
12
12
  * # Library license : HGPL(Help Burma) (see aotra README information for details : https://alqemia.com/aotra.js )
13
- * # Author name : Jérémie Ratomposon (massively helped by its programming egos legions)
13
+ * # Author name : Jérémie Ratomposon (massively helped by his native country free education system)
14
14
  * # Author email : info@alqemia.com
15
15
  * # Organization name : Alqemia
16
16
  * # Organization email : admin@alqemia.com
@@ -7121,7 +7121,7 @@ createFusrodaClient=function(doOnClientReady, doOnDataReception, urlParam=null,
7121
7121
 
7122
7122
 
7123
7123
 
7124
- /*utils GEOMETRY library associated with aotra version : «1.0.0.000 (11/07/2022-00:48:13)»*/
7124
+ /*utils GEOMETRY library associated with aotra version : «1.0.0.000 (11/07/2022-21:05:49)»*/
7125
7125
  /*-----------------------------------------------------------------------------*/
7126
7126
 
7127
7127
 
@@ -7133,7 +7133,7 @@ createFusrodaClient=function(doOnClientReady, doOnDataReception, urlParam=null,
7133
7133
  *
7134
7134
  * # Library name : «aotrautils»
7135
7135
  * # Library license : HGPL(Help Burma) (see aotra README information for details : https://alqemia.com/aotra.js )
7136
- * # Author name : Jérémie Ratomposon (massively helped by its programming egos legions)
7136
+ * # Author name : Jérémie Ratomposon (massively helped by his native country free education system)
7137
7137
  * # Author email : info@alqemia.com
7138
7138
  * # Organization name : Alqemia
7139
7139
  * # Organization email : admin@alqemia.com
@@ -8327,1310 +8327,7 @@ function rayVsUnitSphereClosestPoint(p, r) {
8327
8327
  // MUST REMAIN AT THE END OF THIS LIBRARY FILE !
8328
8328
 
8329
8329
  AOTRAUTILS_GEOMETRY_LIB_IS_LOADED=true;
8330
- /*utils SERVER library associated with aotra version : «1.0.0.000 (11/07/2022-00:48:13)»*/
8331
- /*-----------------------------------------------------------------------------*/
8332
-
8333
-
8334
- /* ## Utility global methods in a javascript, console (nodejs) server, or vanilla javascript with no browser environment.
8335
- *
8336
- * This set of methods gathers utility generic-purpose methods usable in any JS project.
8337
- * Several authors of snippets published freely on the Internet contributed to this library.
8338
- * Feel free to use/modify-enhance/publish them under the terms of its license.
8339
- *
8340
- * # Library name : «aotrautils»
8341
- * # Library license : HGPL(Help Burma) (see aotra README information for details : https://alqemia.com/aotra.js )
8342
- * # Author name : Jérémie Ratomposon (massively helped by its programming egos legions)
8343
- * # Author email : info@alqemia.com
8344
- * # Organization name : Alqemia
8345
- * # Organization email : admin@alqemia.com
8346
- * # Organization website : https://alqemia.com
8347
- *
8348
- *
8349
- */
8350
-
8351
-
8352
-
8353
- // COMPATIBILITY browser javascript / nodejs environment :
8354
-
8355
- if(typeof(window)==="undefined") window=global;
8356
-
8357
-
8358
-
8359
-
8360
- // =================================================================================
8361
- // NODEJS UTILS
8362
-
8363
- const FILE_ENCODING="utf8";
8364
-
8365
-
8366
- // Nodejs filesystem utils :
8367
- if(typeof(fs)==="undefined"){
8368
- // TRACE
8369
- console.log("WARN : Could not find the nodejs dependency «fs», aborting persister setup.");
8370
- window.getPersister=()=>{ return null; };
8371
-
8372
- }else{
8373
-
8374
-
8375
- window.getPersister=function(dataDirPath,suffix=""){
8376
-
8377
- let self={
8378
-
8379
- dataDirPath:dataDirPath,
8380
- suffix:suffix,
8381
-
8382
- //FILE_NAME_PATTERN:"data.clientId.repositoryName.json",
8383
- /*private*/getPath:function(clientId,repositoryName){
8384
- // let path=self.FILE_NAME_PATTERN.replace(new RegExp("@clientId@","g"),clientId);
8385
- let path=`${self.dataDirPath}`
8386
- + (blank(self.suffix)?"":(self.suffix+"."))
8387
- +`${clientId}.${repositoryName}.json`;
8388
- return path;
8389
- },
8390
-
8391
- readTreeObjectFromFile:function(clientId, repositoryName, CLASSNAME_ATTR_NAME=DEFAULT_CLASSNAME_ATTR_NAME){
8392
-
8393
- let path=self.getPath(clientId,repositoryName);
8394
-
8395
- let resultFlat=null;
8396
-
8397
- try{
8398
- resultFlat=fs.readFileSync(path, FILE_ENCODING);
8399
-
8400
- }catch(error){
8401
- // TRACE
8402
- console.log("ERROR : Could not read file «"+path+"».");
8403
-
8404
- return null;
8405
- }
8406
-
8407
-
8408
- let resultData={};
8409
- if(!empty(resultFlat)) resultData=JSON.parse(resultFlat);
8410
-
8411
-
8412
- if(!empty(resultData) && isFlatMap(resultData)){
8413
-
8414
- resultData=getAsTreeStructure(resultData,true
8415
- // We have to keep the type information, here too ! (in the sub-objects)
8416
- ,false);
8417
-
8418
- }
8419
-
8420
- return resultData;
8421
- },
8422
-
8423
-
8424
- saveDataToFileForClient:function(clientId,repositoryName,dataFlatForClient,forceKeepUnflatten=false,doOnSuccess=null){
8425
-
8426
-
8427
-
8428
- if(!empty(dataFlatForClient) && !isFlatMap(dataFlatForClient) && !forceKeepUnflatten){
8429
- dataFlatForClient=getAsFlatStructure(dataFlatForClient,true);
8430
- }
8431
-
8432
- // reserved characters : -/\^$*+?.()|[]{}
8433
- // CANNOT USE stringifyObject(...) function because we are in a common, lower-level library !
8434
- let dataFlatStr=JSON.stringify(dataFlatForClient)
8435
- // We «aerate» the produced JSON :
8436
- .replace(/":[\w]*\{/gim,"\":{\n").replace(/,"/gim,",\n\"")
8437
- // ...except for inline, escaped JSON string representations :
8438
- .replace(/\\\":[\w]*\{\n/gim,"\\\":{");
8439
- // NO : .replace(/}/gim,"}\n");
8440
-
8441
-
8442
- let path=self.getPath(clientId,repositoryName);
8443
-
8444
- fs.writeFile(path, dataFlatStr, FILE_ENCODING, (error) => {
8445
- if(error){
8446
- // TRACE
8447
- console.log("ERROR : Could not write file «"+path+"»:",error);
8448
- throw error;
8449
- }
8450
- if(doOnSuccess) doOnSuccess(dataFlatForClient);
8451
- });
8452
- }
8453
-
8454
- };
8455
-
8456
-
8457
- return self;
8458
- };
8459
-
8460
- }
8461
-
8462
-
8463
-
8464
- // Nodejs server launching helper functions :
8465
- //Networking management :
8466
- //- WEBSOCKETS AND NODEJS :
8467
-
8468
- // -Server :
8469
-
8470
- getServerParams=function(portParam,isSecureParam,certPathParam,keyPathParam){
8471
-
8472
- // Node dependencies :
8473
- // https=require("https");
8474
- // fs=require("fs");
8475
-
8476
- if(!https){
8477
- // TRACE
8478
- console.log("WARN : Could not find the nodejs dependency «https», aborting SSL setup.");
8479
- return null;
8480
- }
8481
- if(!fs){
8482
- // TRACE
8483
- console.log("WARN : Could not find the nodejs dependency «fs», aborting SSL setup.");
8484
- return null;
8485
- }
8486
-
8487
- var result={};
8488
-
8489
- // We read the command-line arguments if needed :
8490
- var argCLPort;
8491
- var argCLCertPath;
8492
- var argCLKeyPath;
8493
- process.argv.forEach(function (val, i){
8494
- if(i<=1) return;
8495
- else if(i==2) argCLPort=val;
8496
- else if(i==3) argCLCertPath=val;
8497
- else if(i==4) argCLKeyPath=val;
8498
- });
8499
-
8500
- // Console, command-line arguments OVERRIDE parameters values :
8501
-
8502
- result.port=nonull(argCLPort,portParam);
8503
- result.certPath=null;
8504
- result.keyPath=null;
8505
- result.isSecure=isSecureParam;
8506
-
8507
- if(isSecureParam){
8508
- result.certPath=nonull(argCLCertPath,certPathParam);
8509
- result.keyPath=nonull(argCLKeyPath,keyPathParam);
8510
- }
8511
-
8512
- // Eventual encryption options :
8513
- result.sslOptions=null;
8514
- if(isSecureParam){
8515
- result.sslOptions={
8516
- cert: fs.readFileSync(certPath),
8517
- key: fs.readFileSync(keyPath),
8518
- };
8519
- }
8520
-
8521
- return result;
8522
- }
8523
-
8524
-
8525
- // NODE ONLY SERVER / CLIENTS :
8526
- WebsocketImplementation={
8527
-
8528
- isNodeContext:true,
8529
- useSocketIOImplementation:false,
8530
- useFlatStrings:false,
8531
-
8532
- // COMMON METHODS
8533
- /*private static*/isInRoom(clientSocket, clientsRoomsTag){
8534
- return !clientsRoomsTag || empty(clientsRoomsTag) || contains(clientsRoomsTag, clientSocket.clientRoomTag);
8535
- },
8536
-
8537
-
8538
- //
8539
- // NODE SERVER
8540
- //
8541
- getStatic:(isNodeContext=true, useSocketIOImplementation=false)=>{
8542
-
8543
- WebsocketImplementation.isNodeContext=isNodeContext;
8544
-
8545
- // cf. https://socket.io/docs/v4/client-socket-instance/
8546
- WebsocketImplementation.useSocketIOImplementation=useSocketIOImplementation;
8547
-
8548
- // OLD : socket.io :
8549
- // https://stackoverflow.com/questions/31156884/how-to-use-https-on-node-js-using-express-socket-io
8550
- // https://stackoverflow.com/questions/6599470/node-js-socket-io-with-ssl
8551
- // https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener
8552
-
8553
- // if(typeof(socketIO)==="undefined"){
8554
- // // TRACE
8555
- // console.log("«socket.io» SERVER library not called yet, calling it now.");
8556
- // socketIO=require("socket.io");
8557
- // return socketIO;
8558
- // }
8559
- // if(typeof(socketIO)==="undefined"){
8560
- // // TRACE
8561
- // console.log("ERROR : «socket.io» SERVER library not found. Cannot launch nodejs server. Aborting.");
8562
- // return null;
8563
- // }
8564
-
8565
- // *********************************************************************************
8566
-
8567
- // NEW : ws :
8568
- // https://github.com/websockets/ws#installing
8569
- // https://github.com/websockets/ws/blob/master/doc/ws.md#event-message
8570
- // ON BROWSER SIDE : Native Websockets :
8571
- // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
8572
- // https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications
8573
- if(typeof(WebSocket)==="undefined"){
8574
- WebSocket=require("ws");
8575
- // TRACE
8576
- console.log("«ws» SERVER library not called yet, calling it now.");
8577
- return WebsocketImplementation;
8578
- }
8579
- if(typeof(WebSocket)==="undefined"){
8580
- // TRACE
8581
- console.log("ERROR : «ws» SERVER library not found. Cannot launch nodejs server. Aborting.");
8582
- return null;
8583
- }
8584
-
8585
- return WebsocketImplementation;
8586
- },
8587
-
8588
-
8589
- getServer:(listenableServer)=>{
8590
-
8591
- if(!WebsocketImplementation.isNodeContext){
8592
- // TRACE
8593
- throw new Error("ERROR : SERVER : Server launch is not supported in a non-nodejs context for any implementation.");
8594
- }
8595
-
8596
- // TODO : FIXME : Use one single interface !
8597
- // NODE SERVER MODE ONLY :
8598
- let serverSocket;
8599
- if(!WebsocketImplementation.useSocketIOImplementation){
8600
- serverSocket=new WebSocket.Server({ "server":listenableServer });
8601
- }else{
8602
- // NOW : socket.io :
8603
- // Loading socket.io
8604
- serverSocket=socketIO.listen(listenableServer);
8605
-
8606
- // Setting up the disctonnect event :
8607
- serverSocket.on("endConnection",()=>{
8608
- serverSocket.disconnect();
8609
- });
8610
-
8611
- }
8612
-
8613
- // NODE SERVER INSTANCE :
8614
- const nodeServerInstance={
8615
-
8616
- onClientLostListeners:[],
8617
-
8618
- clientTimeoutMillis:20000,
8619
- // clientsSockets:[],
8620
- serverSocket:serverSocket,
8621
- receptionEntryPoints:[],
8622
-
8623
- receive:(channelName, doOnIncomingMessage, clientsRoomsTag=null)=>{
8624
-
8625
- const receptionEntryPoint={
8626
- channelName:channelName,
8627
- clientsRoomsTag:clientsRoomsTag,
8628
- execute:(clientSocketParam)=>{
8629
-
8630
-
8631
- // With «ws» library we have no choive than register message events inside a «connection» event !
8632
- // nodeServerInstance.onConnectionToClient((serverParam, clientSocketParam)=>{
8633
-
8634
- // TODO : Find a way to remove this !
8635
- const doOnMessage=(message)=>{
8636
-
8637
- // dataWrapped=JSON.parse(dataWrapped);
8638
- // dataWrapped=getAt(dataWrapped,0);// We get the root element
8639
- const dataWrapped=(WebsocketImplementation.useFlatStrings?JSON.parse(message):message);
8640
-
8641
-
8642
- // Channel information is stored in exchanged data :
8643
- if(dataWrapped.channelName!==receptionEntryPoint.channelName) return;
8644
-
8645
-
8646
- const clientSocket=clientSocketParam;
8647
-
8648
- // TODO : FIXME : Use one single interface !
8649
- // Room information is stored in client socket object :
8650
- if(!WebsocketImplementation.isInRoom(clientSocket, receptionEntryPoint.clientsRoomsTag)) return;
8651
-
8652
- doOnIncomingMessage(dataWrapped.data, clientSocket);
8653
-
8654
- };
8655
-
8656
-
8657
- if(!WebsocketImplementation.useSocketIOImplementation) clientSocketParam.addEventListener("message", doOnMessage);
8658
- else clientSocketParam.on(channelName, doOnMessage);
8659
-
8660
-
8661
-
8662
-
8663
- },
8664
- };
8665
-
8666
- // DBG
8667
- console.log("ADD RECEPTION ENTRY POINT channelName:«"+channelName+"»! nodeServerInstance.receptionEntryPoints.length:",nodeServerInstance.receptionEntryPoints.length);
8668
-
8669
- nodeServerInstance.receptionEntryPoints.push(receptionEntryPoint);
8670
-
8671
-
8672
- return nodeServerInstance;
8673
- },
8674
-
8675
-
8676
- send:(channelName, data, clientsRoomsTag=null, clientSocketParam=null)=>{
8677
-
8678
-
8679
- if(!clientSocketParam){
8680
-
8681
- // TODO : FIXME : Use one single interface !
8682
- let serverClients;
8683
- if(!WebsocketImplementation.useSocketIOImplementation) serverClients=nodeServerInstance.serverSocket.clients;
8684
- else serverClients=nodeServerInstance.serverSocket.sockets.clients();
8685
-
8686
- serverClients.forEach((clientSocket)=>{
8687
-
8688
-
8689
- // TODO : FIXME : Use one single interface !
8690
- if(!WebsocketImplementation.useSocketIOImplementation) if(clientSocket.readyState!==WebSocket.OPEN) return;
8691
- else if(clientSocket.connected) return;
8692
-
8693
-
8694
-
8695
- // Room information is stored in client socket object :
8696
- if(!WebsocketImplementation.isInRoom(clientSocket,clientsRoomsTag)) return;
8697
-
8698
- // Channel information is stored in exchanged data :
8699
- let dataWrapped={channelName:channelName, data:data};
8700
-
8701
-
8702
- dataWrapped=JSON.stringify(dataWrapped);
8703
-
8704
- // TODO : FIXME : Use one single interface !
8705
- if(!WebsocketImplementation.useSocketIOImplementation) clientSocket.send(dataWrapped);
8706
- else clientSocket.emit(channelName,dataWrapped);
8707
-
8708
- });
8709
-
8710
- }else{
8711
-
8712
- // TODO : FIXME : Use one single interface !
8713
- let clientSocket=clientSocketParam;
8714
- if(!WebsocketImplementation.useSocketIOImplementation) if(clientSocket.readyState!==WebSocket.OPEN) return;
8715
- else if(clientSocket.connected) return;
8716
-
8717
-
8718
- // Room information is stored in client socket object :
8719
- if(!WebsocketImplementation.isInRoom(clientSocket,clientsRoomsTag)) return;
8720
-
8721
- // Channel information is stored in exchanged data :
8722
- let dataWrapped={channelName:channelName, data:data};
8723
-
8724
- dataWrapped=JSON.stringify(dataWrapped);
8725
-
8726
- // TODO : FIXME : Use one single interface !
8727
- if(!WebsocketImplementation.useSocketIOImplementation) clientSocket.send(dataWrapped);
8728
- else clientSocket.emit(channelName,dataWrapped);
8729
-
8730
-
8731
- }
8732
-
8733
-
8734
- return nodeServerInstance;
8735
- },
8736
-
8737
-
8738
- onConnectionToClient:(doOnConnection)=>{
8739
- // «connection» is the only event fired by the serverSocket :
8740
- nodeServerInstance.serverSocket.on("connection", (clientSocket)=>{
8741
-
8742
- // DBG
8743
- console.log("SERVER : ON CONNECTION !");
8744
-
8745
-
8746
- // if(contains(nodeServerInstance.clientsSockets, clientSocket)) return;
8747
- // nodeServerInstance.clientsSockets.push(clientSocket);
8748
-
8749
-
8750
- // DBG
8751
- console.log("nodeServerInstance.receptionEntryPoints.length:",nodeServerInstance.receptionEntryPoints.length);
8752
-
8753
-
8754
-
8755
- // We execute the events registration listeners entry points:
8756
- foreach(nodeServerInstance.receptionEntryPoints,(receptionEntryPoint)=>{
8757
-
8758
- // DBG
8759
- console.log("ENTRY POINT !");
8760
-
8761
- receptionEntryPoint.execute(clientSocket);
8762
- });
8763
-
8764
-
8765
- doOnConnection(nodeServerInstance, clientSocket);
8766
-
8767
-
8768
-
8769
-
8770
- // To make the server aware of the clients connections states :
8771
- clientSocket.stateCheckInterval=setInterval(()=>{
8772
-
8773
-
8774
- if (clientSocket.isAlive===false){
8775
- clearInterval(clientSocket.stateCheckInterval);
8776
-
8777
- // TODO : FIXME : DUPLICATED CODE :
8778
- // TODO : FIXME : Use one single interface !
8779
- if(!WebsocketImplementation.useSocketIOImplementation) clientSocket.terminate();
8780
- else clientSocket.emit("endConnection");
8781
-
8782
- // TODO : FIXME : DUPLICATED CODE :
8783
- if(!empty(nodeServerInstance.onClientLostListeners))
8784
- foreach(nodeServerInstance.onClientLostListeners,l=>{l.execute(clientSocket);});
8785
-
8786
- return;
8787
- }
8788
-
8789
- clientSocket.isAlive=false;
8790
- try{
8791
- clientSocket.ping();
8792
- }catch(error){
8793
- lognow("ERROR : A problem occurred when tried to ping client socket : ",error);
8794
- // We effectively end the client connection to this server :
8795
-
8796
- // TODO : FIXME : DUPLICATED CODE :
8797
- // TODO : FIXME : Use one single interface !
8798
- if(!WebsocketImplementation.useSocketIOImplementation) clientSocket.terminate();
8799
- else clientSocket.emit("endConnection");
8800
-
8801
- // TODO : FIXME : DUPLICATED CODE :
8802
- if(!empty(nodeServerInstance.onClientLostListeners))
8803
- foreach(nodeServerInstance.onClientLostListeners,l=>{l.execute(clientSocket);});
8804
-
8805
- return;
8806
- }
8807
-
8808
-
8809
- }, nodeServerInstance.clientTimeoutMillis);
8810
- clientSocket.on("pong",()=>{
8811
- clientSocket.isAlive=true;
8812
- });
8813
-
8814
-
8815
-
8816
- });
8817
-
8818
-
8819
- return nodeServerInstance;
8820
- },
8821
-
8822
- onFinalize:(doOnFinalizeServer)=>{
8823
-
8824
- doOnFinalizeServer(nodeServerInstance);
8825
-
8826
- // TRACE
8827
- console.log("INFO : SERVER : Node server setup complete.");
8828
-
8829
- return nodeServerInstance;
8830
- },
8831
-
8832
- addToRoom:(clientSocket,clientRoomTag)=>{
8833
- clientSocket.clientRoomTag=clientRoomTag;
8834
- },
8835
-
8836
-
8837
-
8838
- };
8839
-
8840
- // Join room server part protocol :
8841
- nodeServerInstance.receive("protocol",(message, clientSocket)=>{
8842
-
8843
- if(message.type!=="joinRoom" || !clientSocket) return;
8844
-
8845
- nodeServerInstance.addToRoom(clientSocket, message.clientRoomTag);
8846
-
8847
- });
8848
-
8849
-
8850
-
8851
- // To make the server aware of the clients connections states :
8852
- nodeServerInstance.serverSocket.on("close", function close() {
8853
-
8854
- // TODO : FIXME : Use one single interface !
8855
- if(!WebsocketImplementation.useSocketIOImplementation) serverClients=nodeServerInstance.serverSocket.clients;
8856
- else serverClients=nodeServerInstance.serverSocket.sockets.clients();
8857
-
8858
- serverClients.forEach((clientSocket)=>{
8859
- clearInterval(clientSocket.stateCheckInterval);
8860
- });
8861
- });
8862
-
8863
-
8864
-
8865
- return nodeServerInstance;
8866
- },
8867
-
8868
-
8869
- // NODE / BROWSER CLIENT CONNECTS TO SERVER MAIN ENTRYPOINT:
8870
- connectToServer:(serverURL, port, isSecure=false, timeout)=>{
8871
-
8872
- // TRACE
8873
- lognow("INFO : Using websocket implementation : "+(WebsocketImplementation.isNodeContext?"node (server-side)":"browser (client-side)"));
8874
-
8875
- if(WebsocketImplementation.isNodeContext)
8876
- return WebsocketImplementation.connectToServerFromNode(serverURL, port, isSecure, timeout);
8877
- else
8878
- return WebsocketImplementation.connectToServerFromBrowser(serverURL, port, isSecure, timeout);
8879
- },
8880
-
8881
-
8882
-
8883
- //
8884
- // NODE CLIENT
8885
- //
8886
- /*private*/connectToServerFromNode:(serverURL, port, isSecure, timeout)=>{
8887
-
8888
-
8889
-
8890
- // NEW : ws :
8891
- if(typeof(WebSocket)==="undefined"){
8892
- // TRACE
8893
- lognow("ERROR : CLIENT : Could not find websocket client lib, aborting client connection.");
8894
- return null;
8895
- }
8896
-
8897
- // NODE CLIENT MODE ONLY :
8898
- let clientSocket;
8899
- if(!WebsocketImplementation.useSocketIOImplementation){
8900
- clientSocket=new WebSocket(serverURL+":"+port,/*WORKAROUND:*/{ rejectUnauthorized:false, secure: isSecure });
8901
- }else{
8902
- // NOW : socket.io :
8903
- //client on server-side:
8904
- if(WebsocketImplementation.isNodeContext && typeof(socketIO)!=="undefined"){
8905
- // // Node client :
8906
- // connectToServer=function (serverURL, port, isSecure, timeout=10000){
8907
- // return socketIO.connect(serverURL + ":" + port,{timeout: timeout});
8908
- // }
8909
- clientSocket=socketIO.connect(serverURL + ":" + port,{timeout: timeout, secure: isSecure});
8910
- }
8911
- }
8912
-
8913
- // NODE CLIENT INSTANCE :
8914
- const nodeClientInstance={
8915
- clientSocket:clientSocket,
8916
-
8917
- receptionEntryPoints:[],
8918
-
8919
- receive:(channelName, doOnIncomingMessage, clientsRoomsTag=null)=>{
8920
-
8921
- const receptionEntryPoint={
8922
- channelName:channelName,
8923
- clientsRoomsTag:clientsRoomsTag,
8924
- execute:(clientSocketParam)=>{
8925
-
8926
- const doOnMessage=(message)=>{
8927
-
8928
- // dataWrapped=JSON.parse(dataWrapped);
8929
- // dataWrapped=getAt(dataWrapped,0);// We get the root element
8930
-
8931
- const dataWrapped=(WebsocketImplementation.useFlatStrings?JSON.parse(message):message);
8932
-
8933
-
8934
- // Channel information is stored in exchanged data :
8935
- if(dataWrapped.channelName && dataWrapped.channelName!==channelName) return;
8936
-
8937
- let clientSocket=nodeClientInstance.clientSocket;
8938
-
8939
- // Room information is stored in client socket object :
8940
- if(!WebsocketImplementation.isInRoom(clientSocket,clientsRoomsTag)) return;
8941
-
8942
- doOnIncomingMessage(dataWrapped.data, clientSocket);
8943
-
8944
- };
8945
-
8946
- if(!WebsocketImplementation.useSocketIOImplementation) nodeClientInstance.clientSocket.addEventListener("message", doOnMessage);
8947
- else nodeClientInstance.clientSocket.on(channelName, doOnMessage);
8948
-
8949
-
8950
- }
8951
- };
8952
-
8953
-
8954
- nodeClientInstance.receptionEntryPoints.push(receptionEntryPoint);
8955
-
8956
- return nodeClientInstance;
8957
- },
8958
-
8959
-
8960
- send:(channelName, data, clientsRoomsTag=null)=>{
8961
-
8962
- let clientSocket=nodeClientInstance.clientSocket;
8963
-
8964
-
8965
- // // DBG
8966
- // console.log("(NODE CLIENT) TRYING TO SEND : clientSocket.readyState:",clientSocket.readyState);
8967
-
8968
- // TODO : FIXME : Use one single interface !
8969
- if(!WebsocketImplementation.useSocketIOImplementation) if(clientSocket.readyState!==WebSocket.OPEN) return;
8970
- else if(clientSocket.connected) return;
8971
-
8972
-
8973
- // Room information is stored in client socket object :
8974
- if(!WebsocketImplementation.isInRoom(clientSocket,clientsRoomsTag)) return;
8975
-
8976
- // Channel information is stored in exchanged data :
8977
- let dataWrapped={channelName:channelName, data:data};
8978
-
8979
-
8980
- // // DBG
8981
- // console.log("(NODE CLIENT) SENDING DATA ! dataWrapped:",dataWrapped);
8982
-
8983
-
8984
- dataWrapped=JSON.stringify(dataWrapped);
8985
-
8986
-
8987
- // // DBG
8988
- // console.log("(NODE CLIENT) SENDING DATA ! channelName:«"+channelName+"» ; clientsRoomsTag:«"+clientsRoomsTag+"»");
8989
- // console.log("(NODE CLIENT) SENDING DATA ! dataWrapped:",dataWrapped);
8990
-
8991
- // TODO : FIXME : Use one single interface !
8992
- if(!WebsocketImplementation.useSocketIOImplementation) clientSocket.send(dataWrapped);
8993
- else clientSocket.emit(channelName,dataWrapped);
8994
-
8995
- return nodeClientInstance;
8996
- },
8997
-
8998
-
8999
- join:(clientRoomTag)=>{
9000
- // Join room client part protocol :
9001
- const message={type:"joinRoom",clientRoomTag:clientRoomTag};
9002
-
9003
- nodeClientInstance.send("protocol",message);
9004
-
9005
- },
9006
-
9007
-
9008
- onConnectionToServer:(doOnConnection)=>{
9009
-
9010
- const doAllOnConnection=()=>{
9011
-
9012
- // To avoid triggering this event several times, depending on the implementation :
9013
- if(nodeClientInstance.hasConnectEventFired) return;
9014
- nodeClientInstance.hasConnectEventFired=true;
9015
-
9016
- let clientSocket=nodeClientInstance.clientSocket;
9017
-
9018
- doOnConnection(nodeClientInstance, clientSocket);
9019
-
9020
- // We execute the listeners entry points:
9021
- foreach(nodeClientInstance.receptionEntryPoints,(receptionEntryPoint)=>{
9022
- receptionEntryPoint.execute(clientSocket);
9023
- });
9024
-
9025
- };
9026
-
9027
- if(!WebsocketImplementation.useSocketIOImplementation) nodeClientInstance.clientSocket.addEventListener("open",doAllOnConnection);
9028
- else nodeClientInstance.clientSocket.on("connect",doAllOnConnection);
9029
-
9030
- },
9031
-
9032
-
9033
- };
9034
-
9035
-
9036
- return nodeClientInstance;
9037
- },
9038
-
9039
-
9040
-
9041
- // BROWSER CLIENT
9042
-
9043
- /*private*/connectToServerFromBrowser:(serverURL, port, isSecure, timeout)=>{
9044
-
9045
- // NEW : ws :
9046
- if(typeof(WebSocket)==="undefined"){
9047
- // TRACE
9048
- lognow("ERROR : CLIENT : Could not find websocket client lib, aborting client connection.");
9049
- return null;
9050
- }
9051
-
9052
- // TODO : FIXME : Use one single interface !
9053
- // BROWSER CLIENT MODE ONLY :
9054
- let clientSocket;
9055
- if(!WebsocketImplementation.useSocketIOImplementation){
9056
- clientSocket=new WebSocket(serverURL+":"+port,["ws","wss"]);
9057
- }else if(typeof(io)!=="undefined"){
9058
- // NOW : socket.io :
9059
- // // Browser client :
9060
- // connectToServer=function (server, port, isSecure, timeout=10000){
9061
- // return io.connect(serverURL + ":" + port,{timeout: timeout});
9062
- //// ALTERNATIVE : return io(serverURL + ":" + port,{timeout: timeout});
9063
- // };
9064
- // }else{
9065
- // // TRACE
9066
- // console.log("ERROR : Could not initialize socket !");
9067
- clientSocket=io.connect(serverURL + ":" + port,{timeout: timeout, secure: isSecure});
9068
- }
9069
-
9070
-
9071
- // BROWSER CLIENT INSTANCE :
9072
- const browserInstance={
9073
- clientSocket:clientSocket,
9074
-
9075
- receive:(channelName, doOnIncomingMessage, clientsRoomsTag=null)=>{
9076
-
9077
- // DBG
9078
- lognow("!!! SETTING UP RECEIVE for :",channelName);
9079
-
9080
- const doOnMessage=(message)=>{
9081
-
9082
- // // DBG
9083
- // lognow("!!! RECEIVED : message",message);
9084
-
9085
- // OLD : let dataWrapped=JSON.parse(event.data);
9086
- // const dataWrapped=JSON.parse(message);
9087
- // dataWrapped=getAt(dataWrapped,0);// We get the root element
9088
-
9089
- const dataWrapped=(WebsocketImplementation.useFlatStrings?JSON.parse(message):message);
9090
-
9091
-
9092
- // Channel information is stored in exchanged data :
9093
- if(dataWrapped.channelName && dataWrapped.channelName!==channelName) return;
9094
-
9095
- let clientSocket=browserInstance.clientSocket;
9096
-
9097
- // Room information is stored in client socket object :
9098
- if(!WebsocketImplementation.isInRoom(clientSocket,clientsRoomsTag)) return;
9099
-
9100
- doOnIncomingMessage(dataWrapped.data, clientSocket);
9101
-
9102
- };
9103
-
9104
-
9105
- if(!WebsocketImplementation.useSocketIOImplementation) browserInstance.clientSocket.addEventListener("message", doOnMessage);
9106
- else browserInstance.clientSocket.on(channelName, doOnMessage);
9107
-
9108
-
9109
- return browserInstance;
9110
- },
9111
-
9112
-
9113
- send:(channelName, data, clientsRoomsTag=null)=>{
9114
-
9115
- let clientSocket=browserInstance.clientSocket;
9116
-
9117
-
9118
- // // DBG
9119
- // console.log("(BROWSER) TRYING TO SEND : clientSocket.readyState:",clientSocket.readyState);
9120
-
9121
- // TODO : FIXME : Use one single interface !
9122
- if(!WebsocketImplementation.useSocketIOImplementation) if(clientSocket.readyState!==WebSocket.OPEN) return;
9123
- else if(clientSocket.connected) return;
9124
-
9125
-
9126
- // Room information is stored in client socket object :
9127
- if(!WebsocketImplementation.isInRoom(clientSocket,clientsRoomsTag)) return;
9128
-
9129
- // Channel information is stored in exchanged data :
9130
- let dataWrapped={channelName:channelName, data:data};
9131
-
9132
-
9133
- // // DBG
9134
- // console.log("(BROWSER) SENDING... : dataWrapped :",dataWrapped);
9135
-
9136
-
9137
- dataWrapped=JSON.stringify(dataWrapped);
9138
-
9139
-
9140
- // TODO : FIXME : Use one single interface !
9141
- if(!WebsocketImplementation.useSocketIOImplementation) clientSocket.send(dataWrapped);
9142
- else clientSocket.emit(channelName,dataWrapped);
9143
-
9144
-
9145
- return browserInstance;
9146
- },
9147
-
9148
-
9149
- join:(clientRoomTag)=>{
9150
- // Join room client part protocol :
9151
- const message={type:"joinRoom",clientRoomTag:clientRoomTag};
9152
- browserInstance.send("protocol",message);
9153
- },
9154
-
9155
-
9156
- onConnectionToServer:(doOnConnection)=>{
9157
-
9158
- // To avoid triggering this event several times, depending on the implementation :
9159
- if(browserInstance.hasConnectEventFired) return;
9160
- browserInstance.hasConnectEventFired=true;
9161
-
9162
- if(!WebsocketImplementation.useSocketIOImplementation) browserInstance.clientSocket.addEventListener("open",doOnConnection);
9163
- else browserInstance.clientSocket.on("connect",doOnConnection);
9164
-
9165
-
9166
- },
9167
-
9168
-
9169
- };
9170
-
9171
-
9172
- return browserInstance;
9173
- },
9174
-
9175
- };
9176
-
9177
-
9178
-
9179
- launchNodeHTTPServer=function(port, doOnConnect=null, doOnFinalizeServer=null, /*OPTIONAL*/sslOptions=null){
9180
-
9181
- const EXCLUDED_FILENAMES_PARTS=[".saltkey."];
9182
-
9183
-
9184
- if(typeof(https)==="undefined"){
9185
- // TRACE
9186
- console.log("«https» SERVER library not called yet, calling it now.");
9187
- https=require("https");
9188
- }
9189
- if(typeof(http)==="undefined"){
9190
- // TRACE
9191
- console.log("«http» SERVER library not called yet, calling it now.");
9192
- http=require("http");
9193
- }
9194
-
9195
-
9196
- const handler=function(request, response){
9197
-
9198
- const url=request.url;
9199
-
9200
- let isURLInExclusionZone=!!foreach(EXCLUDED_FILENAMES_PARTS,(excludedStr)=>{
9201
- if(contains(url,excludedStr)){
9202
- return true;
9203
- }
9204
- });
9205
-
9206
- if(isURLInExclusionZone){
9207
- // TRACE
9208
- console.log("ERROR 403 forbidden access error :");
9209
- console.log(error);
9210
-
9211
- response.writeHead(403);
9212
- response.end("Sorry, cannot access resource : error: "+error.code+" ..\n");
9213
- response.end();
9214
- return;
9215
- }
9216
-
9217
-
9218
- const urlFile="." + url;
9219
-
9220
- let filePath=urlFile.indexOf("?")!==-1?urlFile.split("?")[0]:urlFile;
9221
- if(filePath == "./") filePath="./index.html";
9222
-
9223
- let extname=path.extname(filePath);
9224
- let contentType="text/html";
9225
-
9226
-
9227
- fs.readFile(filePath, function(error, fileContent){
9228
- if(error){
9229
- if(error.code == "ENOENT"){
9230
- // TRACE
9231
- console.log("ERROR 404 file not found :"+filePath);
9232
-
9233
- fs.readFile("./404.html", function(error, fileContent){
9234
- response.writeHead(200, { "Content-Type": contentType });
9235
- response.end(fileContent, "utf-8");
9236
- });
9237
-
9238
- }else {
9239
-
9240
- // TRACE
9241
- console.log("ERROR 500 server error :");
9242
- console.log(error);
9243
-
9244
- response.writeHead(500);
9245
- response.end("Sorry, check with the site admin for error: "+error.code+" ..\n");
9246
- response.end();
9247
-
9248
- }
9249
- }else {
9250
-
9251
- // TRACE
9252
- console.log("INFO 200 OK :"+filePath);
9253
-
9254
- response.writeHead(200, { "Content-Type": contentType });
9255
- response.end(fileContent, "utf-8");
9256
-
9257
- // res.writeHead(200);
9258
- // res.end("hello world\n");
9259
- // res.sendFile(__dirname + "/public/index.html");
9260
-
9261
- }
9262
- });
9263
-
9264
- };
9265
-
9266
-
9267
- let listenableServer;
9268
- if(sslOptions){
9269
- let httpsServer=https.createServer(sslOptions, handler).listen(port);
9270
- // TRACE
9271
- console.log("INFO : SERVER : HTTPS Server launched and listening on port " + port + "!");
9272
- listenableServer=httpsServer;
9273
- }else{
9274
- let httpServer=http.createServer(handler).listen(port);
9275
- // TRACE
9276
- console.log("INFO : SERVER : HTTP Server launched and listening on port " + port + "!");
9277
- listenableServer=httpServer;
9278
- }
9279
-
9280
-
9281
- const server=WebsocketImplementation.getStatic(true).getServer(listenableServer);
9282
-
9283
- // When a client connects, we execute the callback :
9284
- // CAUTION : MUST BE CALLED ONLY ONCE !
9285
- server.onConnectionToClient((serverParam, clientSocketParam)=>{
9286
- if(doOnConnect) doOnConnect(serverParam, clientSocketParam);
9287
- });
9288
-
9289
-
9290
- server.onFinalize((serverParam)=>{
9291
- if(doOnFinalizeServer) doOnFinalizeServer(serverParam);
9292
- });
9293
-
9294
-
9295
- // TRACE
9296
- console.log("INFO : SERVER : Generic Nodejs server launched and listening on port:" + port + "!");
9297
-
9298
-
9299
- return server;
9300
- }
9301
-
9302
-
9303
- initNodeServer=function(doOnClientConnection=null, doOnFinalizeServer=null, /*OPTIONAL*/portParam, /*OPTIONAL*/certPathParam, /*OPTIONAL*/keyPathParam){
9304
-
9305
- // TRACE
9306
- console.log("Server launched.");
9307
- console.log("Usage : node <server.js> conf {port:[port], sslCertPath:[ssl certificate path | unsecure ], sslKeyPath:[ssl key path], serverConfig:[JSON server configuration]}");
9308
- console.log("Or (to generate password hash) : node <server.js> hash <clientId@repositoryName> <clearText>");
9309
- // EXAMPLE : node orita-srv.js hash orita.global@saltkey 1234567890
9310
- console.log("Server launched.");
9311
-
9312
- // We read the command-line arguments if needed :
9313
-
9314
- let argCLPort;
9315
- let argCLCertPath;
9316
- let argCLKeyPath;
9317
- let serverConfig={};
9318
- let isForceUnsecure;
9319
-
9320
- let isHashAsked=false;
9321
- let clearTextParam=null;
9322
- let persisterId=null;
9323
-
9324
-
9325
- process.argv.forEach(function (val, i){
9326
- if(!val) return;
9327
- // 0 corresponds to «node / nodejs»
9328
- if(i<=1) return; // 1 corresponds to « <server.js> »
9329
- else if(i==2){
9330
- if(val==="hash") isHashAsked=true;
9331
- }else if(i==3){
9332
- if(!isHashAsked){
9333
- try{
9334
- const jsonConf=JSON.parse(val);
9335
- argCLPort=jsonConf.port;
9336
- argCLCertPath=jsonConf.sslCertPath;
9337
- argCLKeyPath=jsonConf.sslKeyPath;
9338
- try{
9339
- serverConfig=nonull({},JSON.parse(jsonConf.serverConfig));
9340
- }catch(err1){
9341
- lognow("ERROR : Cannot parse JSON string «"+jsonConf.serverConfig+"».",err1);
9342
- }
9343
- }catch(err2){
9344
- lognow("ERROR : Cannot parse JSON string «"+val+"».",err2);
9345
- isHashAsked=true;
9346
- }
9347
- } else persisterId=val;
9348
- }else if(i==4){
9349
- if(isHashAsked) clearTextParam=val;
9350
- }
9351
- });
9352
- isForceUnsecure=(argCLCertPath==="unsecure");
9353
-
9354
-
9355
-
9356
- const aotraNodeServer={config:serverConfig};
9357
- aotraNodeServer.serverManager={ start:()=>{/*DEFAULT START FUNCTION, WILL BE OVERRIDEN LATER*/}};
9358
-
9359
- if(isHashAsked){
9360
- // We isntanciate a temporary persister just to read the saltkey file:
9361
- const persister=getPersister("./");
9362
- let persisterIdSplits=persisterId.split("@");
9363
- if(empty(persisterIdSplits) || persisterIdSplits.length!=2){
9364
- // TRACE
9365
- console.log("ERROR : No persister repository IDs provided correctly. Cannot read saltkey. Aborting hash generation.");
9366
- return aotraNodeServer;
9367
- }
9368
- const persisterClientId=persisterIdSplits[0];
9369
- const persisterRepositoryName=persisterIdSplits[1];
9370
- let globalSaltkeyObject=persister.readTreeObjectFromFile(persisterClientId, persisterRepositoryName);
9371
- if(!globalSaltkeyObject || !globalSaltkeyObject.saltkey){
9372
- // TRACE
9373
- console.log("WARN : No saltkey found. Generating one now.");
9374
- globalSaltkeyObject={saltkey:getUUID(), hashes:[]};
9375
- persister.saveDataToFileForClient(persisterClientId,persisterRepositoryName,globalSaltkeyObject,false,()=>{
9376
- // TRACE
9377
- console.log("INFO : Saltkey generated and saved successfully.");
9378
- });
9379
- }
9380
- const globalSaltkey=globalSaltkeyObject.saltkey;
9381
-
9382
- let firstHash=getHashedString(clearTextParam);
9383
-
9384
- let generatedHash=getHashedString( firstHash + globalSaltkey, true);// (we use the heavy treatment thing.)
9385
- globalSaltkeyObject.hashes.push(generatedHash);
9386
-
9387
- // We update the repository :
9388
- persister.saveDataToFileForClient(persisterClientId,persisterRepositoryName,globalSaltkeyObject,false,()=>{
9389
- // TRACE
9390
- console.log("INFO : Hash added to repository and saved successfully.");
9391
- });
9392
-
9393
- // OUTPUT
9394
- console.log("Here is your key : share it with your clients but DO NOT LEAK IT !\n********************\n"+clearTextParam+"\n********************\n");
9395
-
9396
- return aotraNodeServer;
9397
- }
9398
-
9399
-
9400
- const DEFAULT_PORT=nonull(argCLPort,25000);
9401
- const DEFAULT_CERT_PATH=nonull(argCLCertPath,"cert.pem");
9402
- const DEFAULT_KEY_PATH=nonull(argCLKeyPath,"key.key");
9403
-
9404
-
9405
- let port=portParam ? portParam : DEFAULT_PORT;
9406
- let certPath=null;
9407
- let keyPath=null;
9408
-
9409
- if(!isForceUnsecure){
9410
- certPath=certPathParam?certPathParam:DEFAULT_CERT_PATH;
9411
- keyPath=keyPathParam?keyPathParam:DEFAULT_KEY_PATH;
9412
- }
9413
-
9414
-
9415
- // UNUSEFUL :
9416
- //aotraNodeServer.serverManager.microClientsSockets=[];
9417
- // UNUSEFUL :
9418
- //aotraNodeServer.serverManager.mainClientsSockets=[];
9419
- aotraNodeServer.serverManager.start=function(){
9420
-
9421
- // Eventual encryption options :
9422
- let sslOptions=null;
9423
- if(!isForceUnsecure){
9424
- if(!fs){
9425
- // TRACE
9426
- lognow("ERROR : «fs» node subsystem not present, cannot access files. Aborting SSL configuration of server.");
9427
- }else{
9428
- try{
9429
- sslOptions={
9430
- cert: fs.readFileSync(certPath),
9431
- key: fs.readFileSync(keyPath),
9432
- };
9433
- }catch(exception){
9434
- // TRACE
9435
- lognow("ERROR : Could not open SSL files certPath:«"+certPath+"» or keyPath:«"+keyPath+"». Aborting SSL configuration of server.");
9436
- }
9437
- }
9438
- }
9439
-
9440
- aotraNodeServer.server=launchNodeHTTPServer(port, doOnClientConnection, doOnFinalizeServer, sslOptions);
9441
-
9442
-
9443
- return aotraNodeServer;
9444
- };
9445
-
9446
- return aotraNodeServer;
9447
- }
9448
-
9449
- // ========================= FUSRODA SERVER : =========================
9450
-
9451
- //
9452
- // DOES NOT WORK : USE Java FusrodaServer instead :
9453
- //
9454
- ///*FUSRODA server stands from FSRD SERVER, for Fucking Simple Remote Desktop SERVER*/
9455
- //createFusrodaServer=function(certPathParam=null,keyPathParam=null,portParam=6080){
9456
- //
9457
- // // https://www.npmjs.com/package/screenshot-desktop
9458
- // // https://github.com/octalmage/robotjs
9459
- // // npm install --save screenshot-desktop
9460
- // //
9461
- // // sudo apt-get install libxtst-dev libx11-dev
9462
- // // npm install --save robotjs
9463
- //
9464
- // // http://getrobot.net/docs/usage.html
9465
- // //
9466
- // // apt-get install build-essential python libxt-dev libxtst-dev libxinerama-dev -y
9467
- //
9468
- // const screenshot=require("screenshot-desktop");
9469
- //
9470
- // const REFRESH_SCREENSHOTS_MILLIS=500;
9471
- //
9472
- //
9473
- // const server=initNodeServer(
9474
- // // On client connection :
9475
- //// (serverParam, clientSocketParam)=>{},
9476
- // null,
9477
- // // On server finalization :
9478
- // (serverParam)=>{
9479
- //
9480
- // serverParam.receive("protocol_fusroda", (message, clientSocket)=> {
9481
- // serverParam.addToRoom(clientSocket,"clients");
9482
- // });
9483
- //
9484
- //
9485
- // serverParam.sendScreenshotsRoutine=setInterval(()=>{
9486
- // if(serverParam.isScreenshotStarted) return;
9487
- //
9488
- // serverParam.isScreenshotStarted=true;
9489
- //
9490
- // screenshot().then((img) => {
9491
- //
9492
- // const data={image:img,messageType:"imageData"};
9493
- // serverParam.send("message", data, "clients");
9494
- //
9495
- // serverParam.isScreenshotStarted=false;
9496
- //
9497
- // }).catch((error) => {
9498
- // // TRACE
9499
- // lognow("ERROR : Error during screenshot :",error);
9500
- // });
9501
- //
9502
- // },REFRESH_SCREENSHOTS_MILLIS);
9503
- //
9504
- //
9505
- // },portParam,certPathParam,keyPathParam);
9506
- //
9507
- //
9508
- //// const doOnConnect=(serverParam, clientSocketParam)=>{
9509
- //// };
9510
- //// const doOnFinalizeServer=(serverParam)=>{
9511
- //// /*DO NOTHING*/
9512
- //// };
9513
- //// const server={};
9514
- //// server.start=(port=6080)=>{
9515
- //// server.httpServer=launchNodeHTTPServer(port, doOnConnect, doOnFinalizeServer, sslOptions);
9516
- //// };
9517
- //
9518
- // return server;
9519
- //}
9520
-
9521
-
9522
- // ========================= UTILITY SERVERSIDE METHODS : =========================
9523
-
9524
- class ListManager{
9525
- constructor(config){
9526
- this.config=config;
9527
- this.maxItemsNumber=nonull(this.config.max,999);
9528
- this.simultaneousItemsNumber=nonull(this.config.simultaneous,1);
9529
- this.sessionDurationSeconds=nonull(this.config.duration,null);
9530
- this.mode=nonull(this.config.mode,"startAtConnexion");
9531
-
9532
- this.itemsInfos={};
9533
- this.time=null;
9534
- this.started=false;
9535
- }
9536
-
9537
- addItem(id,item){
9538
- if(id==null){
9539
- // TRACE
9540
- lognow("ERROR : Cannot add item with no id.");
9541
- return;
9542
- }
9543
- if(!item){
9544
- // TRACE
9545
- lognow("ERROR : Cannot add null item.");
9546
- return;
9547
- }
9548
- const numberOfItemsCurrently=countKeys(this.itemsInfos);
9549
- if(this.maxItemsNumber<=numberOfItemsCurrently){
9550
- // TRACE
9551
- lognow("ERROR : Cannot add item with id «"+id+"», list already full.");
9552
- return;
9553
- }
9554
- if(numberOfItemsCurrently==0 && this.mode==="startAtConnexion"){
9555
- this.startSession();
9556
- }
9557
- this.itemsInfos[id]={
9558
- item:item,
9559
- time:getNow(),
9560
- };
9561
- }
9562
-
9563
- startSession(){
9564
- this.time==getNow();
9565
- this.started=true;
9566
- }
9567
-
9568
- stopSession(){
9569
- this.started=false;
9570
- }
9571
-
9572
- isSessionActive(){
9573
- if(!this.sessionDurationSeconds) return true;
9574
- if(!this.started) return false;
9575
- return !hasDelayPassed(this.time, this.sessionDurationSeconds*1000);
9576
- }
9577
-
9578
- isClientActive(clientId){
9579
- if(!clientsListManager.isSessionActive()) return false;
9580
- const clientPosition=this.getItemPosition(clientId);
9581
- const result=(clientPosition<=this.maxItemsNumber);
9582
- return result;
9583
- }
9584
-
9585
- removeItem(id){
9586
- if(id==null){
9587
- // TRACE
9588
- lognow("ERROR : Cannot remove item, no id specified.");
9589
- return;
9590
- }
9591
- if(!this.itemsInfos[id]){
9592
- // TRACE
9593
- lognow("ERROR : Cannot remove item, item not found for id «"+id+"».");
9594
- return;
9595
- }
9596
- delete this.itemsInfos[id];
9597
- }
9598
-
9599
- // Goes from 1 to <length>:
9600
- getItemPosition(id){
9601
- if(id==null){
9602
- // TRACE
9603
- lognow("ERROR : Cannot calculate item position, no id specified.");
9604
- return;
9605
- }
9606
- if(!this.itemsInfos[id]){
9607
- // TRACE
9608
- lognow("ERROR : Cannot calculate item position, item not found for id «"+id+"».");
9609
- return;
9610
- }
9611
- let result=0;
9612
- foreach(this.itemsInfos,(itemInfo,key)=>{
9613
- result++;
9614
- if(id==key) return "break";
9615
- },null,(itemInfo1,itemInfo2)=>item1.time<item2.time);
9616
- return result;
9617
- }
9618
-
9619
-
9620
- }
9621
-
9622
- function getListManager(config){
9623
- return new ListManager(config);
9624
- }
9625
-
9626
-
9627
-
9628
-
9629
-
9630
-
9631
-
9632
-
9633
- /*utils COMMONS library associated with aotra version : «1.0.0.000 (11/07/2022-00:48:13)»*/
8330
+ /*utils COMMONS library associated with aotra version : «1.0.0.000 (11/07/2022-21:05:49)»*/
9634
8331
  /*-----------------------------------------------------------------------------*/
9635
8332
 
9636
8333
 
@@ -9642,7 +8339,7 @@ function getListManager(config){
9642
8339
  *
9643
8340
  * # Library name : «aotrautils»
9644
8341
  * # Library license : HGPL(Help Burma) (see aotra README information for details : https://alqemia.com/aotra.js )
9645
- * # Author name : Jérémie Ratomposon (massively helped by its programming egos legions)
8342
+ * # Author name : Jérémie Ratomposon (massively helped by his native country free education system)
9646
8343
  * # Author email : info@alqemia.com
9647
8344
  * # Organization name : Alqemia
9648
8345
  * # Organization email : admin@alqemia.com
aotrautils/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "aotrautils",
3
- "version": "0.0.45",
3
+ "version": "0.0.48",
4
4
  "main": "aotrautils.build.js",
5
- "description": "A library for vanilla javascript utils used in aotra javascript CMS",
5
+ "description": "A library for vanilla javascript utils (client-side) used in aotra javascript CMS",
6
6
  "author": "Jeremie Ratomposon <info@alqemia.com> (https://alqemia.com)",
7
7
  "license": "HGPL-1.0",
8
8
  "homepage": "https://alqemia.com",