Merge pull request #2537 from Luis-Fernando-Molina/develop

Contribution: Superalgos P2P Network: Desktop connecting to multiple Network Peers
This commit is contained in:
Luis Fernando Molina authored and GitHub committed 2021-11-07 11:06:45 -04:00
commit b3462c8697
14 files changed
+487 -178

No files matched your search

+49 -29
View File
@@ -1,10 +1,13 @@
exports.newDesktopApp = function newDesktopApp() {
let thisObject = {
socialGraph: undefined,
userProfiles: undefined,
p2pNetworkClient: undefined,
p2pNetwork: undefined,
p2pNetworkPeers: undefined,
webSocketsClient: undefined,
webSocketsInterface: undefined,
socialGraph: undefined,
run: run
}
@@ -13,37 +16,54 @@ 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')
/*
Set up the connections to network nodes.
*/
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
)
}
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)
}
}
}
+3 -2
View File
@@ -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,
@@ -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',
+53 -28
View File
@@ -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,55 @@ 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')
/*
Set up the connections to network nodes.
*/
thisObject.p2pNetworkPeers = SA.projects.network.modules.p2pNetworkPeers.newNetworkModulesP2PNetworkPeers()
await thisObject.p2pNetworkPeers.initialize(
'Network Peer',
thisObject.p2pNetworkNode,
thisObject.p2pNetwork,
global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS
)
}
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)
}
}
}
@@ -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,19 +31,19 @@ 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
}
function initialize() {
let port = JSON.parse(NT.networkNode.p2pNetwork.thisNetworkNode.node.config).webSocketsPort
let port = JSON.parse(NT.networkNode.p2pNetworkNode.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)
/*
@@ -65,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()
@@ -123,19 +123,19 @@ 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
}
}
if (response.result === 'Ok' && messageHeader.payload.requestType === 'Event') {
if (response.result === 'Ok' && JSON.parse(messageHeader.payload).requestType === 'Event') {
broadcastToPeers(messageHeader, caller)
broadcastToClients(messageHeader, caller)
}
@@ -251,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) {
@@ -262,7 +288,6 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock
caller.socket.close()
return
}
caller.userProfileHandle = messageHeader.callerProfileHandle
/*
The caller needs to provide a callerTimestamp.
@@ -492,14 +517,24 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock
}
function broadcastToPeers(messageHeader, 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 }
networkPeer.socket.send(messageHeader)
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.')
}
}
}
@@ -511,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(messageHeader)
networkClient.socket.send(messageHeader.payload)
.catch(onError)
function onError() {
console.log('[ERROR] Web Sockets Interface -> broadcastToPeers -> Sending Message Failed.')
}
}
}
-10
View File
@@ -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.
*/
}
}
@@ -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() {
}
}
+59 -39
View File
@@ -1,9 +1,10 @@
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,
sendMessage: sendMessage,
/* Framework Functions */
initialize: initialize,
@@ -16,63 +17,82 @@ exports.newNetworkModulesP2PNetworkPeers = function newNetworkModulesP2PNetworkP
return thisObject
function finalize() {
thisObject.outgoingConnectedPeers = undefined
thisObject.peers = undefined
clearInterval(intervalIdConnectToPeers)
}
async function initialize() {
async function initialize(
callerRole,
p2pNetworkIdentity,
p2pNetwork,
maxOutgoingPeers
) {
thisObject.outgoingConnectedPeers = []
thisObject.peers = []
connectToPeers()
intervalIdConnectToPeers = setInterval(connectToPeers, RECONNECT_DELAY);
}
async function connectToPeers() {
async function connectToPeers() {
if (thisObject.peers.length >= maxOutgoingPeers) { return }
if (thisObject.outgoingConnectedPeers.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.outgoingConnectedPeers.count >= global.env.P2P_NETWORK_NODE_MAX_OUTGOING_PEERS) { break }
let peer = {}
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)
.then(addPeer)
.catch(onError)
let peer = {
p2pNetworkNode: undefined,
webSocketsClient: undefined
}
function addPeer() {
thisObject.outgoingConnectedPeers.push(peer)
}
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 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 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 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) {
for (let i = 0; i < thisObject.outgoingConnectedPeers.length; i++) {
let connectedPeer = thisObject.outgoingConnectedPeers[i]
if (connectedPeer.webSocketsClient.id === webSocketsClientId) {
thisObject.outgoingConnectedPeers.splice(i, 1)
return
function isConnectedPeer(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
}
}
}
}
}
function isOutgoingConnectedPeer(peer) {
for (let i = 0; i < thisObject.outgoingConnectedPeers.length; i++) {
let connectedPeer = thisObject.outgoingConnectedPeers[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)
}
}
+13 -3
View File
@@ -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
}
}
}
}
@@ -2,16 +2,19 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb
let thisObject = {
id: undefined,
socket: undefined,
isConnected: undefined,
host: undefined,
port: undefined,
callerRole: undefined,
p2pNetworkNode: undefined,
p2pNetworkIdentity: undefined,
onConnectionClosedCallBack: undefined,
sendMessage: sendMessage,
initialize: initialize,
finalize: finalize
}
let socketClient
let web3
let called = {}
let onMessageFunctionsMap = new Map()
@@ -19,33 +22,44 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb
return thisObject
function finalize() {
socketClient.close()
socketClient = undefined
networkInterface = undefined
peerInterface = undefined
thisObject.socket.close()
thisObject.socket = undefined
thisObject.id = undefined
thisObject.isConnected = undefined
thisObject.host = undefined
thisObject.port = undefined
thisObject.callerRole = undefined
thisObject.p2pNetworkNode = undefined
thisObject.p2pNetworkIdentity = undefined
thisObject.onConnectionClosedCallBack = undefined
web3 = undefined
called = undefined
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
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.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 ' + 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 +67,9 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb
try {
socketClient.onopen = () => { onConnectionOpened() }
socketClient.onclose = () => { onConnectionClosed() }
socketClient.onerror = err => { onError(err) }
thisObject.socket.onopen = () => { onConnectionOpened() }
thisObject.socket.onclose = () => { onConnectionClosed() }
thisObject.socket.onerror = err => { onError(err) }
function onConnectionOpened() {
@@ -79,18 +93,19 @@ 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.socket.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,
callerNode: JSON.stringify(thisObject.p2pNetworkIdentity.node),
step: 'One'
}
socketClient.send(JSON.stringify(message))
thisObject.socket.send(JSON.stringify(message))
}
function stepOneResponse(socketMessage) {
@@ -116,7 +131,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 +153,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 +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.
*/
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)
@@ -184,7 +199,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb
signature: JSON.stringify(signature),
step: 'Two'
}
socketClient.send(JSON.stringify(message))
thisObject.socket.send(JSON.stringify(message))
}
function stepTwoResponse(socketMessage) {
@@ -200,7 +215,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.socket.onmessage = socketMessage => { onMenssage(socketMessage) }
resolve()
}
}
@@ -208,10 +223,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 Disconnected from 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 +244,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 +256,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb
function sendSocketMessage(resolve, reject) {
if (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
@@ -253,7 +268,7 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb
payload: message
}
onMessageFunctionsMap.set(socketMessage.messageId, onMenssageFunction)
socketClient.send(
thisObject.socket.send(
JSON.stringify(socketMessage)
)
@@ -279,8 +294,44 @@ exports.newNetworkModulesWebSocketsNetworkClient = function newNetworkModulesWeb
/*
We get the function that is going to resolve or reject the promise given.
*/
onMenssageFunction = onMessageFunctionsMap.get(response.messageId)
onMessageFunctionsMap.delete(response.messageId)
onMenssageFunction(response)
let onMenssageFunction = onMessageFunctionsMap.get(response.messageId)
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.socket.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
}
}
}
}
}
+6
View File
@@ -1419,6 +1419,12 @@
"propertyName": "p2pNetworkPeers",
"functionName": "newNetworkModulesP2PNetworkPeers",
"fileName": "P2PNetworkPeers.js"
},
{
"name": "P2P Network Client",
"propertyName": "p2pNetworkClient",
"functionName": "newNetworkModulesP2PNetworkClient",
"fileName": "P2PNetworkClient.js"
}
],
"utilities": [
@@ -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()
}
}
@@ -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) {
@@ -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,130 @@ exports.newSocialTradingModulesPeerInterface = function newSocialTradingModulesP
function initialize() {
}
async function messageReceived(message) {
let messageHeader
try {
messageHeader = JSON.parse(message)
} catch (err) {
let response = {
result: 'Error',
message: 'Peer Interface message Not Correct JSON Format.'
}
return response
}
function run() {
if (messageHeader.requestType === undefined) {
let response = {
result: 'Error',
message: 'Peer Interface requestType Not Provided.'
}
return response
}
if (messageHeader.requestType !== 'Event' && messageHeader.requestType !== 'Query') {
let response = {
result: 'Error',
message: 'Peer Interface requestType Not Supported.'
}
return response
}
switch (messageHeader.requestType) {
case 'Event': {
return await eventReceived(messageHeader.eventMessage)
}
case 'Query': {
let response = {
result: 'Error',
message: 'Peer Interface requestType Query Not Supported.'
}
return response
}
}
}
async function eventReceived(eventMessage) {
/*
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: 'Peer Interface eventMessage Not Correct JSON Format.'
}
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: 'Ok',
message: 'Peer 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: 'Peer 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] Peer Interface -> err.stack = ' + err.stack)
}
let errorMessage = err.message
if (errorMessage === undefined) { errorMessage = err }
let response = {
result: 'Error',
message: 'Peer Interface ' + errorMessage
}
return response
}
}
}
@@ -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()
}
}