diff --git a/README.md b/README.md index e8e7f06..9914e07 100644 --- a/README.md +++ b/README.md @@ -13,27 +13,45 @@ accepting remote inputs.
There will be ansible instructions which can be executed inside into any virtual environment. This will be a plugin which complements the project [P2PRC](https://p2prc.akilan.io) -# Index +[//]: # (# Index) -- [Testing with X-Plane 11](#testing-with-x-plane-11) -- [Laplace](#laplace) -- [Installation](#installation) - - [Installation required to share keyboard and mouse](#installation-required-to-share-keyboard-and-mouse) - - [What is x2x?](#what-is-x2x) - - [What is Barrier KVM](#what-is-barrier-kvm) - - [Barrier KVM build status and links to install](#barrier-kvm-build-status-and-links-to-install) - - [Build from Source](#build-from-source) -- [Program Execution](#program-execution) - - [Starting game when screen-share is triggered](#starting-game-when-screen-share-is-triggered) - - [Ex: Start X-Plane 11](#ex-start-x-plane-11) - - [Open config file](#open-config-file) - - [Call from built script which starts the server , creates room and outputs the ID](#call-from-built-script-which-starts-the-server--creates-room-and-outputs-the-id) - - [Starting the Server](#starting-server) - - [Starting the Screenshare](#starting-screenshare) -- [Contributing](#contributing) -- [Discord Server Link](#or) +[//]: # () +[//]: # (- [Testing with X-Plane 11](#testing-with-x-plane-11)) ---- +[//]: # (- [Laplace](#laplace)) + +[//]: # (- [Installation](#installation)) + +[//]: # ( - [Installation required to share keyboard and mouse](#installation-required-to-share-keyboard-and-mouse)) + +[//]: # ( - [What is x2x?](#what-is-x2x)) + +[//]: # ( - [What is Barrier KVM](#what-is-barrier-kvm)) + +[//]: # ( - [Barrier KVM build status and links to install](#barrier-kvm-build-status-and-links-to-install)) + +[//]: # ( - [Build from Source](#build-from-source)) + +[//]: # (- [Program Execution](#program-execution)) + +[//]: # ( - [Starting game when screen-share is triggered](#starting-game-when-screen-share-is-triggered)) + +[//]: # ( - [Ex: Start X-Plane 11](#ex-start-x-plane-11)) + +[//]: # ( - [Open config file](#open-config-file)) + +[//]: # ( - [Call from built script which starts the server , creates room and outputs the ID](#call-from-built-script-which-starts-the-server--creates-room-and-outputs-the-id)) + +[//]: # ( - [Starting the Server](#starting-server)) + +[//]: # ( - [Starting the Screenshare](#starting-screenshare)) + +[//]: # (- [Contributing](#contributing)) + +[//]: # (- [Discord Server Link](#or)) + +[//]: # () +[//]: # (---) ## Testing with [X-Plane 11](https://www.x-plane.com/) [![A screenshot of X-Plane 11 (flight simulator game) running smoothly via WebRTC](https://i.ytimg.com/vi/65dn7TRgzeE/hqdefault.jpg)](https://www.youtube.com/watch?v=65dn7TRgzeE "Running X-Plane 11 using WebRTC") @@ -46,14 +64,16 @@ https://github.com/Akilan1999/laplace/tree/keyboard_mouse ### Installation required to share keyboard and mouse -Currently, you can either use [x2x](https://github.com/dottedmag/x2x) or [Barrier KVM]()
-We need to ensure that the client has SSH client installed or Barrierc. +Currently, you can use [Barrier KVM]().
-#### What is x2x? -[x2x](https://github.com/dottedmag/x2x) allows the keyboard, mouse on one X display to be used to control another X -display. It also shares X clipboards between the displays. +[//]: # (#### What is x2x?) -Note: x2x runs on top of SSH. +[//]: # ([x2x](https://github.com/dottedmag/x2x) allows the keyboard, mouse on one X display to be used to control another X) + +[//]: # (display. It also shares X clipboards between the displays.) + +[//]: # () +[//]: # (Note: x2x runs on top of SSH.) #### What is Barrier KVM? @@ -75,75 +95,52 @@ moving your mouse to the edge of the screen, or by using a keypress to switch fo ### Build from source ```bash -# Assumes to be running on ubuntu 20.04 -# Ports required to be allocated internally: -# - 8888 (laplace server) +# Install golang +# https://go.dev/doc/install -# Updating and installing go compiler -apt update -apt install -y golang -apt install -y jq -## Installing git -apt install -y git -# Installing OpenSSH server -apt install -y openssh-server -## Installing x2x -apt install -y x2x -## Installing barrier -apt install -y barrier -## Installing chromium -wget https://github.com/RobRich999/Chromium_Clang/releases/download/v94.0.4585.0-r904940-linux64-deb-avx/chromium-browser-unstable_94.0.4585.0-1_amd64.deb -apt install -y ./chromium-browser-unstable_94.0.4585.0-1_amd64.deb -# -## clone remotegameplay distribution -git clone https://github.com/Akilan1999/remotegameplay -## enter cloned directory -cd remotegameplay -# sets REMOTEGAMEPLAY path -export REMOTEGAMING=$PWD - -# Build laplace binary file +# Build go build . -# Set configuration laplace file -./laplace -setconfig +# Configure (run only once) +./remotegaming -setconfig -# Open config.json file and add SSH password for x2x +# Migrate (run only once) +./remotegaming -Migrate + +# The following are OR Based instruction. +# You could start the server in either of +# of the modes. (run every time you +# would want to start a server) + +# Setting up based on the generated config +# open config.json +{ + "SystemUsername": "", + "BarrierHostName": "", + "Rooms": "", + "IPAddress": "", + "ScriptToExecute": "", + "SSHPassword": "", + "NATEscapeGameServerPort": "", + "NATEscapeScreenSharePort": "", + "NATEscapeBarrierPort": "", + "BackendURL": " or set to a gameserver externally hosted", + "BrowserCommand": "Requires the user to setup the command that triggers the browser from the Terminal or Command line", + "Rate": 0, + "ScreenName": "Entire screen (The default point) or add custom screename or tab", + "InternalGameServerPort": "8088", + "InternalScreenSharePort": "8888" +} + +## Both Servers +## Starts the remote gaming screenshare server and the gameserver +./remotegaming -BothServers +## Start only game server +./remotegaming -GameServer +## Start only screenshare +./remotegaming -tls -headless ``` -## Program Execution - -Executing this project basically serves an HTTP server that will host the frontend and the WebSocket implementation.
-Note that you sometimes need to run HTTPs in order for browser to connect to websocket. - -```bash -$ ./laplace --help - -BinaryToExecute string - Providing path (i.e Absolute path) of binary to execute - -addr string - Listen address (default "0.0.0.0:443") - -certFile string - TLS cert file (default "files/server.crt") - -headless - Creating screenshare using headless mode - -keyFile string - TLS key file (default "files/server.key") - -killChromium - Kills all chromuim - -killServer - Kills the laplace - -roomInfo - Getting room id of headless server - -setconfig - Generates a config file - -tls - Use TLS -``` - -By default, you can run the executable without any argument to listen to TLS port 443.
-A self-signed certificate files are provided to ease up development. If you want to run -with barrier KVM. Run as non-root. - ### Starting game when screen-share is triggered This requires creating a bash script to trigger when the screenshare begins. #### Ex: Start X-Plane 11 @@ -155,38 +152,66 @@ cd /path/.local/share/Steam/steamapps/common/X-Plane\ 11/ # Execute X-Plane 11 binary ./X-Plane-x86_64 ``` -#### Open config file -```bash -{ - "barrierhostname": "", - "ipaddress": "0.0.0.0", - "rooms": "", - "scripttoexecute": "", - "sshpassword": "", - "systemusername": "" -} -``` -### Call from built script which starts the server , creates room and outputs the ID -```bash -sh run.sh -``` -Note: This script starts the server using the port 8888 by default
-The 2 steps below are if you want to start them command by command +[//]: # (#### Open config file ) -### Starting server -```bash -$ ./laplace -tls -addr 0.0.0.0:8888 -2020/03/25 01:01:10 Listening on TLS: 0.0.0.0:8888 -``` +[//]: # (```bash) -### Starting screenshare -```bash -./laplace -headless -addr -``` +[//]: # () +[//]: # ({) -You can then open https://localhost:8888/ to view Laplace page.
-You may need to add certificate exceptions. In Chrome, you can type `thisisunsafe`. +[//]: # ( "barrierhostname": "",) + +[//]: # ( "ipaddress": "0.0.0.0",) + +[//]: # ( "rooms": "",) + +[//]: # ( "scripttoexecute": "",) + +[//]: # ( "sshpassword": "",) + +[//]: # ( "systemusername": "") + +[//]: # (}) + +[//]: # (```) + +[//]: # (### Call from built script which starts the server , creates room and outputs the ID) + +[//]: # (```bash) + +[//]: # (sh run.sh ) + +[//]: # (```) + +[//]: # (Note: This script starts the server using the port 8888 by default
) + +[//]: # (The 2 steps below are if you want to start them command by command ) + +[//]: # () +[//]: # (### Starting server) + +[//]: # (```bash) + +[//]: # ($ ./laplace -tls -addr 0.0.0.0:8888) + +[//]: # (2020/03/25 01:01:10 Listening on TLS: 0.0.0.0:8888) + +[//]: # (```) + +[//]: # () +[//]: # (### Starting screenshare ) + +[//]: # (```bash) + +[//]: # (./laplace -headless -addr ) + +[//]: # (```) + +[//]: # () +[//]: # (You can then open https://localhost:8888/ to view Laplace page.
) + +[//]: # (You may need to add certificate exceptions. In Chrome, you can type `thisisunsafe`.) diff --git a/core/core.go b/core/core.go index 322d020..5ae6637 100644 --- a/core/core.go +++ b/core/core.go @@ -50,7 +50,7 @@ func BroadcastServerToBackend() error { // Game session url //+ file.ID - gameSession.Link = respIpv4orIPv6 + ":" + config.NATEscapeGameServerPort + "/?id=" + room.ID + gameSession.Link = respIpv4orIPv6 + ":" + config.NATEscapeScreenSharePort + "/?id=" + room.ID // Rate for the game session gameSession.Rate = config.Rate // Server specs to struct GameSession diff --git a/main.go b/main.go index 49eadbb..5926bb8 100644 --- a/main.go +++ b/main.go @@ -1,264 +1,264 @@ package main import ( - "encoding/json" - "flag" - "fmt" - "github.com/Akilan1999/remotegameplay/config" - "github.com/Akilan1999/remotegameplay/core" - gameserver "github.com/Akilan1999/remotegameplay/server" - "log" - "math/rand" - "net/http" - "os/exec" - "time" + "encoding/json" + "flag" + "fmt" + "github.com/Akilan1999/remotegameplay/config" + "github.com/Akilan1999/remotegameplay/core" + gameserver "github.com/Akilan1999/remotegameplay/server" + "log" + "math/rand" + "net/http" + "os/exec" + "time" ) func main() { - addr := flag.String("addr", "0.0.0.0", "Listen address") - //port := flag.String("port", "8888", "port for running the server") - barrier := flag.Bool("barrier", false, "set external port barrier") - tls := flag.Bool("tls", false, "Use TLS") - setconfig := flag.Bool("setconfig", false, "Generates a config file") - certFile := flag.String("certFile", "files/server.crt", "TLS cert file") - keyFile := flag.String("keyFile", "files/server.key", "TLS key file") - headless := flag.Bool("headless", false, "Creating screenshare using headless mode") - roomInfo := flag.Bool("roomInfo", false, "Getting room id of headless server") - killServer := flag.Bool("killServer", false, "Kills the laplace") - killChromium := flag.Bool("killChromium", false, "Kills all chromuim") - BinaryToExecute := flag.String("BinaryToExecute", "", "Providing path (i.e Absolute path) of binary to execute") - GameServer := flag.Bool("GameServer", false, "Starts the game server by default") - Migrate := flag.Bool("Migrate", false, "Sets up the tables for the Sqlite database") - BothServers := flag.Bool("BothServers", false, "Starts the Gameserver and screenshare. Also ensures the screenshare can broadcast the availability to the game server") + addr := flag.String("addr", "0.0.0.0", "Listen address") + //port := flag.String("port", "8888", "port for running the server") + barrier := flag.Bool("barrier", false, "set external port barrier") + tls := flag.Bool("tls", false, "Use TLS") + setconfig := flag.Bool("setconfig", false, "Generates a config file") + certFile := flag.String("certFile", "files/server.crt", "TLS cert file") + keyFile := flag.String("keyFile", "files/server.key", "TLS key file") + headless := flag.Bool("headless", false, "Creating screenshare using headless mode") + roomInfo := flag.Bool("roomInfo", false, "Getting room id of headless server") + killServer := flag.Bool("killServer", false, "Kills the laplace") + killChromium := flag.Bool("killChromium", false, "Kills all chromuim") + BinaryToExecute := flag.String("BinaryToExecute", "", "Providing path (i.e Absolute path) of binary to execute") + GameServer := flag.Bool("GameServer", false, "Starts the game server by default") + Migrate := flag.Bool("Migrate", false, "Sets up the tables for the Sqlite database") + BothServers := flag.Bool("BothServers", false, "Starts the Gameserver and screenshare. Also ensures the screenshare can broadcast the availability to the game server") - flag.Parse() + flag.Parse() - rand.Seed(time.Now().UnixNano()) - server := core.GetHttp() + rand.Seed(time.Now().UnixNano()) + server := core.GetHttp() - if *setconfig { - err := config.SetDefaults() - if err != nil { - return - } - return - } + if *setconfig { + err := config.SetDefaults() + if err != nil { + return + } + return + } - Config, err := config.ConfigInit() - if err != nil { - log.Fatalln(err) - } + Config, err := config.ConfigInit() + if err != nil { + log.Fatalln(err) + } - // if barrier flag is provided - if *barrier { - natBarrier, err := core.EscapeNATBarrier() - if err != nil { - fmt.Println(err) - return - } - Config.NATEscapeBarrierPort = natBarrier - err = Config.WriteConfig() - if err != nil { - return - } - fmt.Println(Config.IPAddress + ":" + Config.NATEscapeBarrierPort) - return - } + // if barrier flag is provided + if *barrier { + natBarrier, err := core.EscapeNATBarrier() + if err != nil { + fmt.Println(err) + return + } + Config.NATEscapeBarrierPort = natBarrier + err = Config.WriteConfig() + if err != nil { + return + } + fmt.Println(Config.IPAddress + ":" + Config.NATEscapeBarrierPort) + return + } - // Print out room information - if *roomInfo { - room, err := core.ReadRoomsFile() - if err != nil { - log.Fatalln(err) - } + // Print out room information + if *roomInfo { + room, err := core.ReadRoomsFile() + if err != nil { + log.Fatalln(err) + } - PrettyPrint(room) - return - } + PrettyPrint(room) + return + } - // kills laplace server - if *killServer { - cmd := exec.Command("pkill", "remotegameplay") - if err := cmd.Run(); err != nil { - fmt.Println(err) - } - return - } - // kills chromium server - if *killChromium { - cmd := exec.Command("pkill", "chromium") - if err := cmd.Run(); err != nil { - fmt.Println(err) - } - return - } + // kills laplace server + if *killServer { + cmd := exec.Command("pkill", "remotegameplay") + if err := cmd.Run(); err != nil { + fmt.Println(err) + } + return + } + // kills chromium server + if *killChromium { + cmd := exec.Command("pkill", "chromium") + if err := cmd.Run(); err != nil { + fmt.Println(err) + } + return + } - if *Migrate { - // Connect to Sqlite - connect, err := gameserver.Connect() - if err != nil { - fmt.Println(err) - } - // Migrate table - session, err := gameserver.CreateTables(connect) - if err != nil { - fmt.Println(err) - } - session.Scan(gameserver.GameSession{}) + if *Migrate { + // Connect to Sqlite + connect, err := gameserver.Connect() + if err != nil { + fmt.Println(err) + } + // Migrate table + session, err := gameserver.CreateTables(connect) + if err != nil { + fmt.Println(err) + } + session.Scan(gameserver.GameSession{}) - return - } + return + } - // running implementation to escape NAT - GameServerPort, ScreenSharePort, err := core.EscapeNAT(Config.InternalScreenSharePort, Config.InternalGameServerPort) - if err != nil { - log.Fatalln(err) - } + // running implementation to escape NAT + GameServerPort, ScreenSharePort, err := core.EscapeNAT(Config.InternalScreenSharePort, Config.InternalGameServerPort) + if err != nil { + log.Fatalln(err) + } - Config.IPAddress = "64.227.168.102" - Config.NATEscapeGameServerPort = GameServerPort - Config.NATEscapeScreenSharePort = ScreenSharePort - Config.NATEscapeBarrierPort = "" + Config.IPAddress = "64.227.168.102" + Config.NATEscapeGameServerPort = GameServerPort + Config.NATEscapeScreenSharePort = ScreenSharePort + Config.NATEscapeBarrierPort = "" - err = Config.WriteConfig() - if err != nil { - log.Fatalln(err) - } + err = Config.WriteConfig() + if err != nil { + log.Fatalln(err) + } - // If both server and screenshare have be triggered (first set the according flags to true) - if *BothServers { - *headless = true - *tls = true - *GameServer = true - } + // If both server and screenshare have be triggered (first set the according flags to true) + if *BothServers { + *headless = true + *tls = true + *GameServer = true + } - if *GameServer { - go gameserver.Server(Config.InternalGameServerPort) - time.Sleep(2 * time.Second) - } + if *GameServer { + go gameserver.Server(Config.InternalGameServerPort) + time.Sleep(2 * time.Second) + } - if !*GameServer || *BothServers { - if *tls { - log.Println("Listening on TLS:", *addr+":"+Config.InternalScreenSharePort) - go http.ListenAndServeTLS(*addr+":"+Config.InternalScreenSharePort, *certFile, *keyFile, server) - time.Sleep(2 * time.Second) - } else { - log.Println("Listening:", *addr+":"+Config.InternalScreenSharePort) - go http.ListenAndServe(*addr+":"+Config.InternalScreenSharePort, server) - time.Sleep(2 * time.Second) - } - } + if !*GameServer || *BothServers { + if *tls { + log.Println("Listening on TLS:", *addr+":"+Config.InternalScreenSharePort) + go http.ListenAndServeTLS(*addr+":"+Config.InternalScreenSharePort, *certFile, *keyFile, server) + time.Sleep(2 * time.Second) + } else { + log.Println("Listening:", *addr+":"+Config.InternalScreenSharePort) + go http.ListenAndServe(*addr+":"+Config.InternalScreenSharePort, server) + time.Sleep(2 * time.Second) + } + } - // If both server selected set the remote Gameserver to local now. - if *BothServers { - Config.BackendURL = "http://" + Config.IPAddress + ":" + Config.NATEscapeGameServerPort + "/" - err = Config.WriteConfig() - if err != nil { - fmt.Println(err) - return - } - } + // If both server selected set the remote Gameserver to local now. + if *BothServers { + Config.BackendURL = "http://" + Config.IPAddress + ":" + Config.NATEscapeGameServerPort + "/" + err = Config.WriteConfig() + if err != nil { + fmt.Println(err) + return + } + } - // Running in headless mode - if *headless { - // Running starting a browser as a background process - go func() { - Config, err = config.ConfigInit() - if err != nil { - log.Fatalln(err) - } + // Running in headless mode + if *headless { + // Running starting a browser as a background process + go func() { + Config, err = config.ConfigInit() + if err != nil { + log.Fatalln(err) + } - //// Returns the URl address type - //Addr := Ip4or6(Config.IPAddress) - // - //// If address is provided - //if *addr != "" { - // Addr = *addr - // // Add brackets if the ip address is ipv6 - // Addr = Ip4or6(Addr) - //} + //// Returns the URl address type + //Addr := Ip4or6(Config.IPAddress) + // + //// If address is provided + //if *addr != "" { + // Addr = *addr + // // Add brackets if the ip address is ipv6 + // Addr = Ip4or6(Addr) + //} - var TaskExecute string + var TaskExecute string - if *BinaryToExecute != "" { - TaskExecute = *BinaryToExecute - } else { - // Read binary from config file - TaskExecute = Config.ScriptToExecute - } + if *BinaryToExecute != "" { + TaskExecute = *BinaryToExecute + } else { + // Read binary from config file + TaskExecute = Config.ScriptToExecute + } - // Starting screen share headless - cmd := exec.Command(Config.BrowserCommand, "--no-sandbox", "--auto-select-desktop-capture-source="+Config.ScreenName, "--url", "https://"+*addr+":"+Config.InternalScreenSharePort+"/?mode=headless", "--ignore-certificate-errors") - if err := cmd.Start(); err != nil { - log.Fatalln(err) - } + // Starting screen share headless + cmd := exec.Command(Config.BrowserCommand, "--no-sandbox", "--auto-select-desktop-capture-source="+Config.ScreenName, "--url", "https://"+*addr+":"+Config.InternalScreenSharePort+"/?mode=headless", "--ignore-certificate-errors") + if err := cmd.Start(); err != nil { + log.Fatalln(err) + } - // Makes program sleep for 2 seconds to allow chromium browser to open - time.Sleep(3 * time.Second) + // Makes program sleep for 2 seconds to allow chromium browser to open + time.Sleep(3 * time.Second) - err = core.BroadcastServerToBackend() - if err != nil { - fmt.Println(err) - } else { - fmt.Println("success broadcasting to game server") - } + err = core.BroadcastServerToBackend() + if err != nil { + fmt.Println(err) + } else { + fmt.Println("success broadcasting to game server") + } - // Task to be executed - err = RunTask(TaskExecute) - if err != nil { - fmt.Println(err) - return - } - }() + // Task to be executed + err = RunTask(TaskExecute) + if err != nil { + fmt.Println(err) + return + } + }() - } + } - for { + for { - } + } - // Start P2PRC server - //_, err = abstractions.Start() - //if err != nil { - // return - //} + // Start P2PRC server + //_, err = abstractions.Start() + //if err != nil { + // return + //} } // PrettyPrint print the contents of the obj ( // Reference: https://stackoverflow.com/questions/24512112/how-to-print-struct-variables-in-console func PrettyPrint(data interface{}) { - var p []byte - // var err := error - p, err := json.MarshalIndent(data, "", "\t") - if err != nil { - fmt.Println(err) - return - } - fmt.Printf("%s \n", p) + var p []byte + // var err := error + p, err := json.MarshalIndent(data, "", "\t") + if err != nil { + fmt.Println(err) + return + } + fmt.Printf("%s \n", p) } // Ip4or6 Helper function to check if the IP address is IPV4 or // IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6) func Ip4or6(s string) string { - for i := 0; i < len(s); i++ { - switch s[i] { - case '.': - return s - case ':': - return "[" + s + "]" - } - } - return "[" + s + "]" + for i := 0; i < len(s); i++ { + switch s[i] { + case '.': + return s + case ':': + return "[" + s + "]" + } + } + return "[" + s + "]" } func RunTask(task string) error { - // Halts the process - cmd := exec.Command("sh", task) - if err := cmd.Start(); err != nil { - return err - } + // Halts the process + cmd := exec.Command("sh", task) + if err := cmd.Start(); err != nil { + return err + } - return nil + return nil } diff --git a/server/server.go b/server/server.go index 5251bb6..726a0cb 100644 --- a/server/server.go +++ b/server/server.go @@ -194,7 +194,7 @@ func Server(port string) error { func CheckIfGameSessionIsActiveOrRemove(gorm *gorm.DB) { for { - time.Sleep(2 * time.Second) + time.Sleep(10 * time.Second) Gamesessions, err := DisplayGameSessions(gorm) if err != nil { return