Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ac2c5f8a83 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,7 +31,6 @@ server/docker/containers/
|
|||||||
|
|
||||||
# generic folder to ignore
|
# generic folder to ignore
|
||||||
export/
|
export/
|
||||||
exports/
|
|
||||||
|
|
||||||
# Any testing file
|
# Any testing file
|
||||||
*test
|
*test
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|--------------|-----------------------------------------|
|
|--------------|-----------------------------------------|
|
||||||
| Copyright | Copyright (C) 2006-2024 John MacFarlane |
|
| Copyright | Copyright (C) 2006-2024 John MacFarlane |
|
||||||
| License | GNU GPL, version 2 or above |
|
| License | GNU GPL, version 2 or above |
|
||||||
|
| Maintainer | John MacFarlane \<jgm@berkeley.edu\> |
|
||||||
| Stability | alpha |
|
| Stability | alpha |
|
||||||
| Portability | portable |
|
| Portability | portable |
|
||||||
| Safe Haskell | Safe-Inferred |
|
| Safe Haskell | Safe-Inferred |
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ module API
|
|||||||
( P2PRCapi(..)
|
( P2PRCapi(..)
|
||||||
, MapPortRequest(..)
|
, MapPortRequest(..)
|
||||||
, p2prcAPI
|
, p2prcAPI
|
||||||
, P2PRCommands(..)
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -14,7 +13,6 @@ import System.Process ( ProcessHandle )
|
|||||||
|
|
||||||
import Data.Aeson ( FromJSON )
|
import Data.Aeson ( FromJSON )
|
||||||
|
|
||||||
|
|
||||||
import Error
|
import Error
|
||||||
( IOEitherError
|
( IOEitherError
|
||||||
)
|
)
|
||||||
@@ -51,26 +49,15 @@ data P2PRCapi
|
|||||||
-- ^ List servers in network
|
-- ^ List servers in network
|
||||||
, execMapPort :: MapPortRequest -> IOEitherError MapPortResponse
|
, execMapPort :: MapPortRequest -> IOEitherError MapPortResponse
|
||||||
-- ^ Exposes and associates a local TCP port with a remote DNS address
|
-- ^ 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.
|
-- | 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 =
|
data MapPortRequest =
|
||||||
MkMapPortRequest -- ^ P2PRC's port allocation request value
|
MkMapPortRequest -- ^ P2PRC's port allocation request value
|
||||||
Int -- ^ TCP socket number
|
Int -- ^ TCP socket number
|
||||||
String -- ^ Network domain name
|
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.
|
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.
|
||||||
@@ -107,15 +94,9 @@ 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" #-}
|
{-# 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
|
||||||
p2prcAPI = let
|
p2prcAPI =
|
||||||
|
|
||||||
execTemp :: Maybe MapPortRequest -> PassCustomInformation -> IOEitherError String
|
|
||||||
execTemp mp ci = undefined
|
|
||||||
|
|
||||||
|
|
||||||
in
|
|
||||||
MkP2PRCapi
|
MkP2PRCapi
|
||||||
{ startServer = spawnProcP2PRC p2prcCmdName [ MkOptAtomic "-s" ]
|
{ startServer = spawnProcP2PRC p2prcCmdName [ MkOptAtomic "--s" ]
|
||||||
|
|
||||||
, execListServers =
|
, execListServers =
|
||||||
execProcP2PRCParser [ MkOptAtomic "--ls" ] MkEmptyStdInput
|
execProcP2PRCParser [ MkOptAtomic "--ls" ] MkEmptyStdInput
|
||||||
@@ -134,9 +115,6 @@ p2prcAPI = let
|
|||||||
]
|
]
|
||||||
MkEmptyStdInput
|
MkEmptyStdInput
|
||||||
|
|
||||||
, execMaybeMapPortAndAddCustomInformation = execTemp
|
|
||||||
, execAddCustomInformation = execTemp Nothing
|
|
||||||
|
|
||||||
-- , execInitConfig = do
|
-- , execInitConfig = do
|
||||||
|
|
||||||
-- confInitRes <- execProcP2PRC [ MkOptAtomic "--dc" ] MkEmptyStdInput
|
-- confInitRes <- execProcP2PRC [ MkOptAtomic "--dc" ] MkEmptyStdInput
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
module Engine
|
module Engine
|
||||||
( runP2PRC
|
( runP2PRC
|
||||||
, fn
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ import System.Process ( terminateProcess )
|
|||||||
import API
|
import API
|
||||||
( P2PRCapi(..)
|
( P2PRCapi(..)
|
||||||
, MapPortRequest(..)
|
, MapPortRequest(..)
|
||||||
, p2prcAPI, P2PRCommands
|
, p2prcAPI
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -59,10 +58,14 @@ import API
|
|||||||
@
|
@
|
||||||
-}
|
-}
|
||||||
runP2PRC
|
runP2PRC
|
||||||
:: [P2PRCommands] -- ^ TCP Port Request
|
:: MapPortRequest -- ^ TCP Port Request
|
||||||
-> IO ()
|
-> IO ()
|
||||||
runP2PRC [] = putStrLn ""
|
runP2PRC
|
||||||
runP2PRC nonEmpty@(_:_) =
|
( MkMapPortRequest
|
||||||
|
portNumber
|
||||||
|
domainName
|
||||||
|
)
|
||||||
|
=
|
||||||
let
|
let
|
||||||
|
|
||||||
--
|
--
|
||||||
@@ -95,7 +98,6 @@ runP2PRC nonEmpty@(_:_) =
|
|||||||
-- , execInitConfig = execInitConfig
|
-- , execInitConfig = execInitConfig
|
||||||
, execListServers = execListServers
|
, execListServers = execListServers
|
||||||
, execMapPort = execMapPort
|
, execMapPort = execMapPort
|
||||||
, execAddCustomInformation = _
|
|
||||||
}
|
}
|
||||||
) = p2prcAPI
|
) = p2prcAPI
|
||||||
|
|
||||||
@@ -114,8 +116,7 @@ runP2PRC nonEmpty@(_:_) =
|
|||||||
|
|
||||||
|
|
||||||
case eitherStartProcessHandle of
|
case eitherStartProcessHandle of
|
||||||
(Right startProcessHandle) ->
|
(Right startProcessHandle) -> do
|
||||||
do
|
|
||||||
|
|
||||||
let sleepNSecs i = threadDelay (i * 1000000)
|
let sleepNSecs i = threadDelay (i * 1000000)
|
||||||
|
|
||||||
@@ -124,8 +125,7 @@ runP2PRC nonEmpty@(_:_) =
|
|||||||
outputStr <- execListServers
|
outputStr <- execListServers
|
||||||
print outputStr
|
print outputStr
|
||||||
|
|
||||||
-- mapPortOut <- execMapPort $ MkMapPortRequest portNumber domainName
|
mapPortOut <- execMapPort $ MkMapPortRequest portNumber domainName
|
||||||
mapPortOut <- execMapPort $ MkMapPortRequest undefined undefined
|
|
||||||
|
|
||||||
case mapPortOut of
|
case mapPortOut of
|
||||||
(Right v) -> print v
|
(Right v) -> print v
|
||||||
@@ -159,7 +159,3 @@ runP2PRC nonEmpty@(_:_) =
|
|||||||
when (toLower c /= 'q') $ exitOnQ exitF
|
when (toLower c /= 'q') $ exitOnQ exitF
|
||||||
exitF
|
exitF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn :: undefined
|
|
||||||
fn = undefined
|
|
||||||
@@ -52,7 +52,6 @@ module P2PRC
|
|||||||
, P2PRCConfig(..)
|
, P2PRCConfig(..)
|
||||||
, MapPortRequest(..)
|
, MapPortRequest(..)
|
||||||
, MapPortResponse(..)
|
, MapPortResponse(..)
|
||||||
, P2PRCommands(..)
|
|
||||||
|
|
||||||
-- ** Primitive data types
|
-- ** Primitive data types
|
||||||
-- | These types represent the core data that is communicated between requests and the runtime.
|
-- | These types represent the core data that is communicated between requests and the runtime.
|
||||||
@@ -84,7 +83,6 @@ import API
|
|||||||
( MapPortRequest(..)
|
( MapPortRequest(..)
|
||||||
, P2PRCapi(..)
|
, P2PRCapi(..)
|
||||||
, p2prcAPI
|
, p2prcAPI
|
||||||
, P2PRCommands(..)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,10 @@ module Main where
|
|||||||
import P2PRC
|
import P2PRC
|
||||||
( runP2PRC
|
( runP2PRC
|
||||||
, MapPortRequest(MkMapPortRequest)
|
, MapPortRequest(MkMapPortRequest)
|
||||||
, P2PRCommands(MapPort)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main =let
|
main =
|
||||||
in
|
|
||||||
runP2PRC
|
runP2PRC
|
||||||
[
|
( MkMapPortRequest 8080 "jose.akilan.io"
|
||||||
( MapPort $ MkMapPortRequest 8080 "jose.akilan.io")
|
)
|
||||||
]
|
|
||||||
|
|
||||||
|
|||||||
596
Docs/index.html
596
Docs/index.html
File diff suppressed because it is too large
Load Diff
201
Docs/index.org
201
Docs/index.org
@@ -17,16 +17,16 @@
|
|||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: chapter1-introduction
|
:CUSTOM_ID: chapter1-introduction
|
||||||
:END:
|
:END:
|
||||||
This project focuses on creating a framework for running heavy computational tasks that a regular
|
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
|
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
|
3D animations, and performing complex protein folding simulations. The major focus of this project
|
||||||
is not on financial incentives but rather on building a robust and efficient peer-to-peer (P2P)
|
is not on financial incentives but rather on building a robust and efficient peer-to-peer (P2P)
|
||||||
network to decentralise task execution and increase the computational bandwidth available for
|
network to decentralise task execution and increase the computational bandwidth available for
|
||||||
such tasks.
|
such tasks.
|
||||||
|
|
||||||
The P2PRC framework serves as a foundation for decentralised rendering and computation,
|
The P2PRC framework serves as a foundation for decentralised rendering and computation,
|
||||||
providing insights into how tasks can be distributed efficiently across a network of peers.
|
providing insights into how tasks can be distributed efficiently across a network of peers.
|
||||||
Leveraging the P2PRC approach, this project extends its capabilities to handle a
|
Leveraging the P2PRC approach, this project extends its capabilities to handle a
|
||||||
wider range of computationally intensive tasks.
|
wider range of computationally intensive tasks.
|
||||||
|
|
||||||
** Motivation
|
** Motivation
|
||||||
@@ -182,110 +182,6 @@ 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
|
* Using basic commands
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: using-basic-commands
|
:CUSTOM_ID: using-basic-commands
|
||||||
@@ -296,7 +192,7 @@ The template uses Cabal2Nix which manages the Haskell virtual environment automa
|
|||||||
:END:
|
:END:
|
||||||
|
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc -s
|
p2prc -s
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** View server Specification
|
*** View server Specification
|
||||||
@@ -324,7 +220,7 @@ p2prc --touch=<server ip address> -p <number of ports> --gpu
|
|||||||
The docker id is present in the output where you create a container
|
The docker id is present in the output where you create a container
|
||||||
|
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --rm=<server ip address> --id=<docker container id>
|
p2prc --rm=<server ip address> --id=<docker container id>
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** Adding servers to ip table
|
*** Adding servers to ip table
|
||||||
@@ -332,7 +228,7 @@ p2prc --rm=<server ip address> --id=<docker container id>
|
|||||||
:CUSTOM_ID: adding-servers-to-ip-table
|
:CUSTOM_ID: adding-servers-to-ip-table
|
||||||
:END:
|
:END:
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --as=<server ip address you want to add>
|
p2prc --as=<server ip address you want to add>
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** Update ip table
|
*** Update ip table
|
||||||
@@ -340,7 +236,7 @@ p2prc --as=<server ip address you want to add>
|
|||||||
:CUSTOM_ID: update-ip-table
|
:CUSTOM_ID: update-ip-table
|
||||||
:END:
|
:END:
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --us
|
p2prc --us
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** List Servers
|
*** List Servers
|
||||||
@@ -348,7 +244,7 @@ p2prc --us
|
|||||||
:CUSTOM_ID: list-servers
|
:CUSTOM_ID: list-servers
|
||||||
:END:
|
:END:
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --ls
|
p2prc --ls
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** View Network interfaces
|
*** View Network interfaces
|
||||||
@@ -412,7 +308,7 @@ p2prc --group <group id>
|
|||||||
:CUSTOM_ID: delete-container-from-group
|
:CUSTOM_ID: delete-container-from-group
|
||||||
:END:
|
:END:
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --rmcgroup --group <group id> --id <container id>
|
p2prc --rmcgroup --group <group id> --id <container id>
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** Delete entire group
|
*** Delete entire group
|
||||||
@@ -436,7 +332,7 @@ p2prc --pp <repo link>
|
|||||||
:CUSTOM_ID: deleting-plugin-from-the-plugin-directory
|
:CUSTOM_ID: deleting-plugin-from-the-plugin-directory
|
||||||
:END:
|
:END:
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --rp <plugin name>
|
p2prc --rp <plugin name>
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** Added custom metadata about the current node
|
*** Added custom metadata about the current node
|
||||||
@@ -448,12 +344,12 @@ p2prc --amd "custom metadata"
|
|||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
*** MapPort and link to domain name
|
*** MapPort and link to domain name
|
||||||
Allows to expose remote ports from a machine in the P2P network.
|
Allows to expose remote ports from a machine in the P2P network.
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --mp <port no to map> --dn <domain name to link Mapped port against>
|
p2prc --mp <port no to map> --dn <domain name to link Mapped port against>
|
||||||
#+end_example
|
#+end_example
|
||||||
**** MapPort in remote machine
|
**** MapPort in remote machine
|
||||||
This is to ensure ports on remote machines on the P2PRC can be easily opened.
|
This is to ensure ports on remote machines on the P2PRC can be easily opened.
|
||||||
#+begin_example
|
#+begin_example
|
||||||
p2prc --mp <port no to map> --dn <domain name to link Mapped port against> --ra <remote server address>
|
p2prc --mp <port no to map> --dn <domain name to link Mapped port against> --ra <remote server address>
|
||||||
#+end_example
|
#+end_example
|
||||||
@@ -461,7 +357,7 @@ p2prc --mp <port no to map> --dn <domain name to link Mapped port against> --ra
|
|||||||
--------------
|
--------------
|
||||||
|
|
||||||
*** Add root node
|
*** Add root node
|
||||||
Adds a root node to P2RRC and overwrites all other nodes in the ip table.
|
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
|
To be only added before the network is started and with
|
||||||
the intention of a fresh instance.
|
the intention of a fresh instance.
|
||||||
#+begin_example
|
#+begin_example
|
||||||
@@ -472,10 +368,10 @@ p2prc --arn --ip <root node ip address> -p <root node port no>
|
|||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: p2p-module-implementation
|
:CUSTOM_ID: p2p-module-implementation
|
||||||
:END:
|
:END:
|
||||||
The P2P module is for managing server information within the network.
|
The P2P module is for managing server information within the network.
|
||||||
It maintains and updates the IP table, ensuring accuracy by preventing duplicates and removing
|
It maintains and updates the IP table, ensuring accuracy by preventing duplicates and removing
|
||||||
entries for unreachable servers. Furthermore, the module conducts speed tests on the listed servers
|
entries for unreachable servers. Furthermore, the module conducts speed tests on the listed servers
|
||||||
to determine upload and download speeds. This valuable information enables users to identify nearby
|
to determine upload and download speeds. This valuable information enables users to identify nearby
|
||||||
servers with optimal performance, enhancing their overall network experience.
|
servers with optimal performance, enhancing their overall network experience.
|
||||||
|
|
||||||
#+caption: UML diagram of P2P module
|
#+caption: UML diagram of P2P module
|
||||||
@@ -519,7 +415,7 @@ configuration module.
|
|||||||
"NAT": "<boolean representing if the node is behind NAT or not>",
|
"NAT": "<boolean representing if the node is behind NAT or not>",
|
||||||
"EscapeImplementation": "<NAT traversal implementation>",
|
"EscapeImplementation": "<NAT traversal implementation>",
|
||||||
"ProxyServer": "<If the node listed is acting as a proxy server>",
|
"ProxyServer": "<If the node listed is acting as a proxy server>",
|
||||||
"UnSafeMode": <Unsafe mode if turned on will allow all nodes in the network public keys to be
|
"UnSafeMode": <Unsafe mode if turned on will allow all nodes in the network public keys to be
|
||||||
added to that particular node>",
|
added to that particular node>",
|
||||||
"PublicKey": "<Public key of that particular node>",
|
"PublicKey": "<Public key of that particular node>",
|
||||||
"CustomInformation": "<custom information passed in through all the nodes in the network>"
|
"CustomInformation": "<custom information passed in through all the nodes in the network>"
|
||||||
@@ -642,7 +538,7 @@ Below are a sample set of commands to open the bindings implementation.
|
|||||||
# run
|
# run
|
||||||
cd Bindings/
|
cd Bindings/
|
||||||
# list files
|
# list files
|
||||||
ls
|
ls
|
||||||
# search for file
|
# search for file
|
||||||
Client.go
|
Client.go
|
||||||
#+end_example
|
#+end_example
|
||||||
@@ -757,7 +653,7 @@ cd Bindings/python/export/
|
|||||||
# list files
|
# list files
|
||||||
ls
|
ls
|
||||||
# Expected output
|
# Expected output
|
||||||
SharedObjects/ library.py requirements.txt
|
SharedObjects/ library.py requirements.txt
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Above shows a generated folder which consists of a folder called
|
Above shows a generated folder which consists of a folder called
|
||||||
@@ -772,24 +668,7 @@ called from other programming languages.
|
|||||||
P2PRC officially supports Haskell bindings and will further support
|
P2PRC officially supports Haskell bindings and will further support
|
||||||
project using Haskell to build orchestrators on top of P2PRC.
|
project using Haskell to build orchestrators on top of P2PRC.
|
||||||
|
|
||||||
**** Local machine without Nix
|
[[https://p2prc.akilan.io/Docs/haskell][Read more...]]
|
||||||
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
|
* Config Implementation
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
@@ -863,7 +742,7 @@ The Abstractions package consists of black-boxed functions for P2PRC.
|
|||||||
- =ViewIPTable()=: View the IP table which about nodes in the network.
|
- =ViewIPTable()=: View the IP table which about nodes in the network.
|
||||||
- =UpdateIPTable()=: Force update IP table to learn about new nodes
|
- =UpdateIPTable()=: Force update IP table to learn about new nodes
|
||||||
faster.
|
faster.
|
||||||
|
|
||||||
* NAT Traversal
|
* NAT Traversal
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: nat-traversal
|
:CUSTOM_ID: nat-traversal
|
||||||
@@ -924,7 +803,7 @@ which can be used as shown below:
|
|||||||
** Command
|
** Command
|
||||||
- ***P2PRC instances "number of instances"*** : Starts p2prc processes
|
- ***P2PRC instances "number of instances"*** : Starts p2prc processes
|
||||||
based on the number of number instances provided. This includes
|
based on the number of number instances provided. This includes
|
||||||
creating temporary folders with independent IPTables.
|
creating temporary folders with independent IPTables.
|
||||||
- ***Start all instances "number of instances"***: Starts the P2PRC instances
|
- ***Start all instances "number of instances"***: Starts the P2PRC instances
|
||||||
created. This function enters into the instance directory and runs
|
created. This function enters into the instance directory and runs
|
||||||
```p2prc -s &``` with a delay for approximately 3 seconds. This allows
|
```p2prc -s &``` with a delay for approximately 3 seconds. This allows
|
||||||
@@ -932,8 +811,8 @@ which can be used as shown below:
|
|||||||
- ***IP Tables after Started number of instances"***: Prints the IPTable of
|
- ***IP Tables after Started number of instances"***: Prints the IPTable of
|
||||||
each independant node.
|
each independant node.
|
||||||
- ***Remove all test files***: Removes all test files created which needed for
|
- ***Remove all test files***: Removes all test files created which needed for
|
||||||
testing the generated P2PRC instances.
|
testing the generated P2PRC instances.
|
||||||
- ***Kill all instances***: Kills all the background P2PRC instances created.
|
- ***Kill all instances***: Kills all the background P2PRC instances created.
|
||||||
|
|
||||||
** Sample bash instructions
|
** Sample bash instructions
|
||||||
#+begin_src bash
|
#+begin_src bash
|
||||||
@@ -962,7 +841,7 @@ Source code: https://github.com/Akilan1999/p2p-rendering-computation/blob/master
|
|||||||
- Author: [[http://akilan.io/][Akilan Selvacoumar]]
|
- Author: [[http://akilan.io/][Akilan Selvacoumar]]
|
||||||
- Date: 28-01-2025
|
- Date: 28-01-2025
|
||||||
|
|
||||||
|
|
||||||
- Video tutorial:
|
- Video tutorial:
|
||||||
#+attr_html: :class video
|
#+attr_html: :class video
|
||||||
[[https://youtu.be/rN4SiVowg5E][https://i3.ytimg.com/vi/rN4SiVowg5E/maxresdefault.jpg]]
|
[[https://youtu.be/rN4SiVowg5E][https://i3.ytimg.com/vi/rN4SiVowg5E/maxresdefault.jpg]]
|
||||||
@@ -974,7 +853,7 @@ quickly do a map port and domain name mapping in a single command.
|
|||||||
Let's try to setup a really easy program (Let's do with Linkwarden
|
Let's try to setup a really easy program (Let's do with Linkwarden
|
||||||
with docker compose :) ). This is under the assumption you have docker
|
with docker compose :) ). This is under the assumption you have docker
|
||||||
compose installed on your local machine.
|
compose installed on your local machine.
|
||||||
|
|
||||||
**** Let's run Linkwarden using docker compose and P2PRC
|
**** Let's run Linkwarden using docker compose and P2PRC
|
||||||
[[https://docs.linkwarden.app/self-hosting/installation][Installation instructions]]:
|
[[https://docs.linkwarden.app/self-hosting/installation][Installation instructions]]:
|
||||||
#+BEGIN_SRC
|
#+BEGIN_SRC
|
||||||
@@ -1030,14 +909,14 @@ A entry 217.76.63.222
|
|||||||
|
|
||||||
Your done now just head to the DOMAIN NAME you added.
|
Your done now just head to the DOMAIN NAME you added.
|
||||||
ex: https://linkwarden.akilan.io
|
ex: https://linkwarden.akilan.io
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* Ideas for future potencial features
|
* Ideas for future potencial features
|
||||||
@@ -1074,7 +953,7 @@ network nodes.
|
|||||||
- Spin servers on node not running P2PRC using the P2PRC standard abstractions.
|
- Spin servers on node not running P2PRC using the P2PRC standard abstractions.
|
||||||
- Auto-setup P2PRC nodes with just SSH access via potencially a DSL.
|
- Auto-setup P2PRC nodes with just SSH access via potencially a DSL.
|
||||||
- A neat use case for CHERI for instance would be use the architecture to run light
|
- A neat use case for CHERI for instance would be use the architecture to run light
|
||||||
weight hypervisors.
|
weight hypervisors.
|
||||||
*** Implementation
|
*** Implementation
|
||||||
- To use implementations similar to [[https://linux.die.net/man/1/socat][socat]] to ensure we can bind address of local
|
- To use implementations similar to [[https://linux.die.net/man/1/socat][socat]] to ensure we can bind address of local
|
||||||
nodes to a node running P2PRC and the node running P2PRC can do a local map port.
|
nodes to a node running P2PRC and the node running P2PRC can do a local map port.
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -14,9 +14,6 @@ sharedObjects:
|
|||||||
python:
|
python:
|
||||||
sh build-python-package.sh
|
sh build-python-package.sh
|
||||||
|
|
||||||
haskell:
|
|
||||||
sh build-haskell.sh
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean -modcache
|
go clean -modcache
|
||||||
rm -fr .go-build vendor result*
|
rm -fr .go-build vendor result*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Haskell bindings supported!: [Bindings documentaton](https://p2prc.akilan.io/haskell/P2PRC.html)
|
> Haskell bindings supported!: [Bindings documentaton](https://p2prc.akilan.io/Docs/haskell/P2PRC.html)
|
||||||
|
|
||||||
> [!NOTE]
|
> [!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).
|
> 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
|
```bash
|
||||||
p2prc -h
|
p2prc -h
|
||||||
```
|
```
|
||||||
Read more on command usage: https://p2prc.akilan.io/#using-basic-commands
|
Read more on command usage: https://p2prc.akilan.io/Docs/#using-basic-commands
|
||||||
|
|
||||||
## Latest tutorial
|
## Latest tutorial
|
||||||
[](https://www.youtube.com/watch?v=OMwCpedu5cs")
|
[](https://www.youtube.com/watch?v=OMwCpedu5cs")
|
||||||
@@ -66,7 +66,7 @@ Read more on command usage: https://p2prc.akilan.io/#using-basic-commands
|
|||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### We have documented to our best effort the basics of p2prc: [Link](https://p2prc.akilan.io/)
|
### We have documented to our best effort the basics of p2prc: [Link](https://p2prc.akilan.io/Docs/)
|
||||||
|
|
||||||
<!-- ## Table of contents in the current README -->
|
<!-- ## Table of contents in the current README -->
|
||||||
<!-- 1. [Introduction](#Introduction)
|
<!-- 1. [Introduction](#Introduction)
|
||||||
|
|||||||
@@ -31,11 +31,9 @@ P2PRC_instances() {
|
|||||||
p2prc --as 0.0.0.0 -p "$NEW_PORT"
|
p2prc --as 0.0.0.0 -p "$NEW_PORT"
|
||||||
|
|
||||||
# Replace the ServerPort in config
|
# Replace the ServerPort in config
|
||||||
# test-$counter
|
|
||||||
sed -i.bak "s/\"ServerPort\": \"[0-9]*\"/\"ServerPort\": \"$NEW_PORT\"/" "./config.json"
|
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/\"Test\": false/\"Test\": true/" "./config.json"
|
||||||
sed -i.bak "s/\"BehindNAT\": true/\"BehindNAT\": false/" "./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
|
cat config.json
|
||||||
|
|
||||||
@@ -94,15 +92,6 @@ Update_All_IP_Tables() {
|
|||||||
done
|
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 ---------------
|
# ---------------- Work flow test ---------------
|
||||||
|
|
||||||
@@ -115,12 +104,6 @@ P2PRC_instances 3
|
|||||||
## Start instances
|
## Start instances
|
||||||
Start_all_instances 3
|
Start_all_instances 3
|
||||||
|
|
||||||
|
|
||||||
# Send test information from node 1
|
|
||||||
sleep 10
|
|
||||||
Send_Information
|
|
||||||
|
|
||||||
sleep 10
|
|
||||||
## List ip tables of nodes started
|
## List ip tables of nodes started
|
||||||
IP_Tables_after_Started 3
|
IP_Tables_after_Started 3
|
||||||
#
|
#
|
||||||
@@ -129,4 +112,3 @@ Remove_all_test_files
|
|||||||
|
|
||||||
## Kill all instances
|
## Kill all instances
|
||||||
Kill_all_instances
|
Kill_all_instances
|
||||||
|
|
||||||
|
|||||||
BIN
artwork/.DS_Store
vendored
BIN
artwork/.DS_Store
vendored
Binary file not shown.
BIN
artwork/p2prc-logos/.DS_Store
vendored
BIN
artwork/p2prc-logos/.DS_Store
vendored
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 922 KiB |
@@ -1,31 +0,0 @@
|
|||||||
# 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"
|
|
||||||
@@ -1,40 +1,40 @@
|
|||||||
package clientIPTable
|
package clientIPTable
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/config"
|
"github.com/Akilan1999/p2p-rendering-computation/config"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddCustomInformationToIPTable(text string) error {
|
func AddCustomInformationToIPTable(text string) error {
|
||||||
// Get config information
|
// Get config information
|
||||||
Config, err := config.ConfigInit(nil, nil)
|
Config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get IPTable information
|
// Get IPTable information
|
||||||
table, err := p2p.ReadIpTable()
|
table, err := p2p.ReadIpTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
|
|
||||||
for i, _ := range table.IpAddress {
|
for i, _ := range table.IpAddress {
|
||||||
if table.IpAddress[i].Name == Config.MachineName {
|
if table.IpAddress[i].Name == Config.MachineName {
|
||||||
table.IpAddress[i].CustomInformation = text
|
table.IpAddress[i].CustomInformation = text
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if found {
|
if found {
|
||||||
table.WriteIpTable()
|
table.WriteIpTable()
|
||||||
// update IPTable after modified entry
|
// update IPTable after modified entry
|
||||||
UpdateIpTableListClient()
|
go UpdateIpTableListClient()
|
||||||
} else {
|
} else {
|
||||||
return errors.New("start server with p2prc -s as the server is currently not running")
|
return errors.New("start server with p2prc -s as the server is currently not running")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/Akilan1999/p2p-rendering-computation/abstractions"
|
"github.com/Akilan1999/p2p-rendering-computation/abstractions"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/client"
|
"github.com/Akilan1999/p2p-rendering-computation/client"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
|
"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/config/generate"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/plugin"
|
"github.com/Akilan1999/p2p-rendering-computation/plugin"
|
||||||
@@ -233,12 +232,6 @@ var CliAction = func(ctx *cli.Context) error {
|
|||||||
standardOutput(err, nil)
|
standardOutput(err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// display configuration
|
|
||||||
if ViewConfig {
|
|
||||||
config, err := Config.ConfigInit(nil, nil)
|
|
||||||
standardOutput(err, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ var (
|
|||||||
AddMetaData string
|
AddMetaData string
|
||||||
AddRootNode bool
|
AddRootNode bool
|
||||||
IP string
|
IP string
|
||||||
ViewConfig bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var AppConfigFlags = []cli.Flag{
|
var AppConfigFlags = []cli.Flag{
|
||||||
@@ -289,11 +288,4 @@ var AppConfigFlags = []cli.Flag{
|
|||||||
EnvVars: []string{"IP"},
|
EnvVars: []string{"IP"},
|
||||||
Destination: &IP,
|
Destination: &IP,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "ViewConfig",
|
|
||||||
Aliases: []string{"vc"},
|
|
||||||
Usage: "View config file",
|
|
||||||
EnvVars: []string{"VC"},
|
|
||||||
Destination: &ViewConfig,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ type Config struct {
|
|||||||
UnsafeMode bool
|
UnsafeMode bool
|
||||||
Test bool
|
Test bool
|
||||||
CustomConfig interface{}
|
CustomConfig interface{}
|
||||||
ConfigPath string
|
|
||||||
//NetworkInterface string
|
//NetworkInterface string
|
||||||
//NetworkInterfaceIPV6Index int
|
//NetworkInterfaceIPV6Index int
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, No
|
|||||||
Defaults.BareMetal = false
|
Defaults.BareMetal = false
|
||||||
Defaults.UnsafeMode = false
|
Defaults.UnsafeMode = false
|
||||||
Defaults.Test = false
|
Defaults.Test = false
|
||||||
Defaults.ConfigPath = defaultPath + "config.json"
|
|
||||||
|
|
||||||
// Generate certificate files for SSL
|
// Generate certificate files for SSL
|
||||||
err = GenerateCertificate()
|
err = GenerateCertificate()
|
||||||
|
|||||||
26
flake.nix
26
flake.nix
@@ -75,13 +75,32 @@
|
|||||||
p2prcDefault
|
p2prcDefault
|
||||||
];
|
];
|
||||||
text =
|
text =
|
||||||
|
let
|
||||||
|
# TODO: add the content for the main file
|
||||||
|
# p2prcMainContent = availablePort: availableUrl:
|
||||||
|
# ''
|
||||||
|
# module Main where
|
||||||
|
#
|
||||||
|
# import P2PRC
|
||||||
|
# ( runP2PRC
|
||||||
|
# , MapPortRequest(MkMapPortRequest)
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# main :: IO ()
|
||||||
|
# main =
|
||||||
|
# runP2PRC
|
||||||
|
# ( MkMapPortRequest ${availablePort} "${availableUrl}.akilan.io"
|
||||||
|
# )
|
||||||
|
# '';
|
||||||
|
#
|
||||||
|
# mainFileContent = p2prcMainContent (builtins.toString 8080) "haskell";
|
||||||
|
in
|
||||||
''
|
''
|
||||||
clear
|
clear
|
||||||
|
|
||||||
if [ "$#" -eq 0 ]; then
|
if [ "$#" -eq 0 ]; then
|
||||||
echo "No arguments provided."
|
echo "No arguments provided."
|
||||||
echo "Please provide the name of your project"
|
echo "Please provide the name of your project"
|
||||||
echo "nix run git+https://github:akilan1999/p2p-rendering-computation#initHaskellProject -- <NAME-PROJECT>"
|
echo "nix run github:akilan1999/p2p-rendering-computation#initHaskellProject -- <NAME-PROJECT>"
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -99,9 +118,9 @@
|
|||||||
sed -i 's/base.*$/base, p2prc/' "$PROJECT_DIR".cabal
|
sed -i 's/base.*$/base, p2prc/' "$PROJECT_DIR".cabal
|
||||||
|
|
||||||
cabal2nix . > ./cabal.nix;
|
cabal2nix . > ./cabal.nix;
|
||||||
|
cabal2nix . --shell > shell.nix
|
||||||
|
|
||||||
git add .
|
git add .
|
||||||
|
|
||||||
clear
|
clear
|
||||||
|
|
||||||
echo -e "run the following commands to finish nix development and production environment:\n\n"
|
echo -e "run the following commands to finish nix development and production environment:\n\n"
|
||||||
@@ -110,7 +129,6 @@
|
|||||||
echo -e "nix flake init -t github:akilan1999/p2p-rendering-computation#haskell"
|
echo -e "nix flake init -t github:akilan1999/p2p-rendering-computation#haskell"
|
||||||
echo -e "nix develop"
|
echo -e "nix develop"
|
||||||
echo -e "nix run"
|
echo -e "nix run"
|
||||||
echo -e "\n\n"
|
|
||||||
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|||||||
909
index.org~
Normal file
909
index.org~
Normal file
@@ -0,0 +1,909 @@
|
|||||||
|
#+SETUPFILE: https://fniessen.github.io/org-html-themes/org/theme-readtheorg.setup
|
||||||
|
|
||||||
|
#+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 :align center
|
||||||
|
[[./artwork/p2prc-logos/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]]
|
||||||
|
|
||||||
|
* Introduction
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: chapter1-introduction
|
||||||
|
: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
|
||||||
|
is not on financial incentives but rather on building a robust and efficient peer-to-peer (P2P)
|
||||||
|
network to decentralise task execution and increase the computational bandwidth available for
|
||||||
|
such tasks.
|
||||||
|
|
||||||
|
The P2PRC framework serves as a foundation for decentralised rendering and computation,
|
||||||
|
providing insights into how tasks can be distributed efficiently across a network of peers.
|
||||||
|
Leveraging the P2PRC approach, this project extends its capabilities to handle a
|
||||||
|
wider range of computationally intensive tasks.
|
||||||
|
|
||||||
|
** Motivation
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: motivation
|
||||||
|
:END:
|
||||||
|
Many of the users rely on our PC / Laptop or servers that belong to a
|
||||||
|
server farm to run heavy tasks and with the demand of high creativity
|
||||||
|
requires higher computing power. Buying a powerful computer every few
|
||||||
|
years to run a bunch of heavy tasks which are not executed as frequently
|
||||||
|
to reap the benefits can be inefficient utilization of hardware. On the
|
||||||
|
other end, renting servers to run these heavy tasks can be really
|
||||||
|
useful. Ethically speaking this is leading to monopolisation of
|
||||||
|
computing power similar to what is happening in the web server area. By
|
||||||
|
using peer to peer principles it is possible to remove the
|
||||||
|
monopolisation factor and increase the bandwidth between the client and
|
||||||
|
server.
|
||||||
|
|
||||||
|
* Installation
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: installation
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Over here we will cover the basic steps to get the server and client
|
||||||
|
side running.
|
||||||
|
|
||||||
|
** Latest release install
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: latest-release-install
|
||||||
|
:END:
|
||||||
|
https://github.com/Akilan1999/p2p-rendering-computation/releases
|
||||||
|
|
||||||
|
** Install from Github master branch
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: install-from-github-master-branch
|
||||||
|
:END:
|
||||||
|
*** Install Go lang
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: install-go-lang
|
||||||
|
:END:
|
||||||
|
The entire the implementation of this project is done using Go lang.
|
||||||
|
Thus, we need go lang to compile to code to a binary file.
|
||||||
|
[[https://golang.org/doc/install][Instructions to install Go lang]]
|
||||||
|
|
||||||
|
*** Install Docker
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: install-docker
|
||||||
|
:END:
|
||||||
|
In this project the choice of virtualization is Docker due to it's wide
|
||||||
|
usage in the developer community. In the server module we use the Docker
|
||||||
|
Go API to create and interact with the containers.
|
||||||
|
|
||||||
|
[[https://docs.docker.com/get-docker/][Instructions to install docker]]
|
||||||
|
|
||||||
|
[[https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker][Instructions
|
||||||
|
to install docker GPU]]
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
// Do ensure that the docker command does not need sudo to run
|
||||||
|
sudo chmod 666 /var/run/docker.sock
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Build Project and install project
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: build-project-and-install-project
|
||||||
|
:END:
|
||||||
|
To set up the internal dependencies and build the entire go code into a
|
||||||
|
single binary
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
make
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
**** For Windows
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: for-windows
|
||||||
|
:END:
|
||||||
|
To set up P2PRC on Windows, simply run this batch file. *Make sure you
|
||||||
|
are not in admin mode when running this.*
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
.\install.bat
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Add appropriate paths to =.bashrc=
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: add-appropriate-paths-to-.bashrc
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
export P2PRC=/<PATH>/p2p-rendering-computation
|
||||||
|
export PATH=/<PATH>/p2p-rendering-computation:${PATH}
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Test if binary works
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: test-if-binary-works
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --help
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
**** Output:
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: output
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
NAME:
|
||||||
|
p2p-rendering-computation - p2p cli application to create and access VMs in other servers
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
p2prc [global options] command [command options] [arguments...]
|
||||||
|
|
||||||
|
VERSION:
|
||||||
|
2.0.0
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
help, h Shows a list of commands or help for one command
|
||||||
|
|
||||||
|
GLOBAL OPTIONS:
|
||||||
|
--Server, -s Starts server (default: false) [$SERVER]
|
||||||
|
--UpdateServerList, --us Update List of Server available based on servers iptables (default: false) [$UPDATE_SERVER_LIST]
|
||||||
|
--ListServers, --ls List servers which can render tasks (default: false) [$LIST_SERVERS]
|
||||||
|
--AddServer value, --as value Adds server IP address to iptables [$ADD_SERVER]
|
||||||
|
--ViewImages value, --vi value View images available on the server IP address [$VIEW_IMAGES]
|
||||||
|
--CreateVM value, --touch value Creates Docker container on the selected server [$CREATE_VM]
|
||||||
|
--ContainerName value, --cn value Specifying the container run on the server side [$CONTAINER_NAME]
|
||||||
|
--BaseImage value, --bi value Specifying the docker base image to template the dockerfile [$CONTAINER_NAME]
|
||||||
|
--RemoveVM value, --rm value Stop and Remove Docker container (IP:port) accompanied by container ID via --ID or --id [$REMOVE_VM]
|
||||||
|
--ID value, --id value Docker Container ID [$ID]
|
||||||
|
--Ports value, -p value Number of ports to open for the Docker Container [$NUM_PORTS]
|
||||||
|
--GPU, --gpu Create Docker Containers to access GPU (default: false) [$USE_GPU]
|
||||||
|
--Specification value, --specs value Specs of the server node [$SPECS]
|
||||||
|
--SetDefaultConfig, --dc Sets a default configuration file (default: false) [$SET_DEFAULT_CONFIG]
|
||||||
|
--NetworkInterfaces, --ni Shows the network interface in your computer (default: false) [$NETWORK_INTERFACE]
|
||||||
|
--ViewPlugins, --vp Shows plugins available to be executed (default: false) [$VIEW_PLUGIN]
|
||||||
|
--TrackedContainers, --tc View (currently running) containers which have been created from the client side (default: false) [$TRACKED_CONTAINERS]
|
||||||
|
--ExecutePlugin value, --plugin value Plugin which needs to be executed [$EXECUTE_PLUGIN]
|
||||||
|
--CreateGroup, --cgroup Creates a new group (default: false) [$CREATE_GROUP]
|
||||||
|
--Group value, --group value group flag with argument group ID [$GROUP]
|
||||||
|
--Groups, --groups View all groups (default: false) [$GROUPS]
|
||||||
|
--RemoveContainerGroup, --rmcgroup Remove specific container in the group (default: false) [$REMOVE_CONTAINER_GROUP]
|
||||||
|
--RemoveGroup value, --rmgroup value Removes the entire group [$REMOVE_GROUP]
|
||||||
|
--MAPPort value, --mp value Maps port for a specific port provided as the parameter [$MAPPORT]
|
||||||
|
--DomainName value, --dn value While mapping ports allows to set a domain name to create a mapping in the proxy server [$DOMAINNAME]
|
||||||
|
--Generate value, --gen value Generates a new copy of P2PRC which can be modified based on your needs [$GENERATE]
|
||||||
|
--ModuleName value, --mod value New go project module name [$MODULENAME]
|
||||||
|
--PullPlugin value, --pp value Pulls plugin from git repos [$PULLPLUGIN]
|
||||||
|
--RemovePlugin value, --rp value Removes plugin [$REMOVEPLUGIN]
|
||||||
|
--AddMetaData value, --amd value Adds metadata about the current node in the p2p network which is then propagated through the network [$ADDMETADATA]
|
||||||
|
--help, -h show help (default: false)
|
||||||
|
--version, -v print the version (default: false)
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* Using basic commands
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: using-basic-commands
|
||||||
|
:END:
|
||||||
|
*** Start as a server
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: start-as-a-server
|
||||||
|
:END:
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
p2prc -s
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** View server Specification
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: view-server-specification
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --specs=<ip address>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Run container
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: run-container
|
||||||
|
:END:
|
||||||
|
use the =--gpu= if you know the other machine has a gpu.
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
p2prc --touch=<server ip address> -p <number of ports> --gpu
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Remove container
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: remove-container
|
||||||
|
:END:
|
||||||
|
The docker id is present in the output where you create a container
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
p2prc --rm=<server ip address> --id=<docker container id>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Adding servers to ip table
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: adding-servers-to-ip-table
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --as=<server ip address you want to add>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Update ip table
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: update-ip-table
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --us
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** List Servers
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: list-servers
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --ls
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** View Network interfaces
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: view-network-interfaces
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --ni
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Viewing Containers created Client side
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: viewing-containers-created-client-side
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --tc
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Running plugin
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: running-plugin
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --plugin <plugin name> --id <container id or group id>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Create group
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: create-group
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --cgroup
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Add container to group
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: add-container-to-group
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --group <group id> --id <container id>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** View groups
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: view-groups
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --groups
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** View specific group
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: view-specific-group
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --group <group id>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Delete container from group
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: delete-container-from-group
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --rmcgroup --group <group id> --id <container id>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Delete entire group
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: delete-entire-group
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --rmgroup <group id>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Pulling plugin from a remote repo
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: pulling-plugin-from-a-remote-repo
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --pp <repo link>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Deleting plugin from the plugin directory
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: deleting-plugin-from-the-plugin-directory
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --rp <plugin name>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** Added custom metadata about the current node
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: added-custom-metadata-about-the-current-node
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
p2prc --amd "custom metadata"
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** MapPort and link to domain name
|
||||||
|
Allows to expose remote ports from a machine in the P2P network.
|
||||||
|
#+begin_example
|
||||||
|
p2prc --mp <port no to map> --dn <domain name to link Mapped port against>
|
||||||
|
#+end_example
|
||||||
|
**** MapPort in remote machine
|
||||||
|
This is to ensure ports on remote machines on the P2PRC can be easily opened.
|
||||||
|
#+begin_example
|
||||||
|
p2prc --mp <port no to map> --dn <domain name to link Mapped port against> --ra <remote server address>
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* P2P Module Implementation
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: p2p-module-implementation
|
||||||
|
:END:
|
||||||
|
The P2P module is for managing server information within the network.
|
||||||
|
It maintains and updates the IP table, ensuring accuracy by preventing duplicates and removing
|
||||||
|
entries for unreachable servers. Furthermore, the module conducts speed tests on the listed servers
|
||||||
|
to determine upload and download speeds. This valuable information enables users to identify nearby
|
||||||
|
servers with optimal performance, enhancing their overall network experience.
|
||||||
|
|
||||||
|
#+caption: UML diagram of P2P module
|
||||||
|
[[file:Docs/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
|
||||||
|
Distributed hash table. At the current moment all those heavy features
|
||||||
|
are not needed because the objective is to search and list all possible
|
||||||
|
servers available. The limitation being that to be a part of the network
|
||||||
|
the user has to know at least 1 server. The advantage of building from
|
||||||
|
scratch makes the module super light and possibility for custom
|
||||||
|
functions and structs. The sub topics below will mention the
|
||||||
|
implementations of each functionality in depth.
|
||||||
|
|
||||||
|
** IP Table
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: ip-table
|
||||||
|
:END:
|
||||||
|
The ip table file is a json as the format with a list of servers ip
|
||||||
|
addresses, latencies, downloads and uploads speeds. The functions
|
||||||
|
implemented include read file, write file and remove duplicate IP
|
||||||
|
addresses. The remove duplicate IP address function exists because
|
||||||
|
sometimes servers IP tables can have the same ip addresses as what the
|
||||||
|
client has. The path of the IP table json file is received from the
|
||||||
|
configuration module.
|
||||||
|
|
||||||
|
#+begin_src json
|
||||||
|
{
|
||||||
|
"ip_address": [
|
||||||
|
{
|
||||||
|
"Name": "<hostname of the machine>",
|
||||||
|
"MachineUsername": "<machine username>",
|
||||||
|
"IPV4": "<ipv4 address>",
|
||||||
|
"IPV6": "<ipv6 address (Not used)>",
|
||||||
|
"Latency": <latency to the server>,
|
||||||
|
"Download": <download speed (Not used)>,
|
||||||
|
"Upload": <upload speed (Not used)>,
|
||||||
|
"ServerPort": "<server port no>",
|
||||||
|
"BareMetalSSHPort": "<Baremetal ssh port no>",
|
||||||
|
"NAT": "<boolean representing if the node is behind NAT or not>",
|
||||||
|
"EscapeImplementation": "<NAT traversal implementation>",
|
||||||
|
"ProxyServer": "<If the node listed is acting as a proxy server>",
|
||||||
|
"UnSafeMode": <Unsafe mode if turned on will allow all nodes in the network public keys to be
|
||||||
|
added to that particular node>",
|
||||||
|
"PublicKey": "<Public key of that particular node>",
|
||||||
|
"CustomInformation": "<custom information passed in through all the nodes in the network>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** Latency
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: latency
|
||||||
|
:END:
|
||||||
|
The latency is measured in milliseconds. The route /server_info is
|
||||||
|
called from the server and time it takes to provide a json response is
|
||||||
|
recorded.
|
||||||
|
|
||||||
|
** NAT Traversal
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: nat-traversal
|
||||||
|
:END:
|
||||||
|
P2PRC currently supports TURN for NAT traversal.
|
||||||
|
|
||||||
|
** TURN
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: turn
|
||||||
|
:END:
|
||||||
|
The current TURN implementation used is FRP. The TURN server is also
|
||||||
|
required when a P2PRC node is acting as a Server. The TURN server is
|
||||||
|
determined based on the Node with the least amount of latency based on
|
||||||
|
the Nodes available on the IPTable. Once a TURN server is determined
|
||||||
|
there are 2 actions performed. The first one is =/FRPPort= to the TURN
|
||||||
|
server to receive a port which is used to generate the external port
|
||||||
|
from the TURN server. The flow below describes the workflow.
|
||||||
|
|
||||||
|
*** Client mode
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: client-mode
|
||||||
|
:END:
|
||||||
|
- Call =/FRPPort=
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
http://<turn server ip>:<server port no>/FRPport
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
- Call the TURN server in the following manner. The following is a
|
||||||
|
sample code snippet below.
|
||||||
|
|
||||||
|
#+begin_src go
|
||||||
|
import (
|
||||||
|
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
serverPort, err := frp.GetFRPServerPort("http://" + <lowestLatencyIpAddress.Ipv4> + ":" + lowestLatencyIpAddress.ServerPort)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Create 1 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, <the port you want to expose externally>)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Language Bindings
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: language-bindings
|
||||||
|
:END:
|
||||||
|
[[https://en.wikipedia.org/wiki/Language_binding][Language bindings]]
|
||||||
|
refers to wrappers to bridge 2 programming languages. This is used in
|
||||||
|
P2PRC to extend calling P2PRC functions in other programming languages.
|
||||||
|
Currently this is done by generating =.so= and =.h= from the Go
|
||||||
|
compiler.
|
||||||
|
|
||||||
|
** How to build shared object files
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: how-to-build-shared-object-files
|
||||||
|
:END:
|
||||||
|
**** The easier way
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: the-easier-way
|
||||||
|
:END:
|
||||||
|
#+begin_src sh
|
||||||
|
# Run
|
||||||
|
make sharedObjects
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** Or the direct way
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: or-the-direct-way
|
||||||
|
:END:
|
||||||
|
#+begin_src sh
|
||||||
|
# Run
|
||||||
|
cd Bindings && go build -buildmode=c-shared -o p2prc.so
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** If successfully built:
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: if-successfully-built
|
||||||
|
:END:
|
||||||
|
#+begin_src sh
|
||||||
|
# Enter into the Bindings directory
|
||||||
|
cd Bindings
|
||||||
|
# List files
|
||||||
|
ls
|
||||||
|
# Find files
|
||||||
|
p2prc.h p2prc.so
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Workings under the hood
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: workings-under-the-hood
|
||||||
|
:END:
|
||||||
|
Below are a sample set of commands to open the bindings implementation.
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
# run
|
||||||
|
cd Bindings/
|
||||||
|
# list files
|
||||||
|
ls
|
||||||
|
# search for file
|
||||||
|
Client.go
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
*** In Client go
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: in-client-go
|
||||||
|
:END:
|
||||||
|
There a few things to notice which are different from your standard Go
|
||||||
|
programs:
|
||||||
|
|
||||||
|
**** 1. We import "C" which means [[https://pkg.go.dev/cmd/cgo][Cgo]] is required.
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: we-import-c-which-means-cgo-is-required.
|
||||||
|
:END:
|
||||||
|
#+begin_src go
|
||||||
|
import "C"
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** 2. All functions which are required to be called from other programming languages have comment such as.
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: all-functions-which-are-required-to-be-called-from-other-programming-languages-have-comment-such-as.
|
||||||
|
:END:
|
||||||
|
#+begin_src go
|
||||||
|
//export <function name>
|
||||||
|
|
||||||
|
// ------------ Example ----------------
|
||||||
|
// The function below allows to externally
|
||||||
|
// to call the P2PRC function to start containers
|
||||||
|
// in a specific node in the know list of nodes
|
||||||
|
// in the p2p network.
|
||||||
|
// Note: the comment "//export StartContainer".
|
||||||
|
|
||||||
|
//export StartContainer
|
||||||
|
func StartContainer(IP string) (output *C.char) {
|
||||||
|
container, err := client.StartContainer(IP, 0, false, "", "")
|
||||||
|
if err != nil {
|
||||||
|
return C.CString(err.Error())
|
||||||
|
}
|
||||||
|
return ConvertStructToJSONString(container)
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** 3. While looking through the file (If 2 files are compared it is pretty trivial to notice a common structure).
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: while-looking-through-the-file-if-2-files-are-compared-it-is-pretty-trivial-to-notice-a-common-structure.
|
||||||
|
:END:
|
||||||
|
#+begin_src go
|
||||||
|
// --------- Example ------------
|
||||||
|
|
||||||
|
//export StartContainer
|
||||||
|
func StartContainer(IP string) (output *C.char) {
|
||||||
|
container, err := client.StartContainer(IP, 0, false, "", "")
|
||||||
|
if err != nil {
|
||||||
|
return C.CString(err.Error())
|
||||||
|
}
|
||||||
|
return ConvertStructToJSONString(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ViewPlugin
|
||||||
|
func ViewPlugin() (output *C.char) {
|
||||||
|
plugins, err := plugin.DetectPlugins()
|
||||||
|
if err != nil {
|
||||||
|
return C.CString(err.Error())
|
||||||
|
}
|
||||||
|
return ConvertStructToJSONString(plugins)
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
**** It is easy to notice that:
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: it-is-easy-to-notice-that
|
||||||
|
:END:
|
||||||
|
- =ConvertStructToJSONString(<go object>)=: This is a helper function
|
||||||
|
that convert a go object to JSON string initially and converts it to
|
||||||
|
=CString=.
|
||||||
|
- =(output *C.char)=: This is the return type for most of the functions.
|
||||||
|
|
||||||
|
**** A Pseudo code to refer to the common function implementation shape could be represented as:
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: a-pseudo-code-to-refer-to-the-common-function-implementation-shape-could-be-represented-as
|
||||||
|
:END:
|
||||||
|
#+begin_example
|
||||||
|
func <Function name> (output *C.char) {
|
||||||
|
<response>,<error> := <P2PRC function name>(<parameters if needed>)
|
||||||
|
if <error> != nil {
|
||||||
|
return C.CString(<error>.Error())
|
||||||
|
}
|
||||||
|
return ConvertStructToJSONString(<response>)
|
||||||
|
}
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
** Current languages supported
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: current-languages-supported
|
||||||
|
:END:
|
||||||
|
*** Python
|
||||||
|
|
||||||
|
**** Build sample python program
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: build-sample-python-program
|
||||||
|
:END:
|
||||||
|
The easier way
|
||||||
|
|
||||||
|
#+begin_src sh
|
||||||
|
# Run
|
||||||
|
make python
|
||||||
|
# Expected ouput
|
||||||
|
Output is in the Directory Bindings/python/export/
|
||||||
|
# Run
|
||||||
|
cd Bindings/python/export/
|
||||||
|
# list files
|
||||||
|
ls
|
||||||
|
# Expected output
|
||||||
|
SharedObjects/ library.py requirements.txt
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Above shows a generated folder which consists of a folder called
|
||||||
|
"SharedObjects/" which consists of =p2prc.so= and =p2prc.h= files.
|
||||||
|
=p2prc.py= refers to a sample python script calling P2PRC go functions.
|
||||||
|
To start an any project to extend P2PRC with python, This generated
|
||||||
|
folder can copied and created as a new git repo for P2PRC extensions
|
||||||
|
scripted or used a reference point as proof of concept that P2PRC can be
|
||||||
|
called from other programming languages.
|
||||||
|
|
||||||
|
*** Haskell
|
||||||
|
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...]]
|
||||||
|
|
||||||
|
* Config Implementation
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: config-implementation
|
||||||
|
:END:
|
||||||
|
The configuration module is responsible to store basic information of
|
||||||
|
absolute paths of files being called in the Go code. In a full-fledged
|
||||||
|
Cli the configuration file can be found in the directory /etc/ and from
|
||||||
|
there points to location such as where the IP table file is located. In
|
||||||
|
the future implementation the config file will have information such as
|
||||||
|
number of hops and other parameters to tweak and to improve the
|
||||||
|
effectiveness of the peer to peer network. The configuration module was
|
||||||
|
implemented using the library Viper. The Viper library automates
|
||||||
|
features such as searching in default paths to find out if the
|
||||||
|
configuration file is present. If the configuration file is not present
|
||||||
|
in the default paths then it auto generates the configuration file. The
|
||||||
|
configurations file can be in any format. In this project the
|
||||||
|
configuration file was generated using JSON format.
|
||||||
|
|
||||||
|
#+begin_src json
|
||||||
|
{
|
||||||
|
"MachineName": "pc-74-120.customer.ask4.lan",
|
||||||
|
"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/",
|
||||||
|
"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",
|
||||||
|
"GroupTrackContainersPath": "/Users/akilan/Documents/p2p-rendering-computation/client/trackcontainers/grouptrackcontainers.json",
|
||||||
|
"FRPServerPort": "True",
|
||||||
|
"BehindNAT": "True",
|
||||||
|
"CustomConfig": null
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
* Abstractions
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: abstractions
|
||||||
|
:END:
|
||||||
|
|
||||||
|
The Abstractions package consists of black-boxed functions for P2PRC.
|
||||||
|
|
||||||
|
** Functions
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: functions
|
||||||
|
:END:
|
||||||
|
- =Init(<Project name>)=: Initializes P2PRC with all the needed
|
||||||
|
configurations.
|
||||||
|
- =Start()=: Starts p2prc as a server and makes it possible to extend by
|
||||||
|
adding other routes and functionality to P2PRC.
|
||||||
|
- =MapPort(<port no>)=: On the local machine the port you want to export
|
||||||
|
to world.
|
||||||
|
- =StartContainer(<ip address>)=: The machine on the p2p network where
|
||||||
|
you want to spin up a docker container.
|
||||||
|
- =RemoveContainer(<ip address>,<container id>)=: Terminate container
|
||||||
|
based on the IP address and container name.
|
||||||
|
- =GetSpecs(<ip address>)=: Get specs of a machine on the network based
|
||||||
|
on the IP address.
|
||||||
|
- =ViewIPTable()=: View the IP table which about nodes in the network.
|
||||||
|
- =UpdateIPTable()=: Force update IP table to learn about new nodes
|
||||||
|
faster.
|
||||||
|
|
||||||
|
* NAT Traversal
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: nat-traversal
|
||||||
|
:END:
|
||||||
|
P2PRC currently supports TURN for NAT traversal.
|
||||||
|
|
||||||
|
** TURN
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: turn
|
||||||
|
:END:
|
||||||
|
The current TURN implementation used is FRP. The TURN server is also
|
||||||
|
required when a P2PRC node is acting as a Server. The TURN server is
|
||||||
|
determined based on the Node with the least amount of latency based on
|
||||||
|
the Nodes available on the IPTable. Once a TURN server is determined
|
||||||
|
there are 2 actions performed. The first one is =/FRPPort= to the TURN
|
||||||
|
server to receive a port which is used to generate the external port
|
||||||
|
from the TURN server. The flow below describes the workflow.
|
||||||
|
|
||||||
|
* Client mode
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: client-mode
|
||||||
|
:END:
|
||||||
|
- Call =/FRPPort=
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
http://<turn server ip>:<server port no>/FRPport
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
- Call the TURN server in the following manner. The following is a
|
||||||
|
sample code snippet below.
|
||||||
|
|
||||||
|
#+begin_src go
|
||||||
|
import (
|
||||||
|
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
serverPort, err := frp.GetFRPServerPort("http://" + <lowestLatencyIpAddress.Ipv4> + ":" + lowestLatencyIpAddress.ServerPort)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Create 1 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, <the port you want to expose externally>)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* Blog posts
|
||||||
|
** Self host within 5 minutes any program
|
||||||
|
|
||||||
|
- Author: [[http://akilan.io/][Akilan Selvacoumar]]
|
||||||
|
- Date: 28-01-2025
|
||||||
|
|
||||||
|
|
||||||
|
- Video tutorial:
|
||||||
|
[[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
|
||||||
|
quickly do a map port and domain name mapping in a single command.
|
||||||
|
|
||||||
|
*** 1. Find a program you want to run
|
||||||
|
Let's try to setup a really easy program (Let's do with Linkwarden
|
||||||
|
with docker compose :) ). This is under the assumption you have docker
|
||||||
|
compose installed on your local machine.
|
||||||
|
|
||||||
|
**** Let's run Linkwarden using docker compose and P2PRC
|
||||||
|
[[https://docs.linkwarden.app/self-hosting/installation][Installation instructions]]:
|
||||||
|
#+BEGIN_SRC
|
||||||
|
mkdir linkwarden && cd linkwarden
|
||||||
|
curl -O https://raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/docker-compose.yml
|
||||||
|
curl -L https://raw.githubusercontent.com/linkwarden/linkwarden/refs/heads/main/.env.sample -o ".env"
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Environment configuration
|
||||||
|
#+BEGIN_SRC
|
||||||
|
vim .env
|
||||||
|
|
||||||
|
# Change values
|
||||||
|
NEXTAUTH_URL=https://<DOMAIN NAME>/api/v1/auth
|
||||||
|
NEXTAUTH_SECRET=VERY_SENSITIVE_SECRET
|
||||||
|
POSTGRES_PASSWORD=CUSTOM_POSTGRES_PASSWORD
|
||||||
|
#+END_SRC
|
||||||
|
Run linkwarden!
|
||||||
|
#+BEGIN_SRC
|
||||||
|
docker compose up
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
If setup correctly linkwarden should
|
||||||
|
be running.
|
||||||
|
Local link: http://localhost:3000
|
||||||
|
|
||||||
|
Time to setup P2PRC
|
||||||
|
[[https://p2prc.akilan.io/Docs/#build-project-and-install-project][Installation Instructions]]
|
||||||
|
|
||||||
|
Run p2prc as a background
|
||||||
|
#+BEGIN_SRC
|
||||||
|
p2prc -s &
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Run map port and domain mapping
|
||||||
|
#+BEGIN_SRC
|
||||||
|
p2prc --mp 3000 --dn <DOMAIN NAME>
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Sample response
|
||||||
|
#+BEGIN_SRC
|
||||||
|
{
|
||||||
|
"IPAddress": "217.76.63.222",
|
||||||
|
"PortNo": "61582",
|
||||||
|
"EntireAddress": "217.76.63.222:61582"
|
||||||
|
}
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Add DNS entry
|
||||||
|
#+BEGIN_SRC
|
||||||
|
A entry 217.76.63.222
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
Your done now just head to the DOMAIN NAME you added.
|
||||||
|
ex: https://linkwarden.akilan.io
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* Ideas for future potencial features
|
||||||
|
Consists of personal loideas for the future of P2PRC.
|
||||||
|
At moment only has main contributors writiing to this.
|
||||||
|
|
||||||
|
** To support hetrogenous set of Nodes that cannot run P2PRC
|
||||||
|
This stems from a personal issue I have when doing research
|
||||||
|
on [[https://github.com/CTSRD-CHERI/cheribsd][CheriBSD]] kernel. For my research I am using the ARM morello
|
||||||
|
which is a 128bit ARMv8 processor. At the moment Go programs
|
||||||
|
can cannot compile and run inside the CPU. This means I cannot
|
||||||
|
run P2PRC at the moment inside the ARM morello to remotely access
|
||||||
|
it when it's behind NAT using P2PRC. This would indeed be a common
|
||||||
|
problem when running against various Architectures that do not
|
||||||
|
support running P2PRC. As you will see soon this also creates
|
||||||
|
oppurtunity space to scale faster to nodes in a local network
|
||||||
|
and would introduce a new layer fault tolerance within a local
|
||||||
|
network nodes.
|
||||||
|
|
||||||
|
*** Assumptions:
|
||||||
|
- I have a Morello board that cannot run P2PRC
|
||||||
|
- The Morello has a local IP address (ex: 192.168.0.10)
|
||||||
|
- I have 2 laptops running P2PRC in that local network.
|
||||||
|
- This means I have 2 ways to access the Morello board: Which is to SSH
|
||||||
|
into either 2 laptops and then SSH into 192.168.0.10 to gain access
|
||||||
|
to the board. Wouldn't it be great to automate this whole layer and
|
||||||
|
as well look into custom tasks into the hetrogenous hardware.
|
||||||
|
*** Set of interesting possible:
|
||||||
|
We build a cool set possibilities before and use this to build up the implementation
|
||||||
|
plan.
|
||||||
|
- We can use P2PRC access the morello board remotely in a single command.
|
||||||
|
- We can use the P2PRC protocol to run servers inside the morello board via traversed
|
||||||
|
node locally which can access that Node.
|
||||||
|
- Spin servers on node not running P2PRC using the P2PRC standard abstractions.
|
||||||
|
- Auto-setup P2PRC nodes with just SSH access via potencially a DSL.
|
||||||
|
- A neat use case for CHERI for instance would be use the architecture to run light
|
||||||
|
weight hypervisors.
|
||||||
|
*** Implementation
|
||||||
|
- To use implementations similar to [[https://linux.die.net/man/1/socat][socat]] to ensure we can bind address of local
|
||||||
|
nodes to a node running P2PRC and the node running P2PRC can do a local map port.
|
||||||
|
- We are working on hardening the implementation of the --mp (Map port) to even
|
||||||
|
map ports to machines which remotely running P2PRC. This means of instance I
|
||||||
|
can issue a command to the Morello board without the morello board being in
|
||||||
|
my local network.
|
||||||
|
- We would want to implement the exsisting P2PRC public key mechanism as well so that
|
||||||
|
other nodes can access the Morello board who have permission access.
|
||||||
|
|
||||||
|
#+CAPTION: Implementation idea (To be improved upon)
|
||||||
|
[[./Docs/images/P2PRCRemoteNodes.png]]
|
||||||
@@ -7,13 +7,12 @@
|
|||||||
|
|
||||||
flake-util.url = "github:numtide/flake-utils";
|
flake-util.url = "github:numtide/flake-utils";
|
||||||
|
|
||||||
p2prc-flake.url = "github:akilan1999/p2p-rendering-computation";
|
p2prc-flake.url = "github:xecarlox94/p2p-rendering-computation?ref=nix";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { nixpkgs, p2prc-flake, flake-utils, ... }:
|
outputs = { nixpkgs, p2prc-flake, flake-utils, ... }:
|
||||||
(flake-utils.lib.eachDefaultSystem (system:
|
(flake-utils.lib.eachDefaultSystem (system:
|
||||||
let
|
let
|
||||||
|
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
overlays = [
|
overlays = [
|
||||||
@@ -39,6 +38,8 @@
|
|||||||
cabal-install
|
cabal-install
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# TODO: add cabal2nix shell command
|
||||||
|
# cabal2nix . --shell > ./shell.nix
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
cabal2nix . > ./cabal.nix
|
cabal2nix . > ./cabal.nix
|
||||||
'';
|
'';
|
||||||
|
|||||||
427
p2p/iptable.go
427
p2p/iptable.go
@@ -1,297 +1,296 @@
|
|||||||
package p2p
|
package p2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/config"
|
"github.com/Akilan1999/p2p-rendering-computation/config"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get IP table Data
|
// Get IP table Data
|
||||||
|
|
||||||
type IpAddresses struct {
|
type IpAddresses struct {
|
||||||
IpAddress []IpAddress `json:"ip_address"`
|
IpAddress []IpAddress `json:"ip_address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IpAddress struct {
|
type IpAddress struct {
|
||||||
Name string `json:"Name"`
|
Name string `json:"Name"`
|
||||||
MachineUsername string `json:"MachineUsername"`
|
MachineUsername string `json:"MachineUsername"`
|
||||||
Ipv4 string `json:"IPV4"`
|
Ipv4 string `json:"IPV4"`
|
||||||
Ipv6 string `json:"IPV6"`
|
Ipv6 string `json:"IPV6"`
|
||||||
Latency time.Duration `json:"Latency"`
|
Latency time.Duration `json:"Latency"`
|
||||||
Download float64 `json:"Download"`
|
Download float64 `json:"Download"`
|
||||||
Upload float64 `json:"Upload"`
|
Upload float64 `json:"Upload"`
|
||||||
ServerPort string `json:"ServerPort"`
|
ServerPort string `json:"ServerPort"`
|
||||||
BareMetalSSHPort string `json:"BareMetalSSHPort"`
|
BareMetalSSHPort string `json:"BareMetalSSHPort"`
|
||||||
NAT bool `json:"NAT"`
|
NAT bool `json:"NAT"`
|
||||||
EscapeImplementation string `json:"EscapeImplementation"`
|
EscapeImplementation string `json:"EscapeImplementation"`
|
||||||
ProxyServer bool `json:"ProxyServer"`
|
ProxyServer bool `json:"ProxyServer"`
|
||||||
UnSafeMode bool `json:"UnSafeMode"`
|
UnSafeMode bool `json:"UnSafeMode"`
|
||||||
PublicKey string `json:"PublicKey"`
|
PublicKey string `json:"PublicKey"`
|
||||||
CustomInformation string `json:"CustomInformation"`
|
CustomInformation string `json:"CustomInformation"`
|
||||||
//CustomInformationKey []byte `json:"CustomInformationKey"`
|
//CustomInformationKey []byte `json:"CustomInformationKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type IP struct {
|
type IP struct {
|
||||||
Query string
|
Query string
|
||||||
}
|
}
|
||||||
|
|
||||||
var Test = false
|
var Test = false
|
||||||
|
|
||||||
// ReadIpTable Read data from Ip tables from json file
|
// ReadIpTable Read data from Ip tables from json file
|
||||||
func ReadIpTable() (*IpAddresses, error) {
|
func ReadIpTable() (*IpAddresses, error) {
|
||||||
// Get Path from config
|
// Get Path from config
|
||||||
config, err := config.ConfigInit(nil, nil)
|
config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
jsonFile, err := os.Open(config.IPTable)
|
jsonFile, err := os.Open(config.IPTable)
|
||||||
// if we os.Open returns an error then handle it
|
// if we os.Open returns an error then handle it
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// defer the closing of our jsonFile so that we can parse it later on
|
// defer the closing of our jsonFile so that we can parse it later on
|
||||||
defer jsonFile.Close()
|
defer jsonFile.Close()
|
||||||
|
|
||||||
// read our opened xmlFile as a byte array.
|
// read our opened xmlFile as a byte array.
|
||||||
byteValue, _ := ioutil.ReadAll(jsonFile)
|
byteValue, _ := ioutil.ReadAll(jsonFile)
|
||||||
|
|
||||||
// we initialize our Users array
|
// we initialize our Users array
|
||||||
var ipAddresses IpAddresses
|
var ipAddresses IpAddresses
|
||||||
|
|
||||||
// we unmarshal our byteArray which contains our
|
// we unmarshal our byteArray which contains our
|
||||||
// jsonFile's content into 'users' which we defined above
|
// jsonFile's content into 'users' which we defined above
|
||||||
json.Unmarshal(byteValue, &ipAddresses)
|
json.Unmarshal(byteValue, &ipAddresses)
|
||||||
|
|
||||||
var PublicIP IpAddress
|
var PublicIP IpAddress
|
||||||
|
|
||||||
ipv6, err := GetCurrentIPV6()
|
ipv6, err := GetCurrentIPV6()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ip, err := CurrentPublicIP()
|
ip, err := CurrentPublicIP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
PublicIP.Ipv4 = ip
|
PublicIP.Ipv4 = ip
|
||||||
PublicIP.Ipv6 = ipv6
|
PublicIP.Ipv6 = ipv6
|
||||||
PublicIP.ServerPort = config.ServerPort
|
PublicIP.ServerPort = config.ServerPort
|
||||||
PublicIP.Name = config.MachineName
|
PublicIP.Name = config.MachineName
|
||||||
PublicIP.NAT = config.BehindNAT
|
PublicIP.NAT = config.BehindNAT
|
||||||
PublicIP.EscapeImplementation = "None"
|
PublicIP.EscapeImplementation = "None"
|
||||||
|
|
||||||
// Updates current machine IP address to the IP table
|
// Updates current machine IP address to the IP table
|
||||||
ipAddresses.IpAddress = append(ipAddresses.IpAddress, PublicIP)
|
ipAddresses.IpAddress = append(ipAddresses.IpAddress, PublicIP)
|
||||||
|
|
||||||
//before writing to iptable ensures the duplicates are removed
|
//before writing to iptable ensures the duplicates are removed
|
||||||
if err = ipAddresses.RemoveDuplicates(); err != nil {
|
if err = ipAddresses.RemoveDuplicates(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ipAddresses, nil
|
return &ipAddresses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteIpTable Write to IP table json file
|
// WriteIpTable Write to IP table json file
|
||||||
func (i *IpAddresses) WriteIpTable() error {
|
func (i *IpAddresses) WriteIpTable() error {
|
||||||
//before writing to iptable ensures the duplicates are removed
|
//before writing to iptable ensures the duplicates are removed
|
||||||
if err := i.RemoveDuplicates(); err != nil {
|
if err := i.RemoveDuplicates(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := json.MarshalIndent(i, "", " ")
|
file, err := json.MarshalIndent(i, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Path from config
|
// Get Path from config
|
||||||
config, err := config.ConfigInit(nil, nil)
|
config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(config.IPTable, file, 0644)
|
err = ioutil.WriteFile(config.IPTable, file, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintIpTable Print Ip table data for Cli
|
// PrintIpTable Print Ip table data for Cli
|
||||||
func PrintIpTable() error {
|
func PrintIpTable() error {
|
||||||
table, err := ReadIpTable()
|
table, err := ReadIpTable()
|
||||||
//
|
//
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
//for i := 0; i < len(table.IpAddress); i++ {
|
//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-----------"+
|
// 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,
|
// "-----------------\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)
|
// table.IpAddress[i].Latency, table.IpAddress[i].ServerPort, table.IpAddress[i].NAT, table.IpAddress[i].EscapeImplementation)
|
||||||
//}
|
//}
|
||||||
PrettyPrint(table)
|
PrettyPrint(table)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDuplicates This is a temporary fix current functions failing to remove
|
// RemoveDuplicates This is a temporary fix current functions failing to remove
|
||||||
// Duplicate IP addresses from local IP table
|
// Duplicate IP addresses from local IP table
|
||||||
func (table *IpAddresses) RemoveDuplicates() error {
|
func (table *IpAddresses) RemoveDuplicates() error {
|
||||||
|
|
||||||
var NoDuplicates IpAddresses
|
var NoDuplicates IpAddresses
|
||||||
for i, _ := range table.IpAddress {
|
for i, _ := range table.IpAddress {
|
||||||
Exists := false
|
Exists := false
|
||||||
for k := range NoDuplicates.IpAddress {
|
for k := range NoDuplicates.IpAddress {
|
||||||
// Statements checked for
|
// Statements checked for
|
||||||
// - duplicate IPV4 addresses [<IPV4>:<Port No>]
|
// - duplicate IPV4 addresses [<IPV4>:<Port No>]
|
||||||
// - duplicate IPV6 addresses [<IPV6>]
|
// - duplicate IPV6 addresses [<IPV6>]
|
||||||
// - Node is behind NAT and no escape implementation provided
|
// - Node is behind NAT and no escape implementation provided
|
||||||
if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4 &&
|
if (NoDuplicates.IpAddress[k].Ipv4 != "" && NoDuplicates.IpAddress[k].Ipv4 == table.IpAddress[i].Ipv4 &&
|
||||||
NoDuplicates.IpAddress[k].ServerPort == table.IpAddress[i].ServerPort) ||
|
NoDuplicates.IpAddress[k].ServerPort == table.IpAddress[i].ServerPort) ||
|
||||||
(NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) {
|
(NoDuplicates.IpAddress[k].Ipv6 != "" && NoDuplicates.IpAddress[k].Ipv6 == table.IpAddress[i].Ipv6) {
|
||||||
Exists = true
|
Exists = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if table.IpAddress[i].NAT && table.IpAddress[i].EscapeImplementation == "None" {
|
if table.IpAddress[i].NAT && table.IpAddress[i].EscapeImplementation == "None" {
|
||||||
Exists = true
|
Exists = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if Exists {
|
if Exists {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
NoDuplicates.IpAddress = append(NoDuplicates.IpAddress, table.IpAddress[i])
|
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
|
// CurrentPublicIP Get Current Public IP address
|
||||||
func CurrentPublicIP() (string, error) {
|
func CurrentPublicIP() (string, error) {
|
||||||
// Get configs
|
// Get configs
|
||||||
Config, err := config.ConfigInit(nil, nil)
|
Config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// If test mode is on then return local address
|
// If test mode is on then return local address
|
||||||
if Config.Test {
|
if Config.Test {
|
||||||
return "0.0.0.0", nil
|
return "0.0.0.0", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.Get("http://ip-api.com/json/")
|
req, err := http.Get("http://ip-api.com/json/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer req.Body.Close()
|
defer req.Body.Close()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(req.Body)
|
body, err := ioutil.ReadAll(req.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ip IP
|
var ip IP
|
||||||
json.Unmarshal(body, &ip)
|
json.Unmarshal(body, &ip)
|
||||||
|
|
||||||
return ip.Query, nil
|
|
||||||
|
|
||||||
|
return ip.Query, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentIPV6 gets the current IPV6 address based on the interface
|
// GetCurrentIPV6 gets the current IPV6 address based on the interface
|
||||||
// specified in the config file
|
// specified in the config file
|
||||||
func GetCurrentIPV6() (string, error) {
|
func GetCurrentIPV6() (string, error) {
|
||||||
Config, err := config.ConfigInit(nil, nil)
|
Config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix in future release
|
// Fix in future release
|
||||||
//byNameInterface, err := net.InterfaceByName(Config.NetworkInterface)
|
//byNameInterface, err := net.InterfaceByName(Config.NetworkInterface)
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
// return "",err
|
// return "",err
|
||||||
//}
|
//}
|
||||||
//addresses, err := byNameInterface.Addrs()
|
//addresses, err := byNameInterface.Addrs()
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
// return "",err
|
// return "",err
|
||||||
//}
|
//}
|
||||||
//if addresses[1].String() == "" {
|
//if addresses[1].String() == "" {
|
||||||
// return "",errors.New("IPV6 address not detected")
|
// return "",errors.New("IPV6 address not detected")
|
||||||
//}
|
//}
|
||||||
//IP,_,err := net.ParseCIDR(addresses[Config.NetworkInterfaceIPV6Index].String())
|
//IP,_,err := net.ParseCIDR(addresses[Config.NetworkInterfaceIPV6Index].String())
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
// return "",err
|
// return "",err
|
||||||
//}
|
//}
|
||||||
|
|
||||||
return Config.IPV6Address, nil
|
return Config.IPV6Address, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ViewNetworkInterface This function is created to view the network interfaces available
|
// ViewNetworkInterface This function is created to view the network interfaces available
|
||||||
func ViewNetworkInterface() error {
|
func ViewNetworkInterface() error {
|
||||||
ifaces, err := net.Interfaces()
|
ifaces, err := net.Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, i := range ifaces {
|
for _, i := range ifaces {
|
||||||
addrs, err := i.Addrs()
|
addrs, err := i.Addrs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for index, a := range addrs {
|
for index, a := range addrs {
|
||||||
switch v := a.(type) {
|
switch v := a.(type) {
|
||||||
case *net.IPAddr:
|
case *net.IPAddr:
|
||||||
fmt.Printf("(%v) %v : %s (%s)\n", index, i.Name, v, v.IP.DefaultMask())
|
fmt.Printf("(%v) %v : %s (%s)\n", index, i.Name, v, v.IP.DefaultMask())
|
||||||
|
|
||||||
case *net.IPNet:
|
case *net.IPNet:
|
||||||
fmt.Printf("(%v) %v : %s \n", index, i.Name, v)
|
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
|
// 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)
|
// IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6)
|
||||||
func Ip4or6(s string) string {
|
func Ip4or6(s string) string {
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
switch s[i] {
|
switch s[i] {
|
||||||
case '.':
|
case '.':
|
||||||
return "version 4"
|
return "version 4"
|
||||||
case ':':
|
case ':':
|
||||||
return "version 6"
|
return "version 6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "version 6"
|
return "version 6"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrettyPrint(data interface{}) {
|
func PrettyPrint(data interface{}) {
|
||||||
var p []byte
|
var p []byte
|
||||||
// var err := error
|
// var err := error
|
||||||
p, err := json.MarshalIndent(data, "", "\t")
|
p, err := json.MarshalIndent(data, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("%s \n", p)
|
fmt.Printf("%s \n", p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateHashSHA256(text string) []byte {
|
func GenerateHashSHA256(text string) []byte {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
h.Write([]byte(text))
|
h.Write([]byte(text))
|
||||||
|
|
||||||
return h.Sum(nil)
|
return h.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateHashSHA256 CustomInformationKey the text and check if the text and
|
// ValidateHashSHA256 CustomInformationKey the text and check if the text and
|
||||||
@@ -300,12 +299,12 @@ func GenerateHashSHA256(text string) []byte {
|
|||||||
// SHA256 is the current hashing algorthm
|
// SHA256 is the current hashing algorthm
|
||||||
// used.
|
// used.
|
||||||
func ValidateHashSHA256(text string, Hash []byte) bool {
|
func ValidateHashSHA256(text string, Hash []byte) bool {
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
h.Write([]byte(text))
|
h.Write([]byte(text))
|
||||||
|
|
||||||
textHash := h.Sum(nil)
|
textHash := h.Sum(nil)
|
||||||
if bytes.Equal(textHash, Hash) {
|
if bytes.Equal(textHash, Hash) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
187
p2p/speedtest.go
187
p2p/speedtest.go
@@ -1,137 +1,136 @@
|
|||||||
package p2p
|
package p2p
|
||||||
|
|
||||||
import (
|
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
|
// SpeedTest Runs a speed test and does updates IP tables accordingly
|
||||||
func (ip *IpAddresses) SpeedTest() error {
|
func (ip *IpAddresses) SpeedTest() error {
|
||||||
|
|
||||||
//temp variable to store elements IP addresses and other information
|
//temp variable to store elements IP addresses and other information
|
||||||
// of IP addresses that are pingable
|
// of IP addresses that are pingable
|
||||||
var ActiveIP IpAddresses
|
var ActiveIP IpAddresses
|
||||||
|
|
||||||
// Index to remove from struct
|
// Index to remove from struct
|
||||||
for _, value := range ip.IpAddress {
|
for _, value := range ip.IpAddress {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
//if len(ip.IpAddress) == 1 {
|
//if len(ip.IpAddress) == 1 {
|
||||||
// i = 0
|
// i = 0
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Ping Test
|
// Ping Test
|
||||||
err = value.PingTest()
|
err = value.PingTest()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
//Upload Speed Test
|
//Upload Speed Test
|
||||||
//err = value.UploadSpeed()
|
//err = value.UploadSpeed()
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
// return err
|
// return err
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//err = value.DownloadSpeed()
|
//err = value.DownloadSpeed()
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
// return err
|
// 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()
|
err := ip.WriteIpTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpeedTestUpdatedIPTable Called when ip tables from httpclient/server is also passed on
|
// SpeedTestUpdatedIPTable Called when ip tables from httpclient/server is also passed on
|
||||||
func (ip *IpAddresses) SpeedTestUpdatedIPTable() error {
|
func (ip *IpAddresses) SpeedTestUpdatedIPTable() error {
|
||||||
|
|
||||||
Config, err := config.ConfigInit(nil, nil)
|
Config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
targets, err := ReadIpTable()
|
targets, err := ReadIpTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if baremetal mode and unsafe mode
|
// Checks if baremetal mode and unsafe mode
|
||||||
// is enabled. If it is enabled it adds the
|
// is enabled. If it is enabled it adds the
|
||||||
// the propagated public key to the list.
|
// the propagated public key to the list.
|
||||||
|
|
||||||
AddPublicKey := false
|
AddPublicKey := false
|
||||||
if Config.BareMetal && Config.UnsafeMode {
|
if Config.BareMetal && Config.UnsafeMode {
|
||||||
AddPublicKey = true
|
AddPublicKey = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// To ensure struct has no duplicates IP addresses
|
// To ensure struct has no duplicates IP addresses
|
||||||
//DoNotRead := targets
|
//DoNotRead := targets
|
||||||
|
|
||||||
// Appends all IP addresses
|
// Appends all IP addresses
|
||||||
for i, _ := range targets.IpAddress {
|
for i, _ := range targets.IpAddress {
|
||||||
|
|
||||||
//To ensure that there are no duplicate IP addresses
|
//To ensure that there are no duplicate IP addresses
|
||||||
Exists := false
|
Exists := false
|
||||||
for k := range ip.IpAddress {
|
for k := range ip.IpAddress {
|
||||||
if AddPublicKey && ip.IpAddress[k].PublicKey != "" {
|
if AddPublicKey && ip.IpAddress[k].PublicKey != "" {
|
||||||
// This function call (AddAuthorisationKey) is inefficient but to be optimised later on.
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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
|
// add when needed based on the memory location. This is something is to be discussed
|
||||||
// and look upon later on.
|
// and look upon later on.
|
||||||
AddAuthorisationKey(ip.IpAddress[k].PublicKey)
|
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
|
||||||
// Checks if both the IPV4 addresses are the same or the IPV6 address is not
|
// an empty string and IPV6 address are the same
|
||||||
// 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) {
|
||||||
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
|
||||||
Exists = true
|
break
|
||||||
break
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If the struct exists then continues
|
// If the struct exists then continues
|
||||||
if Exists {
|
if Exists {
|
||||||
continue
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalSpeedTestIpTable Runs speed test in iptables locally only
|
// LocalSpeedTestIpTable Runs speed test in iptables locally only
|
||||||
func LocalSpeedTestIpTable() error {
|
func LocalSpeedTestIpTable() error {
|
||||||
targets, err := ReadIpTable()
|
targets, err := ReadIpTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = targets.SpeedTest()
|
err = targets.SpeedTest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to remove element from an array of a struct
|
// Helper function to remove element from an array of a struct
|
||||||
|
|||||||
782
server/server.go
782
server/server.go
@@ -1,477 +1,479 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
b64 "encoding/base64"
|
b64 "encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
|
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/config"
|
"github.com/Akilan1999/p2p-rendering-computation/config"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
|
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
|
||||||
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
|
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os/user"
|
"os/user"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReverseProxy struct {
|
type ReverseProxy struct {
|
||||||
IPAddress string
|
IPAddress string
|
||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReverseProxies Reverse to the map such as ReverseProxies[<domain nane>]ReverseProxy type
|
// ReverseProxies Reverse to the map such as ReverseProxies[<domain nane>]ReverseProxy type
|
||||||
var ReverseProxies map[string]ReverseProxy
|
var ReverseProxies map[string]ReverseProxy
|
||||||
|
|
||||||
func Server() (*gin.Engine, error) {
|
func Server() (*gin.Engine, error) {
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
// "The make function allocates and initializes a hash map data
|
// "The make function allocates and initializes a hash map data
|
||||||
//structure and returns a map value that points to it.
|
//structure and returns a map value that points to it.
|
||||||
//The specifics of that data structure are an implementation
|
//The specifics of that data structure are an implementation
|
||||||
//detail of the runtime and are not specified by the language itself."
|
//detail of the runtime and are not specified by the language itself."
|
||||||
// source: https://go.dev/blog/maps
|
// source: https://go.dev/blog/maps
|
||||||
ReverseProxies = make(map[string]ReverseProxy)
|
ReverseProxies = make(map[string]ReverseProxy)
|
||||||
|
|
||||||
//Get Server port based on the config file
|
//Get Server port based on the config file
|
||||||
config, err := config.ConfigInit(nil, nil)
|
config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// update IPTable with new port and ip address and update ip table
|
// update IPTable with new port and ip address and update ip table
|
||||||
var ProxyIpAddr p2p.IpAddress
|
var ProxyIpAddr p2p.IpAddress
|
||||||
var lowestLatencyIpAddress p2p.IpAddress
|
var lowestLatencyIpAddress p2p.IpAddress
|
||||||
|
|
||||||
// Gets default information of the server
|
// Gets default information of the server
|
||||||
r.GET("/server_info", func(c *gin.Context) {
|
r.GET("/server_info", func(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, ServerInfo())
|
c.JSON(http.StatusOK, ServerInfo())
|
||||||
})
|
})
|
||||||
|
|
||||||
// Speed test with 50 mbps
|
// Speed test with 50 mbps
|
||||||
r.GET("/50", func(c *gin.Context) {
|
r.GET("/50", func(c *gin.Context) {
|
||||||
// Get Path from config
|
// Get Path from config
|
||||||
c.File(config.SpeedTestFile)
|
c.File(config.SpeedTestFile)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Route build to do a speed test
|
// Route build to do a speed test
|
||||||
r.GET("/upload", func(c *gin.Context) {
|
r.GET("/upload", func(c *gin.Context) {
|
||||||
file, _ := c.FormFile("file")
|
file, _ := c.FormFile("file")
|
||||||
|
|
||||||
// Upload the file to specific dst.
|
// Upload the file to specific dst.
|
||||||
// c.SaveUploadedFile(file, 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
|
//Gets Ip Table from server node
|
||||||
r.POST("/IpTable", func(c *gin.Context) {
|
r.POST("/IpTable", func(c *gin.Context) {
|
||||||
// Getting IPV4 address of client
|
// Getting IPV4 address of client
|
||||||
//var ClientHost p2p.IpAddress
|
//var ClientHost p2p.IpAddress
|
||||||
//
|
//
|
||||||
//if p2p.Ip4or6(c.ClientIP()) == "version 6" {
|
//if p2p.Ip4or6(c.ClientIP()) == "version 6" {
|
||||||
// ClientHost.Ipv6 = c.ClientIP()
|
// ClientHost.Ipv6 = c.ClientIP()
|
||||||
//} else {
|
//} else {
|
||||||
// ClientHost.Ipv4 = c.ClientIP()
|
// ClientHost.Ipv4 = c.ClientIP()
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Variable to store IP table information
|
// Variable to store IP table information
|
||||||
var IPTable p2p.IpAddresses
|
var IPTable p2p.IpAddresses
|
||||||
|
|
||||||
// Receive file from POST request
|
// Receive file from POST request
|
||||||
body, err := c.FormFile("json")
|
body, err := c.FormFile("json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, fmt.Sprint(err))
|
c.String(http.StatusOK, fmt.Sprint(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
open, err := body.Open()
|
open, err := body.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, fmt.Sprint(err))
|
c.String(http.StatusOK, fmt.Sprint(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open received file
|
// Open received file
|
||||||
file, err := ioutil.ReadAll(open)
|
file, err := ioutil.ReadAll(open)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, fmt.Sprint(err))
|
c.String(http.StatusOK, fmt.Sprint(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
json.Unmarshal(file, &IPTable)
|
json.Unmarshal(file, &IPTable)
|
||||||
|
|
||||||
//Add Client IP address to IPTable struct
|
//Add Client IP address to IPTable struct
|
||||||
//IPTable.IpAddress = append(IPTable.IpAddress, ClientHost)
|
//IPTable.IpAddress = append(IPTable.IpAddress, ClientHost)
|
||||||
|
|
||||||
// Runs speed test to return only servers in the IP table pingable
|
// Runs speed test to return only servers in the IP table pingable
|
||||||
err = IPTable.SpeedTestUpdatedIPTable()
|
err = IPTable.SpeedTestUpdatedIPTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, fmt.Sprint(err))
|
c.String(http.StatusOK, fmt.Sprint(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads IP addresses from ip table
|
// Reads IP addresses from ip table
|
||||||
IpAddresses, err := p2p.ReadIpTable()
|
IpAddresses, err := p2p.ReadIpTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, fmt.Sprint(err))
|
c.String(http.StatusOK, fmt.Sprint(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, IpAddresses)
|
c.JSON(http.StatusOK, IpAddresses)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Starts docker container in server
|
// Starts docker container in server
|
||||||
r.GET("/startcontainer", func(c *gin.Context) {
|
r.GET("/startcontainer", func(c *gin.Context) {
|
||||||
// Get Number of ports to open and whether to use GPU or not
|
// Get Number of ports to open and whether to use GPU or not
|
||||||
Ports := c.DefaultQuery("ports", "0")
|
Ports := c.DefaultQuery("ports", "0")
|
||||||
GPU := c.DefaultQuery("GPU", "false")
|
GPU := c.DefaultQuery("GPU", "false")
|
||||||
ContainerName := c.DefaultQuery("ContainerName", "")
|
ContainerName := c.DefaultQuery("ContainerName", "")
|
||||||
BaseImage := c.DefaultQuery("BaseImage", "")
|
BaseImage := c.DefaultQuery("BaseImage", "")
|
||||||
PublicKey := c.DefaultQuery("PublicKey", "")
|
PublicKey := c.DefaultQuery("PublicKey", "")
|
||||||
var PortsInt int
|
var PortsInt int
|
||||||
|
|
||||||
if PublicKey == "" {
|
if PublicKey == "" {
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", "Publickey not passed"))
|
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", "Publickey not passed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
PublicKeyDecoded, err := b64.StdEncoding.DecodeString(PublicKey)
|
PublicKeyDecoded, err := b64.StdEncoding.DecodeString(PublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Get Request value to int
|
// Convert Get Request value to int
|
||||||
fmt.Sscanf(Ports, "%d", &PortsInt)
|
fmt.Sscanf(Ports, "%d", &PortsInt)
|
||||||
|
|
||||||
// Creates container and returns-back result to
|
fmt.Println(string(PublicKeyDecoded[:]))
|
||||||
// access container
|
|
||||||
resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName, BaseImage, string(PublicKeyDecoded[:]))
|
|
||||||
|
|
||||||
if err != nil {
|
// Creates container and returns-back result to
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
// access container
|
||||||
}
|
resp, err := docker.BuildRunContainer(PortsInt, GPU, ContainerName, BaseImage, string(PublicKeyDecoded[:]))
|
||||||
|
|
||||||
// Ensures that FRP is triggered only if a proxy address is provided
|
if err != nil {
|
||||||
if ProxyIpAddr.Ipv4 != "" && c.Request.Host != "localhost:"+config.ServerPort && c.Request.Host != "0.0.0.0:"+config.ServerPort {
|
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
||||||
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)
|
// 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Remove container
|
c.JSON(http.StatusOK, resp)
|
||||||
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
|
//Remove container
|
||||||
r.GET("/ShowImages", func(c *gin.Context) {
|
r.GET("/RemoveContainer", func(c *gin.Context) {
|
||||||
resp, err := docker.ViewAllContainers()
|
ID := c.DefaultQuery("id", "0")
|
||||||
if err != nil {
|
if err := docker.StopAndRemoveContainer(ID); err != nil {
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, resp)
|
c.String(http.StatusOK, "success")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Request for port no from Server with address
|
//Show images available
|
||||||
r.GET("/FRPPort", func(c *gin.Context) {
|
r.GET("/ShowImages", func(c *gin.Context) {
|
||||||
port, err := frp.StartFRPProxyFromRandom()
|
resp, err := docker.ViewAllContainers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err))
|
||||||
}
|
}
|
||||||
|
c.JSON(http.StatusOK, resp)
|
||||||
|
})
|
||||||
|
|
||||||
c.String(http.StatusOK, strconv.Itoa(port))
|
// 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))
|
||||||
|
}
|
||||||
|
|
||||||
r.GET("/MAPPort", func(c *gin.Context) {
|
c.String(http.StatusOK, strconv.Itoa(port))
|
||||||
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)
|
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("/AddProxy", func(c *gin.Context) {
|
c.String(http.StatusOK, url)
|
||||||
DomainName := c.DefaultQuery("domain_name", "")
|
})
|
||||||
ip_address := c.DefaultQuery("ip_address", "")
|
|
||||||
Ports := c.DefaultQuery("port", "")
|
|
||||||
|
|
||||||
if DomainName == "" || ip_address == "" || Ports == "" {
|
r.GET("/AddProxy", func(c *gin.Context) {
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf("All get parameters npt provided"+
|
DomainName := c.DefaultQuery("domain_name", "")
|
||||||
" do ensure domain_name, ip_Address and port no is provided"))
|
ip_address := c.DefaultQuery("ip_address", "")
|
||||||
}
|
Ports := c.DefaultQuery("port", "")
|
||||||
|
|
||||||
err := SaveRegistration(DomainName, ip_address+":"+Ports)
|
if DomainName == "" || ip_address == "" || Ports == "" {
|
||||||
if err != nil {
|
c.String(http.StatusInternalServerError, fmt.Sprintf("All get parameters npt provided"+
|
||||||
c.String(http.StatusInternalServerError, fmt.Sprintf(err.Error()))
|
" do ensure domain_name, ip_Address and port no is provided"))
|
||||||
}
|
}
|
||||||
|
|
||||||
//_, ok := ReverseProxies[DomainName]
|
err := SaveRegistration(DomainName, ip_address+":"+Ports)
|
||||||
//// To check if the subdomain entry exists
|
if err != nil {
|
||||||
//if ok {
|
c.String(http.StatusInternalServerError, fmt.Sprintf(err.Error()))
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//})
|
|
||||||
|
|
||||||
// If there is a proxy port specified
|
//r.GET("/RemoveProxy", func(c *gin.Context) {
|
||||||
// then starts the FRP server
|
// DomainName := c.DefaultQuery("domain_name", "")
|
||||||
//if config.FRPServerPort != "0" {
|
//
|
||||||
// go frp.StartFRPProxyFromRandom()
|
// _, ok := ReverseProxies[DomainName]
|
||||||
//}
|
// if !ok {
|
||||||
|
// c.String(http.StatusInternalServerError, fmt.Sprintf("Domain name does exist in entries of proxies"))
|
||||||
|
// } else {
|
||||||
|
// delete(ReverseProxies, DomainName)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//})
|
||||||
|
|
||||||
// Remove nodes currently not pingable
|
// If there is a proxy port specified
|
||||||
clientIPTable.RemoveOfflineNodes()
|
// then starts the FRP server
|
||||||
|
//if config.FRPServerPort != "0" {
|
||||||
|
// go frp.StartFRPProxyFromRandom()
|
||||||
|
//}
|
||||||
|
|
||||||
table, err := p2p.ReadIpTable()
|
// Remove nodes currently not pingable
|
||||||
|
clientIPTable.RemoveOfflineNodes()
|
||||||
|
|
||||||
// TODO check if IPV6 or Proxy port is specified
|
table, err := p2p.ReadIpTable()
|
||||||
// if not update current entry as proxy address
|
|
||||||
// with appropriate port on IP Table
|
|
||||||
if config.BehindNAT {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var lowestLatency int64
|
// TODO check if IPV6 or Proxy port is specified
|
||||||
// random large number
|
// if not update current entry as proxy address
|
||||||
lowestLatency = 10000000
|
// with appropriate port on IP Table
|
||||||
|
if config.BehindNAT {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for i, _ := range table.IpAddress {
|
var lowestLatency int64
|
||||||
// Checks if the ping is the lowest and if the following node is acting as a proxy
|
// random large number
|
||||||
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
|
lowestLatency = 10000000
|
||||||
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
|
for i, _ := range table.IpAddress {
|
||||||
if lowestLatency != 10000000 {
|
// Checks if the ping is the lowest and if the following node is acting as a proxy
|
||||||
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
|
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
|
||||||
if err != nil {
|
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && !table.IpAddress[i].NAT {
|
||||||
return nil, err
|
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
|
||||||
}
|
lowestLatencyIpAddress = table.IpAddress[i]
|
||||||
// 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
|
// If there is an identified node
|
||||||
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
|
if lowestLatency != 10000000 {
|
||||||
ProxyIpAddr.ServerPort = proxyPort
|
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
|
||||||
ProxyIpAddr.Name = config.MachineName
|
if err != nil {
|
||||||
ProxyIpAddr.NAT = false
|
return nil, err
|
||||||
ProxyIpAddr.ProxyServer = false
|
}
|
||||||
ProxyIpAddr.EscapeImplementation = "FRP"
|
// 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 config.BareMetal {
|
// updating with the current proxy address
|
||||||
_, SSHPort, err := MapPort("22", "")
|
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
|
||||||
if err != nil {
|
ProxyIpAddr.ServerPort = proxyPort
|
||||||
return nil, err
|
ProxyIpAddr.Name = config.MachineName
|
||||||
}
|
ProxyIpAddr.NAT = false
|
||||||
ProxyIpAddr.BareMetalSSHPort = SSHPort
|
ProxyIpAddr.ProxyServer = false
|
||||||
}
|
ProxyIpAddr.EscapeImplementation = "FRP"
|
||||||
|
|
||||||
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
|
if config.BareMetal {
|
||||||
// write information back to the IP Table
|
_, SSHPort, err := MapPort("22", "")
|
||||||
}
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ProxyIpAddr.BareMetalSSHPort = SSHPort
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
|
||||||
ProxyIpAddr.Ipv4, err = p2p.CurrentPublicIP()
|
// write information back to the IP Table
|
||||||
if err != nil {
|
}
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ProxyIpAddr.ServerPort = config.ServerPort
|
} else {
|
||||||
ProxyIpAddr.Name = config.MachineName
|
ProxyIpAddr.Ipv4, err = p2p.CurrentPublicIP()
|
||||||
ProxyIpAddr.NAT = false
|
if err != nil {
|
||||||
if config.ProxyPort != "" {
|
fmt.Println(err)
|
||||||
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()
|
|
||||||
|
|
||||||
if err != nil {
|
// Get machine username
|
||||||
return nil, err
|
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()
|
||||||
|
|
||||||
// append the following to the ip table
|
if err != nil {
|
||||||
table.IpAddress = append(table.IpAddress, ProxyIpAddr)
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Writing results to the IPTable
|
// append the following to the ip table
|
||||||
err = table.WriteIpTable()
|
table.IpAddress = append(table.IpAddress, ProxyIpAddr)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// update ip table
|
// Writing results to the IPTable
|
||||||
go func() error {
|
err = table.WriteIpTable()
|
||||||
err := clientIPTable.UpdateIpTableListClient()
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
fmt.Println(err)
|
}
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
if config.ProxyPort != "" {
|
// update ip table
|
||||||
go ProxyRun(config.ProxyPort)
|
go func() error {
|
||||||
}
|
err := clientIPTable.UpdateIpTableListClient()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
|
||||||
// Run gin server on the specified port
|
if config.ProxyPort != "" {
|
||||||
go r.Run(":" + config.ServerPort)
|
go ProxyRun(config.ProxyPort)
|
||||||
|
}
|
||||||
|
|
||||||
return r, nil
|
// Run gin server on the specified port
|
||||||
|
go r.Run(":" + config.ServerPort)
|
||||||
|
|
||||||
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapPort(port string, domainName string) (string, string, error) {
|
func MapPort(port string, domainName string) (string, string, error) {
|
||||||
|
|
||||||
// if server address is provided to do call RESTAPI to remotely open port.
|
// if server address is provided to do call RESTAPI to remotely open port.
|
||||||
//if serverAddress != "" {
|
//if serverAddress != "" {
|
||||||
// requestURL := fmt.Sprintf("http://%v/MAPPort?port=%v&domain_name=%v", serverAddress, port, domainName)
|
// requestURL := fmt.Sprintf("http://%v/MAPPort?port=%v&domain_name=%v", serverAddress, port, domainName)
|
||||||
// req, err := http.NewRequest(http.MethodGet, requestURL, nil)
|
// req, err := http.NewRequest(http.MethodGet, requestURL, nil)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return "", "", err
|
// return "", "", err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// res, err := http.DefaultClient.Do(req)
|
// res, err := http.DefaultClient.Do(req)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return "", "", err
|
// return "", "", err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// resBody, err := io.ReadAll(res.Body)
|
// resBody, err := io.ReadAll(res.Body)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return "", "", err
|
// return "", "", err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// _, Exposedport, err := net.SplitHostPort(string(resBody))
|
// _, Exposedport, err := net.SplitHostPort(string(resBody))
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return "", "", err
|
// return "", "", err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// return string(resBody), Exposedport, nil
|
// return string(resBody), Exposedport, nil
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//Get Server port based on the config file
|
//Get Server port based on the config file
|
||||||
config, err := config.ConfigInit(nil, nil)
|
config, err := config.ConfigInit(nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// update IPTable with new port and ip address and update ip table
|
// update IPTable with new port and ip address and update ip table
|
||||||
var ProxyIpAddr p2p.IpAddress
|
var ProxyIpAddr p2p.IpAddress
|
||||||
var lowestLatencyIpAddress p2p.IpAddress
|
var lowestLatencyIpAddress p2p.IpAddress
|
||||||
|
|
||||||
clientIPTable.RemoveOfflineNodes()
|
clientIPTable.RemoveOfflineNodes()
|
||||||
|
|
||||||
table, err := p2p.ReadIpTable()
|
table, err := p2p.ReadIpTable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var lowestLatency int64
|
var lowestLatency int64
|
||||||
// random large number
|
// random large number
|
||||||
lowestLatency = 10000000
|
lowestLatency = 10000000
|
||||||
|
|
||||||
for i, _ := range table.IpAddress {
|
for i, _ := range table.IpAddress {
|
||||||
// Checks if the ping is the lowest and if the following node is acting as a proxy
|
// 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].ProxyPort != "" {
|
||||||
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && !table.IpAddress[i].NAT {
|
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && !table.IpAddress[i].NAT {
|
||||||
// Filter based on nodes with proxy enabled
|
// Filter based on nodes with proxy enabled
|
||||||
if domainName != "" && table.IpAddress[i].ProxyServer {
|
if domainName != "" && table.IpAddress[i].ProxyServer {
|
||||||
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
|
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
|
||||||
lowestLatencyIpAddress = table.IpAddress[i]
|
lowestLatencyIpAddress = table.IpAddress[i]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
|
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
|
||||||
lowestLatencyIpAddress = table.IpAddress[i]
|
lowestLatencyIpAddress = table.IpAddress[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is an identified node
|
// If there is an identified node
|
||||||
if lowestLatency != 10000000 {
|
if lowestLatency != 10000000 {
|
||||||
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
|
serverPort, err := frp.GetFRPServerPort("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
// Create 3 second delay to allow FRP server to start
|
// Create 3 second delay to allow FRP server to start
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
// Starts FRP as a client with
|
// Starts FRP as a client with
|
||||||
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, port, "")
|
proxyPort, err := frp.StartFRPClientForServer(lowestLatencyIpAddress.Ipv4, serverPort, port, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doing the proxy mapping for the domain name
|
// Doing the proxy mapping for the domain name
|
||||||
if domainName != "" {
|
if domainName != "" {
|
||||||
fmt.Println("http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4)
|
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
|
URL := "http://" + lowestLatencyIpAddress.Ipv4 + ":" + lowestLatencyIpAddress.ServerPort + "/AddProxy?port=" + proxyPort + "&domain_name=" + domainName + "&ip_address=" + lowestLatencyIpAddress.Ipv4
|
||||||
//} else {
|
//} else {
|
||||||
// URL = "http://" + IP + ":" + serverPort + "/server_info"
|
// URL = "http://" + IP + ":" + serverPort + "/server_info"
|
||||||
//}
|
//}
|
||||||
http.Get(URL)
|
http.Get(URL)
|
||||||
//SaveRegistration(domainName, lowestLatencyIpAddress.Ipv4+":"+proxyPort)
|
//SaveRegistration(domainName, lowestLatencyIpAddress.Ipv4+":"+proxyPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
// updating with the current proxy address
|
// updating with the current proxy address
|
||||||
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
|
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
|
||||||
ProxyIpAddr.ServerPort = proxyPort
|
ProxyIpAddr.ServerPort = proxyPort
|
||||||
ProxyIpAddr.Name = config.MachineName
|
ProxyIpAddr.Name = config.MachineName
|
||||||
ProxyIpAddr.NAT = false
|
ProxyIpAddr.NAT = false
|
||||||
ProxyIpAddr.EscapeImplementation = "FRP"
|
ProxyIpAddr.EscapeImplementation = "FRP"
|
||||||
|
|
||||||
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
|
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
|
||||||
} else {
|
} else {
|
||||||
return "", "", errors.New("proxy IP not found")
|
return "", "", errors.New("proxy IP not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProxyIpAddr.Ipv4 + ":" + ProxyIpAddr.ServerPort, ProxyIpAddr.ServerPort, nil
|
return ProxyIpAddr.Ipv4 + ":" + ProxyIpAddr.ServerPort, ProxyIpAddr.ServerPort, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user