updated README file

This commit is contained in:
2023-03-02 15:50:11 +00:00
parent 2d2c083744
commit 66d53490c7
4 changed files with 355 additions and 330 deletions

257
README.md
View File

@@ -13,27 +13,45 @@ accepting remote inputs.<br>
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]&#40;#testing-with-x-plane-11&#41;)
---
[//]: # (- [Laplace]&#40;#laplace&#41;)
[//]: # (- [Installation]&#40;#installation&#41;)
[//]: # ( - [Installation required to share keyboard and mouse]&#40;#installation-required-to-share-keyboard-and-mouse&#41;)
[//]: # ( - [What is x2x?]&#40;#what-is-x2x&#41;)
[//]: # ( - [What is Barrier KVM]&#40;#what-is-barrier-kvm&#41;)
[//]: # ( - [Barrier KVM build status and links to install]&#40;#barrier-kvm-build-status-and-links-to-install&#41;)
[//]: # ( - [Build from Source]&#40;#build-from-source&#41;)
[//]: # (- [Program Execution]&#40;#program-execution&#41;)
[//]: # ( - [Starting game when screen-share is triggered]&#40;#starting-game-when-screen-share-is-triggered&#41;)
[//]: # ( - [Ex: Start X-Plane 11]&#40;#ex-start-x-plane-11&#41;)
[//]: # ( - [Open config file]&#40;#open-config-file&#41;)
[//]: # ( - [Call from built script which starts the server , creates room and outputs the ID]&#40;#call-from-built-script-which-starts-the-server--creates-room-and-outputs-the-id&#41;)
[//]: # ( - [Starting the Server]&#40;#starting-server&#41;)
[//]: # ( - [Starting the Screenshare]&#40;#starting-screenshare&#41;)
[//]: # (- [Contributing]&#40;#contributing&#41;)
[//]: # (- [Discord Server Link]&#40;#or&#41;)
[//]: # ()
[//]: # (---)
## 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]()<br>
We need to ensure that the client has SSH client installed or Barrierc.
Currently, you can use [Barrier KVM]().<br>
#### 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]&#40;https://github.com/dottedmag/x2x&#41; 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": "<auto-set>",
"BarrierHostName": "<auto-set>",
"Rooms": "<auto-set>",
"IPAddress": "<auto-set>",
"ScriptToExecute": "",
"SSHPassword": "",
"NATEscapeGameServerPort": "<auto-set>",
"NATEscapeScreenSharePort": "<auto-set>",
"NATEscapeBarrierPort": "",
"BackendURL": "<auto-set> 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.<br>
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.<br>
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": "<barrier host name>",
"ipaddress": "0.0.0.0",
"rooms": "<path to room.json file>",
"scripttoexecute": "<path to script to execute (In case the Xplane 11 script)>",
"sshpassword": "<SSH password for x2x>",
"systemusername": "<system username>"
}
```
### Call from built script which starts the server , creates room and outputs the ID
```bash
sh run.sh <IPV6 or Public IPV4 address of server>
```
Note: This script starts the server using the port 8888 by default<br>
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 <public ip address of server>
```
[//]: # ()
[//]: # ({)
You can then open https://localhost:8888/ to view Laplace page.<br>
You may need to add certificate exceptions. In Chrome, you can type `thisisunsafe`.
[//]: # ( "barrierhostname": "<barrier host name>",)
[//]: # ( "ipaddress": "0.0.0.0",)
[//]: # ( "rooms": "<path to room.json file>",)
[//]: # ( "scripttoexecute": "<path to script to execute &#40;In case the Xplane 11 script&#41;>",)
[//]: # ( "sshpassword": "<SSH password for x2x>",)
[//]: # ( "systemusername": "<system username>")
[//]: # (})
[//]: # (```)
[//]: # (### Call from built script which starts the server , creates room and outputs the ID)
[//]: # (```bash)
[//]: # (sh run.sh <IPV6 or Public IPV4 address of server>)
[//]: # (```)
[//]: # (Note: This script starts the server using the port 8888 by default<br>)
[//]: # (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 <public ip address of server> )
[//]: # (```)
[//]: # ()
[//]: # (You can then open https://localhost:8888/ to view Laplace page.<br>)
[//]: # (You may need to add certificate exceptions. In Chrome, you can type `thisisunsafe`.)

View File

@@ -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

424
main.go
View File

@@ -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
}

View File

@@ -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