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

Contribution: Superalgos Network: Websockets Implemented
This commit is contained in:
Luis Fernando Molina authored and GitHub committed 2021-08-31 07:32:47 -04:00
commit cf3c1358e1
15 files changed
+511 -165

No files matched your search

+1 -1
View File
@@ -163,7 +163,7 @@ try {
WEB_SOCKETS_INTERFACE = WEB_SOCKETS_INTERFACE.newWebSocketsInterface()
WEB_SOCKETS_INTERFACE.initialize()
WEB_SOCKETS_INTERFACE.run()
console.log('Web Sockets Interface ....................................... Listening at port ' + global.env.WEB_SOCKETS_INTERFACE_PORT)
console.log('Web Sockets Interface ....................................... Listening at port ' + global.env.CLIENT_WEB_SOCKETS_INTERFACE_PORT)
HTTP_INTERFACE = HTTP_INTERFACE.newHttpInterface()
HTTP_INTERFACE.initialize()
+1 -1
View File
@@ -10,7 +10,7 @@
const WEB_SOCKET = require('ws')
let socketServer
let port = global.env.WEB_SOCKETS_INTERFACE_PORT
let port = global.env.CLIENT_WEB_SOCKETS_INTERFACE_PORT
return thisObject
+1 -1
View File
@@ -2,7 +2,7 @@ exports.newEnvironment = function () {
let thisObject = {
WEB_SERVER_URL: 'localhost',
WEB_SOCKETS_INTERFACE_PORT: 18041,
CLIENT_WEB_SOCKETS_INTERFACE_PORT: 18041,
HTTP_INTERFACE_PORT: 34248,
PATH_TO_TASK_SERVER: './TaskServer',
PATH_TO_DATA_STORAGE: './Data-Storage',
+13 -12
View File
@@ -2,20 +2,21 @@ exports.newEnvironment = function () {
let thisObject = {
WEB_SERVER_URL: 'localhost',
WEB_SOCKETS_INTERFACE_PORT: 18041,
CLIENT_WEB_SOCKETS_INTERFACE_PORT: 18041,
NETWORK_WEB_SOCKETS_INTERFACE_PORT: 18042,
HTTP_INTERFACE_PORT: 34248,
PATH_TO_TASK_SERVER: '../TaskServer',
PATH_TO_DATA_STORAGE: '../Data-Storage',
PATH_TO_PROJECTS: '../Projects',
PATH_TO_LOG_FILES: '../Log-Files',
PATH_TO_TASK_SERVER: './TaskServer',
PATH_TO_DATA_STORAGE: './Data-Storage',
PATH_TO_PROJECTS: './Projects',
PATH_TO_LOG_FILES: './Log-Files',
PATH_TO_PROJECTS_REQUIRED: './Projects',
PATH_TO_PROJECT_SCHEMA: '../Projects/ProjectsSchema.json',
PATH_TO_UI: '../UI',
PATH_TO_DATA_FILES: '../UI/Data-Files/src',
PATH_TO_CLIENT: '../Client/',
PATH_TO_DEFAULT_WORKSPACE: '../Projects/Foundations/Plugins/Workspaces',
PATH_TO_MY_WORKSPACES: '../My-Workspaces',
PATH_TO_FONTS: '../Client/WebServer/Fonts'
PATH_TO_PROJECT_SCHEMA: './Projects/ProjectsSchema.json',
PATH_TO_UI: './UI',
PATH_TO_DATA_FILES: './UI/Data-Files/src',
PATH_TO_CLIENT: './Client/',
PATH_TO_DEFAULT_WORKSPACE: './Projects/Foundations/Plugins/Workspaces',
PATH_TO_MY_WORKSPACES: './My-Workspaces',
PATH_TO_FONTS: './Client/WebServer/Fonts'
}
return thisObject
+17 -46
View File
@@ -1,53 +1,24 @@
/*
The Superalgos Network offers 3 types of services:
exports.newNetworkNode = function newNetworkNode() {
* Social Graph Service
* Search Index Service
* Private Message Service
Users can decide which services to run at their node.
let thisObject = {
run: run
}
This module is the starting point of the Network Node.
return thisObject
*/
function run() {
/*
Let's start the Network Interfaces
*/
NT.webSocketsInterface = NT.projects.network.modules.webSocketsInterface.newNetworkModulesWebSocketsInterface()
NT.webSocketsInterface.initialize()
/*
The NT object is accesible everywhere at the Superalgos Network.
It provides access to all modules built for this Network.
*/
global.NT = {}
/*
The SA object is accesible everywhere at the Superalgos Network.
It provides access to all modules built for Superalgos in general.
*/
global.SA = {}
/* Load Environment Variables */
let ENVIRONMENT = require('../EnvironmentForDebug.js');
let ENVIRONMENT_MODULE = ENVIRONMENT.newEnvironment()
global.env = ENVIRONMENT_MODULE
/*
First thing is to load the project schema file.
*/
global.PROJECTS_SCHEMA = require(global.env.PATH_TO_PROJECT_SCHEMA)
/*
Setting up the modules that will be available for the Servers Running inside this Client
*/
let MULTI_PROJECT = require('../MultiProject.js');
let MULTI_PROJECT_MODULE = MULTI_PROJECT.newMultiProject()
MULTI_PROJECT_MODULE.initialize(NT, 'NT')
MULTI_PROJECT_MODULE.initialize(SA, 'SA')
/*
Setting up external dependencies.
*/
SA.nodeModules = {
fs: require('fs'),
nodeFetch: require('node-fetch'),
web3: require('web3')
}
start()
start()
async function start() {
let socialGraphService = NT.projects.network.modules.socialGraph.newSocialGraph()
await socialGraphService.initialize()
}
async function start() {
let socialGraphService = NT.projects.network.modules.socialGraph.newSocialGraph()
await socialGraphService.initialize()
}
}
-87
View File
@@ -1,87 +0,0 @@
exports.newClientInterface = function newClientInterface() {
/*
This module represents the Interface the Network Node have
with Network Clients connected to it. There are two things
Network Clients can do with this Network Node:
* Send an Event that happened at the Network Client to the Network.
* Make a Query to the Network Node for info needed at the Network Client.
*/
let thisObject = {
eventReceived: eventReceived,
queryReceived: queryReceived,
initialize: initialize,
finalize: finalize
}
return thisObject
function finalize() {
}
function initialize() {
}
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 = JSON.parse(eventMessage)
if (NT.projects.network.globals.memory.maps.EVENTS.get(eventReceived.eventId) !== undefined) {
throw ('Event Already Exists.')
}
let event = NT.projects.network.modules.event.newNetworkModulesEvent()
event.initialize(eventReceived)
NT.projects.network.globals.memory.maps.EVENTS.set(eventReceived.eventId, event)
}
function queryReceived(queryMessage) {
/*
We expect here a JSON string with some or all of the following properties:
{
"equeryId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db",
"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 = JSON.parse(queryMessage)
let query = NT.projects.network.modules.queriesQuery.newNetworkModulesQuery()
query.initialize(queryReceived)
return query.execute()
}
}
+6 -5
View File
@@ -4,13 +4,14 @@ exports.newNetworkGlobalsMemory = function () {
*/
let thisObject = {
maps: {
USER_PROFILES_BY_ID: new Map(), // Here we will store the user profiles by User Profile Id.
USER_PROFILES_BY_HANDLE: new Map(), // Here we will store the user profiles by User Profile Handle.
EVENTS: new Map(), // This is the registry of all events received that prevents processing them more than once.
USER_PROFILES_BY_ID: new Map(), // Here we will store the user profiles by User Profile Id.
USER_PROFILES_BY_HANDLE: new Map(), // Here we will store the user profiles by User Profile Handle.
USER_PROFILES_BY_BLOCHAIN_ACCOUNT: new Map(), // Here we will store the user profiles by Blockchain Account.
EVENTS: new Map(), // This is the registry of all events received that prevents processing them more than once.
},
arrays: {
NETWORK_CLIENTS: [], // These are the Network Clients connected to this Network Node ordered by Ranking.
NETWORK_PEERS: [], // These are the Network Peers connected to this Network Node ordered by Ranking.
NETWORK_CLIENTS: [], // These are the Network Clients connected to this Network Node ordered by Ranking.
NETWORK_PEERS: [], // These are the Network Peers connected to this Network Node ordered by Ranking.
}
}
+3 -2
View File
@@ -36,7 +36,7 @@ exports.newBootstrap = function newBootstrap() {
let config = JSON.parse(userProfilePlugin.config)
let signatureObject = config.signature
let web3 = new SA.nodeModules.web3()
let bloackchainAddress = web3.eth.accounts.recover(signatureObject)
let blockchainAccount = web3.eth.accounts.recover(signatureObject)
let ranking = 0 // TODO: read the blockchain balance and transactions from the Treasury Account to calculate the profile ranking.
let userProfileId = userProfilePlugin.id
let userHandle = config.signature.message
@@ -45,12 +45,13 @@ exports.newBootstrap = function newBootstrap() {
userProfile.initialize(
userProfileId,
userHandle,
bloackchainAddress,
blockchainAccount,
ranking
)
NT.projects.network.globals.memory.maps.USER_PROFILES_BY_ID.set(userProfileId, userProfile)
NT.projects.network.globals.memory.maps.USER_PROFILES_BY_HANDLE.set(userHandle, userProfile)
NT.projects.network.globals.memory.maps.USER_PROFILES_BY_BLOCHAIN_ACCOUNT.set(blockchainAccount, userProfile)
}
}
@@ -0,0 +1,208 @@
exports.newNetworkModulesClientInterface = function newNetworkModulesClientInterface() {
/*
This module represents the Interface the Network Node have
with Network Clients connected to it. There are two things
Network Clients can do with this Network Node:
* Send an Event that happened at the Network Client to the Network.
* Make a Query to the Network Node for info needed at the Network Client.
*/
let thisObject = {
messageReceived: messageReceived,
initialize: initialize,
finalize: finalize
}
return thisObject
function finalize() {
}
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 Coorrect JSON Format.'
}
return response
}
if (messageHeader.messageType === undefined) {
let response = {
result: 'Error',
message: 'Client Interface messageType Not Provided.'
}
return response
}
if (messageHeader.messageType !== 'Event' && messageHeader.messageType !== 'Query') {
let response = {
result: 'Error',
message: 'Client Interface messageType Not Supported.'
}
return response
}
switch (messageHeader.messageType) {
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 Coorrect JSON Format.'
}
return response
}
/*
At the Client Interface, events need to be emmitted 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 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.network.modules.event.newNetworkModulesEvent()
event.initialize(eventReceived)
NT.projects.network.globals.memory.maps.EVENTS.set(eventReceived.eventId, 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.
*/
let response = {
result: 'Error',
message: 'Client Interface ' + err.message
}
return response
}
}
async function queryReceived(queryMessage, userProfile) {
/*
We expect here a JSON string with some or all of the following properties:
{
"equeryId": "a8de78f0-c3e4-4a2a-b7e8-f659073969db",
"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 Coorrect JSON Format.'
}
return response
}
/*
At the Client Interface, queries need to be emmitted 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.network.modules.queriesQuery.newNetworkModulesQuery()
query.initialize(queryReceived)
return query.execute()
} catch (err) {
/*
Any exception that happens while trying to execute the query.
*/
let response = {
result: 'Error',
message: 'Client Interface ' + err.message
}
return response
}
}
}
@@ -1,4 +1,4 @@
exports.newPeerInterface = function newPeerInterface() {
exports.newNetworkModulesPeerInterface = function newNetworkModulesPeerInterface() {
let thisObject = {
initialize: initialize,
@@ -0,0 +1,173 @@
exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSocketsInterface() {
let thisObject = {
initialize: initialize,
finalize: finalize
}
let socketServer
let clientInterface
let peerInterface
return thisObject
function finalize() {
socketServer = undefined
clientInterface = undefined
peerInterface = undefined
}
function initialize() {
socketServer = new SA.nodeModules.ws.Server({ port: global.env.NETWORK_WEB_SOCKETS_INTERFACE_PORT })
clientInterface = NT.projects.network.modules.clientInterface.newNetworkModulesClientInterface()
peerInterface = NT.projects.network.modules.peerInterface.newNetworkModulesPeerInterface()
setUpWebSocketServer()
}
function setUpWebSocketServer() {
try {
socketServer.on('connection', onConnection)
function onConnection(socket) {
let caller = {}
socket.on('message', onMenssage)
async function onMenssage(message) {
try {
let messageHeader
try {
messageHeader = JSON.parse(message)
} catch (err) {
let response = {
result: 'Error',
message: 'messageHeader Not Coorrect JSON Format.'
}
socket.send(JSON.stringify(response))
return
}
/*
We will run some validations.
*/
if (messageHeader.messageType === undefined) {
let response = {
result: 'Error',
message: 'messageType Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
switch (messageHeader.messageType) {
case "Handshake": {
handshakeProducedure(socket, caller, messageHeader)
break
}
case "Request": {
if (caller.userProfile === undefined) {
let response = {
result: 'Error',
message: 'Handshake Not Done Yet.'
}
socket.send(JSON.stringify(response))
return
}
switch (caller.role) {
case 'Network Client': {
let response = await clientInterface.messageReceived(messageHeader.payload, caller.userProfile)
socket.send(JSON.stringify(response))
break
}
case 'Network Peer': {
let response = await peerInterface.messageReceived(messageHeader.payload)
socket.send(JSON.stringify(response))
break
}
}
break
}
}
} catch (err) {
console.log('[ERROR] Network -> Web Sockets Interface -> run -> setUpWebSocketServer -> err.stack = ' + err.stack)
}
}
}
function handshakeProducedure(socket, caller, messageHeader) {
/*
The caller needs to identify itself as either a Network Client or Peer.
*/
if (messageHeader.callerRole === undefined) {
let response = {
result: 'Error',
message: 'callerRole Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
if (messageHeader.callerRole !== 'Network Client' && messageHeader.callerRole !== 'Network Peer') {
let response = {
result: 'Error',
message: 'callerRole Not Supported.'
}
socket.send(JSON.stringify(response))
return
}
caller.role = messageHeader.callerRole
/*
We will identify the caller by the signature at the message.
*/
if (messageHeader.signature === undefined) {
let response = {
result: 'Error',
message: 'signature Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
let web3 = new SA.nodeModules.web3()
let blockchainAccount = web3.eth.accounts.recover(messageHeader.signature)
if (caller.blockchainAccount === undefined) {
let response = {
result: 'Error',
message: 'Bad signature.'
}
socket.send(JSON.stringify(response))
return
}
/*
The signature gives us the blockchain account, and the account the user profile.
*/
let userProfile = NT.projects.network.globals.memory.maps.USER_PROFILES_BY_BLOCHAIN_ACCOUNT.set(blockchainAccount)
if (userProfile === undefined) {
let response = {
result: 'Error',
message: 'userProfile Not Found.'
}
socket.send(JSON.stringify(response))
return
}
/*
We will remember the user profile behind this caller.
*/
caller.userProfile = userProfile
let response = {
result: 'Ok',
message: 'Handshake Successful.'
}
socket.send(JSON.stringify(response))
}
} catch (err) {
console.log('[ERROR] Network -> Web Sockets Interface -> run -> setUpWebSocketServer -> err.stack = ' + err.stack)
}
}
}
+18
View File
@@ -1370,6 +1370,24 @@
"propertyName": "event",
"functionName": "newNetworkModulesEvent",
"fileName": "Event.js"
},
{
"name": "Client Interface",
"propertyName": "clientInterface",
"functionName": "newNetworkModulesClientInterface",
"fileName": "ClientInterface.js"
},
{
"name": "Peer Interface",
"propertyName": "peerInterface",
"functionName": "newNetworkModulesPeerInterface",
"fileName": "PeerInterface.js"
},
{
"name": "Web Sockets Interface",
"propertyName": "webSocketsInterface",
"functionName": "newNetworkModulesWebSocketsInterface",
"fileName": "WebSocketsInterface.js"
}
],
"utilities": [
+15 -8
View File
@@ -977,6 +977,18 @@
"servify": "^0.1.12",
"ws": "^3.0.0",
"xhr-request-promise": "^0.1.2"
},
"dependencies": {
"ws": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
"requires": {
"async-limiter": "~1.0.0",
"safe-buffer": "~5.1.0",
"ultron": "~1.1.0"
}
}
}
},
"ethereum-bloom-filters": {
@@ -2945,14 +2957,9 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"ws": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
"requires": {
"async-limiter": "~1.0.0",
"safe-buffer": "~5.1.0",
"ultron": "~1.1.0"
}
"version": "8.2.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.1.tgz",
"integrity": "sha512-XkgWpJU3sHU7gX8f13NqTn6KQ85bd1WU7noBHTT8fSohx7OS1TPY8k+cyRPCzFkia7C4mM229yeHr1qK9sM4JQ=="
},
"xhr": {
"version": "2.6.0",
+2 -1
View File
@@ -1,6 +1,7 @@
{
"dependencies": {
"node-fetch": "^2.6.1",
"web3": "^1.5.2"
"web3": "^1.5.2",
"ws": "^8.2.1"
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
The Superalgos Network offers 3 types of services:
* Social Graph Service
* Search Index Service
* Private Message Service
Users can decide which services to run at their node.(TODO)
This module is the starting point of the Network Node.
*/
/*
The NT object is accesible everywhere at the Superalgos Network.
It provides access to all modules built for this Network.
*/
global.NT = {}
/*
The SA object is accesible everywhere at the Superalgos Network.
It provides access to all modules built for Superalgos in general.
*/
global.SA = {}
/* Load Environment Variables */
let ENVIRONMENT = require('./EnvironmentForDebug.js');
let ENVIRONMENT_MODULE = ENVIRONMENT.newEnvironment()
global.env = ENVIRONMENT_MODULE
/*
First thing is to load the project schema file.
*/
global.PROJECTS_SCHEMA = require(global.env.PATH_TO_PROJECT_SCHEMA)
/*
Setting up the modules that will be available, defined at the Project Schema file.
*/
let MULTI_PROJECT = require('./MultiProject.js');
let MULTI_PROJECT_MODULE = MULTI_PROJECT.newMultiProject()
MULTI_PROJECT_MODULE.initialize(NT, 'NT')
MULTI_PROJECT_MODULE.initialize(SA, 'SA')
/*
Setting up external dependencies.
*/
SA.nodeModules = {
fs: require('fs'),
nodeFetch: require('node-fetch'),
web3: require('web3'),
ws: require('ws')
}
NT.app = require('./Network/NetwokNode.js').newNetworkNode()
NT.app.run()
console.log('Superalgos Network is Running.')