114 Commits

Author SHA1 Message Date
36930be8e4 added write config support 2025-06-28 12:03:56 +01:00
be1f3308ca Merge branch 'master' of github.com:Akilan1999/p2p-rendering-computation 2025-06-07 14:07:53 +01:00
b3fcc10cd8 fixed p2prc docs 2025-06-07 14:06:55 +01:00
Akilan Selvacoumar
301a87e758 Update README.md 2025-06-06 20:43:47 +01:00
c9f4c8b5c7 added p2prc haskell logo 2025-06-06 17:00:19 +01:00
10b3c6bae3 fixed folder copied inside 2025-06-06 16:16:46 +01:00
d4e73e9d34 added manual installation documentation 2025-06-06 15:59:37 +01:00
4c7deb948f added haskell build instruction 2025-06-06 15:43:48 +01:00
54a675e0c0 changed command line argument for testing 2025-06-06 14:24:26 +01:00
3c3cfac5e2 fixed pass through custom information 2025-06-04 15:51:07 +01:00
6a24da74ef removed index.org~ from main directory 2025-06-03 15:22:05 +01:00
0fe1b0c622 fixed incorrect documentation use 2025-06-03 15:09:45 +01:00
7d3fc9b25f added generated docs html 2025-06-03 15:02:14 +01:00
Akilan Selvacoumar
6281b0f532 Merge pull request #128 from xecarlox94/nix
Nix template addition
2025-06-03 14:46:16 +01:00
1711b01979 finished documentation 2025-06-02 23:59:23 +01:00
438b4d0424 fixed coding bugs, refined text 2025-06-02 21:05:22 +01:00
22c5d61082 finished mvp for nix templating 2025-06-02 00:43:50 +01:00
a1bf13cac3 finishing automated setup 2025-06-02 00:37:28 +01:00
616bf76bda finishing automated setup 2025-06-02 00:31:29 +01:00
539bceee7d finishing automated setup 2025-06-02 00:31:04 +01:00
69b9ea3527 finishing automated setup 2025-06-02 00:11:59 +01:00
27f4615cd1 finishing automated setup 2025-06-02 00:07:53 +01:00
01e19d9a8c adding git actions 2025-06-02 00:03:24 +01:00
aafc0ebdd7 adding git actions 2025-06-01 23:54:25 +01:00
9de0b1b985 adding git actions 2025-06-01 23:52:00 +01:00
4c12d74789 adding git actions 2025-06-01 23:50:41 +01:00
f06df58a8a adding git actions 2025-06-01 23:47:11 +01:00
30004d59c6 adding git actions 2025-06-01 23:44:57 +01:00
4c8cde8857 adding git actions 2025-06-01 23:34:01 +01:00
994c52faf0 adding git actions 2025-06-01 23:25:41 +01:00
5e65381377 adding git actions 2025-06-01 20:57:38 +01:00
ff66d55153 adding git actions 2025-06-01 20:54:38 +01:00
50983dbb19 adding git actions 2025-06-01 20:50:49 +01:00
189edd73b1 adding git actions 2025-06-01 20:48:59 +01:00
27670f2408 adding git actions 2025-06-01 19:55:00 +01:00
b301a54fba adding git actions 2025-06-01 19:53:33 +01:00
05e29aab0d adding git actions 2025-06-01 19:47:17 +01:00
b883feb825 adding git actions 2025-06-01 19:44:43 +01:00
5059444d26 adding git actions 2025-06-01 19:42:23 +01:00
be3be96987 adding git actions 2025-06-01 19:39:32 +01:00
682424074f adding git actions 2025-06-01 19:36:41 +01:00
9d0ec3eba4 adding git actions 2025-06-01 19:34:32 +01:00
bf87217b9a adding git actions 2025-06-01 19:27:52 +01:00
e4638232d3 adding git actions 2025-06-01 19:24:56 +01:00
fb6c3ab091 adding new version for p2prc-hs bootstrapping 2025-06-01 15:12:16 +01:00
a59657a93b removing wasm file 2025-05-31 15:18:27 +01:00
30ea1f810a Merge remote-tracking branch 'refs/remotes/principal/master' 2025-05-31 11:11:00 +01:00
fe72625266 removed erroneous commands 2025-05-31 10:44:10 +01:00
d2030b7d74 updating lock versions 2025-05-31 00:17:59 +01:00
73a283a545 another attempt to test bootstrapping 2025-05-31 00:07:50 +01:00
623cfffb6a another attempt to test bootstrapping 2025-05-31 00:05:04 +01:00
3669fdfad2 adding initHaskellProject to bootstrap project 2025-05-30 23:56:03 +01:00
f39fab04ce adding initHaskellProject to bootstrap project 2025-05-30 23:41:34 +01:00
12ff0ceb37 adding initHaskellProject to bootstrap project 2025-05-30 23:36:27 +01:00
99c62a8dca adding initHaskellProject to bootstrap project 2025-05-30 23:32:49 +01:00
ce5c80a10e adding initHaskellProject to bootstrap project 2025-05-30 23:31:40 +01:00
46ef4e1db9 adding initHaskellProject to bootstrap project 2025-05-30 23:29:28 +01:00
14743f7f9b adding initHaskellProject to bootstrap project 2025-05-30 23:27:10 +01:00
a461c2da64 adding initHaskellProject to bootstrap project 2025-05-30 23:02:06 +01:00
99c9c41528 Documentation for Simulation added 2025-05-30 18:06:32 +01:00
0e260cf8e4 Made simulation simple 2025-05-30 17:10:54 +01:00
02e58493f5 added working version of simulator 2025-05-30 17:09:36 +01:00
a46ec3575c Simulation base code 2025-05-30 16:23:39 +01:00
2d55643dd9 removed heavy WASM binary 2025-05-30 11:59:32 +01:00
1ac0647d46 refactoring nix flake template 2025-05-30 00:04:43 +01:00
a07a412c72 temporary fix to test remote flake init 2025-05-29 23:52:14 +01:00
e04e918328 fixed haskell template 2025-05-29 23:36:11 +01:00
0bb949a1e2 fixed overlay and templates 2025-05-29 23:34:08 +01:00
cf6611087a adding haskell template providing dev/prod environments 2025-05-29 23:29:55 +01:00
b1a69189d3 adding haskell template providing dev/prod environments 2025-05-29 23:20:21 +01:00
ad76773111 adding haskell template providing dev/prod environments 2025-05-29 23:13:11 +01:00
ec46f74c4e adding haskell template providing dev/prod environments 2025-05-29 23:10:12 +01:00
3fb225676f fixed devshell environment 2025-05-29 00:23:42 +01:00
0e86459122 fixed p2prc-hs issue 2025-05-28 22:25:09 +01:00
77ebb76838 updating flake 2025-05-28 00:04:49 +01:00
85806ab035 refactoring flake code 2025-05-27 23:49:08 +01:00
9d92ecb202 working on template for haskell 2025-05-27 23:22:47 +01:00
5fa625160e improving overlays 2025-05-26 21:26:40 +01:00
403ad72ddb fixing environment 2025-05-26 21:08:11 +01:00
6446681719 renaming overlay file 2025-05-26 01:16:03 +01:00
d50534e270 improving executable exposure 2025-05-26 01:06:42 +01:00
8a2dfb7b5b fixed haskell development environment 2025-05-26 00:15:36 +01:00
0f4f52cb8b working on haskell development shell 2025-05-26 00:06:11 +01:00
cd8bb2df8c removed redundant code from flake 2025-05-25 23:45:44 +01:00
fa5b7a27d5 fixed overlays typo 2025-05-25 23:17:03 +01:00
21f0fc79c1 removed executable from haskell project 2025-05-25 22:07:26 +01:00
bebe2a02a0 improving nix flake for haskell library bootstrapping 2025-05-25 19:09:41 +01:00
7b0b2404b2 improving overlay 2025-05-24 17:59:16 +01:00
724daf5eda preparing overlays for build system 2025-05-24 16:58:08 +01:00
c262e612e1 preparing overlays for build system 2025-05-24 16:53:01 +01:00
257d91a432 fixing nix development and build environments 2025-05-21 23:11:56 +01:00
42cf9bd028 fixing nix env 2025-05-20 23:51:33 +01:00
7c34c5385a fix abstraction 2025-05-17 23:30:58 +01:00
d79c28c32f added kill docs script 2025-04-28 23:22:22 +01:00
Akilan Selvacoumar
7b0d36873b Merge pull request #127 from Akilan1999/add-root-node
Added feature to add root node
2025-04-28 23:17:49 +01:00
2283736cc6 added language bindings, python implementation and docs for the feature add
root node
2025-04-28 23:15:35 +01:00
51b253df15 added feature to add root node 2025-04-28 22:22:29 +01:00
b9f5dec9de added static server 2025-04-25 23:53:00 +01:00
30b464449c added basic static server 2025-04-25 23:50:56 +01:00
ffd711f448 added run docs server locally 2025-04-25 23:40:18 +01:00
0d01d70c2b renamed docs directory 2025-04-25 23:22:39 +01:00
6b1edd3d8a revert back docs directory 2025-04-25 23:18:19 +01:00
5cf1e144aa moved docs to root folder 2025-04-25 23:07:24 +01:00
Akilan Selvacoumar
f605e2e06b Merge pull request #126 from Akilan1999/simulation
Haskell and Documentation fixes
2025-04-25 22:31:32 +01:00
873caa911c modified docs 2025-04-25 22:27:39 +01:00
73a470e201 comment out config behavoir since only used for prints 2025-04-25 21:23:42 +01:00
805514edfa uniform variable naming haskell 2025-04-25 20:56:54 +01:00
Akilan Selvacoumar
5e3a4e8b7a Merge pull request #125 from Akilan1999/python-addcustom-information
Python addcustom information
2025-04-25 13:05:38 +01:00
5f8407a37f added comment 2025-04-24 23:28:19 +01:00
a6939ec35e added python function call add custom information 2025-04-24 23:15:02 +01:00
Akilan Selvacoumar
c445ac88c4 Merge pull request #124 from Akilan1999/python-bindings
Python bindings (Base function calls)
2025-04-24 22:17:02 +01:00
9075ab5967 added python bindings 2025-04-24 15:51:47 +01:00
125d113ade added base python bindings 2025-04-07 20:25:25 +01:00
e7e0641f31 removed syscall kill 2025-04-07 18:52:18 +01:00
57 changed files with 2720 additions and 1636 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1,49 +0,0 @@
name: Deploy Jekyll with GitHub Pages dependencies preinstalled
on:
# Runs on pushes targeting the default branch
push:
branches: ["main", "master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Pages
uses: actions/configure-pages@v2
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1

4
.gitignore vendored
View File

@@ -31,6 +31,7 @@ server/docker/containers/
# generic folder to ignore
export/
exports/
# Any testing file
*test
@@ -43,6 +44,9 @@ p2prc.PublicKeyBareMetal
# Ignore pem files
*.pem
# ignore virtual env file
venv
# Nix and Nix flake files
result
result-*

View File

@@ -142,6 +142,24 @@ func MapPort(Port string, DomainName string, ServerAddress string) *C.char {
return C.CString(Address.EntireAddress)
}
//export CustomInformation
func CustomInformation(CustomInformation string) *C.char {
err := abstractions.AddCustomInformation(CustomInformation)
if err != nil {
return C.CString(err.Error())
}
return C.CString("Success")
}
//export AddRootNode
func AddRootNode(IP string, Port string) *C.char {
err := abstractions.AddRootNode(IP, Port)
if err != nil {
return C.CString(err.Error())
}
return C.CString("Success")
}
// --------------------------------- Controlling Server ----------------------------------------
//export Server

2
Bindings/Haskell/.mhsi Normal file
View File

@@ -0,0 +1,2 @@
exit
Exit

View File

@@ -15,7 +15,6 @@
|--------------|-----------------------------------------|
| Copyright | Copyright (C) 2006-2024 John MacFarlane |
| License | GNU GPL, version 2 or above |
| Maintainer | John MacFarlane \<jgm@berkeley.edu\> |
| Stability | alpha |
| Portability | portable |
| Safe Haskell | Safe-Inferred |

View File

@@ -18,23 +18,41 @@
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gomod2nix": {
"inputs": {
"flake-utils": [
"p2prc",
"p2prc-main",
"flake-utils"
],
"nixpkgs": [
"p2prc",
"p2prc-main",
"nixpkgs"
]
},
"locked": {
"lastModified": 1733668782,
"narHash": "sha256-tPsqU00FhgdFr0JiQUiBMgPVbl1jbPCY5gbFiJycL3I=",
"lastModified": 1745875161,
"narHash": "sha256-0YkWCS13jpoo3+sX/3kcgdxBNt1VZTmvF+FhZb4rFKI=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "514283ec89c39ad0079ff2f3b1437404e4cba608",
"rev": "2cbd7fdd6eeab65c494cc426e18f4e4d2a5e35c0",
"type": "github"
},
"original": {
@@ -57,11 +75,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1735834308,
"narHash": "sha256-dklw3AXr3OGO4/XT1Tu3Xz9n/we8GctZZ75ZWVqAVhk=",
"lastModified": 1748026106,
"narHash": "sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6df24922a1400241dae323af55f30e4318a6ca65",
"rev": "063f43f2dbdef86376cc29ad646c45c46e93234c",
"type": "github"
},
"original": {
@@ -71,28 +89,28 @@
"type": "github"
}
},
"p2prc": {
"p2prc-main": {
"inputs": {
"flake-utils": "flake-utils",
"flake-utils": "flake-utils_2",
"gomod2nix": "gomod2nix",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 0,
"narHash": "sha256-f4e4JcQzBS+R+8HqJbQVeecInm2ggInJuSSymj6gtQo=",
"path": "/nix/store/hmk8v0lxifsscll054qsdnzxqfql1998-source",
"narHash": "sha256-5qbaxawuLsg8iu9076zlAbLtTFSNJaTz7WERS5rWRxU=",
"path": "/nix/store/lg694r23fzc6v5ai3qqcszq1fp44djg2-source",
"type": "path"
},
"original": {
"path": "/nix/store/hmk8v0lxifsscll054qsdnzxqfql1998-source",
"path": "/nix/store/lg694r23fzc6v5ai3qqcszq1fp44djg2-source",
"type": "path"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"p2prc": "p2prc",
"utils": "utils"
"p2prc-main": "p2prc-main"
}
},
"systems": {
@@ -124,24 +142,6 @@
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",

View File

@@ -1,24 +1,28 @@
{
description = "Nix flake for P2PRC Haskell library";
inputs = {
p2prc.url = "../../";
utils.url = "github:numtide/flake-utils";
flake-utils.url = "github:numtide/flake-utils";
p2prc-main.url = "../../";
};
outputs = { self, nixpkgs, utils, p2prc }: utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
cabal-install
haskell.compiler.ghc96
zlib.dev
p2prc.outputs.packages.${system}.default
];
};
}
);
outputs = { nixpkgs, flake-utils, p2prc-main, ... }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages.default = pkgs.haskellPackages.callPackage ./project.nix {};
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
cabal2nix
cabal-install
ghc
zlib.dev
p2prc-main.packages.${system}.default
];
};
}
);
}

View File

@@ -3,6 +3,7 @@ module API
( P2PRCapi(..)
, MapPortRequest(..)
, p2prcAPI
, P2PRCommands(..)
)
where
@@ -13,6 +14,7 @@ import System.Process ( ProcessHandle )
import Data.Aeson ( FromJSON )
import Error
( IOEitherError
)
@@ -20,19 +22,21 @@ import Error
import JSON
( IPAddressTable(..)
, MapPortResponse(..)
, P2prcConfig
, P2PRCConfig
)
import CLI
( StdInput(..)
, CLIOpt(..)
, eitherErrDecode
, p2PrcCmdName
, p2prcCmdName
, eitherExecProcess
, eitherExecProcessParser
, spawnProcP2Prc
, spawnProcP2PRC
)
-- import System.Environment (lookupEnv)
-- | Lower level P2PRC Haskell api that exposes basic functionality necessary to joint the network.
@@ -41,21 +45,32 @@ data P2PRCapi
= MkP2PRCapi
{ startServer :: IOEitherError ProcessHandle
-- ^ Start server
, execInitConfig :: IOEitherError P2prcConfig
-- , execInitConfig :: IOEitherError P2PRCConfig
-- ^ Instantiate server configuration
, execListServers :: IOEitherError IPAddressTable
-- ^ List servers in network
, execMapPort :: MapPortRequest -> IOEitherError MapPortResponse
-- ^ Exposes and associates a local TCP port with a remote DNS address
, execMaybeMapPortAndAddCustomInformation :: Maybe MapPortRequest -> PassCustomInformation -> IOEitherError String
, execAddCustomInformation :: PassCustomInformation -> IOEitherError String
}
-- | This defines the request required to create an association between a TCP socket port and a DNS server in the network. If successful, it makes a resource available in the network.
data MapPortRequest =
MkMapPortRequest -- ^ P2PRC's port allocation request value
Int -- ^ TCP socket number
String -- ^ Network domain name
-- | This defined the custom information required to be passed through.
newtype PassCustomInformation =
MkAddCustomInformation
String
data P2PRCommands
= MapPort MapPortRequest
| CustomInformation PassCustomInformation
{-|
This function intiates a pure P2PRC runtime state and builds up a 'P2PRCapi' API instance. It allows a developer to create computing orchestration algorithms using the API primitives.
@@ -92,16 +107,22 @@ main =
{-# WARNING p2prcAPI "This function is currently unstable because the configuration reading is dependent on the following issue: https://github.com/Akilan1999/p2p-rendering-computation/issues/120" #-}
p2prcAPI :: P2PRCapi
p2prcAPI =
p2prcAPI = let
execTemp :: Maybe MapPortRequest -> PassCustomInformation -> IOEitherError String
execTemp mp ci = undefined
in
MkP2PRCapi
{ startServer = spawnProcP2Prc p2PrcCmdName [ MkOptAtomic "--s" ]
{ startServer = spawnProcP2PRC p2prcCmdName [ MkOptAtomic "-s" ]
, execListServers =
execProcP2PrcParser [ MkOptAtomic "--ls" ] MkEmptyStdInput
execProcP2PRCParser [ MkOptAtomic "--ls" ] MkEmptyStdInput
, execMapPort =
\ (MkMapPortRequest portNumber domainName) ->
execProcP2PrcParser
execProcP2PRCParser
[ MkOptTuple
( "--mp"
, show portNumber
@@ -113,39 +134,44 @@ p2prcAPI =
]
MkEmptyStdInput
, execInitConfig = do
, execMaybeMapPortAndAddCustomInformation = execTemp
, execAddCustomInformation = execTemp Nothing
confInitRes <- execProcP2Prc [ MkOptAtomic "--dc" ] MkEmptyStdInput
-- , execInitConfig = do
case confInitRes of
(Right _) -> do
-- confInitRes <- execProcP2PRC [ MkOptAtomic "--dc" ] MkEmptyStdInput
-- TODO: get config file name dynamically
--
currDirectory <- getCurrentDirectory
-- case confInitRes of
-- (Right _) -> do
-- TODO: change values before loading file
let fname = currDirectory ++ "/config.json" :: FilePath
-- maybeValue <- lookupEnv "P2PRC"
-- -- TODO: get config file name dynamically
-- --
-- currDirectory <- getCurrentDirectory
-- -- TODO: change values before loading file
-- let fname = currDirectory ++ "/config.json" :: FilePath
-- TODO: read config check if file exists
configContent <- readFile fname
-- -- TODO: read config check if file exists
-- configContent <- readFile fname
pure $ eitherErrDecode configContent
-- pure $ eitherErrDecode configContent
(Left err) -> pure $ Left err
-- (Left err) -> pure $ Left err
}
where
execProcP2PrcParser ::
execProcP2PRCParser ::
FromJSON a =>
[CLIOpt] -> StdInput -> IOEitherError a
execProcP2PrcParser = eitherExecProcessParser p2PrcCmdName
execProcP2PRCParser = eitherExecProcessParser p2prcCmdName
-- TODO: GHC question, why does it scope down instead staying generic
execProcP2Prc = eitherExecProcess p2PrcCmdName
-- execProcP2PRC = eitherExecProcess p2prcCmdName

View File

@@ -87,8 +87,8 @@ optsToCLI = concatMap _optToCLI
_optToCLI (MkOptTuple (o, v)) = [o, v]
spawnProcP2Prc :: CLICmd -> [CLIOpt] -> IOEitherError ProcessHandle
spawnProcP2Prc cmd opts =
spawnProcP2PRC :: CLICmd -> [CLIOpt] -> IOEitherError ProcessHandle
spawnProcP2PRC cmd opts =
do
let prc = proc cmd $ optsToCLI opts
@@ -115,6 +115,6 @@ eitherErrorDecode esa =
-- assumes the program is ran inside the haskell module in p2prc's repo
-- assumes that last path segment is "haskell" and that p2prc binary's name is "p2p-rendering-computation"
p2PrcCmdName :: String
p2PrcCmdName = "p2p-rendering-computation"
p2prcCmdName :: String
p2prcCmdName = "p2p-rendering-computation"

View File

@@ -2,6 +2,7 @@
module Engine
( runP2PRC
, fn
)
where
@@ -18,7 +19,7 @@ import System.Process ( terminateProcess )
import API
( P2PRCapi(..)
, MapPortRequest(..)
, p2prcAPI
, p2prcAPI, P2PRCommands
)
@@ -58,14 +59,10 @@ import API
@
-}
runP2PRC
:: MapPortRequest -- ^ TCP Port Request
:: [P2PRCommands] -- ^ TCP Port Request
-> IO ()
runP2PRC
( MkMapPortRequest
portNumber
domainName
)
=
runP2PRC [] = putStrLn ""
runP2PRC nonEmpty@(_:_) =
let
--
@@ -95,9 +92,10 @@ runP2PRC
( MkP2PRCapi
{ startServer = startServer
, execInitConfig = execInitConfig
-- , execInitConfig = execInitConfig
, execListServers = execListServers
, execMapPort = execMapPort
, execAddCustomInformation = _
}
) = p2prcAPI
@@ -105,18 +103,19 @@ runP2PRC
let
configValue <- execInitConfig
-- configValue <- execInitConfig
-- TODO: get name of host server from config json
print configValue
putStrLn "\n\n\n"
-- print configValue
-- putStrLn "\n\n\n"
eitherStartProcessHandle <- startServer
case eitherStartProcessHandle of
(Right startProcessHandle) -> do
(Right startProcessHandle) ->
do
let sleepNSecs i = threadDelay (i * 1000000)
@@ -125,7 +124,8 @@ runP2PRC
outputStr <- execListServers
print outputStr
mapPortOut <- execMapPort $ MkMapPortRequest portNumber domainName
-- mapPortOut <- execMapPort $ MkMapPortRequest portNumber domainName
mapPortOut <- execMapPort $ MkMapPortRequest undefined undefined
case mapPortOut of
(Right v) -> print v
@@ -159,3 +159,7 @@ runP2PRC
when (toLower c /= 'q') $ exitOnQ exitF
exitF
fn :: undefined
fn = undefined

View File

@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
module JSON
( P2prcConfig(..)
( P2PRCConfig(..)
, IPAddressTable(..)
, IPAddress(..)
, ServerInfo(..)
@@ -38,11 +38,11 @@ instance FromJSON MapPortResponse where
{-# WARNING P2prcConfig "This type is unstable at the moment due to the P2PRC's library error handling bug. For more information visit: https://github.com/Akilan1999/p2p-rendering-computation/issues/114#issuecomment-2474737015" #-}
{-# WARNING P2PRCConfig "This type is unstable at the moment due to the P2PRC's library error handling bug. For more information visit: https://github.com/Akilan1999/p2p-rendering-computation/issues/114#issuecomment-2474737015" #-}
-- | This represents the server configuration that defines its attributes and behaviours in the network, as well as, the location of the runtime persistence artifacts.
newtype P2prcConfig
= MkP2prConfig
newtype P2PRCConfig
= MkP2PRCConfig
{ machineName :: String -- ^ Machine Name
} deriving Show
@@ -96,13 +96,13 @@ newtype P2prcConfig
-- to have a dedicated port field
instance FromJSON P2prcConfig where
instance FromJSON P2PRCConfig where
parseJSON (Object o) = do
machineName <- o .: "MachineName"
pure
$ MkP2prConfig
$ MkP2PRCConfig
{ machineName=machineName
}

View File

@@ -49,9 +49,10 @@ module P2PRC
-- ** Interface data types
-- | This section gives an overview on the runtime and host machine interfaces.
, P2PRCapi(..)
, P2prcConfig(..)
, P2PRCConfig(..)
, MapPortRequest(..)
, MapPortResponse(..)
, P2PRCommands(..)
-- ** Primitive data types
-- | These types represent the core data that is communicated between requests and the runtime.
@@ -76,13 +77,14 @@ import JSON
, ServerInfo(..)
, IPAddress(..)
, MapPortResponse(..)
, P2prcConfig(..)
, P2PRCConfig(..)
)
import API
( MapPortRequest(..)
, P2PRCapi(..)
, p2prcAPI
, P2PRCommands(..)
)

View File

@@ -0,0 +1,13 @@
{ mkDerivation, aeson, base, bytestring, directory, lib, process
, text
}:
mkDerivation {
pname = "p2prc";
version = "0.1.0.0";
src = ./.;
libraryHaskellDepends = [
aeson base bytestring directory process text
];
description = "P2PRC haskell library";
license = "unknown";
}

View File

@@ -3,10 +3,14 @@ module Main where
import P2PRC
( runP2PRC
, MapPortRequest(MkMapPortRequest)
, P2PRCommands(MapPort)
)
main :: IO ()
main =
main =let
in
runP2PRC
( MkMapPortRequest 8080 "jose.akilan.io"
)
[
( MapPort $ MkMapPortRequest 8080 "jose.akilan.io")
]

Binary file not shown.

129
Bindings/python/library.py Normal file
View File

@@ -0,0 +1,129 @@
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
p2prc = ctypes.CDLL("SharedObjects/p2prc.so")
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 -----------------------------
# ----------------------------------------------------------------------------
def StartServer():
# Starting P2PRC as a server mode
p2prc.Server()
# 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

View File

@@ -1,11 +0,0 @@
import ctypes
p2prc = ctypes.CDLL("SharedOBjects/p2prc.so")
p2prc.Init("")
def StartServer():
# Starting P2PRC as a server mode
p2prc.Server()
for _ in iter(int, 1):
pass

View File

@@ -0,0 +1,4 @@
dacite
schedule
sqlalchemy
requests

14
Bindings/python/test.py Normal file
View 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")

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -3,16 +3,20 @@
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://fniessen.github.io/org-html-themes/src/readtheorg_theme/css/search.css"/>
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="style.css"/>
#+attr_html: :width 300px
[[./Colored-On-Light-Image.png]]
* Guide through video
*** The video below shows the setup and usage of P2PRC.
#+attr_html: :class video
[[https://www.youtube.com/watch?v=OMwCpedu5cs][https://i3.ytimg.com/vi/OMwCpedu5cs/maxresdefault.jpg]]
*** Source code: https://github.com/Akilan1999/p2p-rendering-computation
* Introduction
:PROPERTIES:
:CUSTOM_ID: chapter1-introduction
:END:
** Abstract
:PROPERTIES:
:CUSTOM_ID: abstract
:END:
This project focuses on creating a framework for running heavy computational tasks that a regular
computer cannot handle easily. These tasks may include graphically demanding video games, rendering
3D animations, and performing complex protein folding simulations. The major focus of this project
@@ -178,6 +182,110 @@ GLOBAL OPTIONS:
--------------
* Nix Flake
Nix is a growing ecosystem that allows flexibility on how you develop, build and package software and configurations. It brings all programming languages (and all other tooling) to an equal footing, despite deep design differences. More importantly, integrates all the "packaging" into the context of a "pure" function.
P2PRC aims to become a utility that can be used in various flexible manners and having Nix support is a good alternative to accomplish this goal.
Nix Flake is a format, within the Nix ecosystem, intentionally designed to encourage a standard in packaging distribution. The current packaging assumes that you have "nix flake" installed because it is currently an experimental feature of Nix.
** P2PRC core Go language repo
In case you want to develop, build or integrate using nix, you just need to run either "nix develop" or "nix run" from the command line locally in a cloned git repository or by running "nix run github:akilan1999/p2p-rendering-computation -- --help"
P2PRC library also is ready to be imported into other nix flakes. To accomplish that please make sure to override the target nixpkgs environment in the following manner;
#+begin_example
pkgs = import nixpkgs {
inherit system;
overlays = [
p2prc-flake.overlays.default
];
};
#+end_example
This will make the p2prc executable available in the environment of any application you use.
** P2PRC Haskell library
*** Nix:
The project is structured to provide language bindings to any programming language. The first one being supported in this manner is the Haskell programming language. It provides a bootstrapping script for a new Cabal project with p2prc binary available in the environment and, more relevantly, the Haskell library bindings available in the virtual environment cabal environment.
#+begin_example
nix run git+https://github.com/akilan1999/p2p-rendering-computation#initHaskellProject -- <PROJECT_NAME>
#+end_example
This will generate a new haskell project setup to automatically work with the p2prc development and running environment.
Once completed, you should go into the project directory and copy the nix flake template, necessary to define the project's environment.
#+begin_example
nix flake init -t github:akilan1999/p2p-rendering-computation#haskell
#+end_example
The previous command sets up the flake environment and its dependencies. It will look like the following
#+begin_example
{
description = "Start of Haskell P2PRC flake";
inputs =
{
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-util.url = "github:numtide/flake-utils";
p2prc-flake.url = "github:akilan1999/p2p-rendering-computation";
};
outputs = { nixpkgs, p2prc-flake, flake-utils, ... }:
(flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
p2prc-flake.overlays.default
p2prc-flake.overlays.bindings
];
};
in {
packages.default = pkgs.haskellPackages.callPackage ./cabal.nix { };
devShells.default = pkgs.haskellPackages.shellFor {
packages = p: [
(p.callPackage ./cabal.nix { })
];
buildInputs = with pkgs; [
p2prc-flake.packages.${system}.default
ghc
cabal2nix
cabal-install
];
shellHook = ''
cabal2nix . > ./cabal.nix
'';
};
}
));
}
#+end_example
The template uses Cabal2Nix which manages the Haskell virtual environment automatically. It applies the system overlays, sets up the shell environment for the project (updating the Cabal2Nix configuration) and packages the main executable.
* Using basic commands
:PROPERTIES:
:CUSTOM_ID: using-basic-commands
@@ -352,6 +460,14 @@ p2prc --mp <port no to map> --dn <domain name to link Mapped port against> --ra
--------------
*** Add root node
Adds a root node to P2RRC and overwrites all other nodes in the ip table.
To be only added before the network is started and with
the intention of a fresh instance.
#+begin_example
p2prc --arn --ip <root node ip address> -p <root node port no>
#+end_example
* P2P Module Implementation
:PROPERTIES:
:CUSTOM_ID: p2p-module-implementation
@@ -363,7 +479,7 @@ to determine upload and download speeds. This valuable information enables users
servers with optimal performance, enhancing their overall network experience.
#+caption: UML diagram of P2P module
[[file:images/p2pmoduleArch.png]]
[[file:./images/p2pmoduleArch.png]
The peer to peer implementation was built from scratch. This is because
other peer to peer libraries were on the implementation of the
@@ -641,7 +757,7 @@ cd Bindings/python/export/
# list files
ls
# Expected output
SharedObjects/ p2prc.py
SharedObjects/ library.py requirements.txt
#+end_src
Above shows a generated folder which consists of a folder called
@@ -656,7 +772,24 @@ called from other programming languages.
P2PRC officially supports Haskell bindings and will further support
project using Haskell to build orchestrators on top of P2PRC.
[[https://p2prc.akilan.io/Docs/haskell][Read more...]]
**** Local machine without Nix
On the local machine we just create a folder as exports which copies the p2prc haskell bindings
and the latest build of the p2prc binary. After the binary is copied it runs the --dc in p2prc to setup the
basic p2prc configurations. To do the following just do:
#+begin_example
make haskell
#+end_example
**** Directory to enter into
#+begin_example
cd Bindings/Haskell/exports
#+end_example
**** Run
#+begin_example
- cabal build
- cabal run
#+end_example
[[https://p2prc.akilan.io/haskell][Read more...]]
* Config Implementation
:PROPERTIES:
@@ -678,18 +811,28 @@ configuration file was generated using JSON format.
#+begin_src json
{
"MachineName": "pc-74-120.customer.ask4.lan",
"MachineName": "Akilans-MacBook-Pro.local-975261X",
"IPTable": "/Users/akilan/Documents/p2p-rendering-computation/p2p/iptable/ip_table.json",
"DockerContainers": "/Users/akilan/Documents/p2p-rendering-computation/server/docker/containers/",
"DefaultDockerFile": "/Users/akilan/Documents/p2p-rendering-computation/server/docker/containers/docker-ubuntu-sshd/",
"DockerRunLogs": "/tmp/",
"SpeedTestFile": "/Users/akilan/Documents/p2p-rendering-computation/p2p/50.bin",
"IPV6Address": "",
"PluginPath": "/Users/akilan/Documents/p2p-rendering-computation/plugin/deploy",
"TrackContainersPath": "/Users/akilan/Documents/p2p-rendering-computation/client/trackcontainers/trackcontainers.json",
"ServerPort": "8088",
"ProxyPort": "",
"GroupTrackContainersPath": "/Users/akilan/Documents/p2p-rendering-computation/client/trackcontainers/grouptrackcontainers.json",
"FRPServerPort": "True",
"BehindNAT": "True",
"FRPServerPort": true,
"BehindNAT": true,
"IPTableKey": "QH3yQrGRe2X4",
"PublicKeyFile": "/Users/akilan/Documents/p2p-rendering-computation/p2prc.publicKey",
"PrivateKeyFile": "/Users/akilan/Documents/p2p-rendering-computation/p2prc.privateKey",
"PemFile": "/Users/akilan/Documents/p2p-rendering-computation/cert.pem",
"KeyFile": "/Users/akilan/Documents/p2p-rendering-computation/key.pem",
"BareMetal": false,
"UnsafeMode": false,
"Test": false,
"CustomConfig": null
}
#+end_src
@@ -771,10 +914,48 @@ func main() {
}
}
#+end_src
* Simulation
The simulation library is a really simple library to locally
run serveral instances of P2PRC to test the functionality
of sending information through the network and particularly
the Node discovery mechanism. There are current 5 commands
which can be used as shown below:
** Command
- ***P2PRC instances "number of instances"*** : Starts p2prc processes
based on the number of number instances provided. This includes
creating temporary folders with independent IPTables.
- ***Start all instances "number of instances"***: Starts the P2PRC instances
created. This function enters into the instance directory and runs
```p2prc -s &``` with a delay for approximately 3 seconds. This allows
each independent created node to learn about each other.
- ***IP Tables after Started number of instances"***: Prints the IPTable of
each independant node.
- ***Remove all test files***: Removes all test files created which needed for
testing the generated P2PRC instances.
- ***Kill all instances***: Kills all the background P2PRC instances created.
** Sample bash instructions
#+begin_src bash
# Unset default P2PRC env path
unset P2PRC
# Run with 2 nodes
P2PRC_instances 3
# Start instances
Start_all_instances 3
# List ip tables of nodes started
IP_Tables_after_Started 3
# Remove test files created
Remove_all_test_files
# Kill all instances
Kill_all_instances
#+end_src
Source code: https://github.com/Akilan1999/p2p-rendering-computation/blob/master/Simulation/simulation.sh
* Blog posts
** Self host within 5 minutes any program
@@ -783,6 +964,7 @@ func main() {
- Video tutorial:
#+attr_html: :class video
[[https://youtu.be/rN4SiVowg5E][https://i3.ytimg.com/vi/rN4SiVowg5E/maxresdefault.jpg]]
This is a fun expirement for anyone to try to quickly run a server and

1
Docs/kill-docs.sh Normal file
View File

@@ -0,0 +1 @@
kill -9 $(lsof -t -i:8083)

1
Docs/run-docs.sh Normal file
View File

@@ -0,0 +1 @@
go run staticServer.go &

28
Docs/staticServer.go Normal file
View File

@@ -0,0 +1,28 @@
/*
Serve is a very simple static file server in go
Usage:
-p="8100": port to serve on
-d=".": the directory of static files to host
Navigating to http://localhost:8100 will display the index.html or directory
listing file.
*/
package main
import (
"flag"
"log"
"net/http"
)
func main() {
port := flag.String("p", "8083", "port to serve on")
directory := flag.String("d", ".", "the directory of static file to host")
flag.Parse()
http.Handle("/", http.FileServer(http.Dir(*directory)))
log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}

View File

@@ -23,3 +23,7 @@ h4,h5,h6{
color: #b96c29;
font-weight:300;
}
.video {
box-shadow: 10px 10px 25px rgba(0, 0, 0, 0.3);
}

View File

@@ -14,6 +14,9 @@ sharedObjects:
python:
sh build-python-package.sh
haskell:
sh build-haskell.sh
clean:
go clean -modcache
rm -fr .go-build vendor result*

View File

@@ -1,5 +1,5 @@
> [!TIP]
> Haskell bindings supported!: [Bindings documentaton](https://p2prc.akilan.io/Docs/haskell/P2PRC.html)
> Haskell bindings supported!: [Bindings documentaton](https://p2prc.akilan.io/haskell/P2PRC.html)
> [!NOTE]
> Fixing documentation to latest changes. If you have any questions setting up P2PRC either [create an issue](https://github.com/Akilan1999/p2p-rendering-computation/issues/new/choose) or send me an email (me AT akilan dot io).
@@ -57,7 +57,7 @@ alias p2prc='env P2PRC=<path you want the configs to exist in> nix run github:ak
```bash
p2prc -h
```
Read more on command usage: https://p2prc.akilan.io/Docs/#using-basic-commands
Read more on command usage: https://p2prc.akilan.io/#using-basic-commands
## Latest tutorial
[![IMAGE ALT TEXT](https://i.ytimg.com/vi/OMwCpedu5cs/hqdefault.jpg)](https://www.youtube.com/watch?v=OMwCpedu5cs")
@@ -66,7 +66,7 @@ Read more on command usage: https://p2prc.akilan.io/Docs/#using-basic-commands
## Documentation
### We have documented to our best effort the basics of p2prc: [Link](https://p2prc.akilan.io/Docs/)
### We have documented to our best effort the basics of p2prc: [Link](https://p2prc.akilan.io/)
<!-- ## Table of contents in the current README -->
<!-- 1. [Introduction](#Introduction)

132
Simulation/simulation.sh Normal file
View File

@@ -0,0 +1,132 @@
# Unset P2PRC
unset P2PRC
# Create P2PRC instances
# Parameters:
# 1. Number of nodes
P2PRC_instances() {
local rootPort=""
for (( counter=0; counter<$1; counter++ )); do
mkdir test-$counter/
cd test-$counter/
# Generate a new random port
NEW_PORT=$(shuf -i 2000-65000 -n 1)
# Initialize node
p2prc --dc
# Save rootPort from the first node
if [[ $counter -eq 0 ]]; then
rootPort=$NEW_PORT
fi
echo "Root port: $rootPort"
echo "This node's port: $NEW_PORT"
# Set root port
p2prc --arn --ip 0.0.0.0 -p "$rootPort"
# add current node
p2prc --as 0.0.0.0 -p "$NEW_PORT"
# Replace the ServerPort in config
# test-$counter
sed -i.bak "s/\"ServerPort\": \"[0-9]*\"/\"ServerPort\": \"$NEW_PORT\"/" "./config.json"
sed -i.bak "s/\"Test\": false/\"Test\": true/" "./config.json"
sed -i.bak "s/\"BehindNAT\": true/\"BehindNAT\": false/" "./config.json"
# sed -i.bak "s/\"MachineName\": "Akilans-MacBook-Pro.local-J2UbbkF"/\"MachineName\": \"test-$counter\"/" "./config.json"
cat config.json
# List services
p2prc --ls
cd ..
done
# remove all instances after testing (optional — might want to comment this during testing)
# rm -rf test-*
}
# Arrays of process IDs
pids=()
# Calls all the P2PRC instances created for testing
Start_all_instances() {
for (( counter=0; counter<$1; counter++ )); do
cd test-$counter/
# Start P2PRC as background process
p2prc -s &
pids+=($!)
sleep 3
cd ..
done
}
# Kills all P2PRC instances
Kill_all_instances() {
for pid in "${pids[@]}"; do
kill "$pid"
echo "Killed process $pid"
done
}
# Removes all test files created
Remove_all_test_files() {
rm -rf test-*
}
# List ip tables of all nodes started
IP_Tables_after_Started() {
for (( counter=0; counter<$1; counter++ )); do
cd test-$counter/
p2prc --ls
cd ..
done
}
Update_All_IP_Tables() {
for (( counter=0; counter<$1; counter++ )); do
cd test-$counter/
p2prc --us
cd ..
done
}
# Test function for the root to custom information
# through the network
Send_Information() {
ls
cd test-2/
p2prc --amd "test message"
cd ..
}
# ---------------- Work flow test ---------------
# Unset default P2PRC env path
unset P2PRC
# Run with 2 nodes
P2PRC_instances 3
## Start instances
Start_all_instances 3
# Send test information from node 1
sleep 10
Send_Information
sleep 10
## List ip tables of nodes started
IP_Tables_after_Started 3
#
## Remove test files created
Remove_all_test_files
## Kill all instances
Kill_all_instances

View File

@@ -1,88 +1,108 @@
package abstractions
import "C"
import (
"github.com/Akilan1999/p2p-rendering-computation/client"
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
Config "github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/config/generate"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"github.com/Akilan1999/p2p-rendering-computation/server"
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
"github.com/gin-gonic/gin"
"os"
"github.com/Akilan1999/p2p-rendering-computation/client"
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
Config "github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/config/generate"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"github.com/Akilan1999/p2p-rendering-computation/server"
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
"github.com/gin-gonic/gin"
"os"
)
// Init Initialises p2prc
func Init(customConfig interface{}) (config *Config.Config, err error) {
// Get config file path
// Checks P2PRC path initially
// - Get PATH if environment varaible
path, err := Config.GetPathP2PRC("P2PRC")
if err != nil {
return
}
// check if the config file exists
if _, err = os.Stat(path + "config.json"); err != nil {
// Initialize with base p2prc config files
// set the config file with default paths
config, err = generate.SetDefaults("P2PRC", false, customConfig, false)
if err != nil {
return
}
} else {
// If the configs are available then use them over generating new ones.
config, err = Config.ConfigInit(nil, nil)
if err != nil {
return
}
}
// Get config file path
// Checks P2PRC path initially
// - Get PATH if environment varaible
path, err := Config.GetPathP2PRC("P2PRC")
if err != nil {
return
}
// check if the config file exists
if _, err = os.Stat(path + "config.json"); err != nil {
// Initialize with base p2prc config files
// set the config file with default paths
config, err = generate.SetDefaults("P2PRC", false, customConfig, false)
if err != nil {
return
}
} else {
// If the configs are available then use them over generating new ones.
config, err = Config.ConfigInit(nil, nil)
if err != nil {
return
}
}
return
return
}
// Start p2prc in a server mode
func Start() (*gin.Engine, error) {
engine, err := server.Server()
if err != nil {
return nil, err
}
return engine, nil
engine, err := server.Server()
if err != nil {
return nil, err
}
return engine, nil
}
// MapPort Creates a reverse proxy connection and maps the appropriate port
func MapPort(port string, domainName string, serverAddress string) (response *client.ResponseMAPPort, err error) {
response, err = client.MAPPort(port, domainName, serverAddress)
return
response, err = client.MAPPort(port, domainName, serverAddress)
return
}
// StartContainer Starts docker container on the remote machine
func StartContainer(IP string) (container *docker.DockerVM, err error) {
container, err = client.StartContainer(IP, 0, false, "", "")
return
container, err = client.StartContainer(IP, 0, false, "", "")
return
}
// RemoveContainer Removes docker container based on the IP address and ID
// provided
func RemoveContainer(IP string, ID string) error {
return client.RemoveContianer(IP, ID)
return client.RemoveContianer(IP, ID)
}
// GetSpecs Get spec information about the remote server
func GetSpecs(IP string) (specs *server.SysInfo, err error) {
specs, err = client.GetSpecs(IP)
return
specs, err = client.GetSpecs(IP)
return
}
// ViewIPTable View information of nodes in the network
func ViewIPTable() (table *p2p.IpAddresses, err error) {
table, err = p2p.ReadIpTable()
return
table, err = p2p.ReadIpTable()
return
}
// UpdateIPTable Force updates IP tables based on new
// new nodes discovered in the network
func UpdateIPTable() (err error) {
return clientIPTable.UpdateIpTableListClient()
return clientIPTable.UpdateIpTableListClient()
}
// AddCustomInformation allows to pass custom information
// through the network to which can be listened on
// all peers in the network to execute a task.
func AddCustomInformation(information string) error {
return clientIPTable.AddCustomInformationToIPTable(information)
}
// AddRootNode Adds root node to the network by using defaults except for
// ip address and port no. Supports only IPV4 as of now.
func AddRootNode(rootIP string, portNo string) error {
var rootNode []p2p.IpAddress
rootNode = append(rootNode, p2p.IpAddress{
Name: "",
Ipv4: rootIP,
ServerPort: portNo,
NAT: false,
})
return generate.GenerateIPTableFile(rootNode)
}

BIN
artwork/.DS_Store vendored

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 KiB

31
build-haskell.sh Normal file
View File

@@ -0,0 +1,31 @@
# This bash script consists of the manaul build script of haskell
go build .
# Unset p2prc path
unset p2prc
# Enter the haskell project
cd Bindings/haskell
# Remove exsisting export build
rm -rf exports
# Create exports directory
mkdir exports
# Copy current haskell project into the folder
cp -rf . exports/
# Copy p2prc binary inside haskell folder
cp ../../p2p-rendering-computation exports/
cd exports
# remove exports directory copied inside exports
rm -rf exports/
# Set p2prc variable
echo export P2PRC=$PWD
export P2PRC=$PWD
./p2p-rendering-computation --dc
echo "Run the following commands in the directory: ${PWD}"
echo "To build: cabal build"
echo "To run sample program: cabal run"

View File

@@ -6,12 +6,19 @@ mkdir Bindings/python/export
# Creating SharedObjects directory for python
mkdir Bindings/python/export/SharedObjects
# Builds p2prc.h and p2prc.so file
# as apart of Go FFI to interacted
# with later on.
sh build-bindings.sh
# Copy the shared object files as well to ensure
# that python can interact with the latest snapshot
# of P2PRC
cp Bindings/p2prc.h Bindings/python/export/SharedObjects/
cp Bindings/p2prc.so Bindings/python/export/SharedObjects/
cp Bindings/python/p2prc.py Bindings/python/export/
# Copy python library and tests as export as well
cp Bindings/python/* Bindings/python/export/
echo "Output is in the Directory Bindings/python/export/"

View File

@@ -1,40 +1,40 @@
package clientIPTable
import (
"errors"
"github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"errors"
"github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
)
func AddCustomInformationToIPTable(text string) error {
// Get config information
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
// Get config information
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
// Get IPTable information
table, err := p2p.ReadIpTable()
if err != nil {
return err
}
// Get IPTable information
table, err := p2p.ReadIpTable()
if err != nil {
return err
}
found := false
found := false
for i, _ := range table.IpAddress {
if table.IpAddress[i].Name == Config.MachineName {
table.IpAddress[i].CustomInformation = text
found = true
}
}
for i, _ := range table.IpAddress {
if table.IpAddress[i].Name == Config.MachineName {
table.IpAddress[i].CustomInformation = text
found = true
}
}
if found {
table.WriteIpTable()
// update IPTable after modified entry
go UpdateIpTableListClient()
} else {
return errors.New("start server with p2prc -s as the server is currently not running")
}
if found {
table.WriteIpTable()
// update IPTable after modified entry
UpdateIpTableListClient()
} else {
return errors.New("start server with p2prc -s as the server is currently not running")
}
return nil
return nil
}

View File

@@ -1,16 +1,16 @@
package clientIPTable
import (
"encoding/json"
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"sync"
"encoding/json"
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"sync"
)
var mu sync.Mutex
@@ -18,146 +18,147 @@ var mu sync.Mutex
// UpdateIpTable Does the following to update it's IP table
func UpdateIpTable(IpAddress string, serverPort string, wg *sync.WaitGroup) error {
config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
client := http.Client{}
client := http.Client{}
var resp []byte
var resp []byte
version := p2p.Ip4or6(IpAddress)
if version == "version 6" {
resp, err = UploadMultipartFile(client, "http://["+IpAddress+"]:"+serverPort+"/IpTable", "json", config.IPTable)
if err != nil {
return err
}
} else {
resp, err = UploadMultipartFile(client, "http://"+IpAddress+":"+serverPort+"/IpTable", "json", config.IPTable)
if err != nil {
return err
}
}
version := p2p.Ip4or6(IpAddress)
if version == "version 6" {
resp, err = UploadMultipartFile(client, "http://["+IpAddress+"]:"+serverPort+"/IpTable", "json", config.IPTable)
if err != nil {
return err
}
} else {
resp, err = UploadMultipartFile(client, "http://"+IpAddress+":"+serverPort+"/IpTable", "json", config.IPTable)
if err != nil {
return err
}
}
if resp == nil {
return nil
}
if resp == nil {
return nil
}
//resp, err := SendPostRequest("http://"+IpAddress+":8088/IpTable",
// config.IPTable,
// "json")
//
//if err != nil {
// return err
//}
//resp, err := SendPostRequest("http://"+IpAddress+":8088/IpTable",
// config.IPTable,
// "json")
//
//if err != nil {
// return err
//}
var ipStruct p2p.IpAddresses
json.Unmarshal(resp, &ipStruct)
var ipStruct p2p.IpAddresses
json.Unmarshal(resp, &ipStruct)
// Updates IP table based on information provided
// by the server
if len(ipStruct.IpAddress) > 0 {
err = ipStruct.SpeedTestUpdatedIPTable()
if err != nil {
return err
}
}
// Updates IP table based on information provided
// by the server
if len(ipStruct.IpAddress) > 0 {
err = ipStruct.SpeedTestUpdatedIPTable()
if err != nil {
return err
}
}
// Not required to update IP table as speed test updates the IP Table
//err = ipStruct.WriteIpTable()
//if err != nil {
// return err
//}
// Not required to update IP table as speed test updates the IP Table
//err = ipStruct.WriteIpTable()
//if err != nil {
// return err
//}
wg.Done()
wg.Done()
return nil
return nil
}
// UpdateIpTableListClient updates IP tables (Default 3 hops) based on server information available
// on the ip tables
func UpdateIpTableListClient() error {
// Get config information
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
// Get config information
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
// Ensure that the IP Table has Node pingable
err = p2p.LocalSpeedTestIpTable()
if err != nil {
return err
}
// Ensure that the IP Table has Node pingable
err = p2p.LocalSpeedTestIpTable()
if err != nil {
return err
}
// IP addresses to not append to struct due to
// duplication
// IP addresses to not append to struct due to
// duplication
Addresses, err := p2p.ReadIpTable()
var DoNotRead p2p.IpAddresses
Addresses, err := p2p.ReadIpTable()
var DoNotRead p2p.IpAddresses
currentIPV4, err := p2p.CurrentPublicIP()
if err != nil {
return err
}
currentIPV4, err := p2p.CurrentPublicIP()
if err != nil {
return err
}
var w sync.WaitGroup
var w sync.WaitGroup
// Run loop 2 times
for i := 0; i < 2; i++ {
// Gets information from IP table
Addresses, err = p2p.ReadIpTable()
if err != nil {
return err
}
// Run loop 2 times
for i := 0; i < 2; i++ {
// Gets information from IP table
Addresses, err = p2p.ReadIpTable()
if err != nil {
return err
}
//DoNotRead.IpAddress = append(DoNotRead.IpAddress, PublicIP)
//DoNotRead.IpAddress = append(DoNotRead.IpAddress, PublicIP)
// Updates IP table based on server IP table
for j := range Addresses.IpAddress {
// Updates IP table based on server IP table
for j := range Addresses.IpAddress {
Exists := false
// If the address is local then add to the local list
if currentIPV4 == Addresses.IpAddress[j].Ipv4 && Addresses.IpAddress[j].ServerPort == Config.ServerPort {
Exists = true
}
Exists := false
// If the address is local then add to the local list
if (currentIPV4 == Addresses.IpAddress[j].Ipv4 && !Config.Test) && Addresses.IpAddress[j].ServerPort == Config.ServerPort {
Exists = true
}
// Check if IP addresses is there in the struct DoNotRead
for k := range DoNotRead.IpAddress {
if (DoNotRead.IpAddress[k].Ipv4 == Addresses.IpAddress[j].Ipv4 && DoNotRead.IpAddress[k].ServerPort == Addresses.IpAddress[j].ServerPort) || (DoNotRead.IpAddress[k].Ipv6 != "" && Addresses.IpAddress[j].Ipv6 == DoNotRead.IpAddress[k].Ipv6) {
Exists = true
break
}
}
// Check if IP addresses is there in the struct DoNotRead
for k := range DoNotRead.IpAddress {
if (DoNotRead.IpAddress[k].Ipv4 == Addresses.IpAddress[j].Ipv4 && DoNotRead.IpAddress[k].ServerPort == Addresses.IpAddress[j].ServerPort) || (DoNotRead.IpAddress[k].Ipv6 != "" && Addresses.IpAddress[j].Ipv6 == DoNotRead.IpAddress[k].Ipv6) {
Exists = true
break
}
}
// If the struct exists then continues
if Exists {
continue
}
// If the struct exists then continues
if Exists {
continue
}
w.Add(1)
if Addresses.IpAddress[j].Ipv6 != "" {
go UpdateIpTable(Addresses.IpAddress[j].Ipv6, Addresses.IpAddress[j].ServerPort, &w)
} else if Addresses.IpAddress[j].Ipv4 != currentIPV4 {
go UpdateIpTable(Addresses.IpAddress[j].Ipv4, Addresses.IpAddress[j].ServerPort, &w)
}
w.Wait()
w.Add(1)
//if Addresses.IpAddress[j].Ipv6 != "" {
// go UpdateIpTable(Addresses.IpAddress[j].Ipv6, Addresses.IpAddress[j].ServerPort, &w)
//} else if Addresses.IpAddress[j].Ipv4 != currentIPV4 {
// //go UpdateIpTable(Addresses.IpAddress[j].Ipv4, Addresses.IpAddress[j].ServerPort, &w)
//}
go UpdateIpTable(Addresses.IpAddress[j].Ipv4, Addresses.IpAddress[j].ServerPort, &w)
w.Wait()
//Appends server1 IP address to variable DoNotRead
DoNotRead.IpAddress = append(DoNotRead.IpAddress, Addresses.IpAddress[j])
}
}
//Appends server1 IP address to variable DoNotRead
DoNotRead.IpAddress = append(DoNotRead.IpAddress, Addresses.IpAddress[j])
}
}
return nil
return nil
}
func RemoveOfflineNodes() error {
// Ensure that the IP Table has Node pingable
err := p2p.LocalSpeedTestIpTable()
if err != nil {
return err
}
return nil
// Ensure that the IP Table has Node pingable
err := p2p.LocalSpeedTestIpTable()
if err != nil {
return err
}
return nil
}
// SendPostRequest Sends a file as a
@@ -207,58 +208,58 @@ func RemoveOfflineNodes() error {
//}
func UploadMultipartFile(client http.Client, uri, key, path string) ([]byte, error) {
body, writer := io.Pipe()
body, writer := io.Pipe()
req, err := http.NewRequest(http.MethodPost, uri, body)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPost, uri, body)
if err != nil {
return nil, err
}
mwriter := multipart.NewWriter(writer)
req.Header.Add("Content-Type", mwriter.FormDataContentType())
mwriter := multipart.NewWriter(writer)
req.Header.Add("Content-Type", mwriter.FormDataContentType())
errchan := make(chan error)
errchan := make(chan error)
go func() {
defer close(errchan)
defer writer.Close()
defer mwriter.Close()
go func() {
defer close(errchan)
defer writer.Close()
defer mwriter.Close()
w, err := mwriter.CreateFormFile(key, path)
if err != nil {
errchan <- err
return
}
w, err := mwriter.CreateFormFile(key, path)
if err != nil {
errchan <- err
return
}
in, err := os.Open(path)
if err != nil {
errchan <- err
return
}
defer in.Close()
in, err := os.Open(path)
if err != nil {
errchan <- err
return
}
defer in.Close()
if written, err := io.Copy(w, in); err != nil {
errchan <- fmt.Errorf("error copying %s (%d bytes written): %v", path, written, err)
return
}
if written, err := io.Copy(w, in); err != nil {
errchan <- fmt.Errorf("error copying %s (%d bytes written): %v", path, written, err)
return
}
if err := mwriter.Close(); err != nil {
errchan <- err
return
}
}()
if err := mwriter.Close(); err != nil {
errchan <- err
return
}
}()
resp, err := client.Do(req)
if err != nil {
return nil, err
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
content, err := ioutil.ReadAll(resp.Body)
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
return content, nil
return content, nil
}

View File

@@ -2,8 +2,10 @@ package cmd
import (
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/abstractions"
"github.com/Akilan1999/p2p-rendering-computation/client"
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
Config "github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/config/generate"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"github.com/Akilan1999/p2p-rendering-computation/plugin"
@@ -87,11 +89,7 @@ var CliAction = func(ctx *cli.Context) error {
// Displays all images available on the server side
if ViewImages != "" {
imageRes, err := client.ViewContainers(ViewImages)
if err != nil {
fmt.Print(err)
}
client.PrettyPrint(imageRes)
standardOutput(err, imageRes)
}
// Function called to stop and remove server from Docker
@@ -100,9 +98,7 @@ var CliAction = func(ctx *cli.Context) error {
fmt.Println("provide container ID via --ID or --id")
} else {
err := client.RemoveContianer(RemoveVM, ID)
if err != nil {
fmt.Print(err)
}
standardOutput(err, nil)
}
}
@@ -119,58 +115,40 @@ var CliAction = func(ctx *cli.Context) error {
// Calls function to do Api call to start the container on the server side
imageRes, err := client.StartContainer(CreateVM, PortsInt, GPU, ContainerName, BaseImage)
if err != nil {
fmt.Print(err)
}
client.PrettyPrint(imageRes)
standardOutput(err, imageRes)
}
//Call if specs flag is called
if Specs != "" {
specs, err := client.GetSpecs(Specs)
if err != nil {
return err
}
// Pretty print
client.PrettyPrint(specs)
standardOutput(err, specs)
}
//Sets default paths to the config file
if SetDefaultConfig {
_, err := generate.SetDefaults("P2PRC", false, nil, false)
if err != nil {
fmt.Print(err)
}
standardOutput(err, nil)
}
//If the network interface flag is called
// Then all the network interfaces are displayed
if NetworkInterface {
err := p2p.ViewNetworkInterface()
if err != nil {
fmt.Print(err)
}
standardOutput(err, nil)
}
// If the view plugin flag is called then display all
// plugins available
if ViewPlugin {
plugins, err := plugin.DetectPlugins()
if err != nil {
fmt.Print(err)
}
client.PrettyPrint(plugins)
standardOutput(err, plugins)
}
// If the flag Tracked Container is called or the flag
// --tc
if TrackedContainers {
err, trackedContainers := client.ViewTrackedContainers()
if err != nil {
fmt.Print(err)
}
client.PrettyPrint(trackedContainers)
standardOutput(err, trackedContainers)
}
//Executing plugin when the plugin flag is called
@@ -179,14 +157,11 @@ var CliAction = func(ctx *cli.Context) error {
// To execute plugin requires the container ID or group ID provided when being executed
if ID != "" {
err := plugin.CheckRunPlugin(ExecutePlugin, ID)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Success")
}
} else {
fmt.Println("provide container ID via --ID or --id")
standardOutput(err, nil)
}
//else {
// fmt.Println("provide container ID via --ID or --id")
//}
}
@@ -194,10 +169,7 @@ var CliAction = func(ctx *cli.Context) error {
// Creates new group and outputs JSON file
if CreateGroup {
group, err := client.CreateGroup()
if err != nil {
return err
}
client.PrettyPrint(group)
standardOutput(err, group)
}
// Actions to be performed when the
@@ -208,26 +180,14 @@ var CliAction = func(ctx *cli.Context) error {
// --rmcgroup --id <contianer id>
if RemoveContainerGroup && ID != "" {
group, err := client.RemoveContainerGroup(ID, Group)
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(group)
}
standardOutput(err, group)
} else if ID != "" { // Add container to group based on group ID provided
// --id <Container ID>
group, err := client.AddContainerToGroup(ID, Group)
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(group)
}
standardOutput(err, group)
} else { // View all information about current group
group, err := client.GetGroup(Group)
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(group)
}
standardOutput(err, group)
}
}
@@ -236,63 +196,58 @@ var CliAction = func(ctx *cli.Context) error {
// --rmgroup
if RemoveGroup != "" {
err := client.RemoveGroup(RemoveGroup)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Group Removed")
}
standardOutput(err, nil)
}
// Execute Function to view all groups
if Groups {
groups, err := client.ReadGroup()
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(groups)
}
standardOutput(err, groups)
}
//--------------------------------
if PullPlugin != "" {
err := plugin.DownloadPlugin(PullPlugin)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Success")
}
standardOutput(err, nil)
}
if RemovePlugin != "" {
err := plugin.DeletePlugin(RemovePlugin)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Success")
}
standardOutput(err, nil)
}
if AddMetaData != "" {
err := clientIPTable.AddCustomInformationToIPTable(AddMetaData)
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Success")
}
standardOutput(err, nil)
}
if MAPPort != "" {
address, err := client.MAPPort(MAPPort, DomainName, RemoteAddress)
if err != nil {
return err
}
if err != nil {
fmt.Println(err)
} else {
client.PrettyPrint(address)
}
standardOutput(err, address)
}
// Action called to add root node to network
if AddRootNode && IP != "" && Ports != "" {
err := abstractions.AddRootNode(IP, Ports)
standardOutput(err, nil)
}
// display configuration
if ViewConfig {
config, err := Config.ConfigInit(nil, nil)
standardOutput(err, config)
}
return nil
}
func standardOutput(err error, i interface{}) {
if err != nil {
fmt.Println(err)
} else if i == nil {
fmt.Println("Success")
} else {
client.PrettyPrint(i)
}
}

View File

@@ -41,6 +41,9 @@ var (
PullPlugin string
RemovePlugin string
AddMetaData string
AddRootNode bool
IP string
ViewConfig bool
)
var AppConfigFlags = []cli.Flag{
@@ -272,4 +275,25 @@ var AppConfigFlags = []cli.Flag{
EnvVars: []string{"ADDMETADATA"},
Destination: &AddMetaData,
},
&cli.BoolFlag{
Name: "AddRootNode",
Aliases: []string{"arn"},
Usage: "Adds initial root node to talk to",
EnvVars: []string{"ADDROOTNODE"},
Destination: &AddRootNode,
},
&cli.StringFlag{
Name: "IPAddress",
Aliases: []string{"ip"},
Usage: "IP address",
EnvVars: []string{"IP"},
Destination: &IP,
},
&cli.BoolFlag{
Name: "ViewConfig",
Aliases: []string{"vc"},
Usage: "View config file",
EnvVars: []string{"VC"},
Destination: &ViewConfig,
},
}

View File

@@ -29,8 +29,8 @@ type Config struct {
ServerPort string
ProxyPort string
GroupTrackContainersPath string
FRPServerPort string
BehindNAT string
FRPServerPort bool
BehindNAT bool
IPTableKey string
PublicKeyFile string
PrivateKeyFile string
@@ -38,7 +38,9 @@ type Config struct {
KeyFile string
BareMetal bool
UnsafeMode bool
Test bool
CustomConfig interface{}
ConfigPath string
//NetworkInterface string
//NetworkInterfaceIPV6Index int
}

View File

@@ -78,9 +78,9 @@ func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, No
Defaults.GroupTrackContainersPath = defaultPath + "client/trackcontainers/grouptrackcontainers.json"
Defaults.ServerPort = "8088"
Defaults.ProxyPort = ""
Defaults.FRPServerPort = "True"
Defaults.FRPServerPort = true
Defaults.CustomConfig = CustomConfig
Defaults.BehindNAT = "True"
Defaults.BehindNAT = true
Defaults.DockerRunLogs = "/tmp/"
// Generate a random key to be added to IPTable
Defaults.IPTableKey = String(12)
@@ -95,6 +95,8 @@ func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, No
Defaults.PrivateKeyFile = defaultPath + "p2prc.privateKey"
Defaults.BareMetal = false
Defaults.UnsafeMode = false
Defaults.Test = false
Defaults.ConfigPath = defaultPath + "config.json"
// Generate certificate files for SSL
err = GenerateCertificate()

View File

@@ -16,7 +16,6 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"log"
"math/big"
"net"
@@ -54,7 +53,8 @@ func GenerateCertificate() error {
//flag.Parse()
host, err = p2p.CurrentPublicIP()
//host, err = p2p.CurrentPublicIP()
host = "0.0.0.0"
if err != nil {
return err

View File

@@ -45,9 +45,9 @@ func GenerateIPTableFile(rootNodes []p2p.IpAddress) (err error) {
if len(rootNodes) <= 0 {
rootnode.Name = "Node1"
rootnode.ServerPort = "8078"
rootnode.NAT = "False"
rootnode.NAT = false
rootnode.Ipv4 = "217.76.63.222"
rootnode.ProxyServer = "True"
rootnode.ProxyServer = true
rootnodes.IpAddress = append(rootnodes.IpAddress, rootnode)
} else {

12
flake.lock generated
View File

@@ -28,11 +28,11 @@
]
},
"locked": {
"lastModified": 1733668782,
"narHash": "sha256-tPsqU00FhgdFr0JiQUiBMgPVbl1jbPCY5gbFiJycL3I=",
"lastModified": 1745875161,
"narHash": "sha256-0YkWCS13jpoo3+sX/3kcgdxBNt1VZTmvF+FhZb4rFKI=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "514283ec89c39ad0079ff2f3b1437404e4cba608",
"rev": "2cbd7fdd6eeab65c494cc426e18f4e4d2a5e35c0",
"type": "github"
},
"original": {
@@ -43,11 +43,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1735834308,
"narHash": "sha256-dklw3AXr3OGO4/XT1Tu3Xz9n/we8GctZZ75ZWVqAVhk=",
"lastModified": 1748460289,
"narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6df24922a1400241dae323af55f30e4318a6ca65",
"rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102",
"type": "github"
},
"original": {

152
flake.nix
View File

@@ -1,41 +1,129 @@
{
description = "P2PRC nix flake";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.gomod2nix.url = "github:nix-community/gomod2nix";
inputs.gomod2nix.inputs.nixpkgs.follows = "nixpkgs";
inputs.gomod2nix.inputs.flake-utils.follows = "flake-utils";
inputs = {
outputs = { self, nixpkgs, flake-utils, gomod2nix }:
(flake-utils.lib.eachDefaultSystem
(system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ gomod2nix.overlays.default ];
};
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# pkgs = nixpkgs.legacyPackages.${system};
flake-utils = {
url = "github:numtide/flake-utils";
};
# The current default sdk for macOS fails to compile go projects, so we use a newer one for now.
# This has no effect on other platforms.
callPackage = pkgs.darwin.apple_sdk_11_0.callPackage or pkgs.callPackage;
in
{
gomod2nix = {
url = "github:nix-community/gomod2nix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
packages.default = callPackage ./. { };
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
go
gopls
gotools
go-tools
gomod2nix.packages.${system}.default
sqlite-interactive
];
};
})
);
outputs =
{
nixpkgs,
flake-utils,
gomod2nix,
...
}:
let
bindingsOverlay = import ./nix/overlays/bindings.nix;
coreOverlay = (final: prev: {
p2prc = final.callPackage ./. { };
});
in
(flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
gomod2nix.overlays.default
coreOverlay
bindingsOverlay
];
};
# The current default sdk for macOS fails to compile go projects, so we use a newer one for now.
# This has no effect on other platforms.
callPackage = pkgs.darwin.apple_sdk_11_0.callPackage or pkgs.callPackage;
p2prcDefault = callPackage ./. { };
in
{
packages.default = p2prcDefault;
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
go
gopls
gotools
go-tools
gomod2nix.packages.${system}.default
sqlite-interactive
];
};
packages.initHaskellProject = pkgs.writeShellApplication {
name = "initHaskellProject";
runtimeInputs = with pkgs; [
ghc
cabal2nix
cabal-install
git
p2prcDefault
];
text =
''
clear
if [ "$#" -eq 0 ]; then
echo "No arguments provided."
echo "Please provide the name of your project"
echo "nix run git+https://github:akilan1999/p2p-rendering-computation#initHaskellProject -- <NAME-PROJECT>"
exit 1;
fi
PROJECT_DIR="$1"
mkdir "$PROJECT_DIR"
cd "$PROJECT_DIR"
git init .
clear
cabal init --exe --simple
sed -i 's/base.*$/base, p2prc/' "$PROJECT_DIR".cabal
cabal2nix . > ./cabal.nix;
git add .
clear
echo -e "run the following commands to finish nix development and production environment:\n\n"
echo -e "cd $PROJECT_DIR"
echo -e "nix flake init -t github:akilan1999/p2p-rendering-computation#haskell"
echo -e "nix develop"
echo -e "nix run"
echo -e "\n\n"
'';
};
}
)) //
{
overlays = {
default = coreOverlay;
bindings = bindingsOverlay;
};
templates.haskell = {
path = ./nix/templates/haskell;
description = "Haskell Bindings to p2prc protocol";
};
};
}

View File

@@ -34,10 +34,6 @@ func getFireSignalsChannel() chan os.Signal {
}
func exit() {
syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
}
func main() {
app := cli.NewApp()
app.Name = "p2p-rendering-computation"

View File

@@ -0,0 +1,7 @@
final: prev: {
haskellPackages = prev.haskellPackages.override {
overrides = hfinal: hprev: {
p2prc = hfinal.callPackage ../../Bindings/Haskell/project.nix { };
};
};
}

190
nix/templates/haskell/flake.lock generated Normal file
View File

@@ -0,0 +1,190 @@
{
"nodes": {
"flake-util": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"id": "flake-utils",
"type": "indirect"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gomod2nix": {
"inputs": {
"flake-utils": [
"p2prc-flake",
"flake-utils"
],
"nixpkgs": [
"p2prc-flake",
"nixpkgs"
]
},
"locked": {
"lastModified": 1745875161,
"narHash": "sha256-0YkWCS13jpoo3+sX/3kcgdxBNt1VZTmvF+FhZb4rFKI=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "2cbd7fdd6eeab65c494cc426e18f4e4d2a5e35c0",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "gomod2nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1748460289,
"narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1748370509,
"narHash": "sha256-QlL8slIgc16W5UaI3w7xHQEP+Qmv/6vSNTpoZrrSlbk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4faa5f5321320e49a78ae7848582f684d64783e9",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"p2prc-flake": {
"inputs": {
"flake-utils": "flake-utils_2",
"gomod2nix": "gomod2nix",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1748646470,
"narHash": "sha256-7aZQQ+jHdlxUzFPXzEEYfH1oU3isSZlZnMC7HWUDHCk=",
"owner": "xecarlox94",
"repo": "p2p-rendering-computation",
"rev": "73a283a545d61754a0fe821287541c2cd412bc0e",
"type": "github"
},
"original": {
"owner": "xecarlox94",
"ref": "nix",
"repo": "p2p-rendering-computation",
"type": "github"
}
},
"root": {
"inputs": {
"flake-util": "flake-util",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"p2prc-flake": "p2prc-flake"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -0,0 +1,48 @@
{
description = "Start of Haskell P2PRC flake";
inputs =
{
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-util.url = "github:numtide/flake-utils";
p2prc-flake.url = "github:akilan1999/p2p-rendering-computation";
};
outputs = { nixpkgs, p2prc-flake, flake-utils, ... }:
(flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
p2prc-flake.overlays.default
p2prc-flake.overlays.bindings
];
};
in {
packages.default = pkgs.haskellPackages.callPackage ./cabal.nix { };
devShells.default = pkgs.haskellPackages.shellFor {
packages = p: [
(p.callPackage ./cabal.nix { })
];
buildInputs = with pkgs; [
p2prc-flake.packages.${system}.default
ghc
cabal2nix
cabal-install
];
shellHook = ''
cabal2nix . > ./cabal.nix
'';
};
}
));
}

View File

@@ -1,284 +1,297 @@
package p2p
import (
"bytes"
"crypto/sha256"
"encoding/json"
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/config"
"io/ioutil"
"net"
"net/http"
"os"
"time"
"bytes"
"crypto/sha256"
"encoding/json"
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/config"
"io/ioutil"
"net"
"net/http"
"os"
"time"
)
// Get IP table Data
type IpAddresses struct {
IpAddress []IpAddress `json:"ip_address"`
IpAddress []IpAddress `json:"ip_address"`
}
type IpAddress struct {
Name string `json:"Name"`
MachineUsername string `json:"MachineUsername"`
Ipv4 string `json:"IPV4"`
Ipv6 string `json:"IPV6"`
Latency time.Duration `json:"Latency"`
Download float64 `json:"Download"`
Upload float64 `json:"Upload"`
ServerPort string `json:"ServerPort"`
BareMetalSSHPort string `json:"BareMetalSSHPort"`
NAT string `json:"NAT"`
EscapeImplementation string `json:"EscapeImplementation"`
ProxyServer string `json:"ProxyServer"`
UnSafeMode bool `json:"UnSafeMode"`
PublicKey string `json:"PublicKey"`
CustomInformation string `json:"CustomInformation"`
//CustomInformationKey []byte `json:"CustomInformationKey"`
Name string `json:"Name"`
MachineUsername string `json:"MachineUsername"`
Ipv4 string `json:"IPV4"`
Ipv6 string `json:"IPV6"`
Latency time.Duration `json:"Latency"`
Download float64 `json:"Download"`
Upload float64 `json:"Upload"`
ServerPort string `json:"ServerPort"`
BareMetalSSHPort string `json:"BareMetalSSHPort"`
NAT bool `json:"NAT"`
EscapeImplementation string `json:"EscapeImplementation"`
ProxyServer bool `json:"ProxyServer"`
UnSafeMode bool `json:"UnSafeMode"`
PublicKey string `json:"PublicKey"`
CustomInformation string `json:"CustomInformation"`
//CustomInformationKey []byte `json:"CustomInformationKey"`
}
type IP struct {
Query string
Query string
}
var Test = false
// ReadIpTable Read data from Ip tables from json file
func ReadIpTable() (*IpAddresses, error) {
// Get Path from config
config, err := config.ConfigInit(nil, nil)
if err != nil {
return nil, err
}
jsonFile, err := os.Open(config.IPTable)
// if we os.Open returns an error then handle it
if err != nil {
return nil, err
}
// Get Path from config
config, err := config.ConfigInit(nil, nil)
if err != nil {
return nil, err
}
jsonFile, err := os.Open(config.IPTable)
// if we os.Open returns an error then handle it
if err != nil {
return nil, err
}
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
// read our opened xmlFile as a byte array.
byteValue, _ := ioutil.ReadAll(jsonFile)
// read our opened xmlFile as a byte array.
byteValue, _ := ioutil.ReadAll(jsonFile)
// we initialize our Users array
var ipAddresses IpAddresses
// we initialize our Users array
var ipAddresses IpAddresses
// we unmarshal our byteArray which contains our
// jsonFile's content into 'users' which we defined above
json.Unmarshal(byteValue, &ipAddresses)
// we unmarshal our byteArray which contains our
// jsonFile's content into 'users' which we defined above
json.Unmarshal(byteValue, &ipAddresses)
var PublicIP IpAddress
var PublicIP IpAddress
ipv6, err := GetCurrentIPV6()
if err != nil {
return nil, err
}
ipv6, err := GetCurrentIPV6()
if err != nil {
return nil, err
}
ip, err := CurrentPublicIP()
if err != nil {
return nil, err
}
PublicIP.Ipv4 = ip
PublicIP.Ipv6 = ipv6
PublicIP.ServerPort = config.ServerPort
PublicIP.Name = config.MachineName
PublicIP.NAT = config.BehindNAT
PublicIP.EscapeImplementation = "None"
ip, err := CurrentPublicIP()
if err != nil {
return nil, err
}
PublicIP.Ipv4 = ip
PublicIP.Ipv6 = ipv6
PublicIP.ServerPort = config.ServerPort
PublicIP.Name = config.MachineName
PublicIP.NAT = config.BehindNAT
PublicIP.EscapeImplementation = "None"
// Updates current machine IP address to the IP table
ipAddresses.IpAddress = append(ipAddresses.IpAddress, PublicIP)
// Updates current machine IP address to the IP table
ipAddresses.IpAddress = append(ipAddresses.IpAddress, PublicIP)
//before writing to iptable ensures the duplicates are removed
if err = ipAddresses.RemoveDuplicates(); err != nil {
return nil, err
}
//before writing to iptable ensures the duplicates are removed
if err = ipAddresses.RemoveDuplicates(); err != nil {
return nil, err
}
return &ipAddresses, nil
return &ipAddresses, nil
}
// WriteIpTable Write to IP table json file
func (i *IpAddresses) WriteIpTable() error {
//before writing to iptable ensures the duplicates are removed
if err := i.RemoveDuplicates(); err != nil {
return err
}
//before writing to iptable ensures the duplicates are removed
if err := i.RemoveDuplicates(); err != nil {
return err
}
file, err := json.MarshalIndent(i, "", " ")
if err != nil {
return err
}
file, err := json.MarshalIndent(i, "", " ")
if err != nil {
return err
}
// Get Path from config
config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
// Get Path from config
config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
err = ioutil.WriteFile(config.IPTable, file, 0644)
if err != nil {
return err
}
err = ioutil.WriteFile(config.IPTable, file, 0644)
if err != nil {
return err
}
return nil
return nil
}
// PrintIpTable Print Ip table data for Cli
func PrintIpTable() error {
table, err := ReadIpTable()
//
if err != nil {
return err
}
//
//for i := 0; i < len(table.IpAddress); i++ {
// fmt.Printf("\nMachine Name: %s\nIP Address: %s\nIPV6: %s\nLatency: %s\nServerPort: %s\nbehindNAT: %s\nEscapeImplementation: %s\n-----------"+
// "-----------------\n", table.IpAddress[i].Name, table.IpAddress[i].Ipv4, table.IpAddress[i].Ipv6,
// table.IpAddress[i].Latency, table.IpAddress[i].ServerPort, table.IpAddress[i].NAT, table.IpAddress[i].EscapeImplementation)
//}
PrettyPrint(table)
table, err := ReadIpTable()
//
if err != nil {
return err
}
//
//for i := 0; i < len(table.IpAddress); i++ {
// fmt.Printf("\nMachine Name: %s\nIP Address: %s\nIPV6: %s\nLatency: %s\nServerPort: %s\nbehindNAT: %s\nEscapeImplementation: %s\n-----------"+
// "-----------------\n", table.IpAddress[i].Name, table.IpAddress[i].Ipv4, table.IpAddress[i].Ipv6,
// table.IpAddress[i].Latency, table.IpAddress[i].ServerPort, table.IpAddress[i].NAT, table.IpAddress[i].EscapeImplementation)
//}
PrettyPrint(table)
return nil
return nil
}
// RemoveDuplicates This is a temporary fix current functions failing to remove
// Duplicate IP addresses from local IP table
func (table *IpAddresses) RemoveDuplicates() error {
var NoDuplicates IpAddresses
for i, _ := range table.IpAddress {
Exists := false
for k := range NoDuplicates.IpAddress {
// Statements checked for
// - duplicate IPV4 addresses [<IPV4>:<Port No>]
// - duplicate IPV6 addresses [<IPV6>]
// - Node is behind NAT and no escape implementation provided
if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4 &&
NoDuplicates.IpAddress[k].ServerPort == table.IpAddress[i].ServerPort) ||
(NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) {
Exists = true
break
}
}
var NoDuplicates IpAddresses
for i, _ := range table.IpAddress {
Exists := false
for k := range NoDuplicates.IpAddress {
// Statements checked for
// - duplicate IPV4 addresses [<IPV4>:<Port No>]
// - duplicate IPV6 addresses [<IPV6>]
// - Node is behind NAT and no escape implementation provided
if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4 &&
NoDuplicates.IpAddress[k].ServerPort == table.IpAddress[i].ServerPort) ||
(NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) {
Exists = true
break
}
}
if table.IpAddress[i].NAT == "True" && table.IpAddress[i].EscapeImplementation == "None" {
Exists = true
}
if table.IpAddress[i].NAT && table.IpAddress[i].EscapeImplementation == "None" {
Exists = true
}
if Exists {
continue
}
NoDuplicates.IpAddress = append(NoDuplicates.IpAddress, table.IpAddress[i])
}
if Exists {
continue
}
NoDuplicates.IpAddress = append(NoDuplicates.IpAddress, table.IpAddress[i])
}
table.IpAddress = NoDuplicates.IpAddress
table.IpAddress = NoDuplicates.IpAddress
return nil
return nil
}
// CurrentPublicIP Get Current Public IP address
func CurrentPublicIP() (string, error) {
req, err := http.Get("http://ip-api.com/json/")
if err != nil {
return "", err
}
defer req.Body.Close()
// Get configs
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return "", err
}
// If test mode is on then return local address
if Config.Test {
return "0.0.0.0", nil
}
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return "", err
}
req, err := http.Get("http://ip-api.com/json/")
if err != nil {
return "", err
}
defer req.Body.Close()
var ip IP
json.Unmarshal(body, &ip)
body, err := ioutil.ReadAll(req.Body)
if err != nil {
return "", err
}
var ip IP
json.Unmarshal(body, &ip)
return ip.Query, nil
return ip.Query, nil
}
// GetCurrentIPV6 gets the current IPV6 address based on the interface
// specified in the config file
func GetCurrentIPV6() (string, error) {
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return "", err
}
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return "", err
}
// Fix in future release
//byNameInterface, err := net.InterfaceByName(Config.NetworkInterface)
//if err != nil {
// return "",err
//}
//addresses, err := byNameInterface.Addrs()
//if err != nil {
// return "",err
//}
//if addresses[1].String() == "" {
// return "",errors.New("IPV6 address not detected")
//}
//IP,_,err := net.ParseCIDR(addresses[Config.NetworkInterfaceIPV6Index].String())
//if err != nil {
// return "",err
//}
// Fix in future release
//byNameInterface, err := net.InterfaceByName(Config.NetworkInterface)
//if err != nil {
// return "",err
//}
//addresses, err := byNameInterface.Addrs()
//if err != nil {
// return "",err
//}
//if addresses[1].String() == "" {
// return "",errors.New("IPV6 address not detected")
//}
//IP,_,err := net.ParseCIDR(addresses[Config.NetworkInterfaceIPV6Index].String())
//if err != nil {
// return "",err
//}
return Config.IPV6Address, nil
return Config.IPV6Address, nil
}
// ViewNetworkInterface This function is created to view the network interfaces available
func ViewNetworkInterface() error {
ifaces, err := net.Interfaces()
if err != nil {
return err
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
return err
}
for index, a := range addrs {
switch v := a.(type) {
case *net.IPAddr:
fmt.Printf("(%v) %v : %s (%s)\n", index, i.Name, v, v.IP.DefaultMask())
ifaces, err := net.Interfaces()
if err != nil {
return err
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
return err
}
for index, a := range addrs {
switch v := a.(type) {
case *net.IPAddr:
fmt.Printf("(%v) %v : %s (%s)\n", index, i.Name, v, v.IP.DefaultMask())
case *net.IPNet:
fmt.Printf("(%v) %v : %s \n", index, i.Name, v)
}
case *net.IPNet:
fmt.Printf("(%v) %v : %s \n", index, i.Name, v)
}
}
}
return nil
}
}
return nil
}
// Ip4or6 Helper function to check if the IP address is IPV4 or
// IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6)
func Ip4or6(s string) string {
for i := 0; i < len(s); i++ {
switch s[i] {
case '.':
return "version 4"
case ':':
return "version 6"
}
}
return "version 6"
for i := 0; i < len(s); i++ {
switch s[i] {
case '.':
return "version 4"
case ':':
return "version 6"
}
}
return "version 6"
}
func PrettyPrint(data interface{}) {
var p []byte
// var err := error
p, err := json.MarshalIndent(data, "", "\t")
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s \n", p)
var p []byte
// var err := error
p, err := json.MarshalIndent(data, "", "\t")
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s \n", p)
}
func GenerateHashSHA256(text string) []byte {
h := sha256.New()
h.Write([]byte(text))
h := sha256.New()
h.Write([]byte(text))
return h.Sum(nil)
return h.Sum(nil)
}
// ValidateHashSHA256 CustomInformationKey the text and check if the text and
@@ -287,12 +300,12 @@ func GenerateHashSHA256(text string) []byte {
// SHA256 is the current hashing algorthm
// used.
func ValidateHashSHA256(text string, Hash []byte) bool {
h := sha256.New()
h.Write([]byte(text))
h := sha256.New()
h.Write([]byte(text))
textHash := h.Sum(nil)
if bytes.Equal(textHash, Hash) {
return true
}
return false
textHash := h.Sum(nil)
if bytes.Equal(textHash, Hash) {
return true
}
return false
}

View File

@@ -1,136 +1,137 @@
package p2p
import (
"github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/config"
)
// SpeedTest Runs a speed test and does updates IP tables accordingly
func (ip *IpAddresses) SpeedTest() error {
//temp variable to store elements IP addresses and other information
// of IP addresses that are pingable
var ActiveIP IpAddresses
//temp variable to store elements IP addresses and other information
// of IP addresses that are pingable
var ActiveIP IpAddresses
// Index to remove from struct
for _, value := range ip.IpAddress {
// Index to remove from struct
for _, value := range ip.IpAddress {
var err error
//if len(ip.IpAddress) == 1 {
// i = 0
//}
var err error
//if len(ip.IpAddress) == 1 {
// i = 0
//}
// Ping Test
err = value.PingTest()
// Ping Test
err = value.PingTest()
if err != nil {
continue
}
if err != nil {
continue
}
//Upload Speed Test
//err = value.UploadSpeed()
//if err != nil {
// return err
//}
//
//err = value.DownloadSpeed()
//if err != nil {
// return err
//}
//Upload Speed Test
//err = value.UploadSpeed()
//if err != nil {
// return err
//}
//
//err = value.DownloadSpeed()
//if err != nil {
// return err
//}
//Set value to the list
//Set value to the list
ActiveIP.IpAddress = append(ActiveIP.IpAddress, value)
}
ActiveIP.IpAddress = append(ActiveIP.IpAddress, value)
}
ip.IpAddress = ActiveIP.IpAddress
ip.IpAddress = ActiveIP.IpAddress
err := ip.WriteIpTable()
if err != nil {
return err
}
err := ip.WriteIpTable()
if err != nil {
return err
}
return nil
return nil
}
// SpeedTestUpdatedIPTable Called when ip tables from httpclient/server is also passed on
func (ip *IpAddresses) SpeedTestUpdatedIPTable() error {
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
Config, err := config.ConfigInit(nil, nil)
if err != nil {
return err
}
targets, err := ReadIpTable()
if err != nil {
return err
}
targets, err := ReadIpTable()
if err != nil {
return err
}
// Checks if baremetal mode and unsafe mode
// is enabled. If it is enabled it adds the
// the propagated public key to the list.
// Checks if baremetal mode and unsafe mode
// is enabled. If it is enabled it adds the
// the propagated public key to the list.
AddPublicKey := false
if Config.BareMetal && Config.UnsafeMode {
AddPublicKey = true
}
AddPublicKey := false
if Config.BareMetal && Config.UnsafeMode {
AddPublicKey = true
}
// To ensure struct has no duplicates IP addresses
//DoNotRead := targets
// To ensure struct has no duplicates IP addresses
//DoNotRead := targets
// Appends all IP addresses
for i, _ := range targets.IpAddress {
// Appends all IP addresses
for i, _ := range targets.IpAddress {
//To ensure that there are no duplicate IP addresses
Exists := false
for k := range ip.IpAddress {
if AddPublicKey && ip.IpAddress[k].PublicKey != "" {
// This function call (AddAuthorisationKey) is inefficient but to be optimised later on.
// This is because when if the user is running on as unsafe mode the authorization file
// is opened from the SSH directory and then iterates through every single SSH entry
// to find out if the SSH entry exists or not. This will incur multiple CPU cycles
// for no reason. A better approach would be to have been to store the states on memory and only
// add when needed based on the memory location. This is something is to be discussed
// and look upon later on.
AddAuthorisationKey(ip.IpAddress[k].PublicKey)
}
// Checks if both the IPV4 addresses are the same or the IPV6 address is not
// an empty string and IPV6 address are the same
if (ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 && targets.IpAddress[i].NAT == "True") || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) {
Exists = true
break
}
}
//To ensure that there are no duplicate IP addresses
Exists := false
for k := range ip.IpAddress {
if AddPublicKey && ip.IpAddress[k].PublicKey != "" {
// This function call (AddAuthorisationKey) is inefficient but to be optimised later on.
// This is because when if the user is running on as unsafe mode the authorization file
// is opened from the SSH directory and then iterates through every single SSH entry
// to find out if the SSH entry exists or not. This will incur multiple CPU cycles
// for no reason. A better approach would be to have been to store the states on memory and only
// add when needed based on the memory location. This is something is to be discussed
// and look upon later on.
AddAuthorisationKey(ip.IpAddress[k].PublicKey)
}
targets.IpAddress[i].CustomInformation = ip.IpAddress[k].CustomInformation
// Checks if both the IPV4 addresses are the same or the IPV6 address is not
// an empty string and IPV6 address are the same
if (ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 && targets.IpAddress[i].NAT) || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) {
Exists = true
break
}
}
// If the struct exists then continues
if Exists {
continue
}
// If the struct exists then continues
if Exists {
continue
}
ip.IpAddress = append(ip.IpAddress, targets.IpAddress[i])
}
ip.IpAddress = append(ip.IpAddress, targets.IpAddress[i])
}
err = ip.SpeedTest()
err = ip.SpeedTest()
if err != nil {
return err
}
if err != nil {
return err
}
return nil
return nil
}
// LocalSpeedTestIpTable Runs speed test in iptables locally only
func LocalSpeedTestIpTable() error {
targets, err := ReadIpTable()
if err != nil {
return err
}
targets, err := ReadIpTable()
if err != nil {
return err
}
err = targets.SpeedTest()
if err != nil {
return err
}
err = targets.SpeedTest()
if err != nil {
return err
}
return nil
return nil
}
// Helper function to remove element from an array of a struct

View File

@@ -1,478 +1,477 @@
package server
import (
b64 "encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
"github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
"os/user"
"strconv"
"time"
b64 "encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
"github.com/Akilan1999/p2p-rendering-computation/config"
"github.com/Akilan1999/p2p-rendering-computation/p2p"
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
"github.com/gin-gonic/gin"
"io/ioutil"
"net/http"
"os/user"
"strconv"
"time"
)
type ReverseProxy struct {
IPAddress string
Port string
IPAddress string
Port string
}
// ReverseProxies Reverse to the map such as ReverseProxies[<domain nane>]ReverseProxy type
var ReverseProxies map[string]ReverseProxy
func Server() (*gin.Engine, error) {
r := gin.Default()
r := gin.Default()
// "The make function allocates and initializes a hash map data
//structure and returns a map value that points to it.
//The specifics of that data structure are an implementation
//detail of the runtime and are not specified by the language itself."
// source: https://go.dev/blog/maps
ReverseProxies = make(map[string]ReverseProxy)
// "The make function allocates and initializes a hash map data
//structure and returns a map value that points to it.
//The specifics of that data structure are an implementation
//detail of the runtime and are not specified by the language itself."
// source: https://go.dev/blog/maps
ReverseProxies = make(map[string]ReverseProxy)
//Get Server port based on the config file
config, err := config.ConfigInit(nil, nil)
if err != nil {
return nil, err
}
//Get Server port based on the config file
config, err := config.ConfigInit(nil, nil)
if err != nil {
return nil, err
}
// update IPTable with new port and ip address and update ip table
var ProxyIpAddr p2p.IpAddress
var lowestLatencyIpAddress p2p.IpAddress
// update IPTable with new port and ip address and update ip table
var ProxyIpAddr p2p.IpAddress
var lowestLatencyIpAddress p2p.IpAddress
// Gets default information of the server
r.GET("/server_info", func(c *gin.Context) {
c.JSON(http.StatusOK, ServerInfo())
})
// Gets default information of the server
r.GET("/server_info", func(c *gin.Context) {
c.JSON(http.StatusOK, ServerInfo())
})
// Speed test with 50 mbps
r.GET("/50", func(c *gin.Context) {
// Get Path from config
c.File(config.SpeedTestFile)
})
// Speed test with 50 mbps
r.GET("/50", func(c *gin.Context) {
// Get Path from config
c.File(config.SpeedTestFile)
})
// Route build to do a speed test
r.GET("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
// Route build to do a speed test
r.GET("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
// Upload the file to specific dst.
// c.SaveUploadedFile(file, dst)
// Upload the file to specific dst.
// c.SaveUploadedFile(file, dst)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
//Gets Ip Table from server node
r.POST("/IpTable", func(c *gin.Context) {
// Getting IPV4 address of client
//var ClientHost p2p.IpAddress
//
//if p2p.Ip4or6(c.ClientIP()) == "version 6" {
// ClientHost.Ipv6 = c.ClientIP()
//} else {
// ClientHost.Ipv4 = c.ClientIP()
//}
//Gets Ip Table from server node
r.POST("/IpTable", func(c *gin.Context) {
// Getting IPV4 address of client
//var ClientHost p2p.IpAddress
//
//if p2p.Ip4or6(c.ClientIP()) == "version 6" {
// ClientHost.Ipv6 = c.ClientIP()
//} else {
// ClientHost.Ipv4 = c.ClientIP()
//}
// Variable to store IP table information
var IPTable p2p.IpAddresses
// Variable to store IP table information
var IPTable p2p.IpAddresses
// Receive file from POST request
body, err := c.FormFile("json")
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Receive file from POST request
body, err := c.FormFile("json")
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Open file
open, err := body.Open()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Open file
open, err := body.Open()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Open received file
file, err := ioutil.ReadAll(open)
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Open received file
file, err := ioutil.ReadAll(open)
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
json.Unmarshal(file, &IPTable)
json.Unmarshal(file, &IPTable)
//Add Client IP address to IPTable struct
//IPTable.IpAddress = append(IPTable.IpAddress, ClientHost)
//Add Client IP address to IPTable struct
//IPTable.IpAddress = append(IPTable.IpAddress, ClientHost)
// Runs speed test to return only servers in the IP table pingable
err = IPTable.SpeedTestUpdatedIPTable()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Runs speed test to return only servers in the IP table pingable
err = IPTable.SpeedTestUpdatedIPTable()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Reads IP addresses from ip table
IpAddresses, err := p2p.ReadIpTable()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
// Reads IP addresses from ip table
IpAddresses, err := p2p.ReadIpTable()
if err != nil {
c.String(http.StatusOK, fmt.Sprint(err))
}
c.JSON(http.StatusOK, IpAddresses)
})
c.JSON(http.StatusOK, IpAddresses)
})
// Starts docker container in server
r.GET("/startcontainer", func(c *gin.Context) {
// Get Number of ports to open and whether to use GPU or not
Ports := c.DefaultQuery("ports", "0")
GPU := c.DefaultQuery("GPU", "false")
ContainerName := c.DefaultQuery("ContainerName", "")
BaseImage := c.DefaultQuery("BaseImage", "")
PublicKey := c.DefaultQuery("PublicKey", "")
var PortsInt int
// Starts docker container in server
r.GET("/startcontainer", func(c *gin.Context) {
// Get Number of ports to open and whether to use GPU or not
Ports := c.DefaultQuery("ports", "0")
GPU := c.DefaultQuery("GPU", "false")
ContainerName := c.DefaultQuery("ContainerName", "")
BaseImage := c.DefaultQuery("BaseImage", "")
PublicKey := c.DefaultQuery("PublicKey", "")
var PortsInt int
if PublicKey == "" {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", "Publickey not passed"))
}
if PublicKey == "" {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", "Publickey not passed"))
}
PublicKeyDecoded, err := b64.StdEncoding.DecodeString(PublicKey)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
PublicKeyDecoded, err := b64.StdEncoding.DecodeString(PublicKey)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
// Convert Get Request value to int
fmt.Sscanf(Ports, "%d", &PortsInt)
// Convert Get Request value to int
fmt.Sscanf(Ports, "%d", &PortsInt)
fmt.Println(string(PublicKeyDecoded[:]))
// Creates container and returns-back result to
// access container
resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName, BaseImage, string(PublicKeyDecoded[:]))
// Creates container and returns-back result to
// access container
resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName, BaseImage, string(PublicKeyDecoded[:]))
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
// Ensures that FRP is triggered only if a proxy address is provided
if ProxyIpAddr.Ipv4 != "" && c.Request.Host != "localhost:"+config.ServerPort && c.Request.Host != "0.0.0.0:"+config.ServerPort {
resp, err = frp.StartFRPCDockerContainer(ProxyIpAddr.Ipv4, lowestLatencyIpAddress.ServerPort, resp)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
}
// Ensures that FRP is triggered only if a proxy address is provided
if ProxyIpAddr.Ipv4 != "" && c.Request.Host != "localhost:"+config.ServerPort && c.Request.Host != "0.0.0.0:"+config.ServerPort {
resp, err = frp.StartFRPCDockerContainer(ProxyIpAddr.Ipv4, lowestLatencyIpAddress.ServerPort, resp)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
}
c.JSON(http.StatusOK, resp)
})
c.JSON(http.StatusOK, resp)
})
//Remove container
r.GET("/RemoveContainer", func(c *gin.Context) {
ID := c.DefaultQuery("id", "0")
if err := docker.StopAndRemoveContainer(ID); err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
c.String(http.StatusOK, "success")
})
//Remove container
r.GET("/RemoveContainer", func(c *gin.Context) {
ID := c.DefaultQuery("id", "0")
if err := docker.StopAndRemoveContainer(ID); err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
c.String(http.StatusOK, "success")
})
//Show images available
r.GET("/ShowImages", func(c *gin.Context) {
resp, err := docker.ViewAllContainers()
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
c.JSON(http.StatusOK, resp)
})
//Show images available
r.GET("/ShowImages", func(c *gin.Context) {
resp, err := docker.ViewAllContainers()
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
c.JSON(http.StatusOK, resp)
})
// Request for port no from Server with address
r.GET("/FRPPort", func(c *gin.Context) {
port, err := frp.StartFRPProxyFromRandom()
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
// Request for port no from Server with address
r.GET("/FRPPort", func(c *gin.Context) {
port, err := frp.StartFRPProxyFromRandom()
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
c.String(http.StatusOK, strconv.Itoa(port))
})
c.String(http.StatusOK, strconv.Itoa(port))
})
r.GET("/MAPPort", func(c *gin.Context) {
Ports := c.DefaultQuery("port", "0")
DomainName := c.DefaultQuery("domain_name", "")
url, _, err := MapPort(Ports, DomainName)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
r.GET("/MAPPort", func(c *gin.Context) {
Ports := c.DefaultQuery("port", "0")
DomainName := c.DefaultQuery("domain_name", "")
url, _, err := MapPort(Ports, DomainName)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
}
c.String(http.StatusOK, url)
})
c.String(http.StatusOK, url)
})
r.GET("/AddProxy", func(c *gin.Context) {
DomainName := c.DefaultQuery("domain_name", "")
ip_address := c.DefaultQuery("ip_address", "")
Ports := c.DefaultQuery("port", "")
r.GET("/AddProxy", func(c *gin.Context) {
DomainName := c.DefaultQuery("domain_name", "")
ip_address := c.DefaultQuery("ip_address", "")
Ports := c.DefaultQuery("port", "")
if DomainName == "" || ip_address == "" || Ports == "" {
c.String(http.StatusInternalServerError, fmt.Sprintf("All get parameters npt provided"+
" do ensure domain_name, ip_Address and port no is provided"))
}
if DomainName == "" || ip_address == "" || Ports == "" {
c.String(http.StatusInternalServerError, fmt.Sprintf("All get parameters npt provided"+
" do ensure domain_name, ip_Address and port no is provided"))
}
err := SaveRegistration(DomainName, ip_address+":"+Ports)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf(err.Error()))
}
err := SaveRegistration(DomainName, ip_address+":"+Ports)
if err != nil {
c.String(http.StatusInternalServerError, fmt.Sprintf(err.Error()))
}
//_, ok := ReverseProxies[DomainName]
//// To check if the subdomain entry exists
//if ok {
// c.String(http.StatusInternalServerError, fmt.Sprintf("The domain entry already exists as a reverse"+
// " proxy entry"))
//}
//
//// added proxy as a map entry
//ReverseProxies[DomainName] = ReverseProxy{IPAddress: ip_address, Port: Ports}
c.String(http.StatusOK, "Sucess")
//_, ok := ReverseProxies[DomainName]
//// To check if the subdomain entry exists
//if ok {
// c.String(http.StatusInternalServerError, fmt.Sprintf("The domain entry already exists as a reverse"+
// " proxy entry"))
//}
//
//// added proxy as a map entry
//ReverseProxies[DomainName] = ReverseProxy{IPAddress: ip_address, Port: Ports}
c.String(http.StatusOK, "Sucess")
})
})
//r.GET("/RemoveProxy", func(c *gin.Context) {
// DomainName := c.DefaultQuery("domain_name", "")
//
// _, ok := ReverseProxies[DomainName]
// if !ok {
// c.String(http.StatusInternalServerError, fmt.Sprintf("Domain name does exist in entries of proxies"))
// } else {
// delete(ReverseProxies, DomainName)
// }
//
//})
//r.GET("/RemoveProxy", func(c *gin.Context) {
// DomainName := c.DefaultQuery("domain_name", "")
//
// _, ok := ReverseProxies[DomainName]
// if !ok {
// c.String(http.StatusInternalServerError, fmt.Sprintf("Domain name does exist in entries of proxies"))
// } else {
// delete(ReverseProxies, DomainName)
// }
//
//})
// If there is a proxy port specified
// then starts the FRP server
//if config.FRPServerPort != "0" {
// go frp.StartFRPProxyFromRandom()
//}
// If there is a proxy port specified
// then starts the FRP server
//if config.FRPServerPort != "0" {
// go frp.StartFRPProxyFromRandom()
//}
// Remove nodes currently not pingable
clientIPTable.RemoveOfflineNodes()
// Remove nodes currently not pingable
clientIPTable.RemoveOfflineNodes()
table, err := p2p.ReadIpTable()
table, err := p2p.ReadIpTable()
// TODO check if IPV6 or Proxy port is specified
// if not update current entry as proxy address
// with appropriate port on IP Table
if config.BehindNAT {
if err != nil {
return nil, err
}
// TODO check if IPV6 or Proxy port is specified
// if not update current entry as proxy address
// with appropriate port on IP Table
if config.BehindNAT == "True" {
if err != nil {
return nil, err
}
var lowestLatency int64
// random large number
lowestLatency = 10000000
var lowestLatency int64
// random large number
lowestLatency = 10000000
for i, _ := range table.IpAddress {
// Checks if the ping is the lowest and if the following node is acting as a proxy
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && !table.IpAddress[i].NAT {
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i]
}
}
for i, _ := range table.IpAddress {
// Checks if the ping is the lowest and if the following node is acting as a proxy
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].NAT != "" {
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i]
}
}
// If there is an identified node
if lowestLatency != 10000000 {
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
if err != nil {
return nil, err
}
// Create 3 second delay to allow FRP server to start
time.Sleep(1 * time.Second)
// Starts FRP as a client with
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, config.ServerPort, "")
if err != nil {
return nil, err
}
// If there is an identified node
if lowestLatency != 10000000 {
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
if err != nil {
return nil, err
}
// Create 3 second delay to allow FRP server to start
time.Sleep(1 * time.Second)
// Starts FRP as a client with
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, config.ServerPort, "")
if err != nil {
return nil, err
}
// updating with the current proxy address
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
ProxyIpAddr.ServerPort = proxyPort
ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = false
ProxyIpAddr.ProxyServer = false
ProxyIpAddr.EscapeImplementation = "FRP"
// updating with the current proxy address
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
ProxyIpAddr.ServerPort = proxyPort
ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = "False"
ProxyIpAddr.ProxyServer = "False"
ProxyIpAddr.EscapeImplementation = "FRP"
if config.BareMetal {
_, SSHPort, err := MapPort("22", "")
if err != nil {
return nil, err
}
ProxyIpAddr.BareMetalSSHPort = SSHPort
}
if config.BareMetal {
_, SSHPort, err := MapPort("22", "")
if err != nil {
return nil, err
}
ProxyIpAddr.BareMetalSSHPort = SSHPort
}
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
// write information back to the IP Table
}
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
// write information back to the IP Table
}
} else {
ProxyIpAddr.Ipv4, err = p2p.CurrentPublicIP()
if err != nil {
fmt.Println(err)
}
} else {
ProxyIpAddr.Ipv4, err = p2p.CurrentPublicIP()
if err != nil {
fmt.Println(err)
}
ProxyIpAddr.ServerPort = config.ServerPort
ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = "False"
if config.ProxyPort != "" {
ProxyIpAddr.ProxyServer = "True"
}
ProxyIpAddr.EscapeImplementation = ""
if config.BareMetal {
ProxyIpAddr.BareMetalSSHPort = "22"
}
ProxyIpAddr.ServerPort = config.ServerPort
ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = false
if config.ProxyPort != "" {
ProxyIpAddr.ProxyServer = true
}
ProxyIpAddr.EscapeImplementation = ""
if config.BareMetal {
ProxyIpAddr.BareMetalSSHPort = "22"
}
}
}
// Get machine username
currentUser, err := user.Current()
if err != nil {
return nil, err
}
// Add username p2prc binary is being run under
ProxyIpAddr.MachineUsername = currentUser.Username
ProxyIpAddr.UnSafeMode = config.UnsafeMode
// Adds the public key information to the IPTable
// improving transmission of IPTables without the
// entire public key is future work to be improved
// in the P2PRC protocol level (Improving by adding
// UDP with TCP reliability layer).
ProxyIpAddr.PublicKey, err = config.GetPublicKey()
// Get machine username
currentUser, err := user.Current()
if err != nil {
return nil, err
}
// Add username p2prc binary is being run under
ProxyIpAddr.MachineUsername = currentUser.Username
ProxyIpAddr.UnSafeMode = config.UnsafeMode
// Adds the public key information to the IPTable
// improving transmission of IPTables without the
// entire public key is future work to be improved
// in the P2PRC protocol level (Improving by adding
// UDP with TCP reliability layer).
ProxyIpAddr.PublicKey, err = config.GetPublicKey()
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
// append the following to the ip table
table.IpAddress = append(table.IpAddress, ProxyIpAddr)
// append the following to the ip table
table.IpAddress = append(table.IpAddress, ProxyIpAddr)
// Writing results to the IPTable
err = table.WriteIpTable()
if err != nil {
return nil, err
}
// Writing results to the IPTable
err = table.WriteIpTable()
if err != nil {
return nil, err
}
// update ip table
go func() error {
err := clientIPTable.UpdateIpTableListClient()
if err != nil {
fmt.Println(err)
return err
}
return nil
}()
// update ip table
go func() error {
err := clientIPTable.UpdateIpTableListClient()
if err != nil {
fmt.Println(err)
return err
}
return nil
}()
if config.ProxyPort != "" {
go ProxyRun(config.ProxyPort)
}
if config.ProxyPort != "" {
go ProxyRun(config.ProxyPort)
}
// Run gin server on the specified port
go r.Run(":" + config.ServerPort)
// Run gin server on the specified port
go r.Run(":" + config.ServerPort)
return r, nil
return r, nil
}
func MapPort(port string, domainName string) (string, string, error) {
// if server address is provided to do call RESTAPI to remotely open port.
//if serverAddress != "" {
// requestURL := fmt.Sprintf("http://%v/MAPPort?port=%v&domain_name=%v", serverAddress, port, domainName)
// req, err := http.NewRequest(http.MethodGet, requestURL, nil)
// if err != nil {
// return "", "", err
// }
//
// res, err := http.DefaultClient.Do(req)
// if err != nil {
// return "", "", err
// }
//
// resBody, err := io.ReadAll(res.Body)
// if err != nil {
// return "", "", err
// }
//
// _, Exposedport, err := net.SplitHostPort(string(resBody))
// if err != nil {
// return "", "", err
// }
//
// return string(resBody), Exposedport, nil
//}
// if server address is provided to do call RESTAPI to remotely open port.
//if serverAddress != "" {
// requestURL := fmt.Sprintf("http://%v/MAPPort?port=%v&domain_name=%v", serverAddress, port, domainName)
// req, err := http.NewRequest(http.MethodGet, requestURL, nil)
// if err != nil {
// return "", "", err
// }
//
// res, err := http.DefaultClient.Do(req)
// if err != nil {
// return "", "", err
// }
//
// resBody, err := io.ReadAll(res.Body)
// if err != nil {
// return "", "", err
// }
//
// _, Exposedport, err := net.SplitHostPort(string(resBody))
// if err != nil {
// return "", "", err
// }
//
// return string(resBody), Exposedport, nil
//}
//Get Server port based on the config file
config, err := config.ConfigInit(nil, nil)
if err != nil {
return "", "", err
}
//Get Server port based on the config file
config, err := config.ConfigInit(nil, nil)
if err != nil {
return "", "", err
}
// update IPTable with new port and ip address and update ip table
var ProxyIpAddr p2p.IpAddress
var lowestLatencyIpAddress p2p.IpAddress
// update IPTable with new port and ip address and update ip table
var ProxyIpAddr p2p.IpAddress
var lowestLatencyIpAddress p2p.IpAddress
clientIPTable.RemoveOfflineNodes()
clientIPTable.RemoveOfflineNodes()
table, err := p2p.ReadIpTable()
if err != nil {
return "", "", err
}
table, err := p2p.ReadIpTable()
if err != nil {
return "", "", err
}
var lowestLatency int64
// random large number
lowestLatency = 10000000
var lowestLatency int64
// random large number
lowestLatency = 10000000
for i, _ := range table.IpAddress {
// Checks if the ping is the lowest and if the following node is acting as a proxy
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].NAT != "" {
// Filter based on nodes with proxy enabled
if domainName != "" && table.IpAddress[i].ProxyServer == "True" {
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i]
continue
}
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i]
}
}
for i, _ := range table.IpAddress {
// Checks if the ping is the lowest and if the following node is acting as a proxy
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && !table.IpAddress[i].NAT {
// Filter based on nodes with proxy enabled
if domainName != "" && table.IpAddress[i].ProxyServer {
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i]
continue
}
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
lowestLatencyIpAddress = table.IpAddress[i]
}
}
// If there is an identified node
if lowestLatency != 10000000 {
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
if err != nil {
return "", "", err
}
// Create 3 second delay to allow FRP server to start
time.Sleep(1 * time.Second)
// Starts FRP as a client with
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, port, "")
if err != nil {
return "", "", err
}
// If there is an identified node
if lowestLatency != 10000000 {
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
if err != nil {
return "", "", err
}
// Create 3 second delay to allow FRP server to start
time.Sleep(1 * time.Second)
// Starts FRP as a client with
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, port, "")
if err != nil {
return "", "", err
}
// Doing the proxy mapping for the domain name
if domainName != "" {
fmt.Println("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4)
URL := "http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4
//} else {
// URL = "http://" + IP + ":" + serverPort + "/server_info"
//}
http.Get(URL)
//SaveRegistration(domainName, lowestLatencyIpAddress.Ipv4+":"+proxyPort)
}
// Doing the proxy mapping for the domain name
if domainName != "" {
fmt.Println("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4)
URL := "http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4
//} else {
// URL = "http://" + IP + ":" + serverPort + "/server_info"
//}
http.Get(URL)
//SaveRegistration(domainName, lowestLatencyIpAddress.Ipv4+":"+proxyPort)
}
// updating with the current proxy address
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
ProxyIpAddr.ServerPort = proxyPort
ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = "False"
ProxyIpAddr.EscapeImplementation = "FRP"
// updating with the current proxy address
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
ProxyIpAddr.ServerPort = proxyPort
ProxyIpAddr.Name = config.MachineName
ProxyIpAddr.NAT = false
ProxyIpAddr.EscapeImplementation = "FRP"
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
} else {
return "", "", errors.New("proxy IP not found")
}
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
} else {
return "", "", errors.New("proxy IP not found")
}
return ProxyIpAddr.Ipv4 + ":" + ProxyIpAddr.ServerPort, ProxyIpAddr.ServerPort, nil
return ProxyIpAddr.Ipv4 + ":" + ProxyIpAddr.ServerPort, ProxyIpAddr.ServerPort, nil
}

View File

@@ -1,32 +0,0 @@
body {
font-family: sans-serif;
}
span#discordJoin {
color: red;
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
/* General Page Changing */
body {
background: #121212; /* Background Color */
color: #FFFFFF; /* Text Color */
}
a:link{ /* Unvisited Link */
color: #03DAC5;
}
a:visited { /* Visited Link */
color: #BB86FC;
}
a:hover { /* Mouse over Link */
color: #018786;
}
span#discordJoin { /* Text Color Change */
color: #cc0227;
}
}

BIN
wasm/p2prc.wasm Executable file

Binary file not shown.