Compare commits
13 Commits
python-add
...
add-root-n
| Author | SHA1 | Date | |
|---|---|---|---|
| 2283736cc6 | |||
| 51b253df15 | |||
| b9f5dec9de | |||
| 30b464449c | |||
| ffd711f448 | |||
| 0d01d70c2b | |||
| 6b1edd3d8a | |||
| 5cf1e144aa | |||
|
|
f605e2e06b | ||
| 873caa911c | |||
| 73a470e201 | |||
| 805514edfa | |||
|
|
5e3a4e8b7a |
49
.github/workflows/pages.yml
vendored
49
.github/workflows/pages.yml
vendored
@@ -1,49 +0,0 @@
|
||||
name: Deploy Jekyll with GitHub Pages dependencies preinstalled
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches: ["main", "master"]
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Build job
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
- name: Build with Jekyll
|
||||
uses: actions/jekyll-build-pages@v1
|
||||
with:
|
||||
source: ./
|
||||
destination: ./_site
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
|
||||
# Deployment job
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
@@ -2,11 +2,11 @@ package main
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/Akilan1999/p2p-rendering-computation/abstractions"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/abstractions"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/p2p/frp"
|
||||
)
|
||||
|
||||
// The Client package where data-types
|
||||
@@ -18,20 +18,20 @@ import (
|
||||
|
||||
//export StartContainer
|
||||
func StartContainer(IP string) (output *C.char) {
|
||||
container, err := abstractions.StartContainer(IP)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(container)
|
||||
container, err := abstractions.StartContainer(IP)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(container)
|
||||
}
|
||||
|
||||
//export RemoveContainer
|
||||
func RemoveContainer(IP string, ID string) (output *C.char) {
|
||||
err := abstractions.RemoveContainer(IP, ID)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString("Success")
|
||||
err := abstractions.RemoveContainer(IP, ID)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString("Success")
|
||||
}
|
||||
|
||||
// --------------------------------- Plugin Control ----------------------------------------
|
||||
@@ -77,20 +77,20 @@ func RemoveContainer(IP string, ID string) (output *C.char) {
|
||||
|
||||
//export GetSpecs
|
||||
func GetSpecs(IP string) (output *C.char) {
|
||||
specs, err := abstractions.GetSpecs(IP)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(specs)
|
||||
specs, err := abstractions.GetSpecs(IP)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(specs)
|
||||
}
|
||||
|
||||
//export Init
|
||||
func Init(customConfig string) (output *C.char) {
|
||||
init, err := abstractions.Init(customConfig)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(init)
|
||||
init, err := abstractions.Init(customConfig)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(init)
|
||||
|
||||
}
|
||||
|
||||
@@ -98,81 +98,90 @@ func Init(customConfig string) (output *C.char) {
|
||||
|
||||
//export ViewIPTable
|
||||
func ViewIPTable() (output *C.char) {
|
||||
table, err := abstractions.ViewIPTable()
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(table)
|
||||
table, err := abstractions.ViewIPTable()
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return ConvertStructToJSONString(table)
|
||||
}
|
||||
|
||||
//export UpdateIPTable
|
||||
func UpdateIPTable() (output *C.char) {
|
||||
err := abstractions.UpdateIPTable()
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString("Success")
|
||||
err := abstractions.UpdateIPTable()
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString("Success")
|
||||
}
|
||||
|
||||
//export EscapeFirewall
|
||||
func EscapeFirewall(HostOutsideNATIP string, HostOutsideNATPort string, internalPort string) (output *C.char) {
|
||||
// Get free port from P2PRC server node
|
||||
serverPort, err := frp.GetFRPServerPort("http://" + HostOutsideNATIP + ":" + HostOutsideNATPort)
|
||||
// Get free port from P2PRC server node
|
||||
serverPort, err := frp.GetFRPServerPort("http://" + HostOutsideNATIP + ":" + HostOutsideNATPort)
|
||||
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
ExposedPort, err := frp.StartFRPClientForServer(HostOutsideNATIP+":"+HostOutsideNATPort, serverPort, internalPort, "")
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
ExposedPort, err := frp.StartFRPClientForServer(HostOutsideNATIP+":"+HostOutsideNATPort, serverPort, internalPort, "")
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
|
||||
return C.CString(ExposedPort)
|
||||
return C.CString(ExposedPort)
|
||||
}
|
||||
|
||||
//export MapPort
|
||||
func MapPort(Port string, DomainName string, ServerAddress string) *C.char {
|
||||
Address, err := abstractions.MapPort(Port, DomainName, ServerAddress)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString(Address.EntireAddress)
|
||||
Address, err := abstractions.MapPort(Port, DomainName, ServerAddress)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString(Address.EntireAddress)
|
||||
}
|
||||
|
||||
//export CustomInformation
|
||||
func CustomInformation(CustomInformation string) *C.char {
|
||||
err := abstractions.AddCustomInformation(CustomInformation)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString("Success")
|
||||
err := abstractions.AddCustomInformation(CustomInformation)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString("Success")
|
||||
}
|
||||
|
||||
//export AddRootNode
|
||||
func AddRootNode(IP string, Port string) *C.char {
|
||||
err := abstractions.AddRootNode(IP, Port)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
return C.CString("Success")
|
||||
}
|
||||
|
||||
// --------------------------------- Controlling Server ----------------------------------------
|
||||
|
||||
//export Server
|
||||
func Server() (output *C.char) {
|
||||
_, err := abstractions.Start()
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
_, err := abstractions.Start()
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
|
||||
return ConvertStructToJSONString("")
|
||||
return ConvertStructToJSONString("")
|
||||
}
|
||||
|
||||
// --------------------------------- Helper Functions ----------------------------------------
|
||||
|
||||
func ConvertStructToJSONString(Struct interface{}) *C.char {
|
||||
jsonBytes, err := json.Marshal(Struct)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
jsonBytes, err := json.Marshal(Struct)
|
||||
if err != nil {
|
||||
return C.CString(err.Error())
|
||||
}
|
||||
|
||||
// Convert the JSON bytes to a string
|
||||
return C.CString(string(jsonBytes))
|
||||
// Convert the JSON bytes to a string
|
||||
return C.CString(string(jsonBytes))
|
||||
}
|
||||
|
||||
func main() {}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
module Paths_p2prc where
|
||||
import Data.Version
|
||||
version :: Version; version = makeVersion [0,1,0,0]
|
||||
getDataDir :: IO FilePath; getDataDir = return "/Users/akilan/.mcabal/mhs-0.12.3.0/packages/p2prc-0.1.0.0/data"
|
||||
@@ -20,19 +20,21 @@ import Error
|
||||
import JSON
|
||||
( IPAddressTable(..)
|
||||
, MapPortResponse(..)
|
||||
, P2prcConfig
|
||||
, P2PRCConfig
|
||||
)
|
||||
|
||||
import CLI
|
||||
( StdInput(..)
|
||||
, CLIOpt(..)
|
||||
, eitherErrDecode
|
||||
, p2PrcCmdName
|
||||
, p2prcCmdName
|
||||
, eitherExecProcess
|
||||
, eitherExecProcessParser
|
||||
, spawnProcP2Prc
|
||||
, spawnProcP2PRC
|
||||
)
|
||||
|
||||
-- import System.Environment (lookupEnv)
|
||||
|
||||
|
||||
|
||||
-- | Lower level P2PRC Haskell api that exposes basic functionality necessary to joint the network.
|
||||
@@ -41,7 +43,7 @@ data P2PRCapi
|
||||
= MkP2PRCapi
|
||||
{ startServer :: IOEitherError ProcessHandle
|
||||
-- ^ Start server
|
||||
, execInitConfig :: IOEitherError P2prcConfig
|
||||
-- , execInitConfig :: IOEitherError P2PRCConfig
|
||||
-- ^ Instantiate server configuration
|
||||
, execListServers :: IOEitherError IPAddressTable
|
||||
-- ^ List servers in network
|
||||
@@ -94,14 +96,14 @@ main =
|
||||
p2prcAPI :: P2PRCapi
|
||||
p2prcAPI =
|
||||
MkP2PRCapi
|
||||
{ startServer = spawnProcP2Prc p2PrcCmdName [ MkOptAtomic "--s" ]
|
||||
{ startServer = spawnProcP2PRC p2prcCmdName [ MkOptAtomic "--s" ]
|
||||
|
||||
, execListServers =
|
||||
execProcP2PrcParser [ MkOptAtomic "--ls" ] MkEmptyStdInput
|
||||
execProcP2PRCParser [ MkOptAtomic "--ls" ] MkEmptyStdInput
|
||||
|
||||
, execMapPort =
|
||||
\ (MkMapPortRequest portNumber domainName) ->
|
||||
execProcP2PrcParser
|
||||
execProcP2PRCParser
|
||||
[ MkOptTuple
|
||||
( "--mp"
|
||||
, show portNumber
|
||||
@@ -113,39 +115,41 @@ p2prcAPI =
|
||||
]
|
||||
MkEmptyStdInput
|
||||
|
||||
, execInitConfig = do
|
||||
-- , execInitConfig = do
|
||||
|
||||
confInitRes <- execProcP2Prc [ MkOptAtomic "--dc" ] MkEmptyStdInput
|
||||
-- confInitRes <- execProcP2PRC [ MkOptAtomic "--dc" ] MkEmptyStdInput
|
||||
|
||||
case confInitRes of
|
||||
(Right _) -> do
|
||||
-- case confInitRes of
|
||||
-- (Right _) -> do
|
||||
|
||||
-- TODO: get config file name dynamically
|
||||
--
|
||||
currDirectory <- getCurrentDirectory
|
||||
-- maybeValue <- lookupEnv "P2PRC"
|
||||
|
||||
-- TODO: change values before loading file
|
||||
let fname = currDirectory ++ "/config.json" :: FilePath
|
||||
-- -- TODO: get config file name dynamically
|
||||
-- --
|
||||
-- currDirectory <- getCurrentDirectory
|
||||
|
||||
-- -- TODO: change values before loading file
|
||||
-- let fname = currDirectory ++ "/config.json" :: FilePath
|
||||
|
||||
|
||||
-- TODO: read config check if file exists
|
||||
configContent <- readFile fname
|
||||
-- -- TODO: read config check if file exists
|
||||
-- configContent <- readFile fname
|
||||
|
||||
pure $ eitherErrDecode configContent
|
||||
-- pure $ eitherErrDecode configContent
|
||||
|
||||
(Left err) -> pure $ Left err
|
||||
-- (Left err) -> pure $ Left err
|
||||
|
||||
}
|
||||
|
||||
|
||||
where
|
||||
|
||||
execProcP2PrcParser ::
|
||||
execProcP2PRCParser ::
|
||||
FromJSON a =>
|
||||
[CLIOpt] -> StdInput -> IOEitherError a
|
||||
|
||||
execProcP2PrcParser = eitherExecProcessParser p2PrcCmdName
|
||||
execProcP2PRCParser = eitherExecProcessParser p2prcCmdName
|
||||
-- TODO: GHC question, why does it scope down instead staying generic
|
||||
|
||||
execProcP2Prc = eitherExecProcess p2PrcCmdName
|
||||
-- execProcP2PRC = eitherExecProcess p2prcCmdName
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ optsToCLI = concatMap _optToCLI
|
||||
_optToCLI (MkOptTuple (o, v)) = [o, v]
|
||||
|
||||
|
||||
spawnProcP2Prc :: CLICmd -> [CLIOpt] -> IOEitherError ProcessHandle
|
||||
spawnProcP2Prc cmd opts =
|
||||
spawnProcP2PRC :: CLICmd -> [CLIOpt] -> IOEitherError ProcessHandle
|
||||
spawnProcP2PRC cmd opts =
|
||||
do
|
||||
let prc = proc cmd $ optsToCLI opts
|
||||
|
||||
@@ -115,6 +115,6 @@ eitherErrorDecode esa =
|
||||
|
||||
-- assumes the program is ran inside the haskell module in p2prc's repo
|
||||
-- assumes that last path segment is "haskell" and that p2prc binary's name is "p2p-rendering-computation"
|
||||
p2PrcCmdName :: String
|
||||
p2PrcCmdName = "p2p-rendering-computation"
|
||||
p2prcCmdName :: String
|
||||
p2prcCmdName = "p2prc"
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ runP2PRC
|
||||
|
||||
( MkP2PRCapi
|
||||
{ startServer = startServer
|
||||
, execInitConfig = execInitConfig
|
||||
-- , execInitConfig = execInitConfig
|
||||
, execListServers = execListServers
|
||||
, execMapPort = execMapPort
|
||||
}
|
||||
@@ -105,12 +105,12 @@ runP2PRC
|
||||
let
|
||||
|
||||
|
||||
configValue <- execInitConfig
|
||||
-- configValue <- execInitConfig
|
||||
|
||||
-- TODO: get name of host server from config json
|
||||
|
||||
print configValue
|
||||
putStrLn "\n\n\n"
|
||||
-- print configValue
|
||||
-- putStrLn "\n\n\n"
|
||||
|
||||
eitherStartProcessHandle <- startServer
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module JSON
|
||||
( P2prcConfig(..)
|
||||
( P2PRCConfig(..)
|
||||
, IPAddressTable(..)
|
||||
, IPAddress(..)
|
||||
, ServerInfo(..)
|
||||
@@ -38,11 +38,11 @@ instance FromJSON MapPortResponse where
|
||||
|
||||
|
||||
|
||||
{-# WARNING P2prcConfig "This type is unstable at the moment due to the P2PRC's library error handling bug. For more information visit: https://github.com/Akilan1999/p2p-rendering-computation/issues/114#issuecomment-2474737015" #-}
|
||||
{-# WARNING P2PRCConfig "This type is unstable at the moment due to the P2PRC's library error handling bug. For more information visit: https://github.com/Akilan1999/p2p-rendering-computation/issues/114#issuecomment-2474737015" #-}
|
||||
|
||||
-- | This represents the server configuration that defines its attributes and behaviours in the network, as well as, the location of the runtime persistence artifacts.
|
||||
newtype P2prcConfig
|
||||
= MkP2prConfig
|
||||
newtype P2PRCConfig
|
||||
= MkP2PRCConfig
|
||||
{ machineName :: String -- ^ Machine Name
|
||||
} deriving Show
|
||||
|
||||
@@ -96,13 +96,13 @@ newtype P2prcConfig
|
||||
-- to have a dedicated port field
|
||||
|
||||
|
||||
instance FromJSON P2prcConfig where
|
||||
instance FromJSON P2PRCConfig where
|
||||
parseJSON (Object o) = do
|
||||
|
||||
machineName <- o .: "MachineName"
|
||||
|
||||
pure
|
||||
$ MkP2prConfig
|
||||
$ MkP2PRCConfig
|
||||
{ machineName=machineName
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ module P2PRC
|
||||
-- ** Interface data types
|
||||
-- | This section gives an overview on the runtime and host machine interfaces.
|
||||
, P2PRCapi(..)
|
||||
, P2prcConfig(..)
|
||||
, P2PRCConfig(..)
|
||||
, MapPortRequest(..)
|
||||
, MapPortResponse(..)
|
||||
|
||||
@@ -76,7 +76,7 @@ import JSON
|
||||
, ServerInfo(..)
|
||||
, IPAddress(..)
|
||||
, MapPortResponse(..)
|
||||
, P2prcConfig(..)
|
||||
, P2PRCConfig(..)
|
||||
)
|
||||
|
||||
import API
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
z
|
||||
@@ -44,9 +44,9 @@ class Node:
|
||||
Upload: int
|
||||
ServerPort: str
|
||||
BareMetalSSHPort: str
|
||||
NAT: str
|
||||
NAT: bool
|
||||
EscapeImplementation: str
|
||||
ProxyServer: str
|
||||
ProxyServer: bool
|
||||
UnSafeMode: bool
|
||||
PublicKey: str
|
||||
CustomInformation: str
|
||||
@@ -98,6 +98,21 @@ def ListNodes():
|
||||
dat: IPAddress = dacite.from_dict(IPAddress,ipTableObject)
|
||||
return dat
|
||||
|
||||
# Add a root node to P2RRC and overwrites all other nodes.
|
||||
# To be only added before the network started and with
|
||||
# the intention of a fresh protocol.
|
||||
def AddRootNode(ip="", port="") -> bool:
|
||||
ip = go_string(c_char_p(ip.encode('utf-8')), len(ip))
|
||||
port = go_string(c_char_p(port.encode('utf-8')), len(port))
|
||||
|
||||
p2prc.AddRootNode.restype = c_char_p
|
||||
res = p2prc.AddRootNode(ip, port)
|
||||
if str(res).strip("b'") == "Success":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# python function to pass-through custom
|
||||
# information to interpret which can be
|
||||
# interpreted as a DSL.
|
||||
|
||||
@@ -9,3 +9,6 @@ if __name__ == "__main__":
|
||||
# Add custom information to the network
|
||||
if AddCustomInformation("Test"):
|
||||
print("It worked")
|
||||
|
||||
if AddRootNode("0.0.0.0", "8081"):
|
||||
print("It worked for adding root node")
|
||||
|
||||
BIN
Docs/Colored-On-Light-Image.png
Normal file
BIN
Docs/Colored-On-Light-Image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 276 KiB |
563
Docs/index.html
563
Docs/index.html
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,20 @@
|
||||
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://fniessen.github.io/org-html-themes/src/readtheorg_theme/css/search.css"/>
|
||||
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="style.css"/>
|
||||
|
||||
#+attr_html: :width 300px
|
||||
[[./Colored-On-Light-Image.png]]
|
||||
|
||||
* Guide through video
|
||||
*** The video below shows the setup and usage of P2PRC.
|
||||
#+attr_html: :class video
|
||||
[[https://www.youtube.com/watch?v=OMwCpedu5cs][https://i3.ytimg.com/vi/OMwCpedu5cs/maxresdefault.jpg]]
|
||||
|
||||
*** Source code: https://github.com/Akilan1999/p2p-rendering-computation
|
||||
|
||||
* Introduction
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: chapter1-introduction
|
||||
:END:
|
||||
|
||||
** Abstract
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: abstract
|
||||
:END:
|
||||
This project focuses on creating a framework for running heavy computational tasks that a regular
|
||||
computer cannot handle easily. These tasks may include graphically demanding video games, rendering
|
||||
3D animations, and performing complex protein folding simulations. The major focus of this project
|
||||
@@ -352,6 +356,14 @@ p2prc --mp <port no to map> --dn <domain name to link Mapped port against> --ra
|
||||
|
||||
--------------
|
||||
|
||||
*** Add root node
|
||||
Adds a root node to P2RRC and overwrites all other nodes in the ip table.
|
||||
To be only added before the network is started and with
|
||||
the intention of a fresh instance.
|
||||
#+begin_example
|
||||
p2prc --arn --ip <root node ip address> -p <root node port no>
|
||||
#+end_example
|
||||
|
||||
* P2P Module Implementation
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: p2p-module-implementation
|
||||
@@ -363,7 +375,7 @@ to determine upload and download speeds. This valuable information enables users
|
||||
servers with optimal performance, enhancing their overall network experience.
|
||||
|
||||
#+caption: UML diagram of P2P module
|
||||
[[file:images/p2pmoduleArch.png]]
|
||||
[[file:./images/p2pmoduleArch.png]
|
||||
|
||||
The peer to peer implementation was built from scratch. This is because
|
||||
other peer to peer libraries were on the implementation of the
|
||||
@@ -783,6 +795,7 @@ func main() {
|
||||
|
||||
|
||||
- Video tutorial:
|
||||
#+attr_html: :class video
|
||||
[[https://youtu.be/rN4SiVowg5E][https://i3.ytimg.com/vi/rN4SiVowg5E/maxresdefault.jpg]]
|
||||
|
||||
This is a fun expirement for anyone to try to quickly run a server and
|
||||
|
||||
1
Docs/run-docs.sh
Normal file
1
Docs/run-docs.sh
Normal file
@@ -0,0 +1 @@
|
||||
go run staticServer.go &
|
||||
28
Docs/staticServer.go
Normal file
28
Docs/staticServer.go
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Serve is a very simple static file server in go
|
||||
Usage:
|
||||
|
||||
-p="8100": port to serve on
|
||||
-d=".": the directory of static files to host
|
||||
|
||||
Navigating to http://localhost:8100 will display the index.html or directory
|
||||
listing file.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
port := flag.String("p", "8083", "port to serve on")
|
||||
directory := flag.String("d", ".", "the directory of static file to host")
|
||||
flag.Parse()
|
||||
|
||||
http.Handle("/", http.FileServer(http.Dir(*directory)))
|
||||
|
||||
log.Printf("Serving %s on HTTP port: %s\n", *directory, *port)
|
||||
log.Fatal(http.ListenAndServe(":"+*port, nil))
|
||||
}
|
||||
@@ -23,3 +23,7 @@ h4,h5,h6{
|
||||
color: #b96c29;
|
||||
font-weight:300;
|
||||
}
|
||||
|
||||
.video {
|
||||
box-shadow: 10px 10px 25px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
@@ -2,94 +2,108 @@ package abstractions
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"github.com/Akilan1999/p2p-rendering-computation/client"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
|
||||
Config "github.com/Akilan1999/p2p-rendering-computation/config"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/config/generate"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/server"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
|
||||
"github.com/gin-gonic/gin"
|
||||
"os"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/client"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
|
||||
Config "github.com/Akilan1999/p2p-rendering-computation/config"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/config/generate"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/p2p"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/server"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/server/docker"
|
||||
"github.com/gin-gonic/gin"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Init Initialises p2prc
|
||||
func Init(customConfig interface{}) (config *Config.Config, err error) {
|
||||
|
||||
// Get config file path
|
||||
// Checks P2PRC path initially
|
||||
// - Get PATH if environment varaible
|
||||
path, err := Config.GetPathP2PRC("P2PRC")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// check if the config file exists
|
||||
if _, err = os.Stat(path + "config.json"); err != nil {
|
||||
// Initialize with base p2prc config files
|
||||
// set the config file with default paths
|
||||
config, err = generate.SetDefaults("P2PRC", false, customConfig, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// If the configs are available then use them over generating new ones.
|
||||
config, err = Config.ConfigInit(nil, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// Get config file path
|
||||
// Checks P2PRC path initially
|
||||
// - Get PATH if environment varaible
|
||||
path, err := Config.GetPathP2PRC("P2PRC")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// check if the config file exists
|
||||
if _, err = os.Stat(path + "config.json"); err != nil {
|
||||
// Initialize with base p2prc config files
|
||||
// set the config file with default paths
|
||||
config, err = generate.SetDefaults("P2PRC", false, customConfig, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// If the configs are available then use them over generating new ones.
|
||||
config, err = Config.ConfigInit(nil, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
return
|
||||
}
|
||||
|
||||
// Start p2prc in a server mode
|
||||
func Start() (*gin.Engine, error) {
|
||||
engine, err := server.Server()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return engine, nil
|
||||
engine, err := server.Server()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// MapPort Creates a reverse proxy connection and maps the appropriate port
|
||||
func MapPort(port string, domainName string, serverAddress string) (response *client.ResponseMAPPort, err error) {
|
||||
response, err = client.MAPPort(port, domainName, serverAddress)
|
||||
return
|
||||
response, err = client.MAPPort(port, domainName, serverAddress)
|
||||
return
|
||||
}
|
||||
|
||||
// StartContainer Starts docker container on the remote machine
|
||||
func StartContainer(IP string) (container *docker.DockerVM, err error) {
|
||||
container, err = client.StartContainer(IP, 0, false, "", "")
|
||||
return
|
||||
container, err = client.StartContainer(IP, 0, false, "", "")
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveContainer Removes docker container based on the IP address and ID
|
||||
// provided
|
||||
func RemoveContainer(IP string, ID string) error {
|
||||
return client.RemoveContianer(IP, ID)
|
||||
return client.RemoveContianer(IP, ID)
|
||||
}
|
||||
|
||||
// GetSpecs Get spec information about the remote server
|
||||
func GetSpecs(IP string) (specs *server.SysInfo, err error) {
|
||||
specs, err = client.GetSpecs(IP)
|
||||
return
|
||||
specs, err = client.GetSpecs(IP)
|
||||
return
|
||||
}
|
||||
|
||||
// ViewIPTable View information of nodes in the network
|
||||
func ViewIPTable() (table *p2p.IpAddresses, err error) {
|
||||
table, err = p2p.ReadIpTable()
|
||||
return
|
||||
table, err = p2p.ReadIpTable()
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateIPTable Force updates IP tables based on new
|
||||
// new nodes discovered in the network
|
||||
func UpdateIPTable() (err error) {
|
||||
return clientIPTable.UpdateIpTableListClient()
|
||||
return clientIPTable.UpdateIpTableListClient()
|
||||
}
|
||||
|
||||
// AddCustomInformation allows to pass custom information
|
||||
// through the network to which can be listened on
|
||||
// all peers in the network to execute a task.
|
||||
func AddCustomInformation(information string) error {
|
||||
return clientIPTable.AddCustomInformationToIPTable(information)
|
||||
return clientIPTable.AddCustomInformationToIPTable(information)
|
||||
}
|
||||
|
||||
// AddRootNode Adds root node to the network by using defaults except for
|
||||
// ip address and port no. Supports only IPV4 as of now.
|
||||
func AddRootNode(rootIP string, portNo string) error {
|
||||
var rootNode []p2p.IpAddress
|
||||
|
||||
rootNode = append(rootNode, p2p.IpAddress{
|
||||
Name: "",
|
||||
Ipv4: rootIP,
|
||||
ServerPort: portNo,
|
||||
NAT: false,
|
||||
})
|
||||
return generate.GenerateIPTableFile(rootNode)
|
||||
}
|
||||
|
||||
130
cmd/action.go
130
cmd/action.go
@@ -2,6 +2,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/abstractions"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/client"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/client/clientIPTable"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/config/generate"
|
||||
@@ -87,11 +88,7 @@ var CliAction = func(ctx *cli.Context) error {
|
||||
// Displays all images available on the server side
|
||||
if ViewImages != "" {
|
||||
imageRes, err := client.ViewContainers(ViewImages)
|
||||
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
client.PrettyPrint(imageRes)
|
||||
standardOutput(err, imageRes)
|
||||
}
|
||||
|
||||
// Function called to stop and remove server from Docker
|
||||
@@ -100,9 +97,7 @@ var CliAction = func(ctx *cli.Context) error {
|
||||
fmt.Println("provide container ID via --ID or --id")
|
||||
} else {
|
||||
err := client.RemoveContianer(RemoveVM, ID)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,58 +114,40 @@ var CliAction = func(ctx *cli.Context) error {
|
||||
// Calls function to do Api call to start the container on the server side
|
||||
imageRes, err := client.StartContainer(CreateVM, PortsInt, GPU, ContainerName, BaseImage)
|
||||
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
client.PrettyPrint(imageRes)
|
||||
standardOutput(err, imageRes)
|
||||
}
|
||||
|
||||
//Call if specs flag is called
|
||||
if Specs != "" {
|
||||
specs, err := client.GetSpecs(Specs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Pretty print
|
||||
client.PrettyPrint(specs)
|
||||
standardOutput(err, specs)
|
||||
}
|
||||
|
||||
//Sets default paths to the config file
|
||||
if SetDefaultConfig {
|
||||
_, err := generate.SetDefaults("P2PRC", false, nil, false)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
|
||||
//If the network interface flag is called
|
||||
// Then all the network interfaces are displayed
|
||||
if NetworkInterface {
|
||||
err := p2p.ViewNetworkInterface()
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
|
||||
// If the view plugin flag is called then display all
|
||||
// plugins available
|
||||
if ViewPlugin {
|
||||
plugins, err := plugin.DetectPlugins()
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
client.PrettyPrint(plugins)
|
||||
standardOutput(err, plugins)
|
||||
}
|
||||
|
||||
// If the flag Tracked Container is called or the flag
|
||||
// --tc
|
||||
if TrackedContainers {
|
||||
err, trackedContainers := client.ViewTrackedContainers()
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
}
|
||||
client.PrettyPrint(trackedContainers)
|
||||
standardOutput(err, trackedContainers)
|
||||
}
|
||||
|
||||
//Executing plugin when the plugin flag is called
|
||||
@@ -179,14 +156,11 @@ var CliAction = func(ctx *cli.Context) error {
|
||||
// To execute plugin requires the container ID or group ID provided when being executed
|
||||
if ID != "" {
|
||||
err := plugin.CheckRunPlugin(ExecutePlugin, ID)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println("Success")
|
||||
}
|
||||
} else {
|
||||
fmt.Println("provide container ID via --ID or --id")
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
//else {
|
||||
// fmt.Println("provide container ID via --ID or --id")
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
@@ -194,10 +168,7 @@ var CliAction = func(ctx *cli.Context) error {
|
||||
// Creates new group and outputs JSON file
|
||||
if CreateGroup {
|
||||
group, err := client.CreateGroup()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client.PrettyPrint(group)
|
||||
standardOutput(err, group)
|
||||
}
|
||||
|
||||
// Actions to be performed when the
|
||||
@@ -208,26 +179,14 @@ var CliAction = func(ctx *cli.Context) error {
|
||||
// --rmcgroup --id <contianer id>
|
||||
if RemoveContainerGroup && ID != "" {
|
||||
group, err := client.RemoveContainerGroup(ID, Group)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
client.PrettyPrint(group)
|
||||
}
|
||||
standardOutput(err, group)
|
||||
} else if ID != "" { // Add container to group based on group ID provided
|
||||
// --id <Container ID>
|
||||
group, err := client.AddContainerToGroup(ID, Group)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
client.PrettyPrint(group)
|
||||
}
|
||||
standardOutput(err, group)
|
||||
} else { // View all information about current group
|
||||
group, err := client.GetGroup(Group)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
client.PrettyPrint(group)
|
||||
}
|
||||
standardOutput(err, group)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,63 +195,52 @@ var CliAction = func(ctx *cli.Context) error {
|
||||
// --rmgroup
|
||||
if RemoveGroup != "" {
|
||||
err := client.RemoveGroup(RemoveGroup)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println("Group Removed")
|
||||
}
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
|
||||
// Execute Function to view all groups
|
||||
if Groups {
|
||||
groups, err := client.ReadGroup()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
client.PrettyPrint(groups)
|
||||
}
|
||||
standardOutput(err, groups)
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
if PullPlugin != "" {
|
||||
err := plugin.DownloadPlugin(PullPlugin)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println("Success")
|
||||
}
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
|
||||
if RemovePlugin != "" {
|
||||
err := plugin.DeletePlugin(RemovePlugin)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println("Success")
|
||||
}
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
|
||||
if AddMetaData != "" {
|
||||
err := clientIPTable.AddCustomInformationToIPTable(AddMetaData)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println("Success")
|
||||
}
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
|
||||
if MAPPort != "" {
|
||||
address, err := client.MAPPort(MAPPort, DomainName, RemoteAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
client.PrettyPrint(address)
|
||||
}
|
||||
standardOutput(err, address)
|
||||
}
|
||||
|
||||
// Action called to add root node to network
|
||||
if AddRootNode && IP != "" && Ports != "" {
|
||||
err := abstractions.AddRootNode(IP, Ports)
|
||||
standardOutput(err, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func standardOutput(err error, i interface{}) {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else if i == nil {
|
||||
fmt.Println("Success")
|
||||
} else {
|
||||
client.PrettyPrint(i)
|
||||
}
|
||||
}
|
||||
|
||||
16
cmd/flags.go
16
cmd/flags.go
@@ -41,6 +41,8 @@ var (
|
||||
PullPlugin string
|
||||
RemovePlugin string
|
||||
AddMetaData string
|
||||
AddRootNode bool
|
||||
IP string
|
||||
)
|
||||
|
||||
var AppConfigFlags = []cli.Flag{
|
||||
@@ -272,4 +274,18 @@ var AppConfigFlags = []cli.Flag{
|
||||
EnvVars: []string{"ADDMETADATA"},
|
||||
Destination: &AddMetaData,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "AddRootNode",
|
||||
Aliases: []string{"arn"},
|
||||
Usage: "Adds initial root node to talk to",
|
||||
EnvVars: []string{"ADDROOTNODE"},
|
||||
Destination: &AddRootNode,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "IPAddress",
|
||||
Aliases: []string{"ip"},
|
||||
Usage: "IP address",
|
||||
EnvVars: []string{"IP"},
|
||||
Destination: &IP,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ type Config struct {
|
||||
ServerPort string
|
||||
ProxyPort string
|
||||
GroupTrackContainersPath string
|
||||
FRPServerPort string
|
||||
BehindNAT string
|
||||
FRPServerPort bool
|
||||
BehindNAT bool
|
||||
IPTableKey string
|
||||
PublicKeyFile string
|
||||
PrivateKeyFile string
|
||||
|
||||
@@ -78,9 +78,9 @@ func SetDefaults(envName string, forceDefault bool, CustomConfig interface{}, No
|
||||
Defaults.GroupTrackContainersPath = defaultPath + "client/trackcontainers/grouptrackcontainers.json"
|
||||
Defaults.ServerPort = "8088"
|
||||
Defaults.ProxyPort = ""
|
||||
Defaults.FRPServerPort = "True"
|
||||
Defaults.FRPServerPort = true
|
||||
Defaults.CustomConfig = CustomConfig
|
||||
Defaults.BehindNAT = "True"
|
||||
Defaults.BehindNAT = true
|
||||
Defaults.DockerRunLogs = "/tmp/"
|
||||
// Generate a random key to be added to IPTable
|
||||
Defaults.IPTableKey = String(12)
|
||||
|
||||
@@ -45,9 +45,9 @@ func GenerateIPTableFile(rootNodes []p2p.IpAddress) (err error) {
|
||||
if len(rootNodes) <= 0 {
|
||||
rootnode.Name = "Node1"
|
||||
rootnode.ServerPort = "8078"
|
||||
rootnode.NAT = "False"
|
||||
rootnode.NAT = false
|
||||
rootnode.Ipv4 = "217.76.63.222"
|
||||
rootnode.ProxyServer = "True"
|
||||
rootnode.ProxyServer = true
|
||||
|
||||
rootnodes.IpAddress = append(rootnodes.IpAddress, rootnode)
|
||||
} else {
|
||||
|
||||
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]]
|
||||
@@ -29,9 +29,9 @@ type IpAddress struct {
|
||||
Upload float64 `json:"Upload"`
|
||||
ServerPort string `json:"ServerPort"`
|
||||
BareMetalSSHPort string `json:"BareMetalSSHPort"`
|
||||
NAT string `json:"NAT"`
|
||||
NAT bool `json:"NAT"`
|
||||
EscapeImplementation string `json:"EscapeImplementation"`
|
||||
ProxyServer string `json:"ProxyServer"`
|
||||
ProxyServer bool `json:"ProxyServer"`
|
||||
UnSafeMode bool `json:"UnSafeMode"`
|
||||
PublicKey string `json:"PublicKey"`
|
||||
CustomInformation string `json:"CustomInformation"`
|
||||
@@ -161,7 +161,7 @@ func (table *IpAddresses) RemoveDuplicates() error {
|
||||
}
|
||||
}
|
||||
|
||||
if table.IpAddress[i].NAT == "True" && table.IpAddress[i].EscapeImplementation == "None" {
|
||||
if table.IpAddress[i].NAT && table.IpAddress[i].EscapeImplementation == "None" {
|
||||
Exists = true
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ func (ip *IpAddresses) SpeedTestUpdatedIPTable() error {
|
||||
}
|
||||
// Checks if both the IPV4 addresses are the same or the IPV6 address is not
|
||||
// an empty string and IPV6 address are the same
|
||||
if (ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 && targets.IpAddress[i].NAT == "True") || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) {
|
||||
if (ip.IpAddress[k].Ipv4 == targets.IpAddress[i].Ipv4 && targets.IpAddress[i].NAT) || (targets.IpAddress[i].Ipv6 != "" && ip.IpAddress[k].Ipv6 == targets.IpAddress[i].Ipv6) {
|
||||
Exists = true
|
||||
break
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ func Server() (*gin.Engine, error) {
|
||||
// TODO check if IPV6 or Proxy port is specified
|
||||
// if not update current entry as proxy address
|
||||
// with appropriate port on IP Table
|
||||
if config.BehindNAT == "True" {
|
||||
if config.BehindNAT {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -267,7 +267,7 @@ func Server() (*gin.Engine, error) {
|
||||
for i, _ := range table.IpAddress {
|
||||
// Checks if the ping is the lowest and if the following node is acting as a proxy
|
||||
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
|
||||
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].NAT != "" {
|
||||
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && !table.IpAddress[i].NAT {
|
||||
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
|
||||
lowestLatencyIpAddress = table.IpAddress[i]
|
||||
}
|
||||
@@ -291,8 +291,8 @@ func Server() (*gin.Engine, error) {
|
||||
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
|
||||
ProxyIpAddr.ServerPort = proxyPort
|
||||
ProxyIpAddr.Name = config.MachineName
|
||||
ProxyIpAddr.NAT = "False"
|
||||
ProxyIpAddr.ProxyServer = "False"
|
||||
ProxyIpAddr.NAT = false
|
||||
ProxyIpAddr.ProxyServer = false
|
||||
ProxyIpAddr.EscapeImplementation = "FRP"
|
||||
|
||||
if config.BareMetal {
|
||||
@@ -314,9 +314,9 @@ func Server() (*gin.Engine, error) {
|
||||
}
|
||||
ProxyIpAddr.ServerPort = config.ServerPort
|
||||
ProxyIpAddr.Name = config.MachineName
|
||||
ProxyIpAddr.NAT = "False"
|
||||
ProxyIpAddr.NAT = false
|
||||
if config.ProxyPort != "" {
|
||||
ProxyIpAddr.ProxyServer = "True"
|
||||
ProxyIpAddr.ProxyServer = true
|
||||
}
|
||||
ProxyIpAddr.EscapeImplementation = ""
|
||||
if config.BareMetal {
|
||||
@@ -425,9 +425,9 @@ func MapPort(port string, domainName string) (string, string, error) {
|
||||
for i, _ := range table.IpAddress {
|
||||
// Checks if the ping is the lowest and if the following node is acting as a proxy
|
||||
//if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].ProxyPort != "" {
|
||||
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && table.IpAddress[i].NAT != "" {
|
||||
if table.IpAddress[i].Latency.Milliseconds() < lowestLatency && !table.IpAddress[i].NAT {
|
||||
// Filter based on nodes with proxy enabled
|
||||
if domainName != "" && table.IpAddress[i].ProxyServer == "True" {
|
||||
if domainName != "" && table.IpAddress[i].ProxyServer {
|
||||
lowestLatency = table.IpAddress[i].Latency.Milliseconds()
|
||||
lowestLatencyIpAddress = table.IpAddress[i]
|
||||
continue
|
||||
@@ -466,7 +466,7 @@ func MapPort(port string, domainName string) (string, string, error) {
|
||||
ProxyIpAddr.Ipv4 = lowestLatencyIpAddress.Ipv4
|
||||
ProxyIpAddr.ServerPort = proxyPort
|
||||
ProxyIpAddr.Name = config.MachineName
|
||||
ProxyIpAddr.NAT = "False"
|
||||
ProxyIpAddr.NAT = false
|
||||
ProxyIpAddr.EscapeImplementation = "FRP"
|
||||
|
||||
//ProxyIpAddr.CustomInformationKey = p2p.GenerateHashSHA256(config.IPTableKey)
|
||||
|
||||
32
style.css
32
style.css
@@ -1,32 +0,0 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
span#discordJoin {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* Dark mode */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
/* General Page Changing */
|
||||
body {
|
||||
background: #121212; /* Background Color */
|
||||
color: #FFFFFF; /* Text Color */
|
||||
}
|
||||
|
||||
a:link{ /* Unvisited Link */
|
||||
color: #03DAC5;
|
||||
}
|
||||
|
||||
a:visited { /* Visited Link */
|
||||
color: #BB86FC;
|
||||
}
|
||||
|
||||
a:hover { /* Mouse over Link */
|
||||
color: #018786;
|
||||
}
|
||||
|
||||
span#discordJoin { /* Text Color Change */
|
||||
color: #cc0227;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user