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 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) 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) [//]: # (- [Testing with X-Plane 11]&#40;#testing-with-x-plane-11&#41;)
- [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)
--- [//]: # (- [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/) ## 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") [![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 ### Installation required to share keyboard and mouse
Currently, you can either use [x2x](https://github.com/dottedmag/x2x) or [Barrier KVM]()<br> Currently, you can use [Barrier KVM]().<br>
We need to ensure that the client has SSH client installed or Barrierc.
#### What is x2x? [//]: # (#### 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.
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? #### 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 ### Build from source
```bash ```bash
# Assumes to be running on ubuntu 20.04 # Install golang
# Ports required to be allocated internally: # https://go.dev/doc/install
# - 8888 (laplace server)
# Updating and installing go compiler # Build
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
go build . go build .
# Set configuration laplace file # Configure (run only once)
./laplace -setconfig ./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 ### Starting game when screen-share is triggered
This requires creating a bash script to trigger when the screenshare begins. This requires creating a bash script to trigger when the screenshare begins.
#### Ex: Start X-Plane 11 #### Ex: Start X-Plane 11
@@ -155,38 +152,66 @@ cd /path/.local/share/Steam/steamapps/common/X-Plane\ 11/
# Execute X-Plane 11 binary # Execute X-Plane 11 binary
./X-Plane-x86_64 ./X-Plane-x86_64
``` ```
#### Open config file
```bash
{ [//]: # (#### Open config file )
"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
### Starting server [//]: # (```bash)
```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> [//]: # ( "barrierhostname": "<barrier host name>",)
You may need to add certificate exceptions. In Chrome, you can type `thisisunsafe`.
[//]: # ( "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 // Game session url
//+ file.ID //+ file.ID
gameSession.Link = respIpv4orIPv6 + ":" + config.NATEscapeGameServerPort + "/?id=" + room.ID gameSession.Link = respIpv4orIPv6 + ":" + config.NATEscapeScreenSharePort + "/?id=" + room.ID
// Rate for the game session // Rate for the game session
gameSession.Rate = config.Rate gameSession.Rate = config.Rate
// Server specs to struct GameSession // Server specs to struct GameSession

424
main.go
View File

@@ -1,264 +1,264 @@
package main package main
import ( import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"github.com/Akilan1999/remotegameplay/config" "github.com/Akilan1999/remotegameplay/config"
"github.com/Akilan1999/remotegameplay/core" "github.com/Akilan1999/remotegameplay/core"
gameserver "github.com/Akilan1999/remotegameplay/server" gameserver "github.com/Akilan1999/remotegameplay/server"
"log" "log"
"math/rand" "math/rand"
"net/http" "net/http"
"os/exec" "os/exec"
"time" "time"
) )
func main() { func main() {
addr := flag.String("addr", "0.0.0.0", "Listen address") addr := flag.String("addr", "0.0.0.0", "Listen address")
//port := flag.String("port", "8888", "port for running the server") //port := flag.String("port", "8888", "port for running the server")
barrier := flag.Bool("barrier", false, "set external port barrier") barrier := flag.Bool("barrier", false, "set external port barrier")
tls := flag.Bool("tls", false, "Use TLS") tls := flag.Bool("tls", false, "Use TLS")
setconfig := flag.Bool("setconfig", false, "Generates a config file") setconfig := flag.Bool("setconfig", false, "Generates a config file")
certFile := flag.String("certFile", "files/server.crt", "TLS cert file") certFile := flag.String("certFile", "files/server.crt", "TLS cert file")
keyFile := flag.String("keyFile", "files/server.key", "TLS key file") keyFile := flag.String("keyFile", "files/server.key", "TLS key file")
headless := flag.Bool("headless", false, "Creating screenshare using headless mode") headless := flag.Bool("headless", false, "Creating screenshare using headless mode")
roomInfo := flag.Bool("roomInfo", false, "Getting room id of headless server") roomInfo := flag.Bool("roomInfo", false, "Getting room id of headless server")
killServer := flag.Bool("killServer", false, "Kills the laplace") killServer := flag.Bool("killServer", false, "Kills the laplace")
killChromium := flag.Bool("killChromium", false, "Kills all chromuim") killChromium := flag.Bool("killChromium", false, "Kills all chromuim")
BinaryToExecute := flag.String("BinaryToExecute", "", "Providing path (i.e Absolute path) of binary to execute") 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") GameServer := flag.Bool("GameServer", false, "Starts the game server by default")
Migrate := flag.Bool("Migrate", false, "Sets up the tables for the Sqlite database") 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") 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()) rand.Seed(time.Now().UnixNano())
server := core.GetHttp() server := core.GetHttp()
if *setconfig { if *setconfig {
err := config.SetDefaults() err := config.SetDefaults()
if err != nil { if err != nil {
return return
} }
return return
} }
Config, err := config.ConfigInit() Config, err := config.ConfigInit()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
// if barrier flag is provided // if barrier flag is provided
if *barrier { if *barrier {
natBarrier, err := core.EscapeNATBarrier() natBarrier, err := core.EscapeNATBarrier()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
Config.NATEscapeBarrierPort = natBarrier Config.NATEscapeBarrierPort = natBarrier
err = Config.WriteConfig() err = Config.WriteConfig()
if err != nil { if err != nil {
return return
} }
fmt.Println(Config.IPAddress + ":" + Config.NATEscapeBarrierPort) fmt.Println(Config.IPAddress + ":" + Config.NATEscapeBarrierPort)
return return
} }
// Print out room information // Print out room information
if *roomInfo { if *roomInfo {
room, err := core.ReadRoomsFile() room, err := core.ReadRoomsFile()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
PrettyPrint(room) PrettyPrint(room)
return return
} }
// kills laplace server // kills laplace server
if *killServer { if *killServer {
cmd := exec.Command("pkill", "remotegameplay") cmd := exec.Command("pkill", "remotegameplay")
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
fmt.Println(err) fmt.Println(err)
} }
return return
} }
// kills chromium server // kills chromium server
if *killChromium { if *killChromium {
cmd := exec.Command("pkill", "chromium") cmd := exec.Command("pkill", "chromium")
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
fmt.Println(err) fmt.Println(err)
} }
return return
} }
if *Migrate { if *Migrate {
// Connect to Sqlite // Connect to Sqlite
connect, err := gameserver.Connect() connect, err := gameserver.Connect()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
// Migrate table // Migrate table
session, err := gameserver.CreateTables(connect) session, err := gameserver.CreateTables(connect)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
session.Scan(gameserver.GameSession{}) session.Scan(gameserver.GameSession{})
return return
} }
// running implementation to escape NAT // running implementation to escape NAT
GameServerPort, ScreenSharePort, err := core.EscapeNAT(Config.InternalScreenSharePort, Config.InternalGameServerPort) GameServerPort, ScreenSharePort, err := core.EscapeNAT(Config.InternalScreenSharePort, Config.InternalGameServerPort)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
Config.IPAddress = "64.227.168.102" Config.IPAddress = "64.227.168.102"
Config.NATEscapeGameServerPort = GameServerPort Config.NATEscapeGameServerPort = GameServerPort
Config.NATEscapeScreenSharePort = ScreenSharePort Config.NATEscapeScreenSharePort = ScreenSharePort
Config.NATEscapeBarrierPort = "" Config.NATEscapeBarrierPort = ""
err = Config.WriteConfig() err = Config.WriteConfig()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
// If both server and screenshare have be triggered (first set the according flags to true) // If both server and screenshare have be triggered (first set the according flags to true)
if *BothServers { if *BothServers {
*headless = true *headless = true
*tls = true *tls = true
*GameServer = true *GameServer = true
} }
if *GameServer { if *GameServer {
go gameserver.Server(Config.InternalGameServerPort) go gameserver.Server(Config.InternalGameServerPort)
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
} }
if !*GameServer || *BothServers { if !*GameServer || *BothServers {
if *tls { if *tls {
log.Println("Listening on TLS:", *addr+":"+Config.InternalScreenSharePort) log.Println("Listening on TLS:", *addr+":"+Config.InternalScreenSharePort)
go http.ListenAndServeTLS(*addr+":"+Config.InternalScreenSharePort, *certFile, *keyFile, server) go http.ListenAndServeTLS(*addr+":"+Config.InternalScreenSharePort, *certFile, *keyFile, server)
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
} else { } else {
log.Println("Listening:", *addr+":"+Config.InternalScreenSharePort) log.Println("Listening:", *addr+":"+Config.InternalScreenSharePort)
go http.ListenAndServe(*addr+":"+Config.InternalScreenSharePort, server) go http.ListenAndServe(*addr+":"+Config.InternalScreenSharePort, server)
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
} }
} }
// If both server selected set the remote Gameserver to local now. // If both server selected set the remote Gameserver to local now.
if *BothServers { if *BothServers {
Config.BackendURL = "http://" + Config.IPAddress + ":" + Config.NATEscapeGameServerPort + "/" Config.BackendURL = "http://" + Config.IPAddress + ":" + Config.NATEscapeGameServerPort + "/"
err = Config.WriteConfig() err = Config.WriteConfig()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
} }
// Running in headless mode // Running in headless mode
if *headless { if *headless {
// Running starting a browser as a background process // Running starting a browser as a background process
go func() { go func() {
Config, err = config.ConfigInit() Config, err = config.ConfigInit()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
//// Returns the URl address type //// Returns the URl address type
//Addr := Ip4or6(Config.IPAddress) //Addr := Ip4or6(Config.IPAddress)
// //
//// If address is provided //// If address is provided
//if *addr != "" { //if *addr != "" {
// Addr = *addr // Addr = *addr
// // Add brackets if the ip address is ipv6 // // Add brackets if the ip address is ipv6
// Addr = Ip4or6(Addr) // Addr = Ip4or6(Addr)
//} //}
var TaskExecute string var TaskExecute string
if *BinaryToExecute != "" { if *BinaryToExecute != "" {
TaskExecute = *BinaryToExecute TaskExecute = *BinaryToExecute
} else { } else {
// Read binary from config file // Read binary from config file
TaskExecute = Config.ScriptToExecute TaskExecute = Config.ScriptToExecute
} }
// Starting screen share headless // 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") 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 { if err := cmd.Start(); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
// Makes program sleep for 2 seconds to allow chromium browser to open // Makes program sleep for 2 seconds to allow chromium browser to open
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
err = core.BroadcastServerToBackend() err = core.BroadcastServerToBackend()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} else { } else {
fmt.Println("success broadcasting to game server") fmt.Println("success broadcasting to game server")
} }
// Task to be executed // Task to be executed
err = RunTask(TaskExecute) err = RunTask(TaskExecute)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
}() }()
} }
for { for {
} }
// Start P2PRC server // Start P2PRC server
//_, err = abstractions.Start() //_, err = abstractions.Start()
//if err != nil { //if err != nil {
// return // return
//} //}
} }
// PrettyPrint print the contents of the obj ( // PrettyPrint print the contents of the obj (
// Reference: https://stackoverflow.com/questions/24512112/how-to-print-struct-variables-in-console // Reference: https://stackoverflow.com/questions/24512112/how-to-print-struct-variables-in-console
func PrettyPrint(data interface{}) { func PrettyPrint(data interface{}) {
var p []byte var p []byte
// var err := error // var err := error
p, err := json.MarshalIndent(data, "", "\t") p, err := json.MarshalIndent(data, "", "\t")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
fmt.Printf("%s \n", p) fmt.Printf("%s \n", p)
} }
// Ip4or6 Helper function to check if the IP address is IPV4 or // Ip4or6 Helper function to check if the IP address is IPV4 or
// IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6) // IPV6 (https://socketloop.com/tutorials/golang-check-if-ip-address-is-version-4-or-6)
func Ip4or6(s string) string { func Ip4or6(s string) string {
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
switch s[i] { switch s[i] {
case '.': case '.':
return s return s
case ':': case ':':
return "[" + s + "]" return "[" + s + "]"
} }
} }
return "[" + s + "]" return "[" + s + "]"
} }
func RunTask(task string) error { func RunTask(task string) error {
// Halts the process // Halts the process
cmd := exec.Command("sh", task) cmd := exec.Command("sh", task)
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
return err return err
} }
return nil return nil
} }

View File

@@ -194,7 +194,7 @@ func Server(port string) error {
func CheckIfGameSessionIsActiveOrRemove(gorm *gorm.DB) { func CheckIfGameSessionIsActiveOrRemove(gorm *gorm.DB) {
for { for {
time.Sleep(2 * time.Second) time.Sleep(10 * time.Second)
Gamesessions, err := DisplayGameSessions(gorm) Gamesessions, err := DisplayGameSessions(gorm)
if err != nil { if err != nil {
return return