added base simulation
This commit is contained in:
BIN
Simulation/__pycache__/library.cpython-313.pyc
Normal file
BIN
Simulation/__pycache__/library.cpython-313.pyc
Normal file
Binary file not shown.
143
Simulation/library.py
Normal file
143
Simulation/library.py
Normal file
@@ -0,0 +1,143 @@
|
||||
import ctypes
|
||||
from ctypes import Structure, c_char_p, c_int, cdll
|
||||
from dataclasses import dataclass, astuple
|
||||
import time
|
||||
import json
|
||||
from urllib.parse import urlparse
|
||||
from typing import List
|
||||
import subprocess
|
||||
import uuid
|
||||
import dacite
|
||||
import os
|
||||
import sqlalchemy
|
||||
import dataclasses
|
||||
from typing import Union
|
||||
import schedule
|
||||
import threading
|
||||
import requests
|
||||
import subprocess
|
||||
|
||||
# p2prc.Init("")
|
||||
|
||||
# Start running schedule
|
||||
schedule.run_pending()
|
||||
|
||||
# # Create Sqlite database to track processes
|
||||
# engine=sqlalchemy.create_engine(f'sqlite:///homeserver.db')
|
||||
|
||||
# Global variable
|
||||
# A global variable will be populated on runtime.
|
||||
# It is read from P2PRC directly or from a local
|
||||
# database.
|
||||
|
||||
# Node information
|
||||
# Generated using: https://jsonformatter.org/json-to-python
|
||||
@dataclass
|
||||
class Node:
|
||||
Name: str
|
||||
MachineUsername: str
|
||||
IPV4: str
|
||||
IPV6: str
|
||||
Latency: int
|
||||
Download: int
|
||||
Upload: int
|
||||
ServerPort: str
|
||||
BareMetalSSHPort: str
|
||||
NAT: bool
|
||||
EscapeImplementation: str
|
||||
ProxyServer: bool
|
||||
UnSafeMode: bool
|
||||
PublicKey: str
|
||||
CustomInformation: str
|
||||
|
||||
@dataclass
|
||||
class IPAddress:
|
||||
ip_address: List[Node]
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# ----------------------------- Helper functions -----------------------------
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
p2prc = None
|
||||
|
||||
def LoadDLL(envPath=""):
|
||||
global p2prc
|
||||
# os.environ["P2PRC"] = envPath
|
||||
print(envPath)
|
||||
# env = "P2PRC=" + envPath
|
||||
os.system("sh setEnv.sh " + envPath)
|
||||
# subprocess.call("sh setEnv.sh " + envPath)
|
||||
p2prc = ctypes.CDLL("SharedObjects/p2prc.so")
|
||||
|
||||
|
||||
def StartServer():
|
||||
# Starting P2PRC as a server mode
|
||||
p2prc.Server()
|
||||
|
||||
def Init():
|
||||
p2prc.Init("")
|
||||
|
||||
# Class to create string to pass as string function
|
||||
# parameter to shared object file
|
||||
class go_string(Structure):
|
||||
_fields_ = [
|
||||
("p", c_char_p),
|
||||
("n", c_int)]
|
||||
|
||||
# Ensuring local port can escape NAT and responds
|
||||
# with the public ip and port no.
|
||||
# If the domain name is specified then the public IP
|
||||
# can be used as an A name entry.
|
||||
def P2PRCMapPort(port="",domainname="",serveraddress=""):
|
||||
port = go_string(c_char_p(port.encode('utf-8')), len(port))
|
||||
domainname = go_string(c_char_p(domainname.encode('utf-8')), len(domainname))
|
||||
serveraddress = go_string(c_char_p(serveraddress.encode('utf-8')), len(serveraddress))
|
||||
|
||||
# Defining the response type of the GoLang function
|
||||
# function
|
||||
p2prc.MapPort.restype = c_char_p
|
||||
# Calling the Go function
|
||||
address = p2prc.MapPort(port,domainname,serveraddress)
|
||||
res = str(address).strip("b'")
|
||||
return res
|
||||
|
||||
# Lists all avaliable nodes in the network
|
||||
def ListNodes():
|
||||
# View IP Table information
|
||||
p2prc.ViewIPTable.restype = c_char_p
|
||||
ipTable = p2prc.ViewIPTable()
|
||||
# View IP Table as
|
||||
ipTableObject = json.loads((str(ipTable).strip("b'")))
|
||||
dat: IPAddress = dacite.from_dict(IPAddress,ipTableObject)
|
||||
return dat
|
||||
|
||||
# Add a root node to P2RRC and overwrites all other nodes.
|
||||
# To be only added before the network started and with
|
||||
# the intention of a fresh protocol.
|
||||
def AddRootNode(ip="", port="") -> bool:
|
||||
ip = go_string(c_char_p(ip.encode('utf-8')), len(ip))
|
||||
port = go_string(c_char_p(port.encode('utf-8')), len(port))
|
||||
|
||||
p2prc.AddRootNode.restype = c_char_p
|
||||
res = p2prc.AddRootNode(ip, port)
|
||||
if str(res).strip("b'") == "Success":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# python function to pass-through custom
|
||||
# information to interpret which can be
|
||||
# interpreted as a DSL.
|
||||
def AddCustomInformation(message="") -> bool:
|
||||
message = go_string(c_char_p(message.encode('utf-8')), len(message))
|
||||
|
||||
p2prc.CustomInformation.restype = c_char_p
|
||||
status = p2prc.CustomInformation(message)
|
||||
if str(status).strip("b'") == "Success":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
6
Simulation/requests
Normal file
6
Simulation/requests
Normal file
@@ -0,0 +1,6 @@
|
||||
dacite
|
||||
schedule
|
||||
sqlalchemy
|
||||
dacite
|
||||
schedule
|
||||
sqlalchemy
|
||||
4
Simulation/requirements.txt
Normal file
4
Simulation/requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
dacite
|
||||
schedule
|
||||
sqlalchemy
|
||||
requests
|
||||
1
Simulation/setEnv.sh
Normal file
1
Simulation/setEnv.sh
Normal file
@@ -0,0 +1 @@
|
||||
export P2PRC=$1
|
||||
145
Simulation/simulation.py
Normal file
145
Simulation/simulation.py
Normal file
@@ -0,0 +1,145 @@
|
||||
# This repo consists of the P2PRC simulation to ensure
|
||||
# that we can test various nodes locally with just processes.
|
||||
# Note: This implementation is for local nodes only.
|
||||
|
||||
from library import *
|
||||
import os
|
||||
import socket
|
||||
from contextlib import closing
|
||||
|
||||
# Stores the base information
|
||||
# required to know about a P2PRC node
|
||||
@dataclass
|
||||
class P2PRCNode:
|
||||
Name: str
|
||||
ConfigLocation: str
|
||||
ServerPort: str
|
||||
RunningState: bool
|
||||
RootNodePort: str
|
||||
|
||||
@dataclass
|
||||
class P2PRCNodes:
|
||||
P2PRCNodes: List[P2PRCNode]
|
||||
|
||||
# Tracker for P2PRC nodes
|
||||
PublicP2PRCNodes: Union[P2PRCNodes, None] = None
|
||||
|
||||
# Tracker of root Node
|
||||
RootNode: P2PRCNode
|
||||
|
||||
# Sets up P2PRC with default configuration
|
||||
def SetupP2PRCNode(name=""):
|
||||
# Unset environment variables
|
||||
os.environ.pop('P2PRC', None)
|
||||
# Create Test folder
|
||||
Dirname = "P2PRC-Test-" + name
|
||||
try:
|
||||
os.mkdir(Dirname)
|
||||
print(f"Directory '{Dirname}' created successfully.")
|
||||
except FileExistsError:
|
||||
print(f"Directory '{Dirname}' already exists.")
|
||||
KillProcedure()
|
||||
|
||||
# Set env variable for session
|
||||
envPath = os.path.abspath(os.getcwd()) + "/" + Dirname
|
||||
LoadDLL(envPath)
|
||||
|
||||
# Generate random 4
|
||||
ServerPortNo = str(find_free_port())
|
||||
|
||||
# Initialise data class
|
||||
p2prcNode = P2PRCNode(
|
||||
Name = name,
|
||||
ConfigLocation = envPath,
|
||||
ServerPort = ServerPortNo,
|
||||
RunningState = True,
|
||||
RootNodePort = "",
|
||||
)
|
||||
|
||||
# Adds P2PRC node to memory
|
||||
AddP2PRCNodeToMemory(p2prcNode)
|
||||
|
||||
# Initialise P2PRC instance
|
||||
Init()
|
||||
|
||||
# Add root node to ip table
|
||||
AddRootNode("0.0.0.0",ServerPortNo)
|
||||
|
||||
# Change server port no on Config
|
||||
ChangeFileValue(envPath + "/config.json", "ServerPort", ServerPortNo)
|
||||
|
||||
thread = threading.Thread(target = StartServer)
|
||||
thread.start()
|
||||
|
||||
|
||||
# Find free TCP port avaliable
|
||||
# Source: https://stackoverflow.com/questions/1365265/on-localhost-how-do-i-pick-a-free-port-number
|
||||
def find_free_port():
|
||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
|
||||
s.bind(('', 0))
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
return s.getsockname()[1]
|
||||
|
||||
# Standard function called after
|
||||
# a simulation is terminated or
|
||||
# when error exception is called
|
||||
def KillProcedure():
|
||||
RemoveAllP2PRCNodesFromMemoryAndConfigFile()
|
||||
|
||||
# -------------------------- helper functions -----------------------
|
||||
def ChangeFileValue(file_path, key, new_value):
|
||||
"""
|
||||
Reads a JSON file, updates a key with a new value, and writes it back.
|
||||
|
||||
:param file_path: Path to the JSON file
|
||||
:param key: Key in the JSON to update
|
||||
:param new_value: New value to assign to the key
|
||||
"""
|
||||
# Read from the JSON file
|
||||
with open(file_path, 'r') as file:
|
||||
data = json.load(file)
|
||||
|
||||
# Update the key with the new value
|
||||
data[key] = new_value
|
||||
|
||||
# Write the updated data back to the JSON file
|
||||
with open(file_path, 'w') as file:
|
||||
json.dump(data, file, indent=4)
|
||||
|
||||
# Adds the process dataclass the to
|
||||
# the global variable PublicProcess.
|
||||
def AddP2PRCNodeToMemory(p2prcNode: P2PRCNode):
|
||||
global PublicP2PRCNodes
|
||||
global RootNode
|
||||
if PublicP2PRCNodes == None:
|
||||
PublicP2PRCNodes = P2PRCNodes(P2PRCNodes=[p2prcNode])
|
||||
p2prcNode.RootNodePort = p2prcNode.ServerPort
|
||||
RootNode = p2prcNode
|
||||
else:
|
||||
p2prcNode.RootNodePort = RootNode.ServerPort
|
||||
PublicP2PRCNodes.P2PRCNodes.append(p2prcNode)
|
||||
|
||||
# Remove all nodes test nodes generated
|
||||
def RemoveAllP2PRCNodesFromMemoryAndConfigFile():
|
||||
global PublicP2PRCNodes
|
||||
if PublicP2PRCNodes is not None:
|
||||
for node in PublicP2PRCNodes.P2PRCNodes:
|
||||
config_path = node.ConfigLocation
|
||||
# Safely remove the folder if it exists
|
||||
if os.path.exists(config_path) and os.path.isdir(config_path):
|
||||
try:
|
||||
shutil.rmtree(config_path)
|
||||
print(f"Deleted folder: {config_path}")
|
||||
except Exception as e:
|
||||
print(f"Failed to delete {config_path}: {e}")
|
||||
# Clear the node list
|
||||
PublicP2PRCNodes = None
|
||||
print("All P2PRC nodes removed from memory.")
|
||||
else:
|
||||
print("No P2PRC nodes to remove.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Setting up 2 P2PRC nodes
|
||||
SetupP2PRCNode(name="Test")
|
||||
SetupP2PRCNode(name="Test1")
|
||||
14
Simulation/test.py
Normal file
14
Simulation/test.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from library import *
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
P2PRCNodes = ListNodes()
|
||||
# Print nodes in the network
|
||||
print(P2PRCNodes)
|
||||
|
||||
# Add custom information to the network
|
||||
if AddCustomInformation("Test"):
|
||||
print("It worked")
|
||||
|
||||
if AddRootNode("0.0.0.0", "8081"):
|
||||
print("It worked for adding root node")
|
||||
Reference in New Issue
Block a user