aotrautils 0.0.1828 → 0.0.1830
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/aotrautils.build.js +1352 -6
- aotrautils/package.json +1 -1
aotrautils/aotrautils.build.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
/*utils COMMONS library associated with aotra version : «1_29072022-2359 (17/03/2026-
|
|
3
|
+
/*utils COMMONS library associated with aotra version : «1_29072022-2359 (17/03/2026-16:49:48)»*/
|
|
4
4
|
/*-----------------------------------------------------------------------------*/
|
|
5
5
|
|
|
6
6
|
|
|
@@ -5076,7 +5076,7 @@ AOTRAUTILS_LIB_IS_LOADED=true;
|
|
|
5076
5076
|
|
|
5077
5077
|
|
|
5078
5078
|
|
|
5079
|
-
/*utils CLIENT library associated with aotra version : «1_29072022-2359 (17/03/2026-
|
|
5079
|
+
/*utils CLIENT library associated with aotra version : «1_29072022-2359 (17/03/2026-16:49:48)»*/
|
|
5080
5080
|
/*-----------------------------------------------------------------------------*/
|
|
5081
5081
|
/* ## Utility global methods in a browser (htmljs) client environment.
|
|
5082
5082
|
*
|
|
@@ -13161,7 +13161,7 @@ createOritaMicroClient=function(url, port, isNode=false, staticMicroClientIdPara
|
|
|
13161
13161
|
|
|
13162
13162
|
|
|
13163
13163
|
|
|
13164
|
-
/*utils GEOMETRY library associated with aotra version : «1_29072022-2359 (17/03/2026-
|
|
13164
|
+
/*utils GEOMETRY library associated with aotra version : «1_29072022-2359 (17/03/2026-16:49:48)»*/
|
|
13165
13165
|
/*-----------------------------------------------------------------------------*/
|
|
13166
13166
|
|
|
13167
13167
|
|
|
@@ -14490,10 +14490,10 @@ function rayVsUnitSphereClosestPoint(p, r) {
|
|
|
14490
14490
|
// MUST REMAIN AT THE END OF THIS LIBRARY FILE !
|
|
14491
14491
|
|
|
14492
14492
|
AOTRAUTILS_GEOMETRY_LIB_IS_LOADED=true;
|
|
14493
|
-
/*utils 3D library associated with aotra version : «1_29072022-2359 (17/03/2026-
|
|
14493
|
+
/*utils 3D library associated with aotra version : «1_29072022-2359 (17/03/2026-16:49:48)»*/
|
|
14494
14494
|
/*-----------------------------------------------------------------------------*/
|
|
14495
14495
|
|
|
14496
|
-
/*utils AI library associated with aotra version : «1_29072022-2359 (17/03/2026-
|
|
14496
|
+
/*utils AI library associated with aotra version : «1_29072022-2359 (17/03/2026-16:49:48)»*/
|
|
14497
14497
|
/*-----------------------------------------------------------------------------*/
|
|
14498
14498
|
|
|
14499
14499
|
|
|
@@ -14639,7 +14639,7 @@ getOpenAIAPIClient=(modelName, apiURL, agentRole, defaultPrompt)=>{
|
|
|
14639
14639
|
|
|
14640
14640
|
|
|
14641
14641
|
|
|
14642
|
-
/*utils CONSOLE library associated with aotra version : «1_29072022-2359 (17/03/2026-
|
|
14642
|
+
/*utils CONSOLE library associated with aotra version : «1_29072022-2359 (17/03/2026-16:49:48)»*/
|
|
14643
14643
|
/*-----------------------------------------------------------------------------*/
|
|
14644
14644
|
|
|
14645
14645
|
|
|
@@ -15645,6 +15645,1352 @@ function capitalize(str){
|
|
|
15645
15645
|
}
|
|
15646
15646
|
|
|
15647
15647
|
|
|
15648
|
+
/* ## Utility global methods in a javascript, console (nodejs) or vanilla javascript with no browser environment.
|
|
15649
|
+
*
|
|
15650
|
+
* This set of methods gathers utility generic-purpose methods usable in any JS project.
|
|
15651
|
+
* Several authors of snippets published freely on the Internet contributed to this library.
|
|
15652
|
+
* Feel free to use/modify-enhance/publish them under the terms of its license.
|
|
15653
|
+
*
|
|
15654
|
+
* # Library name : «aotrautils»
|
|
15655
|
+
* # Library license : HGPL(Help Burma) (see aotra README information for details : https://alqemia.com/aotra.js )
|
|
15656
|
+
* # Author name : Jérémie Ratomposon (massively helped by his native country free education system)
|
|
15657
|
+
* # Author email : info@alqemia.com
|
|
15658
|
+
* # Organization name : Alqemia
|
|
15659
|
+
* # Organization email : admin@alqemia.com
|
|
15660
|
+
* # Organization website : https://alqemia.com
|
|
15661
|
+
*
|
|
15662
|
+
*
|
|
15663
|
+
*/
|
|
15664
|
+
|
|
15665
|
+
|
|
15666
|
+
// COMPATIBILITY browser javascript / nodejs environment :
|
|
15667
|
+
if(typeof(window)==="undefined") window=global;
|
|
15668
|
+
|
|
15669
|
+
|
|
15670
|
+
|
|
15671
|
+
// OLD : socket.io :
|
|
15672
|
+
// https://stackoverflow.com/questions/31156884/how-to-use-https-on-node-js-using-express-socket-io
|
|
15673
|
+
// https://stackoverflow.com/questions/6599470/node-js-socket-io-with-ssl
|
|
15674
|
+
// https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener
|
|
15675
|
+
// https://socket.io/docs/v4/client-socket-instance/
|
|
15676
|
+
|
|
15677
|
+
// NEW : ws :
|
|
15678
|
+
// https://github.com/websockets/ws#installing
|
|
15679
|
+
// https://github.com/websockets/ws/blob/master/doc/ws.md#event-message
|
|
15680
|
+
// ON BROWSER SIDE : Native Websockets :
|
|
15681
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
|
|
15682
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications
|
|
15683
|
+
|
|
15684
|
+
|
|
15685
|
+
|
|
15686
|
+
// =================================================================================
|
|
15687
|
+
// NODEJS UTILS
|
|
15688
|
+
|
|
15689
|
+
const FILE_ENCODING="utf8";
|
|
15690
|
+
|
|
15691
|
+
const ADD_CORS_HEADER=true;
|
|
15692
|
+
|
|
15693
|
+
|
|
15694
|
+
// DEBUG
|
|
15695
|
+
console.log("DEBUG : Importing «fs» dependency.");
|
|
15696
|
+
|
|
15697
|
+
|
|
15698
|
+
if(typeof(require)!=="undefined" && typeof(fs)==="undefined" ){
|
|
15699
|
+
window.fs=require("fs");
|
|
15700
|
+
}
|
|
15701
|
+
|
|
15702
|
+
// For debug (WORKAROUND):
|
|
15703
|
+
fs=window.fs;
|
|
15704
|
+
|
|
15705
|
+
|
|
15706
|
+
// Nodejs filesystem utils :
|
|
15707
|
+
if(typeof(fs)==="undefined"){
|
|
15708
|
+
// TRACE
|
|
15709
|
+
console.log("WARN : Could not find the nodejs dependency «fs», aborting persister setup.");
|
|
15710
|
+
window.getPersister=()=>{ return null; };
|
|
15711
|
+
|
|
15712
|
+
}else{
|
|
15713
|
+
|
|
15714
|
+
|
|
15715
|
+
window.getPersister=function(dataDirPath,prefix=""){
|
|
15716
|
+
|
|
15717
|
+
let self={
|
|
15718
|
+
|
|
15719
|
+
dataDirPath:dataDirPath,
|
|
15720
|
+
prefix:prefix,
|
|
15721
|
+
|
|
15722
|
+
//FILE_NAME_PATTERN:"data.clientId.repositoryName.json",
|
|
15723
|
+
/*private*/getPath:function(clientId="noclient", repositoryName="norepository"){
|
|
15724
|
+
// let path=self.FILE_NAME_PATTERN.replace(new RegExp("@clientId@","g"),clientId);
|
|
15725
|
+
let path=`${self.dataDirPath}`
|
|
15726
|
+
+ (blank(self.prefix)?"":(self.prefix+"."))
|
|
15727
|
+
+`${clientId}.${repositoryName}.json`;
|
|
15728
|
+
return path;
|
|
15729
|
+
},
|
|
15730
|
+
|
|
15731
|
+
readTreeObjectFromFile:function(clientId="noclient", repositoryName="norepository", keepClassName=false){
|
|
15732
|
+
|
|
15733
|
+
let path=self.getPath(clientId,repositoryName);
|
|
15734
|
+
let resultFlat=null;
|
|
15735
|
+
|
|
15736
|
+
try{
|
|
15737
|
+
|
|
15738
|
+
resultFlat=fs.readFileSync(path, FILE_ENCODING);
|
|
15739
|
+
|
|
15740
|
+
}catch(error){
|
|
15741
|
+
// TRACE
|
|
15742
|
+
console.log("ERROR : Could not read file «"+path+"».");
|
|
15743
|
+
|
|
15744
|
+
return null;
|
|
15745
|
+
}
|
|
15746
|
+
|
|
15747
|
+
|
|
15748
|
+
let resultData={};
|
|
15749
|
+
|
|
15750
|
+
// 1)
|
|
15751
|
+
if(!empty(resultFlat)) resultData=parseJSON(resultFlat);
|
|
15752
|
+
|
|
15753
|
+
// 2)
|
|
15754
|
+
if(!empty(resultData) && isFlatMap(resultData)){
|
|
15755
|
+
// CAUTION : We have to keep the type information, here too ! (in the sub-objects)
|
|
15756
|
+
resultData=getAsTreeStructure(resultData, keepClassName);
|
|
15757
|
+
}
|
|
15758
|
+
|
|
15759
|
+
return resultData;
|
|
15760
|
+
},
|
|
15761
|
+
|
|
15762
|
+
|
|
15763
|
+
saveDataToFileForClient:function(clientId,repositoryName,dataFlatForClient,forceKeepUnflatten=false,doOnSuccess=null){
|
|
15764
|
+
|
|
15765
|
+
if(!empty(dataFlatForClient) && !isFlatMap(dataFlatForClient) && !forceKeepUnflatten){
|
|
15766
|
+
dataFlatForClient=getAsFlatStructure(dataFlatForClient);
|
|
15767
|
+
}
|
|
15768
|
+
|
|
15769
|
+
// reserved characters : -/\^$*+?.()|[]{}
|
|
15770
|
+
// CANNOT USE stringifyObject(...) function because we are in a common, lower-level library !
|
|
15771
|
+
let dataFlatStr=stringifyObject(dataFlatForClient)
|
|
15772
|
+
// We «aerate» the produced JSON :
|
|
15773
|
+
.replace(/":[\w]*\{/gim,"\":{\n").replace(/,"/gim,",\n\"")
|
|
15774
|
+
// ...except for inline, escaped JSON string representations :
|
|
15775
|
+
.replace(/\\\":[\w]*\{\n/gim,"\\\":{");
|
|
15776
|
+
// NO : .replace(/}/gim,"}\n");
|
|
15777
|
+
|
|
15778
|
+
|
|
15779
|
+
let path=self.getPath(clientId,repositoryName);
|
|
15780
|
+
fs.writeFile(path, dataFlatStr, FILE_ENCODING, (error) => {
|
|
15781
|
+
if(error){
|
|
15782
|
+
// TRACE
|
|
15783
|
+
console.log("ERROR : Could not write file «"+path+"»:",error);
|
|
15784
|
+
throw error;
|
|
15785
|
+
}
|
|
15786
|
+
if(doOnSuccess) doOnSuccess(dataFlatForClient);
|
|
15787
|
+
});
|
|
15788
|
+
}
|
|
15789
|
+
|
|
15790
|
+
};
|
|
15791
|
+
|
|
15792
|
+
|
|
15793
|
+
return self;
|
|
15794
|
+
};
|
|
15795
|
+
|
|
15796
|
+
}
|
|
15797
|
+
|
|
15798
|
+
|
|
15799
|
+
window.fileExists=(filePath)=>{
|
|
15800
|
+
if(typeof(fs)=="undefined"){
|
|
15801
|
+
// TRACE
|
|
15802
|
+
lognow("ERROR : «fs» node dependency is not available ! Cannot test if file exists.");
|
|
15803
|
+
return null;
|
|
15804
|
+
}
|
|
15805
|
+
return fs.existsSync(filePath);
|
|
15806
|
+
};
|
|
15807
|
+
|
|
15808
|
+
|
|
15809
|
+
|
|
15810
|
+
// Nodejs server launching helper functions :
|
|
15811
|
+
//Networking management :
|
|
15812
|
+
//- WEBSOCKETS AND NODEJS :
|
|
15813
|
+
|
|
15814
|
+
function isConnected(clientSocket){
|
|
15815
|
+
if(!WebsocketImplementation.useSocketIOImplementation)
|
|
15816
|
+
return (clientSocket.readyState===WebSocket.OPEN)
|
|
15817
|
+
return (clientSocket.connected);
|
|
15818
|
+
}
|
|
15819
|
+
|
|
15820
|
+
// Client-side or Server-side :
|
|
15821
|
+
window.getURLOrConsoleParameter=(parameterName)=>{
|
|
15822
|
+
if(typeof(getURLParameter)!="undefined") return getURLParameter(parameterName);
|
|
15823
|
+
return getConsoleParam(parameterName);
|
|
15824
|
+
}
|
|
15825
|
+
|
|
15826
|
+
|
|
15827
|
+
// Server-side :
|
|
15828
|
+
|
|
15829
|
+
getConsoleServerParams=function(portParam=null, certPathParam=null, keyPathParam=null, ignoreConsoleArgs=false, argsOffset=0){
|
|
15830
|
+
|
|
15831
|
+
// Node dependencies :
|
|
15832
|
+
// https=require("https");
|
|
15833
|
+
// fs=require("fs");
|
|
15834
|
+
|
|
15835
|
+
if(typeof(https)==="undefined"){
|
|
15836
|
+
// TRACE
|
|
15837
|
+
console.log("WARN : Could not find the nodejs dependency «https», aborting SSL setup.");
|
|
15838
|
+
return null;
|
|
15839
|
+
}
|
|
15840
|
+
if(typeof(fs)==="undefined"){
|
|
15841
|
+
// TRACE
|
|
15842
|
+
console.log("WARN : Could not find the nodejs dependency «fs», aborting SSL setup.");
|
|
15843
|
+
return null;
|
|
15844
|
+
}
|
|
15845
|
+
|
|
15846
|
+
const result={};
|
|
15847
|
+
|
|
15848
|
+
// We read the command-line arguments if needed :
|
|
15849
|
+
const argCLPort=getConsoleParam(0, argsOffset);
|
|
15850
|
+
const argCLCertPath=getConsoleParam(1, argsOffset);
|
|
15851
|
+
const argCLKeyPath=getConsoleParam(2, argsOffset);
|
|
15852
|
+
|
|
15853
|
+
// Console, command-line arguments OVERRIDE parameters values :
|
|
15854
|
+
|
|
15855
|
+
result.port=(ignoreConsoleArgs?portParam:nonull(argCLPort,portParam));
|
|
15856
|
+
result.certPath=null;
|
|
15857
|
+
result.keyPath=null;
|
|
15858
|
+
result.isSecure=!!(certPathParam || keyPathParam);
|
|
15859
|
+
|
|
15860
|
+
if(result.isSecure){
|
|
15861
|
+
result.certPath=(ignoreConsoleArgs?certPathParam:nonull(argCLCertPath,certPathParam));
|
|
15862
|
+
result.keyPath=(ignoreConsoleArgs?keyPathParam:nonull(argCLKeyPath,keyPathParam));
|
|
15863
|
+
}
|
|
15864
|
+
|
|
15865
|
+
// Eventual encryption options :
|
|
15866
|
+
result.sslOptions=null;
|
|
15867
|
+
if(result.isSecure){
|
|
15868
|
+
result.sslOptions={
|
|
15869
|
+
cert: fs.readFileSync(result.certPath),
|
|
15870
|
+
key: fs.readFileSync(result.keyPath),
|
|
15871
|
+
};
|
|
15872
|
+
}
|
|
15873
|
+
|
|
15874
|
+
return result;
|
|
15875
|
+
}
|
|
15876
|
+
|
|
15877
|
+
getConsoleParam=function(indexOrName=0, argsOffset=2/*arg 0 is «node» and arg 1 is the js file*/){
|
|
15878
|
+
if(!process){
|
|
15879
|
+
throw new Error("ERROR : Cannot extract console parameter in this context !");
|
|
15880
|
+
}
|
|
15881
|
+
|
|
15882
|
+
const allArgs=process.argv;
|
|
15883
|
+
if(empty(allArgs)) return null;
|
|
15884
|
+
|
|
15885
|
+
// Case indexOrName is a number for the parameter index :
|
|
15886
|
+
if(!isString(indexOrName) && isNumber(indexOrName)){
|
|
15887
|
+
return allArgs[indexOrName+argsOffset];
|
|
15888
|
+
}
|
|
15889
|
+
|
|
15890
|
+
// Case indexOrName is a string for the parameter name :
|
|
15891
|
+
for(let i=argsOffset;i<allArgs.length;i++){
|
|
15892
|
+
const val=allArgs[i];
|
|
15893
|
+
if(!contains(val,"="))
|
|
15894
|
+
continue;
|
|
15895
|
+
const splits=val.split("=");
|
|
15896
|
+
if(splits.length<2)
|
|
15897
|
+
continue;
|
|
15898
|
+
const name=splits[0].trim();
|
|
15899
|
+
const value=splits[1].trim();
|
|
15900
|
+
if(name==indexOrName)
|
|
15901
|
+
return value;
|
|
15902
|
+
}
|
|
15903
|
+
return null;
|
|
15904
|
+
}
|
|
15905
|
+
|
|
15906
|
+
|
|
15907
|
+
|
|
15908
|
+
window.getConsoleCLI=(doOnCommands={"makeSandiwch":()=>{}}, promptText="Enter command> ")=>{
|
|
15909
|
+
|
|
15910
|
+
const readline = require("node:readline");
|
|
15911
|
+
|
|
15912
|
+
const cliInterface = readline.createInterface({
|
|
15913
|
+
input: process.stdin,
|
|
15914
|
+
output: process.stdout,
|
|
15915
|
+
prompt: nonoull(promptText,"Enter command> ")
|
|
15916
|
+
});
|
|
15917
|
+
|
|
15918
|
+
cliInterface.prompt();
|
|
15919
|
+
|
|
15920
|
+
cliInterface.on("line", (line) => {
|
|
15921
|
+
const input = line.trim();
|
|
15922
|
+
switch (input) {
|
|
15923
|
+
case "quit":
|
|
15924
|
+
console.log("Bye!");
|
|
15925
|
+
cliInterface.close();
|
|
15926
|
+
break;
|
|
15927
|
+
case "help":
|
|
15928
|
+
console.log("Available commands: quit, help and :", Object.keys(doOnCommands));
|
|
15929
|
+
break;
|
|
15930
|
+
default:
|
|
15931
|
+
if(doOnCommands) doOnCommands[input]();
|
|
15932
|
+
break;
|
|
15933
|
+
}
|
|
15934
|
+
|
|
15935
|
+
// Show the prompt again :
|
|
15936
|
+
cliInterface.prompt();
|
|
15937
|
+
|
|
15938
|
+
}).on("close", () => {
|
|
15939
|
+
process.exit(0);
|
|
15940
|
+
});
|
|
15941
|
+
|
|
15942
|
+
return cliInterface
|
|
15943
|
+
};
|
|
15944
|
+
|
|
15945
|
+
|
|
15946
|
+
|
|
15947
|
+
|
|
15948
|
+
|
|
15949
|
+
// NODE ONLY SERVER / CLIENTS :
|
|
15950
|
+
WebsocketImplementation={
|
|
15951
|
+
|
|
15952
|
+
|
|
15953
|
+
isNodeContext:true,
|
|
15954
|
+
useSocketIOImplementation:false,
|
|
15955
|
+
useFlatStrings:false,
|
|
15956
|
+
|
|
15957
|
+
// COMMON METHODS
|
|
15958
|
+
/*private static*/isInRoom(clientSocket, clientsRoomsTag){
|
|
15959
|
+
return (!clientsRoomsTag || empty(clientsRoomsTag) || contains(clientsRoomsTag, clientSocket.clientRoomTag));
|
|
15960
|
+
},
|
|
15961
|
+
|
|
15962
|
+
|
|
15963
|
+
//
|
|
15964
|
+
// CONSOLE NODE SERVER/CLIENT
|
|
15965
|
+
//
|
|
15966
|
+
getStatic:(isNodeContext=true, useSocketIOImplementation=/*DEBUG*/false)=>{
|
|
15967
|
+
|
|
15968
|
+
WebsocketImplementation.isNodeContext=isNodeContext;
|
|
15969
|
+
WebsocketImplementation.useSocketIOImplementation=useSocketIOImplementation;
|
|
15970
|
+
|
|
15971
|
+
if(!WebsocketImplementation.useSocketIOImplementation){
|
|
15972
|
+
// TRACE
|
|
15973
|
+
lognow("INFO : (SERVER/CLIENT) Using native WebSocket implementation.");
|
|
15974
|
+
|
|
15975
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications
|
|
15976
|
+
if(isNodeContext){
|
|
15977
|
+
if(typeof(WebSocket)==="undefined"){
|
|
15978
|
+
// TRACE
|
|
15979
|
+
console.log("«ws» SERVER library not called yet, calling it now.");
|
|
15980
|
+
|
|
15981
|
+
window.WebSocket=require("ws");
|
|
15982
|
+
|
|
15983
|
+
if(typeof(WebSocket)==="undefined"){
|
|
15984
|
+
// TRACE
|
|
15985
|
+
console.log("ERROR : «ws» CONSOLE/BROWSER CLIENT/SERVER library not found. Cannot launch nodejs server. Aborting.");
|
|
15986
|
+
}
|
|
15987
|
+
}
|
|
15988
|
+
}
|
|
15989
|
+
|
|
15990
|
+
}else{
|
|
15991
|
+
// TRACE
|
|
15992
|
+
lognow("INFO : (SERVER/CLIENT) Using socket.io websocket implementation.");
|
|
15993
|
+
|
|
15994
|
+
if(isNodeContext){
|
|
15995
|
+
|
|
15996
|
+
// NODE SERVER :
|
|
15997
|
+
// DBG
|
|
15998
|
+
lognow("INFO : Loading NODE SERVER socket.io libraries.")
|
|
15999
|
+
if(typeof(Socket)==="undefined"){
|
|
16000
|
+
// TRACE
|
|
16001
|
+
console.log("«socket.io» NODE SERVER library not called yet, calling it now.");
|
|
16002
|
+
Socket=require("socket.io");
|
|
16003
|
+
}
|
|
16004
|
+
if(typeof(Socket)==="undefined"){
|
|
16005
|
+
// TRACE
|
|
16006
|
+
console.log("ERROR : «socket.io» NODE CLIENT/SERVER library not found. Cannot launch nodejs server. Aborting.");
|
|
16007
|
+
}
|
|
16008
|
+
|
|
16009
|
+
// NODE CLIENT :
|
|
16010
|
+
// DBG
|
|
16011
|
+
lognow("INFO : Loading NODE CLIENT socket.io libraries.")
|
|
16012
|
+
if(typeof(io)==="undefined"){
|
|
16013
|
+
// TRACE
|
|
16014
|
+
console.log("«socket.io-client» NODE CLIENT library not called yet, calling it now.");
|
|
16015
|
+
io=require("socket.io-client");
|
|
16016
|
+
}
|
|
16017
|
+
if(typeof(io)==="undefined"){
|
|
16018
|
+
// TRACE
|
|
16019
|
+
console.log("ERROR : «socket-client.io» NODE CLIENT library not found. Cannot launch nodejs server. Aborting.");
|
|
16020
|
+
}
|
|
16021
|
+
}
|
|
16022
|
+
|
|
16023
|
+
|
|
16024
|
+
}
|
|
16025
|
+
|
|
16026
|
+
// *********************************************************************************
|
|
16027
|
+
|
|
16028
|
+
return WebsocketImplementation;
|
|
16029
|
+
},
|
|
16030
|
+
|
|
16031
|
+
|
|
16032
|
+
/*private*/getMessageDataBothImplementations:(eventOrMessageParam)=>{
|
|
16033
|
+
|
|
16034
|
+
const eventOrMessage=(!WebsocketImplementation.useSocketIOImplementation?eventOrMessageParam.data:eventOrMessageParam);
|
|
16035
|
+
|
|
16036
|
+
let dataResult=eventOrMessage;
|
|
16037
|
+
|
|
16038
|
+
try{
|
|
16039
|
+
dataResult=(WebsocketImplementation.useFlatStrings || isString(eventOrMessage)?parseJSON(eventOrMessage):eventOrMessage);
|
|
16040
|
+
}catch(error1){
|
|
16041
|
+
// TRACE
|
|
16042
|
+
lognow(`ERROR : Failed to parse JSON for string «${dataResult}»`,error1);
|
|
16043
|
+
dataResult=(isString(eventOrMessage)?eventOrMessage:stringifyObject(eventOrMessage));
|
|
16044
|
+
}
|
|
16045
|
+
|
|
16046
|
+
return dataResult;
|
|
16047
|
+
},
|
|
16048
|
+
|
|
16049
|
+
|
|
16050
|
+
getServer:(listenableServer)=>{
|
|
16051
|
+
|
|
16052
|
+
if(!WebsocketImplementation.isNodeContext){
|
|
16053
|
+
// TRACE
|
|
16054
|
+
throw new Error("ERROR : SERVER : Server launch is not supported in a non-nodejs context for any implementation.");
|
|
16055
|
+
}
|
|
16056
|
+
|
|
16057
|
+
|
|
16058
|
+
// TODO : FIXME : Use one single interface !
|
|
16059
|
+
// NODE SERVER MODE ONLY :
|
|
16060
|
+
let serverSocket;
|
|
16061
|
+
if(!WebsocketImplementation.useSocketIOImplementation){
|
|
16062
|
+
serverSocket=new WebSocket.Server({ "server":listenableServer });
|
|
16063
|
+
}else{
|
|
16064
|
+
|
|
16065
|
+
// NOW : socket.io :
|
|
16066
|
+
// Loading socket.io
|
|
16067
|
+
// OLD SYNTAX : serverSocket=Socket.listen(listenableServer);
|
|
16068
|
+
serverSocket=new Socket.Server(listenableServer);
|
|
16069
|
+
|
|
16070
|
+
if(listenableServer.cert || listenableServer.key){
|
|
16071
|
+
// TRACE :
|
|
16072
|
+
lognow("WARN : CAUTION ! ON TODAY (01/08/2022) socket.io SERVER LIBRARY IS BOGUS AND WON'T WORK (node clients can't connect !!) IF listenableServer IS A https SERVER !!!");
|
|
16073
|
+
}
|
|
16074
|
+
|
|
16075
|
+
// Setting up the disconnect event for a client :
|
|
16076
|
+
serverSocket.on("endConnection",()=>{
|
|
16077
|
+
serverSocket.disconnect();
|
|
16078
|
+
});
|
|
16079
|
+
}
|
|
16080
|
+
|
|
16081
|
+
serverSocket.on("error",(error)=>{
|
|
16082
|
+
// TRACE
|
|
16083
|
+
lognow("ERROR : An error occurred when trying to start the server : ",error);
|
|
16084
|
+
|
|
16085
|
+
});
|
|
16086
|
+
|
|
16087
|
+
// NODE SERVER INSTANCE :
|
|
16088
|
+
const nodeServerInstance=new NodeServerInstance(serverSocket, listenableServer);
|
|
16089
|
+
|
|
16090
|
+
// Join room server part protocol :
|
|
16091
|
+
nodeServerInstance.receive("protocol",(message, clientSocket)=>{
|
|
16092
|
+
nodeServerInstance.addToRoom(clientSocket, message.clientRoomTag);
|
|
16093
|
+
},{listenerMessageType:"joinRoom"});
|
|
16094
|
+
|
|
16095
|
+
// To make the server aware of the clients connections states :
|
|
16096
|
+
nodeServerInstance.serverSocket.on("close", function close() {
|
|
16097
|
+
|
|
16098
|
+
// TODO : FIXME : Use one single interface !
|
|
16099
|
+
if(!WebsocketImplementation.useSocketIOImplementation) serverClients=nodeServerInstance.serverSocket.clients;
|
|
16100
|
+
// OLD : else serverClients=nodeServerInstance.serverSocket.sockets.clients();
|
|
16101
|
+
else serverClients=nodeServerInstance.serverSocket.sockets.sockets;
|
|
16102
|
+
|
|
16103
|
+
serverClients.forEach((clientSocket)=>{
|
|
16104
|
+
clearInterval(clientSocket.stateCheckInterval);
|
|
16105
|
+
});
|
|
16106
|
+
});
|
|
16107
|
+
|
|
16108
|
+
return nodeServerInstance;
|
|
16109
|
+
},
|
|
16110
|
+
|
|
16111
|
+
// DO NOT USE DIRECTLY, USE INSTEAD initClient(...) (this function uses connectToServer(...)) !
|
|
16112
|
+
// NODE / BROWSER CLIENT CONNECTS TO SERVER MAIN ENTRYPOINT:
|
|
16113
|
+
connectToServer:(serverURL, port, isSecure=false, timeout)=>{
|
|
16114
|
+
|
|
16115
|
+
// TRACE
|
|
16116
|
+
lognow("INFO : Using socket library flavor : "+(WebsocketImplementation.isNodeContext?"node (client/server-side)":"browser (client-side only)"));
|
|
16117
|
+
|
|
16118
|
+
if(WebsocketImplementation.isNodeContext)
|
|
16119
|
+
return WebsocketImplementation.connectToServerFromNode(serverURL, port, isSecure, timeout);
|
|
16120
|
+
else
|
|
16121
|
+
return WebsocketImplementation.connectToServerFromBrowser(serverURL, port, isSecure, timeout);
|
|
16122
|
+
},
|
|
16123
|
+
|
|
16124
|
+
|
|
16125
|
+
//
|
|
16126
|
+
// NODE CLIENT
|
|
16127
|
+
//
|
|
16128
|
+
/*private*/connectToServerFromNode:(serverURL, port, isSecure, timeout)=>{
|
|
16129
|
+
|
|
16130
|
+
// NODE CLIENT MODE ONLY :
|
|
16131
|
+
let clientSocket;
|
|
16132
|
+
if(!WebsocketImplementation.useSocketIOImplementation){
|
|
16133
|
+
|
|
16134
|
+
// NEW : ws :
|
|
16135
|
+
if(typeof(WebSocket)==="undefined"){
|
|
16136
|
+
// TRACE
|
|
16137
|
+
lognow("ERROR : CLIENT : Could not find websocket client lib, aborting client connection.");
|
|
16138
|
+
return null;
|
|
16139
|
+
}
|
|
16140
|
+
|
|
16141
|
+
clientSocket=new WebSocket(serverURL+":"+port,/*WORKAROUND:*/{
|
|
16142
|
+
// CAUTION : SECURITY BREACH :
|
|
16143
|
+
// BUT ALSO NECESSARY TO ALLOW SELF-SIGNED CERTIFICATES USAGE WITH THE YESBOT SYSTEM !
|
|
16144
|
+
rejectUnauthorized:false, // (THIS IS A KNOWN SECURITY BREACH)
|
|
16145
|
+
secure: isSecure
|
|
16146
|
+
});
|
|
16147
|
+
|
|
16148
|
+
clientSocket.addEventListener("error", error=>{
|
|
16149
|
+
// TRACE
|
|
16150
|
+
lognow("ERROR : (NODEJS) A WebSocket client error occurred while trying to connect to server:", error.message);
|
|
16151
|
+
});
|
|
16152
|
+
|
|
16153
|
+
}else{
|
|
16154
|
+
// NOW : socket.io :
|
|
16155
|
+
//client on server-side:
|
|
16156
|
+
|
|
16157
|
+
if(WebsocketImplementation.isNodeContext && typeof(io)!=="undefined"){
|
|
16158
|
+
|
|
16159
|
+
// OLD SYNTAX: clientSocket=Socket.connect(serverURL + ":" + port,{timeout: timeout, secure: isSecure});
|
|
16160
|
+
// NO : clientSocket=new Socket.Client(serverURL + ":" + port,{timeout: timeout, secure: isSecure});
|
|
16161
|
+
clientSocket=io(serverURL + ":" + port,{timeout: timeout, secure: isSecure, autoConnect:true});
|
|
16162
|
+
// UNUSEFUL (since we have the autoconnect:true option) : clientSocket.connect();
|
|
16163
|
+
|
|
16164
|
+
clientSocket.on("connect_error", error=>{
|
|
16165
|
+
// TRACE
|
|
16166
|
+
lognow("ERROR : (NODEJS) A SocketIO client error occurred while trying to connect to server:", error.message);
|
|
16167
|
+
});
|
|
16168
|
+
|
|
16169
|
+
}
|
|
16170
|
+
}
|
|
16171
|
+
|
|
16172
|
+
// DBG
|
|
16173
|
+
lognow("DEBUG : CLIENT : clientSocket created:");
|
|
16174
|
+
|
|
16175
|
+
const nodeClientInstance=new ClientInstance(clientSocket);
|
|
16176
|
+
return nodeClientInstance;
|
|
16177
|
+
},
|
|
16178
|
+
|
|
16179
|
+
//
|
|
16180
|
+
// BROWSER CLIENT
|
|
16181
|
+
//
|
|
16182
|
+
|
|
16183
|
+
/*private*/connectToServerFromBrowser:(serverURL, port, isSecure, timeout)=>{
|
|
16184
|
+
|
|
16185
|
+
// NEW : ws :
|
|
16186
|
+
if(typeof(WebSocket)==="undefined"){
|
|
16187
|
+
// TRACE
|
|
16188
|
+
lognow("ERROR : CLIENT : Could not find websocket client lib, aborting client connection.");
|
|
16189
|
+
return null;
|
|
16190
|
+
}
|
|
16191
|
+
|
|
16192
|
+
// TODO : FIXME : Use one single interface !
|
|
16193
|
+
// BROWSER CLIENT MODE ONLY :
|
|
16194
|
+
let clientSocket;
|
|
16195
|
+
if(!WebsocketImplementation.useSocketIOImplementation){
|
|
16196
|
+
// CAUTION : PARAMETER rejectUnauthorized:false WILL DO NOTHING,
|
|
16197
|
+
// BECAUSE THIS IS COMPLETLY HANDLED BY THE BROWSER SECURITY POLICY !
|
|
16198
|
+
// SO TO CLEAR THE SSL ERROR :
|
|
16199
|
+
// - FIRST GO TO THE HTTPS:// SERVER ADDRESS WITH BROWSER
|
|
16200
|
+
// - THEN ADD THE SECURITY EXCEPTION IN THE BROWSER !
|
|
16201
|
+
clientSocket=new WebSocket(serverURL+":"+port,["ws","wss"]);
|
|
16202
|
+
|
|
16203
|
+
clientSocket.addEventListener("error", error=>{
|
|
16204
|
+
// TRACE
|
|
16205
|
+
lognow("ERROR : (BROWSER) A WebSocket client error occurred while trying to connect to server:", error.message);
|
|
16206
|
+
});
|
|
16207
|
+
|
|
16208
|
+
}else if(typeof(io)!=="undefined"){
|
|
16209
|
+
// OLD SYNTAX :clientSocket=io.connect(serverURL + ":" + port,{timeout: timeout, secure: isSecure});
|
|
16210
|
+
// ALTERNATIVE :
|
|
16211
|
+
clientSocket=io(serverURL + ":" + port,{timeout: timeout, secure: isSecure});
|
|
16212
|
+
|
|
16213
|
+
clientSocket.on("connect_error", error=>{
|
|
16214
|
+
// TRACE
|
|
16215
|
+
lognow("ERROR : (BROWSER) A SocketIO client error occurred while trying to connect to server:", error.message);
|
|
16216
|
+
});
|
|
16217
|
+
|
|
16218
|
+
}
|
|
16219
|
+
|
|
16220
|
+
// BROWSER CLIENT INSTANCE :
|
|
16221
|
+
const browserClientInstance=new ClientInstance(clientSocket);
|
|
16222
|
+
return browserClientInstance;
|
|
16223
|
+
},
|
|
16224
|
+
|
|
16225
|
+
};
|
|
16226
|
+
|
|
16227
|
+
|
|
16228
|
+
|
|
16229
|
+
launchNodeHTTPServer=function(port, doOnConnect=null, doOnFinalizeServer=null, /*OPTIONAL*/sslOptions=null, httpHandlerParam=null, addCORSHeader=ADD_CORS_HEADER){
|
|
16230
|
+
|
|
16231
|
+
const EXCLUDED_FILENAMES_PARTS=[".keyHash.",".pem"];
|
|
16232
|
+
|
|
16233
|
+
|
|
16234
|
+
|
|
16235
|
+
if(typeof(https)==="undefined"){
|
|
16236
|
+
// TRACE
|
|
16237
|
+
console.log("«https» SERVER library not called yet, calling it now.");
|
|
16238
|
+
https=require("https");
|
|
16239
|
+
}
|
|
16240
|
+
if(typeof(http)==="undefined"){
|
|
16241
|
+
// TRACE
|
|
16242
|
+
console.log("«http» SERVER library not called yet, calling it now.");
|
|
16243
|
+
http=require("http");
|
|
16244
|
+
}
|
|
16245
|
+
|
|
16246
|
+
|
|
16247
|
+
const DEFAULT_HANDLER=function(request, response){
|
|
16248
|
+
|
|
16249
|
+
const url=request.url;
|
|
16250
|
+
|
|
16251
|
+
let isURLInExclusionZone=!!foreach(EXCLUDED_FILENAMES_PARTS,(excludedStr)=>{
|
|
16252
|
+
if(contains(url,excludedStr)){
|
|
16253
|
+
return true;
|
|
16254
|
+
}
|
|
16255
|
+
});
|
|
16256
|
+
|
|
16257
|
+
if(isURLInExclusionZone){
|
|
16258
|
+
// TRACE
|
|
16259
|
+
console.log("ERROR 403 forbidden access error :");
|
|
16260
|
+
console.log(error);
|
|
16261
|
+
|
|
16262
|
+
response.writeHead(403);
|
|
16263
|
+
response.end("Sorry, cannot access resource : error: "+error.code+" ..\n");
|
|
16264
|
+
response.end();
|
|
16265
|
+
return;
|
|
16266
|
+
}
|
|
16267
|
+
|
|
16268
|
+
|
|
16269
|
+
|
|
16270
|
+
const urlFile="." + url;
|
|
16271
|
+
|
|
16272
|
+
let filePath=urlFile.indexOf("?")!==-1?urlFile.split("?")[0]:urlFile;
|
|
16273
|
+
if(filePath=="./") filePath="./index.html";
|
|
16274
|
+
|
|
16275
|
+
let contentType="text/html";
|
|
16276
|
+
|
|
16277
|
+
const headers={ "Content-Type": contentType };
|
|
16278
|
+
|
|
16279
|
+
// To remove the CORS error message (cf. https://medium.com/@dtkatz/3-ways-to-fix-the-cors-error-and-how-access-control-allow-origin-works-d97d55946d9)
|
|
16280
|
+
if(addCORSHeader) headers["Access-Control-Allow-Origin"]="*";
|
|
16281
|
+
|
|
16282
|
+
|
|
16283
|
+
fs.readFile(filePath, function(error, fileContent){
|
|
16284
|
+
if(error){
|
|
16285
|
+
if(error.code=="ENOENT"){
|
|
16286
|
+
// TRACE
|
|
16287
|
+
console.log("ERROR 404 file not found :"+filePath);
|
|
16288
|
+
|
|
16289
|
+
fs.readFile("./404.html", function(error, fileContent){
|
|
16290
|
+
response.writeHead(200, headers);
|
|
16291
|
+
response.end(fileContent, "utf-8");
|
|
16292
|
+
});
|
|
16293
|
+
|
|
16294
|
+
}else {
|
|
16295
|
+
|
|
16296
|
+
// TRACE
|
|
16297
|
+
console.log("ERROR 500 server error :");
|
|
16298
|
+
console.log(error);
|
|
16299
|
+
|
|
16300
|
+
response.writeHead(500);
|
|
16301
|
+
response.end("Sorry, check with the site admin for error: "+error.code+" ..\n");
|
|
16302
|
+
response.end();
|
|
16303
|
+
|
|
16304
|
+
}
|
|
16305
|
+
}else {
|
|
16306
|
+
|
|
16307
|
+
// TRACE
|
|
16308
|
+
console.log("INFO 200 OK :"+filePath);
|
|
16309
|
+
|
|
16310
|
+
|
|
16311
|
+
response.writeHead(200, headers);
|
|
16312
|
+
response.end(fileContent, "utf-8");
|
|
16313
|
+
|
|
16314
|
+
// res.writeHead(200);
|
|
16315
|
+
// res.end("hello world\n");
|
|
16316
|
+
// res.sendFile(__dirname + "/public/index.html");
|
|
16317
|
+
|
|
16318
|
+
}
|
|
16319
|
+
});
|
|
16320
|
+
|
|
16321
|
+
};
|
|
16322
|
+
|
|
16323
|
+
|
|
16324
|
+
const handler=nonull(httpHandlerParam, DEFAULT_HANDLER);
|
|
16325
|
+
|
|
16326
|
+
|
|
16327
|
+
|
|
16328
|
+
let listenableServer;
|
|
16329
|
+
if(sslOptions){
|
|
16330
|
+
let httpsServer=https.createServer(sslOptions, handler).listen(port);
|
|
16331
|
+
// TRACE
|
|
16332
|
+
console.log("INFO : SERVER : HTTPS Server launched and listening on port " + port + "!");
|
|
16333
|
+
listenableServer=httpsServer;
|
|
16334
|
+
}else{
|
|
16335
|
+
let httpServer=http.createServer(handler).listen(port);
|
|
16336
|
+
// TRACE
|
|
16337
|
+
console.log("INFO : SERVER : HTTP Server launched and listening on port " + port + "!");
|
|
16338
|
+
listenableServer=httpServer;
|
|
16339
|
+
}
|
|
16340
|
+
|
|
16341
|
+
|
|
16342
|
+
const server=WebsocketImplementation.getStatic(true).getServer(listenableServer);
|
|
16343
|
+
|
|
16344
|
+
// When a client connects, we execute the callback :
|
|
16345
|
+
// CAUTION : MUST BE CALLED ONLY ONCE !
|
|
16346
|
+
server.onConnectionToClient((serverParam, clientSocketParam)=>{
|
|
16347
|
+
if(doOnConnect) doOnConnect(serverParam, clientSocketParam);
|
|
16348
|
+
});
|
|
16349
|
+
|
|
16350
|
+
|
|
16351
|
+
server.onFinalize((serverParam)=>{
|
|
16352
|
+
|
|
16353
|
+
// DBG
|
|
16354
|
+
lognow("onFinalize() server");
|
|
16355
|
+
|
|
16356
|
+
if(doOnFinalizeServer) doOnFinalizeServer(serverParam);
|
|
16357
|
+
});
|
|
16358
|
+
|
|
16359
|
+
|
|
16360
|
+
// TRACE
|
|
16361
|
+
console.log("INFO : SERVER : Generic Nodejs server launched and listening on port:" + port + "!");
|
|
16362
|
+
|
|
16363
|
+
|
|
16364
|
+
|
|
16365
|
+
|
|
16366
|
+
|
|
16367
|
+
return server;
|
|
16368
|
+
}
|
|
16369
|
+
|
|
16370
|
+
|
|
16371
|
+
initNodeServerInfrastructureWrapper=function(doOnClientConnection=null, doOnFinalizeServer=null,
|
|
16372
|
+
/*OPTIONAL*/portParam,
|
|
16373
|
+
/*OPTIONAL*/certPathParam,
|
|
16374
|
+
/*OPTIONAL*/keyPathParam){
|
|
16375
|
+
|
|
16376
|
+
// TRACE
|
|
16377
|
+
console.log("Server launched.");
|
|
16378
|
+
console.log("Usage : node <server.js> conf {port:[port], sslCertPath:[ssl certificate path | unsecure ], sslKeyPath:[ssl key path], serverConfig:[JSON server configuration]}");
|
|
16379
|
+
console.log("Or (to generate password hash) : node <server.js> hash <clientId@repositoryName> <clearTextSecretString>");
|
|
16380
|
+
// EXAMPLE : node orita-srv.js hash orita.global@keyHash 1234567890
|
|
16381
|
+
console.log("Server launched.");
|
|
16382
|
+
|
|
16383
|
+
|
|
16384
|
+
// We read the command-line arguments if needed :
|
|
16385
|
+
|
|
16386
|
+
let argCLPort;
|
|
16387
|
+
let argCLCertPath;
|
|
16388
|
+
let argCLKeyPath;
|
|
16389
|
+
|
|
16390
|
+
let serverConfig={};
|
|
16391
|
+
let isForceUnsecure;
|
|
16392
|
+
|
|
16393
|
+
let isHashAsked=false;
|
|
16394
|
+
let clearTextParam=null;
|
|
16395
|
+
let persisterId=null;
|
|
16396
|
+
|
|
16397
|
+
|
|
16398
|
+
process.argv.forEach(function (val, i){
|
|
16399
|
+
if(!val) return;
|
|
16400
|
+
// 0 corresponds to «node / nodejs»
|
|
16401
|
+
if(i<=1) return; // 1 corresponds to « <server.js> »
|
|
16402
|
+
else if(i==2){
|
|
16403
|
+
if(val==="hash") isHashAsked=true;
|
|
16404
|
+
}else if(i==3){
|
|
16405
|
+
if(!isHashAsked){
|
|
16406
|
+
try{
|
|
16407
|
+
const jsonConf=parseJSON(val);
|
|
16408
|
+
argCLPort=jsonConf.port;
|
|
16409
|
+
argCLCertPath=jsonConf.sslCertPath;
|
|
16410
|
+
argCLKeyPath=jsonConf.sslKeyPath;
|
|
16411
|
+
serverConfig=nonull(jsonConf.serverConfig,{});
|
|
16412
|
+
}catch(err1){
|
|
16413
|
+
lognow("WARN : Cannot parse argument JSON string «"+val+"».");
|
|
16414
|
+
}
|
|
16415
|
+
} else persisterId=val;
|
|
16416
|
+
}else if(i==4){
|
|
16417
|
+
if(isHashAsked) clearTextParam=val;
|
|
16418
|
+
}
|
|
16419
|
+
});
|
|
16420
|
+
isForceUnsecure=(argCLCertPath==="unsecure");
|
|
16421
|
+
|
|
16422
|
+
|
|
16423
|
+
|
|
16424
|
+
|
|
16425
|
+
|
|
16426
|
+
const aotraNodeServer={config:serverConfig};
|
|
16427
|
+
aotraNodeServer.serverManager={ start:()=>{/*DEFAULT START FUNCTION, WILL BE OVERRIDEN LATER*/}};
|
|
16428
|
+
|
|
16429
|
+
if(isHashAsked){
|
|
16430
|
+
// We instanciate a temporary persister just to read the key hash file:
|
|
16431
|
+
const persister=getPersister("./");
|
|
16432
|
+
let persisterIdSplits=persisterId.split("@");
|
|
16433
|
+
if(empty(persisterIdSplits) || persisterIdSplits.length!=2){
|
|
16434
|
+
// TRACE
|
|
16435
|
+
console.log("ERROR : No persister repository IDs provided correctly. Cannot read key hash. Aborting hash generation.");
|
|
16436
|
+
return aotraNodeServer;
|
|
16437
|
+
}
|
|
16438
|
+
const persisterClientId=persisterIdSplits[0];
|
|
16439
|
+
const persisterRepositoryName=persisterIdSplits[1];
|
|
16440
|
+
let globalKeyHashObject=persister.readTreeObjectFromFile(persisterClientId, persisterRepositoryName);
|
|
16441
|
+
if(!globalKeyHashObject || !globalKeyHashObject.keyHash){
|
|
16442
|
+
// TRACE
|
|
16443
|
+
console.log("WARN : No key hash found. Generating one now.");
|
|
16444
|
+
globalKeyHashObject={keyHash:getUUID(), hashes:[]};
|
|
16445
|
+
persister.saveDataToFileForClient(persisterClientId,persisterRepositoryName,globalKeyHashObject,false,()=>{
|
|
16446
|
+
// TRACE
|
|
16447
|
+
console.log("INFO : Key hash generated and saved successfully.");
|
|
16448
|
+
});
|
|
16449
|
+
}
|
|
16450
|
+
const globalKeyHash=globalKeyHashObject.keyHash;
|
|
16451
|
+
|
|
16452
|
+
let firstHash=getHashedString(clearTextParam);
|
|
16453
|
+
|
|
16454
|
+
let generatedHash=getHashedString( firstHash + globalKeyHash, "SHA-256", true);// (we use the heavy treatment thing.)
|
|
16455
|
+
globalKeyHashObject.hashes.push(generatedHash);
|
|
16456
|
+
|
|
16457
|
+
// We update the repository :
|
|
16458
|
+
persister.saveDataToFileForClient(persisterClientId,persisterRepositoryName,globalKeyHashObject,false,()=>{
|
|
16459
|
+
// TRACE
|
|
16460
|
+
console.log("INFO : Hash added to repository and saved successfully.");
|
|
16461
|
+
});
|
|
16462
|
+
|
|
16463
|
+
// OUTPUT
|
|
16464
|
+
console.log("Here is your key : share it with your main clients but DO NOT LEAK IT !\n********************\n"+clearTextParam+"\n********************\n");
|
|
16465
|
+
|
|
16466
|
+
return aotraNodeServer;
|
|
16467
|
+
}
|
|
16468
|
+
|
|
16469
|
+
|
|
16470
|
+
const DEFAULT_PORT=nonull(argCLPort,25000);
|
|
16471
|
+
const DEFAULT_CERT_PATH=nonull(argCLCertPath,"cert.pem");
|
|
16472
|
+
const DEFAULT_KEY_PATH=nonull(argCLKeyPath,"key.key");
|
|
16473
|
+
|
|
16474
|
+
|
|
16475
|
+
let port=portParam ? portParam : DEFAULT_PORT;
|
|
16476
|
+
let certPath=null;
|
|
16477
|
+
let keyPath=null;
|
|
16478
|
+
|
|
16479
|
+
if(!isForceUnsecure){
|
|
16480
|
+
certPath=certPathParam?certPathParam:DEFAULT_CERT_PATH;
|
|
16481
|
+
keyPath=keyPathParam?keyPathParam:DEFAULT_KEY_PATH;
|
|
16482
|
+
}
|
|
16483
|
+
|
|
16484
|
+
|
|
16485
|
+
|
|
16486
|
+
|
|
16487
|
+
// UNUSEFUL :
|
|
16488
|
+
//aotraNodeServer.serverManager.microClientsSockets=[];
|
|
16489
|
+
// UNUSEFUL :
|
|
16490
|
+
//aotraNodeServer.serverManager.mainClientsSockets=[];
|
|
16491
|
+
|
|
16492
|
+
aotraNodeServer.serverManager.start=function(){
|
|
16493
|
+
|
|
16494
|
+
// Eventual encryption options :
|
|
16495
|
+
let sslOptions=null;
|
|
16496
|
+
if(!isForceUnsecure){
|
|
16497
|
+
if(typeof(fs)==="undefined"){
|
|
16498
|
+
// TRACE
|
|
16499
|
+
lognow("ERROR : «fs» node subsystem not present, cannot access files. Aborting SSL configuration of server.");
|
|
16500
|
+
}else{
|
|
16501
|
+
try{
|
|
16502
|
+
sslOptions={
|
|
16503
|
+
cert: fs.readFileSync(certPath, {encoding: "utf8"}),
|
|
16504
|
+
key: fs.readFileSync(keyPath, {encoding: "utf8"}),
|
|
16505
|
+
};
|
|
16506
|
+
}catch(exception){
|
|
16507
|
+
// TRACE
|
|
16508
|
+
lognow("ERROR : Could not open SSL files certPath:«"+certPath+"» or keyPath:«"+keyPath+"». Aborting SSL configuration of server.");
|
|
16509
|
+
}
|
|
16510
|
+
}
|
|
16511
|
+
}
|
|
16512
|
+
|
|
16513
|
+
aotraNodeServer.server=launchNodeHTTPServer(port, doOnClientConnection, doOnFinalizeServer, sslOptions);
|
|
16514
|
+
|
|
16515
|
+
|
|
16516
|
+
return aotraNodeServer;
|
|
16517
|
+
};
|
|
16518
|
+
|
|
16519
|
+
return aotraNodeServer;
|
|
16520
|
+
}
|
|
16521
|
+
|
|
16522
|
+
// ========================= FUSRODA SERVER : =========================
|
|
16523
|
+
|
|
16524
|
+
//
|
|
16525
|
+
// DOES NOT WORK : USE Java FusrodaServer instead :
|
|
16526
|
+
//
|
|
16527
|
+
///*FUSRODA server stands from FSRD SERVER, for Fucking Simple Remote Desktop SERVER*/
|
|
16528
|
+
//createFusrodaServer=function(certPathParam=null,keyPathParam=null,portParam=4000){
|
|
16529
|
+
//
|
|
16530
|
+
// // https://www.npmjs.com/package/screenshot-desktop
|
|
16531
|
+
// // https://github.com/octalmage/robotjs
|
|
16532
|
+
// // npm install --save screenshot-desktop
|
|
16533
|
+
// //
|
|
16534
|
+
// // sudo apt-get install libxtst-dev libx11-dev
|
|
16535
|
+
// // npm install --save robotjs
|
|
16536
|
+
//
|
|
16537
|
+
// // http://getrobot.net/docs/usage.html
|
|
16538
|
+
// //
|
|
16539
|
+
// // apt-get install build-essential python libxt-dev libxtst-dev libxinerama-dev -y
|
|
16540
|
+
//
|
|
16541
|
+
// const screenshot=require("screenshot-desktop");
|
|
16542
|
+
//
|
|
16543
|
+
// const REFRESH_SCREENSHOTS_MILLIS=500;
|
|
16544
|
+
//
|
|
16545
|
+
//
|
|
16546
|
+
// const server=initNodeServerInfrastructureWrapper(
|
|
16547
|
+
// // On each client connection :
|
|
16548
|
+
// // (serverParam, clientSocketParam)=>{},
|
|
16549
|
+
// null,
|
|
16550
|
+
// // On server finalization :
|
|
16551
|
+
// (serverParam)=>{
|
|
16552
|
+
//
|
|
16553
|
+
// serverParam.receive("protocol_fusroda", (message, clientSocket)=> {
|
|
16554
|
+
// serverParam.addToRoom(clientSocket,"clients");
|
|
16555
|
+
// });
|
|
16556
|
+
//
|
|
16557
|
+
//
|
|
16558
|
+
// serverParam.sendScreenshotsRoutine=setInterval(()=>{
|
|
16559
|
+
// if(serverParam.isScreenshotStarted) return;
|
|
16560
|
+
//
|
|
16561
|
+
// serverParam.isScreenshotStarted=true;
|
|
16562
|
+
//
|
|
16563
|
+
// screenshot().then((img) => {
|
|
16564
|
+
//
|
|
16565
|
+
// const data={image:img,listenerMessageType:"imageData"};
|
|
16566
|
+
// serverParam.send("message", data, "clients");
|
|
16567
|
+
//
|
|
16568
|
+
// serverParam.isScreenshotStarted=false;
|
|
16569
|
+
//
|
|
16570
|
+
// }).catch((error) => {
|
|
16571
|
+
// // TRACE
|
|
16572
|
+
// lognow("ERROR : Error during screenshot :",error);
|
|
16573
|
+
// });
|
|
16574
|
+
//
|
|
16575
|
+
// },REFRESH_SCREENSHOTS_MILLIS);
|
|
16576
|
+
//
|
|
16577
|
+
//
|
|
16578
|
+
// },portParam,certPathParam,keyPathParam);
|
|
16579
|
+
//
|
|
16580
|
+
//
|
|
16581
|
+
// // const doOnConnect=(serverParam, clientSocketParam)=>{
|
|
16582
|
+
// // };
|
|
16583
|
+
// // const doOnFinalizeServer=(serverParam)=>{
|
|
16584
|
+
// // /*DO NOTHING*/
|
|
16585
|
+
// // };
|
|
16586
|
+
// // const server={};
|
|
16587
|
+
// // server.start=(port=4000)=>{
|
|
16588
|
+
// // server.httpServer=launchNodeHTTPServer(port, doOnConnect, doOnFinalizeServer, sslOptions);
|
|
16589
|
+
// // };
|
|
16590
|
+
//
|
|
16591
|
+
// return server;
|
|
16592
|
+
//}
|
|
16593
|
+
|
|
16594
|
+
|
|
16595
|
+
// ========================= UTILITY SERVERSIDE METHODS : =========================
|
|
16596
|
+
|
|
16597
|
+
class ListManager{
|
|
16598
|
+
|
|
16599
|
+
constructor(config){
|
|
16600
|
+
this.config=config;
|
|
16601
|
+
this.maxItemsNumber=nonull(this.config.max,999);
|
|
16602
|
+
this.simultaneousItemsNumber=nonull(this.config.simultaneous,1);
|
|
16603
|
+
this.sessionDurationSeconds=nonull(this.config.duration,null);
|
|
16604
|
+
this.mode=nonull(this.config.mode,"startAtConnexion");
|
|
16605
|
+
|
|
16606
|
+
this.itemsInfos={};
|
|
16607
|
+
this.time=null;
|
|
16608
|
+
this.started=false;
|
|
16609
|
+
}
|
|
16610
|
+
|
|
16611
|
+
addItem(id,item){
|
|
16612
|
+
if(id==null){
|
|
16613
|
+
// TRACE
|
|
16614
|
+
lognow("ERROR : Cannot add item with no id.");
|
|
16615
|
+
return;
|
|
16616
|
+
}
|
|
16617
|
+
if(!item){
|
|
16618
|
+
// TRACE
|
|
16619
|
+
lognow("ERROR : Cannot add null item.");
|
|
16620
|
+
return;
|
|
16621
|
+
}
|
|
16622
|
+
const numberOfItemsCurrently=getArraySize(this.itemsInfos);
|
|
16623
|
+
|
|
16624
|
+
// DBG
|
|
16625
|
+
lognow(">>>>>>>>>numberOfItemsCurrently:",numberOfItemsCurrently);
|
|
16626
|
+
lognow(">>>>>>>>>Object.keys(arrayOfValues):",Object.keys(this.itemsInfos));
|
|
16627
|
+
|
|
16628
|
+
|
|
16629
|
+
if(this.maxItemsNumber<=numberOfItemsCurrently){
|
|
16630
|
+
// TRACE
|
|
16631
|
+
lognow("ERROR : Cannot add item with id «"+id+"», list already full.");
|
|
16632
|
+
return;
|
|
16633
|
+
}
|
|
16634
|
+
|
|
16635
|
+
|
|
16636
|
+
if(numberOfItemsCurrently==0 && this.mode==="startAtConnexion"){
|
|
16637
|
+
|
|
16638
|
+
// DBG
|
|
16639
|
+
lognow(">>>>>>>>>START SESSION !!!!");
|
|
16640
|
+
|
|
16641
|
+
this.startSession();
|
|
16642
|
+
}
|
|
16643
|
+
this.itemsInfos[id]={
|
|
16644
|
+
item:item,
|
|
16645
|
+
time:getNow(),
|
|
16646
|
+
};
|
|
16647
|
+
}
|
|
16648
|
+
|
|
16649
|
+
startSession(){
|
|
16650
|
+
this.time=getNow();
|
|
16651
|
+
this.started=true;
|
|
16652
|
+
}
|
|
16653
|
+
|
|
16654
|
+
stopSession(){
|
|
16655
|
+
this.started=false;
|
|
16656
|
+
}
|
|
16657
|
+
|
|
16658
|
+
isSessionActive(){
|
|
16659
|
+
|
|
16660
|
+
// DBG
|
|
16661
|
+
lognow(" !!! this.sessionDurationSeconds : "+this.sessionDurationSeconds);
|
|
16662
|
+
lognow(" !!! this.started : "+this.started);
|
|
16663
|
+
lognow(" !!! this.time : "+this.time);
|
|
16664
|
+
|
|
16665
|
+
|
|
16666
|
+
if(!this.sessionDurationSeconds) return true;
|
|
16667
|
+
if(!this.started) return false;
|
|
16668
|
+
const result=!hasDelayPassed(this.time, this.sessionDurationSeconds*1000);
|
|
16669
|
+
|
|
16670
|
+
// DBG
|
|
16671
|
+
lognow(" !!! HAS DELAY PASSED : "+result);
|
|
16672
|
+
|
|
16673
|
+
return result;
|
|
16674
|
+
}
|
|
16675
|
+
|
|
16676
|
+
isClientActive(clientId){
|
|
16677
|
+
|
|
16678
|
+
// DBG
|
|
16679
|
+
lognow(" this.isSessionActive()"+this.isSessionActive());
|
|
16680
|
+
|
|
16681
|
+
if(!this.isSessionActive()) return false;
|
|
16682
|
+
const clientPosition=this.getItemPosition(clientId);
|
|
16683
|
+
//CAUTION : Client position starts at 1 !
|
|
16684
|
+
const clientIndex=(clientPosition-1);
|
|
16685
|
+
const result=(clientIndex<=this.maxItemsNumber && clientIndex<=this.simultaneousItemsNumber);
|
|
16686
|
+
|
|
16687
|
+
return result;
|
|
16688
|
+
}
|
|
16689
|
+
|
|
16690
|
+
removeItemById(id){
|
|
16691
|
+
if(id==null){
|
|
16692
|
+
// TRACE
|
|
16693
|
+
lognow("ERROR : Cannot remove item, no id specified.");
|
|
16694
|
+
return;
|
|
16695
|
+
}
|
|
16696
|
+
if(!this.itemsInfos[id]){
|
|
16697
|
+
// TRACE
|
|
16698
|
+
lognow("ERROR : Cannot remove item, item not found for id «"+id+"».");
|
|
16699
|
+
return;
|
|
16700
|
+
}
|
|
16701
|
+
delete this.itemsInfos[id];
|
|
16702
|
+
}
|
|
16703
|
+
|
|
16704
|
+
removeItem(item){
|
|
16705
|
+
if(item==null){
|
|
16706
|
+
// TRACE
|
|
16707
|
+
lognow("ERROR : Cannot remove item, none specified.");
|
|
16708
|
+
return;
|
|
16709
|
+
}
|
|
16710
|
+
|
|
16711
|
+
let id=null;
|
|
16712
|
+
foreach(this.itemsInfos,(itemInfos,key)=>{
|
|
16713
|
+
if(itemInfos.item===item
|
|
16714
|
+
// DEBUG ONLY :
|
|
16715
|
+
|| (itemInfos.item.id && item.id && itemInfos.item.id===item.id)
|
|
16716
|
+
){
|
|
16717
|
+
id=key;
|
|
16718
|
+
return "break";
|
|
16719
|
+
}
|
|
16720
|
+
|
|
16721
|
+
});
|
|
16722
|
+
|
|
16723
|
+
if(!id){
|
|
16724
|
+
// TRACE
|
|
16725
|
+
lognow("ERROR : Cannot remove item, item not found for id «"+id+"».");
|
|
16726
|
+
return;
|
|
16727
|
+
}
|
|
16728
|
+
|
|
16729
|
+
this.removeItemById(id);
|
|
16730
|
+
}
|
|
16731
|
+
|
|
16732
|
+
// Goes from 1 to <length>:
|
|
16733
|
+
getItemPosition(id){
|
|
16734
|
+
if(id==null){
|
|
16735
|
+
// TRACE
|
|
16736
|
+
lognow("ERROR : Cannot calculate item position, no id specified.");
|
|
16737
|
+
return null;
|
|
16738
|
+
}
|
|
16739
|
+
if(!this.itemsInfos[id]){
|
|
16740
|
+
// TRACE
|
|
16741
|
+
lognow("ERROR : Cannot calculate item position, item not found for id «"+id+"».");
|
|
16742
|
+
return null;
|
|
16743
|
+
}
|
|
16744
|
+
let result=0;
|
|
16745
|
+
foreach(this.itemsInfos, (itemInfo, key)=>{
|
|
16746
|
+
result++;
|
|
16747
|
+
if(id===key) return "break";
|
|
16748
|
+
},null,(item1, item2)=>item1.time<item2.time);
|
|
16749
|
+
return result;
|
|
16750
|
+
}
|
|
16751
|
+
|
|
16752
|
+
getItemsNumber(){
|
|
16753
|
+
return getArraySize(this.itemsInfos);
|
|
16754
|
+
}
|
|
16755
|
+
|
|
16756
|
+
};
|
|
16757
|
+
|
|
16758
|
+
getListManager=function(config){
|
|
16759
|
+
return new ListManager(config);
|
|
16760
|
+
};
|
|
16761
|
+
|
|
16762
|
+
|
|
16763
|
+
// CAUTION ! TODO : FIXME : We replace in response all single quotes with "`" (egrave) in order to avoid errors !
|
|
16764
|
+
// NO : IN A NODE CONTEXT WITH require("...") WILL RESULT IN AN UNDEFINED FUNCTION ERROR !!!
|
|
16765
|
+
// function performHTTPRequest(...){...
|
|
16766
|
+
// USE THIS INSTEAD :
|
|
16767
|
+
performHTTPRequest=function(completeURL, httpMethod="GET", headers={}, requestBodyOrNamedArgs=null, isNodeContext=false, addCORSHeader=ADD_CORS_HEADER){
|
|
16768
|
+
|
|
16769
|
+
// Body
|
|
16770
|
+
let requestBodyOrNamedArgsStr=null;
|
|
16771
|
+
if(requestBodyOrNamedArgs){
|
|
16772
|
+
if(isString(requestBodyOrNamedArgs) && !isObject(requestBodyOrNamedArgs)){
|
|
16773
|
+
// If it's already a string, we assume it's a valid JSOn string already :
|
|
16774
|
+
requestBodyOrNamedArgsStr=requestBodyOrNamedArgs.replace(/[\r\n]+/gim, ""); // We remove all the breaklines
|
|
16775
|
+
}else{
|
|
16776
|
+
try{
|
|
16777
|
+
requestBodyOrNamedArgsStr=stringifyObject(requestBodyOrNamedArgs).replace(/[\r\n]+/gim, ""); // We remove all the breaklines
|
|
16778
|
+
}catch(parseErr){
|
|
16779
|
+
requestBodyOrNamedArgsStr=""+requestBodyOrNamedArgs;
|
|
16780
|
+
}
|
|
16781
|
+
}
|
|
16782
|
+
}
|
|
16783
|
+
|
|
16784
|
+
let body=null;
|
|
16785
|
+
// Not the same way to send parameters, with POST/PUT http method :
|
|
16786
|
+
if(contains(["POST","PUT"],httpMethod) && requestBodyOrNamedArgs){
|
|
16787
|
+
body=requestBodyOrNamedArgsStr;
|
|
16788
|
+
}
|
|
16789
|
+
|
|
16790
|
+
// Headers
|
|
16791
|
+
if(contains(["POST","PUT"],httpMethod)){
|
|
16792
|
+
headers["Content-Type"]="application/json";
|
|
16793
|
+
|
|
16794
|
+
if(requestBodyOrNamedArgsStr && isString(body)){
|
|
16795
|
+
headers["Content-Length"]=Buffer.byteLength(requestBodyOrNamedArgsStr);
|
|
16796
|
+
}
|
|
16797
|
+
|
|
16798
|
+
// To remove the CORS error message (cf. https://medium.com/@dtkatz/3-ways-to-fix-the-cors-error-and-how-access-control-allow-origin-works-d97d55946d9)
|
|
16799
|
+
if(addCORSHeader) headers["Access-Control-Allow-Origin"]="*";
|
|
16800
|
+
|
|
16801
|
+
} else if(httpMethod==="GET" && requestBodyOrNamedArgs){
|
|
16802
|
+
// Not the same way to send parameters in GET http method :
|
|
16803
|
+
// DBG
|
|
16804
|
+
lognow("unformatted API URL : "+completeURL);
|
|
16805
|
+
|
|
16806
|
+
completeURL=appendGetParameters(completeURL, requestBodyOrNamedArgs);
|
|
16807
|
+
|
|
16808
|
+
// DBG
|
|
16809
|
+
lognow("formatted API URL : "+completeURL);
|
|
16810
|
+
}
|
|
16811
|
+
|
|
16812
|
+
// CASE BROWSER CONTEXT :
|
|
16813
|
+
if(!isNodeContext || typeof(require)=="undefined"){
|
|
16814
|
+
// TRACE
|
|
16815
|
+
lognow("INFO : We are not running in a browser context (isNodeContext:"+isNodeContext+";typeof(require):"+(typeof(require))+"). Using browser library.");
|
|
16816
|
+
|
|
16817
|
+
return new Promise((resolve,reject)=>{
|
|
16818
|
+
fetch(completeURL, {
|
|
16819
|
+
method: httpMethod,
|
|
16820
|
+
headers: headers,
|
|
16821
|
+
body: body,
|
|
16822
|
+
})
|
|
16823
|
+
// STRANGE : DOES NOT WORK !!:
|
|
16824
|
+
//.then(response => response.json())
|
|
16825
|
+
// STRANGE : DOES WORK :
|
|
16826
|
+
.then(response => {
|
|
16827
|
+
|
|
16828
|
+
// DBG
|
|
16829
|
+
console.log("~~~~~~~~~~~response :",response);
|
|
16830
|
+
|
|
16831
|
+
return response.json();
|
|
16832
|
+
}).then(data => {
|
|
16833
|
+
|
|
16834
|
+
// CAUTION : .request(...) => statusCode, .fetch(...) => status (performHTTPRequest(...) uses fetch(...))
|
|
16835
|
+
const status=data.status;
|
|
16836
|
+
// if(status!=200 && data.error){
|
|
16837
|
+
// // const error=nonull(data.error, data.detail);
|
|
16838
|
+
// const error=data.error;
|
|
16839
|
+
// // TRACE
|
|
16840
|
+
// console.error("Error:", error);
|
|
16841
|
+
// reject({error:""+error, httpStatus:status});
|
|
16842
|
+
// return;
|
|
16843
|
+
// }
|
|
16844
|
+
|
|
16845
|
+
// DBG
|
|
16846
|
+
console.log("~~~~~~~~~~~data :",data);
|
|
16847
|
+
|
|
16848
|
+
data.httpStatus=status;
|
|
16849
|
+
resolve(data);
|
|
16850
|
+
}).catch(error => {
|
|
16851
|
+
// TRACE
|
|
16852
|
+
console.error("Error:", error);
|
|
16853
|
+
reject({error:`${error}`, httpStatus:null});
|
|
16854
|
+
});
|
|
16855
|
+
});
|
|
16856
|
+
}// else :
|
|
16857
|
+
|
|
16858
|
+
// CASE NODEJS CONTEXT :
|
|
16859
|
+
|
|
16860
|
+
// TRACE
|
|
16861
|
+
lognow("INFO : We are running in a nodejs context (isNodeContext:"+isNodeContext+";typeof(require):"+(typeof(require))+"). Using nodejs library.");
|
|
16862
|
+
|
|
16863
|
+
|
|
16864
|
+
const isSecure=(!empty(completeURL) && contains(completeURL.toLowerCase(),"https://"));
|
|
16865
|
+
const httpHandler=isSecure?require("https"):require("http");
|
|
16866
|
+
|
|
16867
|
+
// Options for the HTTP request
|
|
16868
|
+
const options = {
|
|
16869
|
+
url: completeURL,
|
|
16870
|
+
method: httpMethod,
|
|
16871
|
+
};
|
|
16872
|
+
|
|
16873
|
+
if(contains(["POST","PUT"],httpMethod)){
|
|
16874
|
+
options.json=true;
|
|
16875
|
+
}
|
|
16876
|
+
|
|
16877
|
+
options.headers=headers;
|
|
16878
|
+
|
|
16879
|
+
return new Promise((resolve,reject)=>{
|
|
16880
|
+
|
|
16881
|
+
// Create the HTTP request
|
|
16882
|
+
// DOES NOT WORK : const request = httpHandler.request(options, (response) => {
|
|
16883
|
+
// UNLESS YOU SPECIFY in options : hostname, port, path
|
|
16884
|
+
const request = httpHandler.request(completeURL, options, (response) => {
|
|
16885
|
+
|
|
16886
|
+
let responseDataStr = "";
|
|
16887
|
+
|
|
16888
|
+
// A chunk of data has been received.
|
|
16889
|
+
response.on("data", (chunk) => {
|
|
16890
|
+
responseDataStr += chunk;
|
|
16891
|
+
// // DEBUG ONLY
|
|
16892
|
+
// const str = Buffer.from(chunk).toString("utf8");
|
|
16893
|
+
// lognow(">>>str:"+str);
|
|
16894
|
+
});
|
|
16895
|
+
|
|
16896
|
+
// The whole response has been received.
|
|
16897
|
+
response.on("end", () => {
|
|
16898
|
+
|
|
16899
|
+
try{
|
|
16900
|
+
let responseData;
|
|
16901
|
+
try{
|
|
16902
|
+
responseData=parseJSON(responseDataStr);
|
|
16903
|
+
}catch(parseError1){
|
|
16904
|
+
// CAUTION ! TODO : FIXME : We replace in response all single quotes with "`" (egrave) in order to avoid errors !
|
|
16905
|
+
// DEBUG
|
|
16906
|
+
responseDataStr=responseDataStr.replace(/'/gim,"`");
|
|
16907
|
+
try{
|
|
16908
|
+
responseData=parseJSON(responseDataStr);
|
|
16909
|
+
}catch(parseError2){
|
|
16910
|
+
// DBG
|
|
16911
|
+
lognow("WARN : Could not JSON parse the response data ! Must deal with the raw string:«"+responseDataStr+"»", parseError2);
|
|
16912
|
+
resolve( {response:response, responseDataStr:responseDataStr} );
|
|
16913
|
+
return;
|
|
16914
|
+
}
|
|
16915
|
+
}
|
|
16916
|
+
|
|
16917
|
+
// CAUTION : .request(...) => statusCode, .fetch(...) => status (performHTTPRequest(...) uses fetch(...))
|
|
16918
|
+
const status=response.statusCode;
|
|
16919
|
+
// if(status!=200){
|
|
16920
|
+
// const error=nonull(response.statusMessage, "No error message for error code "+status);
|
|
16921
|
+
// // TRACE
|
|
16922
|
+
// console.error("Error:", error);
|
|
16923
|
+
// reject({error:""+error, httpStatus:status});
|
|
16924
|
+
// return;
|
|
16925
|
+
// }
|
|
16926
|
+
|
|
16927
|
+
resolve( {responseData:responseData, response:response, responseDataStr:responseDataStr, httpStatus: status} );
|
|
16928
|
+
}catch(parseError3){
|
|
16929
|
+
// DBG
|
|
16930
|
+
lognow("WARN : Could not JSON parse the response data ! Must deal with the raw string:«"+responseDataStr+"»", parseError3);
|
|
16931
|
+
resolve( {response:response, responseDataStr:responseDataStr} );
|
|
16932
|
+
return;
|
|
16933
|
+
}
|
|
16934
|
+
|
|
16935
|
+
});
|
|
16936
|
+
});
|
|
16937
|
+
|
|
16938
|
+
// Handle errors
|
|
16939
|
+
request.on("error", (error) => {
|
|
16940
|
+
reject({error:error, httpStatus:null});
|
|
16941
|
+
});
|
|
16942
|
+
|
|
16943
|
+
// Not the same way to send parameters, with POST/PUT http method :
|
|
16944
|
+
if(contains(["POST","PUT"],httpMethod) && body){
|
|
16945
|
+
request.write(body);
|
|
16946
|
+
}
|
|
16947
|
+
|
|
16948
|
+
// End the request
|
|
16949
|
+
request.end();
|
|
16950
|
+
|
|
16951
|
+
});
|
|
16952
|
+
|
|
16953
|
+
};
|
|
16954
|
+
|
|
16955
|
+
|
|
16956
|
+
|
|
16957
|
+
|
|
16958
|
+
replacePathVariablesNamesWithValuesIfPossible=function(apiURL, namedArgs){
|
|
16959
|
+
let result=apiURL;
|
|
16960
|
+
foreach(namedArgs,(namedArgValue, namedArgKey)=>{
|
|
16961
|
+
result=result.replace("{"+namedArgKey+"}",namedArgValue);
|
|
16962
|
+
});
|
|
16963
|
+
return result;
|
|
16964
|
+
};
|
|
16965
|
+
|
|
16966
|
+
appendGetParameters=function(apiURL, namedArgsParam){
|
|
16967
|
+
if(nothing(namedArgsParam)) return "";
|
|
16968
|
+
try{
|
|
16969
|
+
|
|
16970
|
+
const namedArgs=isString(namedArgsParam)?parseJSON(namedArgsParam):namedArgsParam;
|
|
16971
|
+
|
|
16972
|
+
let result=apiURL;
|
|
16973
|
+
|
|
16974
|
+
const paramCouples=[];
|
|
16975
|
+
foreach(namedArgs,(value,key)=>{paramCouples.push(key+"="+value);});
|
|
16976
|
+
|
|
16977
|
+
if(!empty(paramCouples)) result+=("?"+paramCouples.join("&"));
|
|
16978
|
+
|
|
16979
|
+
return result;
|
|
16980
|
+
}catch(parseError){
|
|
16981
|
+
// TRACE
|
|
16982
|
+
lognow("ERROR : Could not parse string parameters object «"+namedArgsParam+"», aborting GET parameter request string calculation:", parseError);
|
|
16983
|
+
return "";
|
|
16984
|
+
}
|
|
16985
|
+
};
|
|
16986
|
+
|
|
16987
|
+
|
|
16988
|
+
|
|
16989
|
+
|
|
16990
|
+
|
|
16991
|
+
|
|
16992
|
+
|
|
16993
|
+
|
|
15648
16994
|
/* ## Utility network global methods in a javascript, console (nodejs), or vanilla javascript with no browser environment.
|
|
15649
16995
|
*
|
|
15650
16996
|
* This set of methods gathers utility generic-purpose methods usable in any JS project.
|
aotrautils/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aotrautils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.1830",
|
|
4
4
|
"main": "aotrautils.build.js",
|
|
5
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)",
|