From 8461d6b98ec62e361268507024083ec403727055 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 6 Nov 2021 14:53:44 +0100 Subject: [PATCH 1/5] Bug Fixes --- Environment.js | 4 +- .../Network/NT/Modules/WebSocketsInterface.js | 14 +- .../SA/Modules/WebSocketsNetworkClient.js | 6 +- .../NT/Modules/PeerInterface.js | 216 +++++++++++++++++- 4 files changed, 225 insertions(+), 15 deletions(-) diff --git a/Environment.js b/Environment.js index bb00891ce..2e75c6265 100644 --- a/Environment.js +++ b/Environment.js @@ -11,9 +11,9 @@ exports.newEnvironment = function () { DEMO_MODE: false, BASE_PATH: basePath, WEB_SERVER_URL: 'localhost', - PLATFORM_WEB_SOCKETS_INTERFACE_PORT: 18041, + PLATFORM_WEB_SOCKETS_INTERFACE_PORT: 16042, + DESKTOP_WEB_SOCKETS_INTERFACE_PORT: 17042, NETWORK_WEB_SOCKETS_INTERFACE_PORT: 18042, - DESKTOP_WEB_SOCKETS_INTERFACE_PORT: 18043, DESKTOP_WEB_SOCKETS_INTERFACE_HOST: 'localhost', PLATFORM_HTTP_INTERFACE_PORT: 34248, DESKTOP_HTTP_INTERFACE_PORT: 34249, diff --git a/Projects/Network/NT/Modules/WebSocketsInterface.js b/Projects/Network/NT/Modules/WebSocketsInterface.js index 16c2593e6..73c490818 100644 --- a/Projects/Network/NT/Modules/WebSocketsInterface.js +++ b/Projects/Network/NT/Modules/WebSocketsInterface.js @@ -135,9 +135,9 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock break } } - if (response.result === 'Ok' && messageHeader.payload.requestType === 'Event') { - broadcastToPeers(messageHeader, caller) - broadcastToClients(messageHeader, caller) + if (response.result === 'Ok' && JSON.parse(messageHeader.payload).requestType === 'Event') { + broadcastToPeers(message, caller) + broadcastToClients(message, caller) } break } @@ -491,7 +491,7 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock } } - function broadcastToPeers(messageHeader, caller) { + function broadcastToPeers(message, caller) { let callerIdToAVoid if (caller.role === 'Network Peer') { callerIdToAVoid = caller.socket.id @@ -499,11 +499,11 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock for (let i = 0; i < thisObject.networkPeers.length; i++) { let networkPeer = thisObject.networkPeers[i] if (networkPeer.socket.id === callerIdToAVoid) { continue } - networkPeer.socket.send(messageHeader) + networkPeer.socket.send(message) } } - function broadcastToClients(messageHeader, caller) { + function broadcastToClients(message, caller) { let callerIdToAVoid if (caller.role === 'Network Client') { callerIdToAVoid = caller.socket.id @@ -511,7 +511,7 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock for (let i = 0; i < thisObject.networkClients.length; i++) { let networkClient = thisObject.networkClients[i] if (networkClient.socket.id === callerIdToAVoid) { continue } - networkClient.socket.send(messageHeader) + networkClient.socket.send(message) } } diff --git a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js index 38fed2cea..b6681fe37 100644 --- a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js +++ b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js @@ -41,7 +41,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb socketClient = new SA.nodeModules.ws('ws://' + thisObject.host + ':' + thisObject.port) await setUpWebsocketClient(callerRole, p2pNetworkNode, onConnectionClosedCallBack) - console.log('Websockets Client Connected to Network Node via Web Sockets .............. Connected to ' + p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) + console.log('Websockets Client Connected to Network Node via Web Sockets ................ Connected to ' + p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) thisObject.isConnected = true } @@ -208,7 +208,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb function onConnectionClosed() { if (thisObject.isConnected === true) { - console.log('Websockets Client Connected to Network Node via Web Sockets .............. Disconnected from ' + p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) + console.log('Websockets Client Connected to Network Node via Web Sockets ............... Disconnected from ' + p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) } if (onConnectionClosedCallBack !== undefined) { onConnectionClosedCallBack(thisObject.id) @@ -279,7 +279,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb /* We get the function that is going to resolve or reject the promise given. */ - onMenssageFunction = onMessageFunctionsMap.get(response.messageId) + let onMenssageFunction = onMessageFunctionsMap.get(response.messageId) onMessageFunctionsMap.delete(response.messageId) onMenssageFunction(response) } diff --git a/Projects/Social-Trading/NT/Modules/PeerInterface.js b/Projects/Social-Trading/NT/Modules/PeerInterface.js index e25193d5d..30bf6855c 100644 --- a/Projects/Social-Trading/NT/Modules/PeerInterface.js +++ b/Projects/Social-Trading/NT/Modules/PeerInterface.js @@ -8,9 +8,9 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP websockets interface. */ let thisObject = { + messageReceived: messageReceived, initialize: initialize, - finalize: finalize, - run: run + finalize: finalize } return thisObject @@ -22,8 +22,218 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP function initialize() { } + + async function messageReceived(message, userProfile) { + let messageHeader + try { + messageHeader = JSON.parse(message) + } catch (err) { + let response = { + result: 'Error', + message: 'Client Interface message Not Correct JSON Format.' + } + return response + } - function run() { + if (messageHeader.requestType === undefined) { + let response = { + result: 'Error', + message: 'Client Interface requestType Not Provided.' + } + return response + } + if (messageHeader.requestType !== 'Event' && messageHeader.requestType !== 'Query') { + let response = { + result: 'Error', + message: 'Client Interface requestType Not Supported.' + } + return response + } + + switch (messageHeader.requestType) { + case 'Event': { + return await eventReceived(messageHeader.eventMessage, userProfile) + } + case 'Query': { + return await queryReceived(messageHeader.queryMessage, userProfile) + } + } + } + + async function eventReceived(eventMessage, userProfile) { + /* + We expect here a JSON string with some or all of the following properties: + + { + "eventId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "eventType": 10, + "emitterUserProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "targetUserProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "emitterBotProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "targetBBotProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "emitterPostHash": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "targetPostHash": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "timestamp": 124234234234, + "botAsset": "BTC", + "botExchange": "Binance", + "botEnabled": true + } + */ + + let eventReceived + try { + eventReceived = JSON.parse(eventMessage) + } catch (err) { + let response = { + result: 'Error', + message: 'Client Interface eventMessage Not Correct JSON Format.' + } + return response + } + /* + At the Client Interface, events need to be emitted by the same userProfile that is + connected at the Network Node. + */ + if (eventReceived.emitterUserProfileId !== userProfile.userProfileId) { + let response = { + result: 'Error', + message: 'Client Interface emitterUserProfileId !== userProfileId Connected to Network Node.' + } + return response + } + /* + We will not accept events that don't have an eventId. + */ + if (eventReceived.eventId === undefined) { + let response = { + result: 'Error', + message: 'eventId Not Provided.' + } + return response + } + /* + We will not accept events that have already been processed. + */ + + if (NT.projects.network.globals.memory.maps.EVENTS.get(eventReceived.eventId) !== undefined) { + let response = { + result: 'Error', + message: 'Client Interface Event Already Exists.' + } + return response + } + /* + Here we will process the event and change the state of the Social Graph. + */ + try { + let event = NT.projects.socialTrading.modules.event.newSocialTradingModulesEvent() + event.initialize(eventReceived) + NT.projects.network.globals.memory.maps.EVENTS.set(eventReceived.eventId, event) + NT.projects.network.globals.memory.arrays.EVENTS.push(event) + + let response = { + result: 'Ok', + message: 'Client Interface Event Processed.' + } + return response + + } catch (err) { + /* + Any exception that happens while trying to change the state of the Social Graph, + will be returned to the caller without doing anything else here. + */ + if (err.stack !== undefined) { + console.log('[ERROR] Client Interface -> err.stack = ' + err.stack) + } + let errorMessage = err.message + if (errorMessage === undefined) { errorMessage = err } + let response = { + result: 'Error', + message: 'Client Interface ' + errorMessage + } + return response + } + } + + async function queryReceived(queryMessage, userProfile) { + /* + We expect here a JSON string with some or all of the following properties: + + { + "queryType": 10, + "emitterUserProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "targetUserProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "emitterUserProfileHandle": "Luis-Fernando-Molina", + "targetUserProfileHandle": "Luis-Fernando-Molina", + "emitterBotProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "targetBBotProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "emitterPostHash": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "targetPostHash": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", + "timestamp": 124234234234, + "botAsset": "BTC", + "botExchange": "Binance", + "botEnabled": true, + "initialIndex": 35, + "amountRequested": 50, + "direction": "Past" + } + */ + + let queryReceived + try { + queryReceived = JSON.parse(queryMessage) + } catch (err) { + let response = { + result: 'Error', + message: 'Client Interface queryMessage Not Correct JSON Format.' + } + return response + } + /* + At the Client Interface, queries need to be emitted by the same userProfile that is + connected at the Network Node. + */ + if (queryReceived.emitterUserProfileId !== userProfile.userProfileId) { + let response = { + result: 'Error', + message: 'Client Interface emitterUserProfileId !== userProfileId Connected to Network Node.' + } + return response + } + /* + Here we will process the query. This does not change the state of the Social Graph. + */ + try { + let query = NT.projects.socialTrading.modules.query.newSocialTradingModulesQuery() + query.initialize(queryReceived) + + // console.log((new Date()).toISOString(), '- Client Interface', '- Query Message Received', queryMessage) + + let response = { + result: 'Ok', + message: 'Client Interface Query Processed.', + data: query.execute() + } + + // console.log((new Date()).toISOString(), '- Client Interface', '- Query Response Sent', JSON.stringify(response)) + + return response + + } catch (err) { + /* + Any exception that happens while trying to execute the query. + */ + if (err.stack !== undefined) { + console.log('[ERROR] Client Interface -> err.stack = ' + err.stack) + } + let errorMessage = err.message + if (errorMessage === undefined) { errorMessage = err } + let response = { + result: 'Error', + message: 'Client Interface ' + errorMessage + } + return response + } } } \ No newline at end of file From 5324c943060a7f93801feb1b924b141be852ff4d Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sat, 6 Nov 2021 15:34:07 +0100 Subject: [PATCH 2/5] Defining how to broadcast messages --- .../Network/NT/Modules/WebSocketsInterface.js | 25 ++-- .../SA/Modules/WebSocketsNetworkClient.js | 109 +++++++++++++----- 2 files changed, 90 insertions(+), 44 deletions(-) diff --git a/Projects/Network/NT/Modules/WebSocketsInterface.js b/Projects/Network/NT/Modules/WebSocketsInterface.js index 73c490818..99cee0fc1 100644 --- a/Projects/Network/NT/Modules/WebSocketsInterface.js +++ b/Projects/Network/NT/Modules/WebSocketsInterface.js @@ -12,6 +12,9 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock and sending messages to those entities. */ let thisObject = { + socketServer: undefined, + clientInterface: undefined, + peerInterface: undefined, networkClients: undefined, networkPeers: undefined, callersMap: undefined, @@ -19,10 +22,6 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock finalize: finalize } - let socketServer - let clientInterface - let peerInterface - let web3 = new SA.nodeModules.web3() return thisObject @@ -32,9 +31,9 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock thisObject.networkPeers = undefined callersMap = undefined - socketServer = undefined - clientInterface = undefined - peerInterface = undefined + thisObject.socketServer = undefined + thisObject.clientInterface = undefined + thisObject.peerInterface = undefined web3 = undefined } @@ -42,9 +41,9 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock function initialize() { let port = JSON.parse(NT.networkNode.p2pNetwork.thisNetworkNode.node.config).webSocketsPort - socketServer = new SA.nodeModules.ws.Server({ port: port }) - clientInterface = NT.projects.socialTrading.modules.clientInterface.newSocialTradingModulesClientInterface() - peerInterface = NT.projects.socialTrading.modules.peerInterface.newSocialTradingModulesPeerInterface() + thisObject.socketServer = new SA.nodeModules.ws.Server({ port: port }) + thisObject.clientInterface = NT.projects.socialTrading.modules.clientInterface.newSocialTradingModulesClientInterface() + thisObject.peerInterface = NT.projects.socialTrading.modules.peerInterface.newSocialTradingModulesPeerInterface() thisObject.networkClients = [] thisObject.networkPeers = [] @@ -55,7 +54,7 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock function setUpWebSocketServer() { try { - socketServer.on('connection', onConnectionOpened) + thisObject.socketServer.on('connection', onConnectionOpened) function onConnectionOpened(socket) /* @@ -123,13 +122,13 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock let response switch (caller.role) { case 'Network Client': { - response = await clientInterface.messageReceived(messageHeader.payload, caller.userProfile) + response = await thisObject.clientInterface.messageReceived(messageHeader.payload, caller.userProfile) response.messageId = messageHeader.messageId caller.socket.send(JSON.stringify(response)) break } case 'Network Peer': { - response = await peerInterface.messageReceived(messageHeader.payload) + response = await thisObject.peerInterface.messageReceived(messageHeader.payload) response.messageId = messageHeader.messageId caller.socket.send(JSON.stringify(response)) break diff --git a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js index b6681fe37..a7605f6b9 100644 --- a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js +++ b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js @@ -2,16 +2,18 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb let thisObject = { id: undefined, + socketClient: undefined, isConnected: undefined, host: undefined, port: undefined, + callerRole: undefined, + p2pNetworkNode: undefined, + onConnectionClosedCallBack: undefined, sendMessage: sendMessage, initialize: initialize, finalize: finalize } - let socketClient - let web3 let called = {} let onMessageFunctionsMap = new Map() @@ -19,10 +21,15 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb return thisObject function finalize() { - socketClient.close() - socketClient = undefined - networkInterface = undefined - peerInterface = undefined + thisObject.socketClient.close() + thisObject.socketClient = undefined + thisObject.id = undefined + thisObject.isConnected = undefined + thisObject.host = undefined + thisObject.port = undefined + thisObject.callerRole = undefined + thisObject.p2pNetworkNode = undefined + thisObject.onConnectionClosedCallBack = undefined web3 = undefined called = undefined @@ -31,21 +38,25 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb async function initialize(callerRole, p2pNetworkNode, onConnectionClosedCallBack) { + thisObject.callerRole = callerRole + thisObject.p2pNetworkNode = p2pNetworkNode + thisObject.onConnectionClosedCallBack = onConnectionClosedCallBack + web3 = new SA.nodeModules.web3() thisObject.id = SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId() - thisObject.host = JSON.parse(p2pNetworkNode.node.config).host - thisObject.port = JSON.parse(p2pNetworkNode.node.config).webSocketsPort + thisObject.host = JSON.parse(thisObject.p2pNetworkNode.node.config).host + thisObject.port = JSON.parse(thisObject.p2pNetworkNode.node.config).webSocketsPort - socketClient = new SA.nodeModules.ws('ws://' + thisObject.host + ':' + thisObject.port) - await setUpWebsocketClient(callerRole, p2pNetworkNode, onConnectionClosedCallBack) + thisObject.socketClient = new SA.nodeModules.ws('ws://' + thisObject.host + ':' + thisObject.port) + await setUpWebSocketClient() - console.log('Websockets Client Connected to Network Node via Web Sockets ................ Connected to ' + p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) + console.log('Websockets Client Connected to Network Node via Web Sockets ................ Connected to ' + thisObject.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + thisObject.p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) thisObject.isConnected = true } - async function setUpWebsocketClient(callerRole, p2pNetworkNode, onConnectionClosedCallBack) { + async function setUpWebSocketClient() { return new Promise(connectToNewtwork) @@ -53,9 +64,9 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb try { - socketClient.onopen = () => { onConnectionOpened() } - socketClient.onclose = () => { onConnectionClosed() } - socketClient.onerror = err => { onError(err) } + thisObject.socketClient.onopen = () => { onConnectionOpened() } + thisObject.socketClient.onclose = () => { onConnectionClosed() } + thisObject.socketClient.onerror = err => { onError(err) } function onConnectionOpened() { @@ -79,18 +90,18 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb it's own identity, and later we will sign it's own handle to prove ours. */ - socketClient.onmessage = socketMessage => { stepOneResponse(socketMessage) } + thisObject.socketClient.onmessage = socketMessage => { stepOneResponse(socketMessage) } callerTimestamp = (new Date()).valueOf() let message = { messageType: 'Handshake', - callerRole: callerRole, + callerRole: thisObject.callerRole, callerProfileHandle: SA.secrets.map.get(global.env.DESKTOP_APP_SIGNING_ACCOUNT).userProfileHandle, callerTimestamp: callerTimestamp, step: 'One' } - socketClient.send(JSON.stringify(message)) + thisObject.socketClient.send(JSON.stringify(message)) } function stepOneResponse(socketMessage) { @@ -116,7 +127,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb We will check that the blockchain account taken from the signature matches the one we have on record for the user profile of the Network Node we are calling. */ - if (called.blockchainAccount !== p2pNetworkNode.blockchainAccount) { + if (called.blockchainAccount !== thisObject.p2pNetworkNode.blockchainAccount) { console.log('[ERROR] Web Sockets Client -> stepOneResponse -> The Network Node called does not have the expected Profile Handle.') reject() return @@ -138,7 +149,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb We will check that the Network Node that responded has the same User Profile Handle that we have on record, otherwise something is wrong and we should not proceed. */ - if (signedMessage.calledProfileHandle !== p2pNetworkNode.userProfile.userProfileHandle) { + if (signedMessage.calledProfileHandle !== thisObject.p2pNetworkNode.userProfile.userProfileHandle) { console.log('[ERROR] Web Sockets Client -> stepOneResponse -> The Network Node called does not have the expected Profile Handle.') reject() return @@ -175,7 +186,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb Here we will sign a message with the Network Node profile handle and timestamp to prove our own identity. */ - socketClient.onmessage = socketMessage => { stepTwoResponse(socketMessage) } + thisObject.socketClient.onmessage = socketMessage => { stepTwoResponse(socketMessage) } let signature = web3.eth.accounts.sign(JSON.stringify(signedMessage), SA.secrets.map.get(global.env.DESKTOP_APP_SIGNING_ACCOUNT).privateKey) @@ -184,7 +195,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb signature: JSON.stringify(signature), step: 'Two' } - socketClient.send(JSON.stringify(message)) + thisObject.socketClient.send(JSON.stringify(message)) } function stepTwoResponse(socketMessage) { @@ -200,7 +211,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb Network Node and from now on, all response messages will be received at this following function. */ - socketClient.onmessage = socketMessage => { onMenssage(socketMessage) } + thisObject.socketClient.onmessage = socketMessage => { onMenssage(socketMessage) } resolve() } } @@ -208,10 +219,10 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb function onConnectionClosed() { if (thisObject.isConnected === true) { - console.log('Websockets Client Connected to Network Node via Web Sockets ............... Disconnected from ' + p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) + console.log('Websockets Client Connected to Network Node via Web Sockets ............... Disconnected from ' + thisObject.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + thisObject.p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) } - if (onConnectionClosedCallBack !== undefined) { - onConnectionClosedCallBack(thisObject.id) + if (thisObject.onConnectionClosedCallBack !== undefined) { + thisObject.onConnectionClosedCallBack(thisObject.id) } thisObject.isConnected = false } @@ -229,7 +240,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb } } catch (err) { - console.log('[ERROR] Web Sockets Client -> setUpWebsocketClient -> err.stack = ' + err.stack) + console.log('[ERROR] Web Sockets Client -> setUpWebSocketClient -> err.stack = ' + err.stack) } } @@ -241,7 +252,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb function sendSocketMessage(resolve, reject) { - if (socketClient.readyState !== 1) { // 1 means connected and ready. + if (thisObject.socketClient.readyState !== 1) { // 1 means connected and ready. console.log('[ERROR] Web Sockets Client -> sendMessage -> Cannot send message while connection is closed.') reject('Websockets Connection Not Ready.') return @@ -253,7 +264,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb payload: message } onMessageFunctionsMap.set(socketMessage.messageId, onMenssageFunction) - socketClient.send( + thisObject.socketClient.send( JSON.stringify(socketMessage) ) @@ -280,7 +291,43 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb We get the function that is going to resolve or reject the promise given. */ let onMenssageFunction = onMessageFunctionsMap.get(response.messageId) - onMessageFunctionsMap.delete(response.messageId) - onMenssageFunction(response) + + if (onMenssageFunction !== undefined) { + /* + The message received is a response to a message sent. + */ + onMessageFunctionsMap.delete(response.messageId) + onMenssageFunction(response) + } else { + /* + The message received is a not response to a message sent. + */ + let messageHeader + try { + messageHeader = JSON.parse(message) + } catch (err) { + console.log('[ERROR] Web Sockets Client -> onMenssage -> message = ' + message) + console.log('[ERROR] Web Sockets Client -> onMenssage -> err.stack = ' + err.stack) + thisObject.socketClient.close() + return + } + + switch (thisObject.callerRole) { + case 'Network Client': { + /* + This is the use case of a network client receiving a notification of + somethinig that happened at the network that is relevant to itself. + */ + break + } + case 'Network Peer': { + /* + No use cases so far were a Network Peer would send a message through an + incomming websockets connection, without having received a request first. + */ + break + } + } + } } } \ No newline at end of file From 8b28e9c09be1c5e4e411e3877cdb286cc74a33ae Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 7 Nov 2021 10:33:44 +0100 Subject: [PATCH 3/5] Ready to Test Peer Broadcasting --- Desktop/DesktopApp.js | 76 ++++++++++++------- Network/NetwokNode.js | 76 ++++++++++++------- .../Network/NT/Modules/WebSocketsInterface.js | 45 +++++++++-- Projects/Network/SA/Modules/P2PNetwork.js | 10 --- .../Network/SA/Modules/P2PNetworkClient.js | 27 +++++++ .../Network/SA/Modules/P2PNetworkPeers.js | 2 +- Projects/Network/SA/Modules/UserProfiles.js | 16 +++- .../SA/Modules/WebSocketsNetworkClient.js | 6 +- Projects/ProjectsSchema.json | 6 ++ .../Social-Trading/DK/modules/SocialGraph.js | 4 +- .../Social-Trading/NT/Modules/SocialGraph.js | 5 +- 11 files changed, 188 insertions(+), 85 deletions(-) create mode 100644 Projects/Network/SA/Modules/P2PNetworkClient.js diff --git a/Desktop/DesktopApp.js b/Desktop/DesktopApp.js index 6581230a1..90693c4a7 100644 --- a/Desktop/DesktopApp.js +++ b/Desktop/DesktopApp.js @@ -1,10 +1,12 @@ exports.newDesktopApp = function newDesktopApp() { let thisObject = { - socialGraph: undefined, + userProfiles: undefined, + p2pNetworkClient: undefined, p2pNetwork: undefined, webSocketsClient: undefined, webSocketsInterface: undefined, + socialGraph: undefined, run: run } @@ -13,37 +15,53 @@ exports.newDesktopApp = function newDesktopApp() { return thisObject async function run() { - /* - This is the Personal Social Graph for the user running this App. - */ - thisObject.socialGraph = DK.projects.socialTrading.modules.socialGraph.newSocialTradingModulesSocialGraph() - await thisObject.socialGraph.initialize() - /* - We can join now the P2P Network as a client app. - */ - thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork() - await thisObject.p2pNetwork.initialize('Network Client') - /* - Here we will pick a Network Node from all users profiles available that do have a Network Node running. - */ - let selectedNetworkNode = thisObject.p2pNetwork.p2pNodesToConnect[0] - /* - This is the Web Sockets client that interacts with the Superalgos Network. - */ - thisObject.webSocketsClient = SA.projects.network.modules.webSocketsNetworkClient.newNetworkModulesWebSocketsNetworkClient() - await thisObject.webSocketsClient.initialize('Network Client', selectedNetworkNode) - /* - These are the Network Interfaces by which the Web App interacts with this Desktop Client. - */ - thisObject.webSocketsInterface = DK.projects.socialTrading.modules.webSocketsInterface.newDesktopModulesWebSocketsInterface() - thisObject.webSocketsInterface.initialize() - console.log('Desktop Client Web Sockets Interface ....................................... Listening at port ' + global.env.DESKTOP_WEB_SOCKETS_INTERFACE_PORT) + setupNetwork() + setupServices() + async function setupNetwork() { + /* + We set up ourselves as a Network Client. + */ + thisObject.p2pNetworkClient = SA.projects.network.modules.p2pNetworkClient.newNetworkModulesP2PNetworkClient() + await thisObject.p2pNetworkClient.initialize() + /* + We will read all user profiles plugins and get from there our network identity. + */ + thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles() + await thisObject.userProfiles.initialize(global.env.DESKTOP_APP_SIGNING_ACCOUNT, thisObject.p2pNetworkClient) + /* + We set up the P2P Network. + */ + thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork() + await thisObject.p2pNetwork.initialize('Network Client') + /* + Here we will pick a Network Node from all users profiles available that do have a Network Node running. + */ + let selectedNetworkNode = thisObject.p2pNetwork.p2pNodesToConnect[0] + /* + This is the Web Sockets client that interacts with the Superalgos Network. + */ + thisObject.webSocketsClient = SA.projects.network.modules.webSocketsNetworkClient.newNetworkModulesWebSocketsNetworkClient() + await thisObject.webSocketsClient.initialize('Network Client', thisObject.p2pNetworkClient, selectedNetworkNode) + } - thisObject.httpInterface = DK.projects.socialTrading.modules.httpInterface.newDesktopModulesHttpInterface() - thisObject.httpInterface.initialize() - console.log('Desktop Client Http Interface .............................................. Listening at port ' + global.env.DESKTOP_HTTP_INTERFACE_PORT) + async function setupServices() { + /* + This is the Personal Social Graph for the user running this App. + */ + thisObject.socialGraph = DK.projects.socialTrading.modules.socialGraph.newSocialTradingModulesSocialGraph() + await thisObject.socialGraph.initialize() + /* + These are the Network Interfaces by which the Web App interacts with this Desktop Client. + */ + thisObject.webSocketsInterface = DK.projects.socialTrading.modules.webSocketsInterface.newDesktopModulesWebSocketsInterface() + thisObject.webSocketsInterface.initialize() + console.log('Desktop Client Web Sockets Interface ....................................... Listening at port ' + global.env.DESKTOP_WEB_SOCKETS_INTERFACE_PORT) + thisObject.httpInterface = DK.projects.socialTrading.modules.httpInterface.newDesktopModulesHttpInterface() + thisObject.httpInterface.initialize() + console.log('Desktop Client Http Interface .............................................. Listening at port ' + global.env.DESKTOP_HTTP_INTERFACE_PORT) + } } } diff --git a/Network/NetwokNode.js b/Network/NetwokNode.js index 91fb26487..faa70ab93 100644 --- a/Network/NetwokNode.js +++ b/Network/NetwokNode.js @@ -1,11 +1,13 @@ exports.newNetworkNode = function newNetworkNode() { let thisObject = { + userProfiles: undefined, + p2pNetwork: undefined, + p2pNetworkPeers: undefined, + p2pNetworkNode: undefined, webSocketsInterface: undefined, socialGraphService: undefined, storage: undefined, - p2pNetwork: undefined, - p2pNetworkPeers: undefined, run: run } @@ -14,32 +16,50 @@ exports.newNetworkNode = function newNetworkNode() { return thisObject async function run() { - /* - The Social Graph Service is the first and for now, the only service this Network Node provides. - */ - thisObject.socialGraphService = NT.projects.socialTrading.modules.socialGraph.newNetworkModulesSocialGraph() - await thisObject.socialGraphService.initialize() - /* - The Sotrage deals with persisting the Social Graph. - */ - thisObject.storage = NT.projects.socialTrading.modules.storage.newSocialTradingModulesStorage() - thisObject.storage.initialize() - /* - Let's discover who is at the p2p network. - */ - thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork() - await thisObject.p2pNetwork.initialize('Network Peer') - /* - We can join now the P2P Network as a new peer there. - */ - thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers() - await thisObject.p2pNetworkPeers.initialize() - /* - Other Network Nodes and Client Apps will communicate with this Network Node via it's Websocket Interface. - */ - thisObject.webSocketsInterface = NT.projects.network.modules.webSocketsInterface.newNetworkModulesWebSocketsInterface() - thisObject.webSocketsInterface.initialize() - console.log('Network Node Web Sockets Interface ....................................... Listening at port ' + JSON.parse(NT.networkNode.p2pNetwork.thisNetworkNode.node.config).webSocketsPort) + await setupNetwork() + await setupServices() + + async function setupNetwork() { + /* + We set up ourselves as a Network Node. + */ + thisObject.p2pNetworkNode = SA.projects.network.modules.p2pNetworkNode.newNetworkModulesP2PNetworkNode() + await thisObject.p2pNetworkNode.initialize() + /* + We will read all user profiles plugins and get from there our network identity. + */ + thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles() + await thisObject.userProfiles.initialize(global.env.P2P_NETWORK_NODE_SIGNING_ACCOUNT, thisObject.p2pNetworkNode) + /* + Let's discover who is at the p2p network. + */ + thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork() + await thisObject.p2pNetwork.initialize('Network Peer') + /* + We can join now the P2P Network as a new peer there. + */ + thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers() + await thisObject.p2pNetworkPeers.initialize() + } + + async function setupServices() { + /* + The Social Graph Service is the first and for now, the only service this Network Node provides. + */ + thisObject.socialGraphService = NT.projects.socialTrading.modules.socialGraph.newNetworkModulesSocialGraph() + await thisObject.socialGraphService.initialize() + /* + The Sotrage deals with persisting the Social Graph. + */ + thisObject.storage = NT.projects.socialTrading.modules.storage.newSocialTradingModulesStorage() + thisObject.storage.initialize() + /* + Other Network Nodes and Client Apps will communicate with this Network Node via it's Websocket Interface. + */ + thisObject.webSocketsInterface = NT.projects.network.modules.webSocketsInterface.newNetworkModulesWebSocketsInterface() + thisObject.webSocketsInterface.initialize() + console.log('Network Node Web Sockets Interface ....................................... Listening at port ' + JSON.parse(NT.networkNode.p2pNetworkNode.node.config).webSocketsPort) + } } } diff --git a/Projects/Network/NT/Modules/WebSocketsInterface.js b/Projects/Network/NT/Modules/WebSocketsInterface.js index 99cee0fc1..2ceaf7182 100644 --- a/Projects/Network/NT/Modules/WebSocketsInterface.js +++ b/Projects/Network/NT/Modules/WebSocketsInterface.js @@ -39,7 +39,7 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock } function initialize() { - let port = JSON.parse(NT.networkNode.p2pNetwork.thisNetworkNode.node.config).webSocketsPort + let port = JSON.parse(NT.networkNode.p2pNetworkNode.node.config).webSocketsPort thisObject.socketServer = new SA.nodeModules.ws.Server({ port: port }) thisObject.clientInterface = NT.projects.socialTrading.modules.clientInterface.newSocialTradingModulesClientInterface() @@ -64,7 +64,8 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock let caller = { socket: socket, userProfile: undefined, - role: undefined + role: undefined, + node: undefined } caller.socket.id = SA.projects.foundations.utilities.miscellaneousFunctions.genereteUniqueId() @@ -250,6 +251,32 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock } } /* + The caller needs to provide it's Node. + */ + if (messageHeader.callerNode === undefined) { + let response = { + result: 'Error', + message: 'node Not Provided.' + } + caller.socket.send(JSON.stringify(response)) + caller.socket.close() + return + } + /* + The caller's Node needs to be parseable. + */ + try { + caller.node = JSON.parse(messageHeader.callerNode) + } catch (err) { + let response = { + result: 'Error', + message: 'node Not Coorrect JSON Format.' + } + caller.socket.send(JSON.stringify(response)) + caller.socket.close() + return + } + /* The caller needs to provide it's User Profile Handle. */ if (messageHeader.callerProfileHandle === undefined) { @@ -261,7 +288,6 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock caller.socket.close() return } - caller.userProfileHandle = messageHeader.callerProfileHandle /* The caller needs to provide a callerTimestamp. @@ -491,13 +517,18 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock } function broadcastToPeers(message, caller) { + /* + The Boradcast to network peers is not done via + the network peers incomming connections, but + on the outgoing connections only. + */ let callerIdToAVoid if (caller.role === 'Network Peer') { - callerIdToAVoid = caller.socket.id + callerIdToAVoid = caller.node.id } - for (let i = 0; i < thisObject.networkPeers.length; i++) { - let networkPeer = thisObject.networkPeers[i] - if (networkPeer.socket.id === callerIdToAVoid) { continue } + for (let i = 0; i < NT.networkNode.p2pNetworkPeers.outgoingConnectedPeers.length; i++) { + let networkPeer = NT.networkNode.p2pNetworkPeers.outgoingConnectedPeers[i] + if (networkPeer.p2pNetworkNode.node.id === callerIdToAVoid) { continue } networkPeer.socket.send(message) } } diff --git a/Projects/Network/SA/Modules/P2PNetwork.js b/Projects/Network/SA/Modules/P2PNetwork.js index 131f82e60..9c660c2e4 100644 --- a/Projects/Network/SA/Modules/P2PNetwork.js +++ b/Projects/Network/SA/Modules/P2PNetwork.js @@ -4,9 +4,7 @@ exports.newNetworkModulesP2PNetwork = function newNetworkModulesP2PNetwork() { of this current node to other peers. */ let thisObject = { - joinTheNetworkAsNetworkPeer: joinTheNetworkAsNetworkPeer, p2pNodesToConnect: undefined, - thisNetworkNode: undefined, /* Framework Functions */ initialize: initialize, finalize: finalize @@ -38,18 +36,10 @@ exports.newNetworkModulesP2PNetwork = function newNetworkModulesP2PNetwork() { let p2pNetworkNode = SA.projects.network.globals.memory.arrays.P2P_NETWORK_NODES[i] if (thisP2PNodeId !== p2pNetworkNode.node.id) { thisObject.p2pNodesToConnect.push(p2pNetworkNode) - } else { - thisObject.thisNetworkNode = p2pNetworkNode } } break } } } - - function joinTheNetworkAsNetworkPeer() { - /* - To join the network we will need to thorugh the list of Network Nodes and pick one to connect to. - */ - } } \ No newline at end of file diff --git a/Projects/Network/SA/Modules/P2PNetworkClient.js b/Projects/Network/SA/Modules/P2PNetworkClient.js new file mode 100644 index 000000000..daa0bdb08 --- /dev/null +++ b/Projects/Network/SA/Modules/P2PNetworkClient.js @@ -0,0 +1,27 @@ +exports.newNetworkModulesP2PNetworkClient = function newNetworkModulesP2PNetworkClient() { + /* + This module represents the P2P Network Client running at the moment. + */ + let thisObject = { + + node: undefined, + blockchainAccount: undefined, + userProfile: undefined, + + /* Framework Functions */ + initialize: initialize, + finalize: finalize + } + + return thisObject + + function finalize() { + thisObject.node = undefined + thisObject.blockchainAccount = undefined + thisObject.userProfile = undefined + } + + async function initialize() { + + } +} \ No newline at end of file diff --git a/Projects/Network/SA/Modules/P2PNetworkPeers.js b/Projects/Network/SA/Modules/P2PNetworkPeers.js index e22197804..fe8b5aac0 100644 --- a/Projects/Network/SA/Modules/P2PNetworkPeers.js +++ b/Projects/Network/SA/Modules/P2PNetworkPeers.js @@ -39,7 +39,7 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP peer.p2pNetworkNode = NT.networkNode.p2pNetwork.p2pNodesToConnect[i] if (isOutgoingConnectedPeer(peer) === true) { continue } peer.webSocketsClient = SA.projects.network.modules.webSocketsNetworkClient.newNetworkModulesWebSocketsNetworkClient() - await peer.webSocketsClient.initialize('Network Peer', peer.p2pNetworkNode, onConnectionClosed) + await peer.webSocketsClient.initialize('Network Peer', NT.networkNode.p2pNetworkNode, peer.p2pNetworkNode, onConnectionClosed) .then(addPeer) .catch(onError) diff --git a/Projects/Network/SA/Modules/UserProfiles.js b/Projects/Network/SA/Modules/UserProfiles.js index 48f8a2f76..09df3e54a 100644 --- a/Projects/Network/SA/Modules/UserProfiles.js +++ b/Projects/Network/SA/Modules/UserProfiles.js @@ -18,7 +18,7 @@ exports.newNetworkModulesUserProfiles = function newNetworkModulesUserProfiles() } - async function initialize() { + async function initialize(signingAccountChildCodeName, p2pNetworkIdentity) { let pluginFileNames = await SA.projects.communityPlugins.utilities.plugins.getPluginFileNames( 'Governance', @@ -65,7 +65,7 @@ exports.newNetworkModulesUserProfiles = function newNetworkModulesUserProfiles() let signatureObject = config.signature let web3 = new SA.nodeModules.web3() let blockchainAccount = web3.eth.accounts.recover(signatureObject) - SA.projects.network.globals.memory.maps.USER_PROFILES_BY_BLOKCHAIN_ACCOUNT.set(blockchainAccount, userProfile) + SA.projects.network.globals.memory.maps.USER_PROFILES_BY_BLOKCHAIN_ACCOUNT.set(blockchainAccount, userProfile) /* If the Signing Account is for a P2P node, we will add the node to the array of available nodes at the p2p network. */ @@ -85,12 +85,22 @@ exports.newNetworkModulesUserProfiles = function newNetworkModulesUserProfiles() } if (config.webSocketsPort === undefined) { continue - } + } let p2pNetworkNode = SA.projects.network.modules.p2pNetworkNode.newNetworkModulesP2PNetworkNode() p2pNetworkNode.initialize(signingAccount.signingAccountChild, userProfile, blockchainAccount) SA.projects.network.globals.memory.arrays.P2P_NETWORK_NODES.push(p2pNetworkNode) } + /* + Now, we will extract the information from the User Profile, specifically of our identity at the p2p network. + */ + if ( + signingAccount.signingAccountChild.id === SA.secrets.map.get(signingAccountChildCodeName).signingAccountChildId + ) { + p2pNetworkIdentity.node = signingAccount.signingAccountChild + p2pNetworkIdentity.blockchainAccount = blockchainAccount + p2pNetworkIdentity.userProfile = userProfile + } } } } diff --git a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js index a7605f6b9..4760e1919 100644 --- a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js +++ b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js @@ -8,6 +8,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb port: undefined, callerRole: undefined, p2pNetworkNode: undefined, + p2pNetworkIdentity: undefined, onConnectionClosedCallBack: undefined, sendMessage: sendMessage, initialize: initialize, @@ -29,6 +30,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb thisObject.port = undefined thisObject.callerRole = undefined thisObject.p2pNetworkNode = undefined + thisObject.p2pNetworkIdentity = undefined thisObject.onConnectionClosedCallBack = undefined web3 = undefined @@ -36,9 +38,10 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb onMessageFunctionsMap = undefined } - async function initialize(callerRole, p2pNetworkNode, onConnectionClosedCallBack) { + async function initialize(callerRole, p2pNetworkIdentity, p2pNetworkNode, onConnectionClosedCallBack) { thisObject.callerRole = callerRole + thisObject.p2pNetworkIdentity = p2pNetworkIdentity thisObject.p2pNetworkNode = p2pNetworkNode thisObject.onConnectionClosedCallBack = onConnectionClosedCallBack @@ -99,6 +102,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb callerRole: thisObject.callerRole, callerProfileHandle: SA.secrets.map.get(global.env.DESKTOP_APP_SIGNING_ACCOUNT).userProfileHandle, callerTimestamp: callerTimestamp, + callerNode: JSON.stringify(thisObject.p2pNetworkIdentity.node), step: 'One' } thisObject.socketClient.send(JSON.stringify(message)) diff --git a/Projects/ProjectsSchema.json b/Projects/ProjectsSchema.json index feebfdbbf..93a9be097 100644 --- a/Projects/ProjectsSchema.json +++ b/Projects/ProjectsSchema.json @@ -1419,6 +1419,12 @@ "propertyName": "p2pNetworkPeers", "functionName": "newNetworkModulesP2PNetworkPeers", "fileName": "P2PNetworkPeers.js" + }, + { + "name": "P2P Network Client", + "propertyName": "p2pNetworkClient", + "functionName": "newNetworkModulesP2PNetworkClient", + "fileName": "P2PNetworkClient.js" } ], "utilities": [ diff --git a/Projects/Social-Trading/DK/modules/SocialGraph.js b/Projects/Social-Trading/DK/modules/SocialGraph.js index faf71cee4..7816d51e5 100644 --- a/Projects/Social-Trading/DK/modules/SocialGraph.js +++ b/Projects/Social-Trading/DK/modules/SocialGraph.js @@ -14,7 +14,6 @@ exports.newSocialTradingModulesSocialGraph = function newSocialTradingModulesSoc no need to ask it to a network node. */ let thisObject = { - userProfiles: undefined, initialize: initialize, finalize: finalize } @@ -26,7 +25,6 @@ exports.newSocialTradingModulesSocialGraph = function newSocialTradingModulesSoc } async function initialize() { - thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles() - await thisObject.userProfiles.initialize() + } } \ No newline at end of file diff --git a/Projects/Social-Trading/NT/Modules/SocialGraph.js b/Projects/Social-Trading/NT/Modules/SocialGraph.js index f31c44a43..d3b611439 100644 --- a/Projects/Social-Trading/NT/Modules/SocialGraph.js +++ b/Projects/Social-Trading/NT/Modules/SocialGraph.js @@ -9,7 +9,7 @@ exports.newNetworkModulesSocialGraph = function newNetworkModulesSocialGraph() { their posts. */ let thisObject = { - userProfiles: undefined, + /* Framework Functions */ initialize: initialize, finalize: finalize @@ -22,7 +22,6 @@ exports.newNetworkModulesSocialGraph = function newNetworkModulesSocialGraph() { } async function initialize() { - thisObject.userProfiles = SA.projects.network.modules.userProfiles.newNetworkModulesUserProfiles() - await thisObject.userProfiles.initialize() + } } \ No newline at end of file From 5a281b5de01e3540d928e03a7d00c061ac352754 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 7 Nov 2021 14:12:11 +0100 Subject: [PATCH 4/5] Boradcasting Events to Peers Working --- .../Network/NT/Modules/WebSocketsInterface.js | 28 ++-- .../Network/SA/Modules/P2PNetworkPeers.js | 31 +++-- .../SA/Modules/WebSocketsNetworkClient.js | 30 ++--- .../NT/Modules/PeerInterface.js | 120 +++--------------- 4 files changed, 68 insertions(+), 141 deletions(-) diff --git a/Projects/Network/NT/Modules/WebSocketsInterface.js b/Projects/Network/NT/Modules/WebSocketsInterface.js index 2ceaf7182..af01c391f 100644 --- a/Projects/Network/NT/Modules/WebSocketsInterface.js +++ b/Projects/Network/NT/Modules/WebSocketsInterface.js @@ -136,8 +136,8 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock } } if (response.result === 'Ok' && JSON.parse(messageHeader.payload).requestType === 'Event') { - broadcastToPeers(message, caller) - broadcastToClients(message, caller) + broadcastToPeers(messageHeader, caller) + broadcastToClients(messageHeader, caller) } break } @@ -516,7 +516,7 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock } } - function broadcastToPeers(message, caller) { + function broadcastToPeers(messageHeader, caller) { /* The Boradcast to network peers is not done via the network peers incomming connections, but @@ -526,14 +526,19 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock if (caller.role === 'Network Peer') { callerIdToAVoid = caller.node.id } - for (let i = 0; i < NT.networkNode.p2pNetworkPeers.outgoingConnectedPeers.length; i++) { - let networkPeer = NT.networkNode.p2pNetworkPeers.outgoingConnectedPeers[i] - if (networkPeer.p2pNetworkNode.node.id === callerIdToAVoid) { continue } - networkPeer.socket.send(message) + for (let i = 0; i < NT.networkNode.p2pNetworkPeers.peers.length; i++) { + let peer = NT.networkNode.p2pNetworkPeers.peers[i] + if (peer.p2pNetworkNode.node.id === callerIdToAVoid) { continue } + peer.webSocketsClient.sendMessage(messageHeader.payload) + .catch(onError) + + function onError() { + console.log('[ERROR] Web Sockets Interface -> broadcastToPeers -> Sending Message Failed.') + } } } - function broadcastToClients(message, caller) { + function broadcastToClients(messageHeader, caller) { let callerIdToAVoid if (caller.role === 'Network Client') { callerIdToAVoid = caller.socket.id @@ -541,7 +546,12 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock for (let i = 0; i < thisObject.networkClients.length; i++) { let networkClient = thisObject.networkClients[i] if (networkClient.socket.id === callerIdToAVoid) { continue } - networkClient.socket.send(message) + networkClient.socket.send(messageHeader.payload) + .catch(onError) + + function onError() { + console.log('[ERROR] Web Sockets Interface -> broadcastToPeers -> Sending Message Failed.') + } } } diff --git a/Projects/Network/SA/Modules/P2PNetworkPeers.js b/Projects/Network/SA/Modules/P2PNetworkPeers.js index fe8b5aac0..19e90e8da 100644 --- a/Projects/Network/SA/Modules/P2PNetworkPeers.js +++ b/Projects/Network/SA/Modules/P2PNetworkPeers.js @@ -1,9 +1,9 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkPeers() { /* - This module holds the P2P Nodes we are coonected to and that are connected to us. + This module holds the P2P Nodes we are coonected to. */ let thisObject = { - outgoingConnectedPeers: undefined, + peers: undefined, /* Framework Functions */ initialize: initialize, @@ -16,13 +16,13 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP return thisObject function finalize() { - thisObject.outgoingConnectedPeers = undefined + thisObject.peers = undefined clearInterval(intervalIdConnectToPeers) } async function initialize() { - thisObject.outgoingConnectedPeers = [] + thisObject.peers = [] connectToPeers() intervalIdConnectToPeers = setInterval(connectToPeers, RECONNECT_DELAY); @@ -31,11 +31,16 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP async function connectToPeers() { - if (thisObject.outgoingConnectedPeers.count >= global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS) { return } + if (thisObject.peers.count >= global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS) { return } for (let i = 0; i < NT.networkNode.p2pNetwork.p2pNodesToConnect.length; i++) { - if (thisObject.outgoingConnectedPeers.count >= global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS) { break } - let peer = {} + if (thisObject.peers.count >= global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS) { break } + + let peer = { + p2pNetworkNode: undefined, + webSocketsClient: undefined + } + peer.p2pNetworkNode = NT.networkNode.p2pNetwork.p2pNodesToConnect[i] if (isOutgoingConnectedPeer(peer) === true) { continue } peer.webSocketsClient = SA.projects.network.modules.webSocketsNetworkClient.newNetworkModulesWebSocketsNetworkClient() @@ -44,7 +49,7 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP .catch(onError) function addPeer() { - thisObject.outgoingConnectedPeers.push(peer) + thisObject.peers.push(peer) } function onError(err) { @@ -56,10 +61,10 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP } function onConnectionClosed(webSocketsClientId) { - for (let i = 0; i < thisObject.outgoingConnectedPeers.length; i++) { - let connectedPeer = thisObject.outgoingConnectedPeers[i] + for (let i = 0; i < thisObject.peers.length; i++) { + let connectedPeer = thisObject.peers[i] if (connectedPeer.webSocketsClient.id === webSocketsClientId) { - thisObject.outgoingConnectedPeers.splice(i, 1) + thisObject.peers.splice(i, 1) return } } @@ -67,8 +72,8 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP } function isOutgoingConnectedPeer(peer) { - for (let i = 0; i < thisObject.outgoingConnectedPeers.length; i++) { - let connectedPeer = thisObject.outgoingConnectedPeers[i] + for (let i = 0; i < thisObject.peers.length; i++) { + let connectedPeer = thisObject.peers[i] if (connectedPeer.p2pNetworkNode.node.id === peer.p2pNetworkNode.node.id) { return true } diff --git a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js index 4760e1919..9c028e18c 100644 --- a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js +++ b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js @@ -2,7 +2,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb let thisObject = { id: undefined, - socketClient: undefined, + socket: undefined, isConnected: undefined, host: undefined, port: undefined, @@ -22,8 +22,8 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb return thisObject function finalize() { - thisObject.socketClient.close() - thisObject.socketClient = undefined + thisObject.socket.close() + thisObject.socket = undefined thisObject.id = undefined thisObject.isConnected = undefined thisObject.host = undefined @@ -52,7 +52,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb thisObject.host = JSON.parse(thisObject.p2pNetworkNode.node.config).host thisObject.port = JSON.parse(thisObject.p2pNetworkNode.node.config).webSocketsPort - thisObject.socketClient = new SA.nodeModules.ws('ws://' + thisObject.host + ':' + thisObject.port) + thisObject.socket = new SA.nodeModules.ws('ws://' + thisObject.host + ':' + thisObject.port) await setUpWebSocketClient() console.log('Websockets Client Connected to Network Node via Web Sockets ................ Connected to ' + thisObject.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + thisObject.p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) @@ -67,9 +67,9 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb try { - thisObject.socketClient.onopen = () => { onConnectionOpened() } - thisObject.socketClient.onclose = () => { onConnectionClosed() } - thisObject.socketClient.onerror = err => { onError(err) } + thisObject.socket.onopen = () => { onConnectionOpened() } + thisObject.socket.onclose = () => { onConnectionClosed() } + thisObject.socket.onerror = err => { onError(err) } function onConnectionOpened() { @@ -93,7 +93,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb it's own identity, and later we will sign it's own handle to prove ours. */ - thisObject.socketClient.onmessage = socketMessage => { stepOneResponse(socketMessage) } + thisObject.socket.onmessage = socketMessage => { stepOneResponse(socketMessage) } callerTimestamp = (new Date()).valueOf() @@ -105,7 +105,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb callerNode: JSON.stringify(thisObject.p2pNetworkIdentity.node), step: 'One' } - thisObject.socketClient.send(JSON.stringify(message)) + thisObject.socket.send(JSON.stringify(message)) } function stepOneResponse(socketMessage) { @@ -190,7 +190,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb Here we will sign a message with the Network Node profile handle and timestamp to prove our own identity. */ - thisObject.socketClient.onmessage = socketMessage => { stepTwoResponse(socketMessage) } + thisObject.socket.onmessage = socketMessage => { stepTwoResponse(socketMessage) } let signature = web3.eth.accounts.sign(JSON.stringify(signedMessage), SA.secrets.map.get(global.env.DESKTOP_APP_SIGNING_ACCOUNT).privateKey) @@ -199,7 +199,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb signature: JSON.stringify(signature), step: 'Two' } - thisObject.socketClient.send(JSON.stringify(message)) + thisObject.socket.send(JSON.stringify(message)) } function stepTwoResponse(socketMessage) { @@ -215,7 +215,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb Network Node and from now on, all response messages will be received at this following function. */ - thisObject.socketClient.onmessage = socketMessage => { onMenssage(socketMessage) } + thisObject.socket.onmessage = socketMessage => { onMenssage(socketMessage) } resolve() } } @@ -256,7 +256,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb function sendSocketMessage(resolve, reject) { - if (thisObject.socketClient.readyState !== 1) { // 1 means connected and ready. + if (thisObject.socket.readyState !== 1) { // 1 means connected and ready. console.log('[ERROR] Web Sockets Client -> sendMessage -> Cannot send message while connection is closed.') reject('Websockets Connection Not Ready.') return @@ -268,7 +268,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb payload: message } onMessageFunctionsMap.set(socketMessage.messageId, onMenssageFunction) - thisObject.socketClient.send( + thisObject.socket.send( JSON.stringify(socketMessage) ) @@ -312,7 +312,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb } catch (err) { console.log('[ERROR] Web Sockets Client -> onMenssage -> message = ' + message) console.log('[ERROR] Web Sockets Client -> onMenssage -> err.stack = ' + err.stack) - thisObject.socketClient.close() + thisObject.socket.close() return } diff --git a/Projects/Social-Trading/NT/Modules/PeerInterface.js b/Projects/Social-Trading/NT/Modules/PeerInterface.js index 30bf6855c..344e356c5 100644 --- a/Projects/Social-Trading/NT/Modules/PeerInterface.js +++ b/Projects/Social-Trading/NT/Modules/PeerInterface.js @@ -23,14 +23,14 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP } - async function messageReceived(message, userProfile) { + async function messageReceived(message) { let messageHeader try { messageHeader = JSON.parse(message) } catch (err) { let response = { result: 'Error', - message: 'Client Interface message Not Correct JSON Format.' + message: 'Peer Interface message Not Correct JSON Format.' } return response } @@ -38,7 +38,7 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP if (messageHeader.requestType === undefined) { let response = { result: 'Error', - message: 'Client Interface requestType Not Provided.' + message: 'Peer Interface requestType Not Provided.' } return response } @@ -46,22 +46,26 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP if (messageHeader.requestType !== 'Event' && messageHeader.requestType !== 'Query') { let response = { result: 'Error', - message: 'Client Interface requestType Not Supported.' + message: 'Peer Interface requestType Not Supported.' } return response } switch (messageHeader.requestType) { case 'Event': { - return await eventReceived(messageHeader.eventMessage, userProfile) + return await eventReceived(messageHeader.eventMessage) } case 'Query': { - return await queryReceived(messageHeader.queryMessage, userProfile) + let response = { + result: 'Error', + message: 'Peer Interface requestType Query Not Supported.' + } + return response } } } - async function eventReceived(eventMessage, userProfile) { + async function eventReceived(eventMessage) { /* We expect here a JSON string with some or all of the following properties: @@ -87,18 +91,7 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP } catch (err) { let response = { result: 'Error', - message: 'Client Interface eventMessage Not Correct JSON Format.' - } - return response - } - /* - At the Client Interface, events need to be emitted by the same userProfile that is - connected at the Network Node. - */ - if (eventReceived.emitterUserProfileId !== userProfile.userProfileId) { - let response = { - result: 'Error', - message: 'Client Interface emitterUserProfileId !== userProfileId Connected to Network Node.' + message: 'Peer Interface eventMessage Not Correct JSON Format.' } return response } @@ -119,7 +112,7 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP if (NT.projects.network.globals.memory.maps.EVENTS.get(eventReceived.eventId) !== undefined) { let response = { result: 'Error', - message: 'Client Interface Event Already Exists.' + message: 'Peer Interface Event Already Exists.' } return response } @@ -134,7 +127,7 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP let response = { result: 'Ok', - message: 'Client Interface Event Processed.' + message: 'Peer Interface Event Processed.' } return response @@ -144,94 +137,13 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP will be returned to the caller without doing anything else here. */ if (err.stack !== undefined) { - console.log('[ERROR] Client Interface -> err.stack = ' + err.stack) + console.log('[ERROR] Peer Interface -> err.stack = ' + err.stack) } let errorMessage = err.message if (errorMessage === undefined) { errorMessage = err } let response = { result: 'Error', - message: 'Client Interface ' + errorMessage - } - return response - } - } - - async function queryReceived(queryMessage, userProfile) { - /* - We expect here a JSON string with some or all of the following properties: - - { - "queryType": 10, - "emitterUserProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", - "targetUserProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", - "emitterUserProfileHandle": "Luis-Fernando-Molina", - "targetUserProfileHandle": "Luis-Fernando-Molina", - "emitterBotProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", - "targetBBotProfileId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", - "emitterPostHash": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", - "targetPostHash": "a8de78f0-c3e4-4a2a-b7e8-f659073969db", - "timestamp": 124234234234, - "botAsset": "BTC", - "botExchange": "Binance", - "botEnabled": true, - "initialIndex": 35, - "amountRequested": 50, - "direction": "Past" - } - */ - - let queryReceived - try { - queryReceived = JSON.parse(queryMessage) - } catch (err) { - let response = { - result: 'Error', - message: 'Client Interface queryMessage Not Correct JSON Format.' - } - return response - } - /* - At the Client Interface, queries need to be emitted by the same userProfile that is - connected at the Network Node. - */ - if (queryReceived.emitterUserProfileId !== userProfile.userProfileId) { - let response = { - result: 'Error', - message: 'Client Interface emitterUserProfileId !== userProfileId Connected to Network Node.' - } - return response - } - /* - Here we will process the query. This does not change the state of the Social Graph. - */ - try { - let query = NT.projects.socialTrading.modules.query.newSocialTradingModulesQuery() - query.initialize(queryReceived) - - // console.log((new Date()).toISOString(), '- Client Interface', '- Query Message Received', queryMessage) - - let response = { - result: 'Ok', - message: 'Client Interface Query Processed.', - data: query.execute() - } - - // console.log((new Date()).toISOString(), '- Client Interface', '- Query Response Sent', JSON.stringify(response)) - - return response - - } catch (err) { - /* - Any exception that happens while trying to execute the query. - */ - if (err.stack !== undefined) { - console.log('[ERROR] Client Interface -> err.stack = ' + err.stack) - } - let errorMessage = err.message - if (errorMessage === undefined) { errorMessage = err } - let response = { - result: 'Error', - message: 'Client Interface ' + errorMessage + message: 'Peer Interface ' + errorMessage } return response } From 8024d0c476d6479f7c6cf5f21362ea3534bac1ef Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Sun, 7 Nov 2021 16:04:00 +0100 Subject: [PATCH 5/5] Superalgos P2P Network: Desktop connecting to multiple Network Peers --- Desktop/DesktopApp.js | 16 ++-- Environment.js | 1 + Network/NetwokNode.js | 9 +- .../Network/SA/Modules/P2PNetworkPeers.js | 89 +++++++++++-------- .../SA/Modules/WebSocketsNetworkClient.js | 2 +- .../DK/modules/WebAppInterface.js | 4 +- .../NT/Modules/PeerInterface.js | 2 +- 7 files changed, 73 insertions(+), 50 deletions(-) diff --git a/Desktop/DesktopApp.js b/Desktop/DesktopApp.js index 90693c4a7..5da36f492 100644 --- a/Desktop/DesktopApp.js +++ b/Desktop/DesktopApp.js @@ -4,6 +4,7 @@ exports.newDesktopApp = function newDesktopApp() { userProfiles: undefined, p2pNetworkClient: undefined, p2pNetwork: undefined, + p2pNetworkPeers: undefined, webSocketsClient: undefined, webSocketsInterface: undefined, socialGraph: undefined, @@ -36,14 +37,15 @@ exports.newDesktopApp = function newDesktopApp() { thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork() await thisObject.p2pNetwork.initialize('Network Client') /* - Here we will pick a Network Node from all users profiles available that do have a Network Node running. + Set up the connections to network nodes. */ - let selectedNetworkNode = thisObject.p2pNetwork.p2pNodesToConnect[0] - /* - This is the Web Sockets client that interacts with the Superalgos Network. - */ - thisObject.webSocketsClient = SA.projects.network.modules.webSocketsNetworkClient.newNetworkModulesWebSocketsNetworkClient() - await thisObject.webSocketsClient.initialize('Network Client', thisObject.p2pNetworkClient, selectedNetworkNode) + thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers() + await thisObject.p2pNetworkPeers.initialize( + 'Network Client', + thisObject.p2pNetworkClient, + thisObject.p2pNetwork, + global.env.DESKTOP_APP_MAX_OUTGOING_PEERS + ) } async function setupServices() { diff --git a/Environment.js b/Environment.js index 2e75c6265..04b9a78a4 100644 --- a/Environment.js +++ b/Environment.js @@ -28,6 +28,7 @@ exports.newEnvironment = function () { PATH_TO_MY_WORKSPACES: path.join(basePath, './Platform/My-Workspaces'), PATH_TO_FONTS: path.join(basePath, './Platform/WebServer/Fonts'), DESKTOP_APP_SIGNING_ACCOUNT: 'Social-Trading-Desktop-App-1', + DESKTOP_APP_MAX_OUTGOING_PEERS: 2, MOBILE_APP_SIGNING_ACCOUNT: 'Social-Trading-Mobile-App-1', SERVER_APP_SIGNING_ACCOUNT: 'Social-Trading-Server-App-1', PLATFORM_APP_SIGNING_ACCOUNT: 'Algo-Traders-Platform-1', diff --git a/Network/NetwokNode.js b/Network/NetwokNode.js index faa70ab93..8edc1c6f4 100644 --- a/Network/NetwokNode.js +++ b/Network/NetwokNode.js @@ -37,10 +37,15 @@ exports.newNetworkNode = function newNetworkNode() { thisObject.p2pNetwork = SA.projects.network.modules.p2pNetwork.newNetworkModulesP2PNetwork() await thisObject.p2pNetwork.initialize('Network Peer') /* - We can join now the P2P Network as a new peer there. + Set up the connections to network nodes. */ thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers() - await thisObject.p2pNetworkPeers.initialize() + await thisObject.p2pNetworkPeers.initialize( + 'Network Peer', + thisObject.p2pNetworkNode, + thisObject.p2pNetwork, + global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS + ) } async function setupServices() { diff --git a/Projects/Network/SA/Modules/P2PNetworkPeers.js b/Projects/Network/SA/Modules/P2PNetworkPeers.js index 19e90e8da..a11e388d3 100644 --- a/Projects/Network/SA/Modules/P2PNetworkPeers.js +++ b/Projects/Network/SA/Modules/P2PNetworkPeers.js @@ -4,6 +4,7 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP */ let thisObject = { peers: undefined, + sendMessage: sendMessage, /* Framework Functions */ initialize: initialize, @@ -20,64 +21,78 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP clearInterval(intervalIdConnectToPeers) } - async function initialize() { + async function initialize( + callerRole, + p2pNetworkIdentity, + p2pNetwork, + maxOutgoingPeers + ) { thisObject.peers = [] connectToPeers() intervalIdConnectToPeers = setInterval(connectToPeers, RECONNECT_DELAY); - } + async function connectToPeers() { - async function connectToPeers() { + if (thisObject.peers.length >= maxOutgoingPeers) { return } - if (thisObject.peers.count >= global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS) { return } + for (let i = 0; i < p2pNetwork.p2pNodesToConnect.length; i++) { + if (thisObject.peers.length >= maxOutgoingPeers) { break } - for (let i = 0; i < NT.networkNode.p2pNetwork.p2pNodesToConnect.length; i++) { - if (thisObject.peers.count >= global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS) { break } - - let peer = { - p2pNetworkNode: undefined, - webSocketsClient: undefined - } + let peer = { + p2pNetworkNode: undefined, + webSocketsClient: undefined + } - peer.p2pNetworkNode = NT.networkNode.p2pNetwork.p2pNodesToConnect[i] - if (isOutgoingConnectedPeer(peer) === true) { continue } - peer.webSocketsClient = SA.projects.network.modules.webSocketsNetworkClient.newNetworkModulesWebSocketsNetworkClient() - await peer.webSocketsClient.initialize('Network Peer', NT.networkNode.p2pNetworkNode, peer.p2pNetworkNode, onConnectionClosed) - .then(addPeer) - .catch(onError) + peer.p2pNetworkNode = p2pNetwork.p2pNodesToConnect[i] + if (isConnectedPeer(peer) === true) { continue } + peer.webSocketsClient = SA.projects.network.modules.webSocketsNetworkClient.newNetworkModulesWebSocketsNetworkClient() + await peer.webSocketsClient.initialize(callerRole, p2pNetworkIdentity, peer.p2pNetworkNode, onConnectionClosed) + .then(addPeer) + .catch(onError) - function addPeer() { - thisObject.peers.push(peer) - } + function addPeer() { + thisObject.peers.push(peer) + } - function onError(err) { - if (err !== undefined) { - console.log('[ERROR] P2P Network Peers -> onError -> While connecting to node -> ' + peer.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + peer.p2pNetworkNode.node.name + ' -> ' + err.message) - } else { - console.log('[WARN] P2P Network Peers -> onError -> Peer Not Available at the Moment -> ' + peer.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + peer.p2pNetworkNode.node.name) + function onError(err) { + if (err !== undefined) { + console.log('[ERROR] P2P Network Peers -> onError -> While connecting to node -> ' + peer.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + peer.p2pNetworkNode.node.name + ' -> ' + err.message) + } else { + console.log('[WARN] P2P Network Peers -> onError -> Peer Not Available at the Moment -> ' + peer.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + peer.p2pNetworkNode.node.name) + } + } + + function onConnectionClosed(webSocketsClientId) { + for (let i = 0; i < thisObject.peers.length; i++) { + let connectedPeer = thisObject.peers[i] + if (connectedPeer.webSocketsClient.id === webSocketsClientId) { + thisObject.peers.splice(i, 1) + return + } + } } } - function onConnectionClosed(webSocketsClientId) { + function isConnectedPeer(peer) { for (let i = 0; i < thisObject.peers.length; i++) { let connectedPeer = thisObject.peers[i] - if (connectedPeer.webSocketsClient.id === webSocketsClientId) { - thisObject.peers.splice(i, 1) - return + if (connectedPeer.p2pNetworkNode.node.id === peer.p2pNetworkNode.node.id) { + return true } } } } + } - function isOutgoingConnectedPeer(peer) { - for (let i = 0; i < thisObject.peers.length; i++) { - let connectedPeer = thisObject.peers[i] - if (connectedPeer.p2pNetworkNode.node.id === peer.p2pNetworkNode.node.id) { - return true - } - } - } + async function sendMessage(message) { + /* + This function will send the message from a random picked network node + selected from the array of already connected peers. + */ + let peerIndex = Math.max(Math.round(Math.random() * thisObject.peers.length) - 1, 0) + let peer = thisObject.peers[peerIndex] + return await peer.webSocketsClient.sendMessage(message) } } \ No newline at end of file diff --git a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js index 9c028e18c..1542e743f 100644 --- a/Projects/Network/SA/Modules/WebSocketsNetworkClient.js +++ b/Projects/Network/SA/Modules/WebSocketsNetworkClient.js @@ -223,7 +223,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb function onConnectionClosed() { if (thisObject.isConnected === true) { - console.log('Websockets Client Connected to Network Node via Web Sockets ............... Disconnected from ' + thisObject.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + thisObject.p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) + console.log('Websockets Client Disconnected from Network Node via Web Sockets ......... Disconnected from ' + thisObject.p2pNetworkNode.userProfile.userProfileHandle + ' -> ' + thisObject.p2pNetworkNode.node.name + ' -> ' + thisObject.host + ':' + thisObject.port) } if (thisObject.onConnectionClosedCallBack !== undefined) { thisObject.onConnectionClosedCallBack(thisObject.id) diff --git a/Projects/Social-Trading/DK/modules/WebAppInterface.js b/Projects/Social-Trading/DK/modules/WebAppInterface.js index d4b522dd7..96830e81e 100644 --- a/Projects/Social-Trading/DK/modules/WebAppInterface.js +++ b/Projects/Social-Trading/DK/modules/WebAppInterface.js @@ -58,11 +58,11 @@ exports.newSocialTradingModulesWebAppInterface = function newSocialTradingModule response = { result: 'Ok', message: 'Web App Interface Query Processed.', - data: await DK.desktopApp.webSocketsClient.sendMessage(JSON.stringify(messageHeader)) + data: await DK.desktopApp.p2pNetworkPeers.sendMessage(JSON.stringify(messageHeader)) } } else { - let events = await DK.desktopApp.webSocketsClient.sendMessage(JSON.stringify(messageHeader)) + let events = await DK.desktopApp.p2pNetworkPeers.sendMessage(JSON.stringify(messageHeader)) for (let i = 0; i < events.length; i++) { let event = events[i] if (event.eventType === SA.projects.socialTrading.globals.eventTypes.NEW_USER_POST) { diff --git a/Projects/Social-Trading/NT/Modules/PeerInterface.js b/Projects/Social-Trading/NT/Modules/PeerInterface.js index 344e356c5..29ff7c114 100644 --- a/Projects/Social-Trading/NT/Modules/PeerInterface.js +++ b/Projects/Social-Trading/NT/Modules/PeerInterface.js @@ -111,7 +111,7 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP if (NT.projects.network.globals.memory.maps.EVENTS.get(eventReceived.eventId) !== undefined) { let response = { - result: 'Error', + result: 'Ok', message: 'Peer Interface Event Already Exists.' } return response