support for x2x and barrier KVM
This commit is contained in:
28
README.md
28
README.md
@@ -24,15 +24,31 @@ https://github.com/Akilan1999/laplace/tree/keyboard_mouse
|
|||||||
|
|
||||||
|
|
||||||
### Installation required to share keyboard and mouse
|
### Installation required to share keyboard and mouse
|
||||||
We need to ensure that the client has SSH client installed.
|
Currently, you can either use [x2x](https://github.com/dottedmag/x2x) or [Barrier KVM]()
|
||||||
We use the popular open repository known as [x2x](https://github.com/dottedmag/x2x).
|
We need to ensure that the client has SSH client installed or Barrierc.
|
||||||
|
|
||||||
Note: x2x runs on top of SSH.
|
|
||||||
|
|
||||||
#### What is x2x?
|
#### What is x2x?
|
||||||
x2x allows the keyboard, mouse on one X display to be used to control another X
|
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.
|
display. It also shares X clipboards between the displays.
|
||||||
|
|
||||||
|
Note: x2x runs on top of SSH.
|
||||||
|
|
||||||
|
#### What is Barrier kvm?
|
||||||
|
|
||||||
|
Barrier is software that mimics the functionality of a KVM switch, which historically would allow you to use a single
|
||||||
|
keyboard and mouse to control multiple computers by physically turning a dial on the box to switch the machine you're
|
||||||
|
controlling at any given moment. Barrier does this in software, allowing you to tell it which machine to control by
|
||||||
|
moving your mouse to the edge of the screen, or by using a keypress to switch focus to a different system.
|
||||||
|
|
||||||
|
#### Barrier KVM build status and links to install
|
||||||
|
|Platform |Build Status|
|
||||||
|
| --:|:-- |
|
||||||
|
|Linux |[](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|
||||||
|
|Mac |[](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|
||||||
|
|Windows Debug |[](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|
||||||
|
|Windows Release|[](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|
||||||
|
|Snap |[](https://build.snapcraft.io/user/debauchee/barrier)|
|
||||||
|
|
||||||
|
|
||||||
### Build from source
|
### Build from source
|
||||||
|
|
||||||
@@ -51,6 +67,8 @@ apt install -y git
|
|||||||
apt install -y openssh-server
|
apt install -y openssh-server
|
||||||
## Installing x2x
|
## Installing x2x
|
||||||
apt install -y x2x
|
apt install -y x2x
|
||||||
|
## Installing barrier
|
||||||
|
apt install -y barrier
|
||||||
## Installing chromium
|
## 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
|
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
|
apt install -y ./chromium-browser-unstable_94.0.4585.0-1_amd64.deb
|
||||||
@@ -117,11 +135,13 @@ cd /path/.local/share/Steam/steamapps/common/X-Plane\ 11/
|
|||||||
```
|
```
|
||||||
#### Open config file
|
#### Open config file
|
||||||
```bash
|
```bash
|
||||||
|
|
||||||
{
|
{
|
||||||
"barrierhostname": "<barrier host name>",
|
"barrierhostname": "<barrier host name>",
|
||||||
"ipaddress": "0.0.0.0",
|
"ipaddress": "0.0.0.0",
|
||||||
"rooms": "<path to room.json file>",
|
"rooms": "<path to room.json file>",
|
||||||
"scripttoexecute": "<path to script to execute (In case the Xplane 11 script)>",
|
"scripttoexecute": "<path to script to execute (In case the Xplane 11 script)>",
|
||||||
|
"sshpassword": "<SSH password for x2x>",
|
||||||
"systemusername": "<system username>"
|
"systemusername": "<system username>"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,23 +8,23 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
defaultPath string
|
defaultPath string
|
||||||
defaults = map[string]interface{}{
|
defaults = map[string]interface{}{
|
||||||
"SystemUsername": "",
|
"SystemUsername": "",
|
||||||
"BarrierHostName": "",
|
"BarrierHostName": "",
|
||||||
}
|
}
|
||||||
configName = "config"
|
configName = "config"
|
||||||
configType = "json"
|
configType = "json"
|
||||||
configFile = "config.json"
|
configFile = "config.json"
|
||||||
configPaths []string
|
configPaths []string
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
SystemUsername string
|
SystemUsername string
|
||||||
BarrierHostName string
|
BarrierHostName string
|
||||||
Rooms string
|
Rooms string
|
||||||
IPAddress string
|
IPAddress string
|
||||||
ScriptToExecute string
|
ScriptToExecute string
|
||||||
SSHPassword string
|
SSHPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exists reports whether the named file or directory exists.
|
// Exists reports whether the named file or directory exists.
|
||||||
@@ -47,7 +47,7 @@ func SetDefaults() error {
|
|||||||
defaultPath = curDir + "/"
|
defaultPath = curDir + "/"
|
||||||
|
|
||||||
// Get system username
|
// Get system username
|
||||||
user ,err := user.Current()
|
user, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -59,8 +59,8 @@ func SetDefaults() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Setting default paths for the config file
|
//Setting default paths for the config file
|
||||||
defaults["SystemUsername"] = user.Username
|
defaults["SystemUsername"] = user.Username
|
||||||
defaults["BarrierHostName"] = name
|
defaults["BarrierHostName"] = name
|
||||||
defaults["Rooms"] = defaultPath + "room.json"
|
defaults["Rooms"] = defaultPath + "room.json"
|
||||||
defaults["IPAddress"] = "0.0.0.0"
|
defaults["IPAddress"] = "0.0.0.0"
|
||||||
defaults["ScriptToExecute"] = ""
|
defaults["ScriptToExecute"] = ""
|
||||||
@@ -88,7 +88,7 @@ func SetDefaults() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConfigInit()(*Config,error) {
|
func ConfigInit() (*Config, error) {
|
||||||
|
|
||||||
curDir := os.Getenv("REMOTEGAMING")
|
curDir := os.Getenv("REMOTEGAMING")
|
||||||
//Setting current directory to default path
|
//Setting current directory to default path
|
||||||
@@ -97,7 +97,7 @@ func ConfigInit()(*Config,error) {
|
|||||||
configPaths = append(configPaths, defaultPath)
|
configPaths = append(configPaths, defaultPath)
|
||||||
|
|
||||||
//Add all possible configurations paths
|
//Add all possible configurations paths
|
||||||
for _,v := range configPaths {
|
for _, v := range configPaths {
|
||||||
viper.AddConfigPath(v)
|
viper.AddConfigPath(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,23 +105,23 @@ func ConfigInit()(*Config,error) {
|
|||||||
if err := viper.ReadInConfig(); err != nil {
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
// If the error thrown is config file not found
|
// If the error thrown is config file not found
|
||||||
//Sets default configuration to viper
|
//Sets default configuration to viper
|
||||||
for k,v := range defaults {
|
for k, v := range defaults {
|
||||||
viper.SetDefault(k,v)
|
viper.SetDefault(k, v)
|
||||||
}
|
}
|
||||||
viper.SetConfigName(configName)
|
viper.SetConfigName(configName)
|
||||||
viper.SetConfigFile(configFile)
|
viper.SetConfigFile(configFile)
|
||||||
viper.SetConfigType(configType)
|
viper.SetConfigType(configType)
|
||||||
|
|
||||||
if err = viper.WriteConfig(); err != nil {
|
if err = viper.WriteConfig(); err != nil {
|
||||||
return nil,err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds configuration to the struct
|
// Adds configuration to the struct
|
||||||
var config Config
|
var config Config
|
||||||
if err := viper.Unmarshal(&config); err != nil {
|
if err := viper.Unmarshal(&config); err != nil {
|
||||||
return nil,err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &config,nil
|
return &config, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigInit(t *testing.T) {
|
func TestConfigInit(t *testing.T) {
|
||||||
_,err := ConfigInit()
|
_, err := ConfigInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -17,4 +16,4 @@ func TestSetDefaults(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,20 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"laplace/config"
|
"github.com/Akilan1999/remotegameplay/config"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Barrier It's preferred that the IP address used is a IPV6 address
|
// Barrier It's preferred that the IP address used is a IPV6 address
|
||||||
type Barrier struct {
|
type Barrier struct {
|
||||||
NodeName string
|
NodeName string
|
||||||
IPAddress string
|
IPAddress string
|
||||||
Mode string
|
Mode string
|
||||||
Process *exec.Cmd
|
Process *exec.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBarrierSession Command to run "barrier.barrierc --debug INFO -f 192.168.0.175"
|
// CreateBarrierSession Command to run "barrier.barrierc --debug INFO -f 192.168.0.175"
|
||||||
func (b *Barrier)CreateBarrierSession() error {
|
func (b *Barrier) CreateBarrierSession() error {
|
||||||
//Checks if barrier client exists
|
//Checks if barrier client exists
|
||||||
|
|
||||||
if err := DetectBarrier(); err != nil {
|
if err := DetectBarrier(); err != nil {
|
||||||
@@ -31,7 +31,7 @@ func (b *Barrier)CreateBarrierSession() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command("sudo","-u",configResp.SystemUsername,"barrierc","-f","--debug", "DEBUG" ,"--log", "/tmp/barrier.log",b.IPAddress)
|
cmd := exec.Command("sudo", "-u", configResp.SystemUsername, "barrierc", "-f", "--debug", "DEBUG", "--log", "/tmp/barrier.log", b.IPAddress)
|
||||||
|
|
||||||
// USE THE FOLLOWING TO DEBUG
|
// USE THE FOLLOWING TO DEBUG
|
||||||
//cmdReader, err := cmd.StdoutPipe()
|
//cmdReader, err := cmd.StdoutPipe()
|
||||||
@@ -62,18 +62,17 @@ func (b *Barrier)CreateBarrierSession() error {
|
|||||||
|
|
||||||
println(cmd.Path)
|
println(cmd.Path)
|
||||||
|
|
||||||
|
|
||||||
// Saves the state of the command in the struct
|
// Saves the state of the command in the struct
|
||||||
b.Process = cmd
|
b.Process = cmd
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBarrierSession Deletes barrier client session running
|
// DeleteBarrierSession Deletes barrier client session running
|
||||||
func (b *Barrier)DeleteBarrierSession() error {
|
func (b *Barrier) DeleteBarrierSession() error {
|
||||||
// Halts the process
|
// Halts the process
|
||||||
cmd := exec.Command("pkill" ,"barrierc")
|
cmd := exec.Command("pkill", "barrierc")
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -86,4 +85,4 @@ func DetectBarrier() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,497 +1,497 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
left = [...]string{
|
left = [...]string{
|
||||||
"admiring",
|
"admiring",
|
||||||
"adoring",
|
"adoring",
|
||||||
"affectionate",
|
"affectionate",
|
||||||
"agitated",
|
"agitated",
|
||||||
"amazing",
|
"amazing",
|
||||||
"angry",
|
"angry",
|
||||||
"awesome",
|
"awesome",
|
||||||
"beautiful",
|
"beautiful",
|
||||||
"blissful",
|
"blissful",
|
||||||
"bold",
|
"bold",
|
||||||
"boring",
|
"boring",
|
||||||
"brave",
|
"brave",
|
||||||
"busy",
|
"busy",
|
||||||
"charming",
|
"charming",
|
||||||
"clever",
|
"clever",
|
||||||
"cool",
|
"cool",
|
||||||
"compassionate",
|
"compassionate",
|
||||||
"competent",
|
"competent",
|
||||||
"condescending",
|
"condescending",
|
||||||
"confident",
|
"confident",
|
||||||
"cranky",
|
"cranky",
|
||||||
"crazy",
|
"crazy",
|
||||||
"dazzling",
|
"dazzling",
|
||||||
"determined",
|
"determined",
|
||||||
"distracted",
|
"distracted",
|
||||||
"dreamy",
|
"dreamy",
|
||||||
"eager",
|
"eager",
|
||||||
"ecstatic",
|
"ecstatic",
|
||||||
"elastic",
|
"elastic",
|
||||||
"elated",
|
"elated",
|
||||||
"elegant",
|
"elegant",
|
||||||
"eloquent",
|
"eloquent",
|
||||||
"epic",
|
"epic",
|
||||||
"exciting",
|
"exciting",
|
||||||
"fervent",
|
"fervent",
|
||||||
"festive",
|
"festive",
|
||||||
"flamboyant",
|
"flamboyant",
|
||||||
"focused",
|
"focused",
|
||||||
"friendly",
|
"friendly",
|
||||||
"frosty",
|
"frosty",
|
||||||
"funny",
|
"funny",
|
||||||
"gallant",
|
"gallant",
|
||||||
"gifted",
|
"gifted",
|
||||||
"goofy",
|
"goofy",
|
||||||
"gracious",
|
"gracious",
|
||||||
"great",
|
"great",
|
||||||
"happy",
|
"happy",
|
||||||
"hardcore",
|
"hardcore",
|
||||||
"heuristic",
|
"heuristic",
|
||||||
"hopeful",
|
"hopeful",
|
||||||
"hungry",
|
"hungry",
|
||||||
"infallible",
|
"infallible",
|
||||||
"inspiring",
|
"inspiring",
|
||||||
"interesting",
|
"interesting",
|
||||||
"intelligent",
|
"intelligent",
|
||||||
"jolly",
|
"jolly",
|
||||||
"jovial",
|
"jovial",
|
||||||
"keen",
|
"keen",
|
||||||
"kind",
|
"kind",
|
||||||
"laughing",
|
"laughing",
|
||||||
"loving",
|
"loving",
|
||||||
"lucid",
|
"lucid",
|
||||||
"magical",
|
"magical",
|
||||||
"mystifying",
|
"mystifying",
|
||||||
"modest",
|
"modest",
|
||||||
"musing",
|
"musing",
|
||||||
"naughty",
|
"naughty",
|
||||||
"nervous",
|
"nervous",
|
||||||
"nice",
|
"nice",
|
||||||
"nifty",
|
"nifty",
|
||||||
"nostalgic",
|
"nostalgic",
|
||||||
"objective",
|
"objective",
|
||||||
"optimistic",
|
"optimistic",
|
||||||
"peaceful",
|
"peaceful",
|
||||||
"pedantic",
|
"pedantic",
|
||||||
"pensive",
|
"pensive",
|
||||||
"practical",
|
"practical",
|
||||||
"priceless",
|
"priceless",
|
||||||
"quirky",
|
"quirky",
|
||||||
"quizzical",
|
"quizzical",
|
||||||
"recursing",
|
"recursing",
|
||||||
"relaxed",
|
"relaxed",
|
||||||
"reverent",
|
"reverent",
|
||||||
"romantic",
|
"romantic",
|
||||||
"sad",
|
"sad",
|
||||||
"serene",
|
"serene",
|
||||||
"sharp",
|
"sharp",
|
||||||
"silly",
|
"silly",
|
||||||
"sleepy",
|
"sleepy",
|
||||||
"stoic",
|
"stoic",
|
||||||
"strange",
|
"strange",
|
||||||
"stupefied",
|
"stupefied",
|
||||||
"suspicious",
|
"suspicious",
|
||||||
"sweet",
|
"sweet",
|
||||||
"tender",
|
"tender",
|
||||||
"thirsty",
|
"thirsty",
|
||||||
"trusting",
|
"trusting",
|
||||||
"unruffled",
|
"unruffled",
|
||||||
"upbeat",
|
"upbeat",
|
||||||
"vibrant",
|
"vibrant",
|
||||||
"vigilant",
|
"vigilant",
|
||||||
"vigorous",
|
"vigorous",
|
||||||
"wizardly",
|
"wizardly",
|
||||||
"wonderful",
|
"wonderful",
|
||||||
"xenodochial",
|
"xenodochial",
|
||||||
"youthful",
|
"youthful",
|
||||||
"zealous",
|
"zealous",
|
||||||
"zen",
|
"zen",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Docker, starting from 0.7.x, generates names from notable scientists and hackers.
|
// Docker, starting from 0.7.x, generates names from notable scientists and hackers.
|
||||||
// Please, for any amazing man that you add to the list, consider adding an equally amazing woman to it, and vice versa.
|
// Please, for any amazing man that you add to the list, consider adding an equally amazing woman to it, and vice versa.
|
||||||
right = [...]string{
|
right = [...]string{
|
||||||
"aardvark",
|
"aardvark",
|
||||||
"abyssinian",
|
"abyssinian",
|
||||||
"affenpinscher",
|
"affenpinscher",
|
||||||
"akbash",
|
"akbash",
|
||||||
"akita",
|
"akita",
|
||||||
"albatross",
|
"albatross",
|
||||||
"alligator",
|
"alligator",
|
||||||
"alpaca",
|
"alpaca",
|
||||||
"angelfish",
|
"angelfish",
|
||||||
"ant",
|
"ant",
|
||||||
"anteater",
|
"anteater",
|
||||||
"antelope",
|
"antelope",
|
||||||
"ape",
|
"ape",
|
||||||
"armadillo",
|
"armadillo",
|
||||||
"ass",
|
"ass",
|
||||||
"avocet",
|
"avocet",
|
||||||
"axolotl",
|
"axolotl",
|
||||||
"baboon",
|
"baboon",
|
||||||
"badger",
|
"badger",
|
||||||
"balinese",
|
"balinese",
|
||||||
"bandicoot",
|
"bandicoot",
|
||||||
"barb",
|
"barb",
|
||||||
"barnacle",
|
"barnacle",
|
||||||
"barracuda",
|
"barracuda",
|
||||||
"bat",
|
"bat",
|
||||||
"beagle",
|
"beagle",
|
||||||
"bear",
|
"bear",
|
||||||
"beaver",
|
"beaver",
|
||||||
"bee",
|
"bee",
|
||||||
"beetle",
|
"beetle",
|
||||||
"binturong",
|
"binturong",
|
||||||
"bird",
|
"bird",
|
||||||
"birman",
|
"birman",
|
||||||
"bison",
|
"bison",
|
||||||
"bloodhound",
|
"bloodhound",
|
||||||
"boar",
|
"boar",
|
||||||
"bobcat",
|
"bobcat",
|
||||||
"bombay",
|
"bombay",
|
||||||
"bongo",
|
"bongo",
|
||||||
"bonobo",
|
"bonobo",
|
||||||
"booby",
|
"booby",
|
||||||
"budgerigar",
|
"budgerigar",
|
||||||
"buffalo",
|
"buffalo",
|
||||||
"bulldog",
|
"bulldog",
|
||||||
"bullfrog",
|
"bullfrog",
|
||||||
"burmese",
|
"burmese",
|
||||||
"butterfly",
|
"butterfly",
|
||||||
"caiman",
|
"caiman",
|
||||||
"camel",
|
"camel",
|
||||||
"capybara",
|
"capybara",
|
||||||
"caracal",
|
"caracal",
|
||||||
"caribou",
|
"caribou",
|
||||||
"cassowary",
|
"cassowary",
|
||||||
"cat",
|
"cat",
|
||||||
"caterpillar",
|
"caterpillar",
|
||||||
"catfish",
|
"catfish",
|
||||||
"cattle",
|
"cattle",
|
||||||
"centipede",
|
"centipede",
|
||||||
"chameleon",
|
"chameleon",
|
||||||
"chamois",
|
"chamois",
|
||||||
"cheetah",
|
"cheetah",
|
||||||
"chicken",
|
"chicken",
|
||||||
"chihuahua",
|
"chihuahua",
|
||||||
"chimpanzee",
|
"chimpanzee",
|
||||||
"chinchilla",
|
"chinchilla",
|
||||||
"chinook",
|
"chinook",
|
||||||
"chipmunk",
|
"chipmunk",
|
||||||
"chough",
|
"chough",
|
||||||
"cichlid",
|
"cichlid",
|
||||||
"clam",
|
"clam",
|
||||||
"coati",
|
"coati",
|
||||||
"cobra",
|
"cobra",
|
||||||
"cockroach",
|
"cockroach",
|
||||||
"cod",
|
"cod",
|
||||||
"collie",
|
"collie",
|
||||||
"coral",
|
"coral",
|
||||||
"cormorant",
|
"cormorant",
|
||||||
"cougar",
|
"cougar",
|
||||||
"cow",
|
"cow",
|
||||||
"coyote",
|
"coyote",
|
||||||
"crab",
|
"crab",
|
||||||
"crane",
|
"crane",
|
||||||
"crocodile",
|
"crocodile",
|
||||||
"crow",
|
"crow",
|
||||||
"curlew",
|
"curlew",
|
||||||
"cuscus",
|
"cuscus",
|
||||||
"cuttlefish",
|
"cuttlefish",
|
||||||
"dachshund",
|
"dachshund",
|
||||||
"dalmatian",
|
"dalmatian",
|
||||||
"deer",
|
"deer",
|
||||||
"dhole",
|
"dhole",
|
||||||
"dingo",
|
"dingo",
|
||||||
"dinosaur",
|
"dinosaur",
|
||||||
"discus",
|
"discus",
|
||||||
"dodo",
|
"dodo",
|
||||||
"dog",
|
"dog",
|
||||||
"dogfish",
|
"dogfish",
|
||||||
"dolphin",
|
"dolphin",
|
||||||
"donkey",
|
"donkey",
|
||||||
"dormouse",
|
"dormouse",
|
||||||
"dotterel",
|
"dotterel",
|
||||||
"dove",
|
"dove",
|
||||||
"dragonfly",
|
"dragonfly",
|
||||||
"drever",
|
"drever",
|
||||||
"duck",
|
"duck",
|
||||||
"dugong",
|
"dugong",
|
||||||
"dunker",
|
"dunker",
|
||||||
"dunlin",
|
"dunlin",
|
||||||
"eagle",
|
"eagle",
|
||||||
"earwig",
|
"earwig",
|
||||||
"echidna",
|
"echidna",
|
||||||
"eel",
|
"eel",
|
||||||
"eland",
|
"eland",
|
||||||
"elephant",
|
"elephant",
|
||||||
"elk",
|
"elk",
|
||||||
"emu",
|
"emu",
|
||||||
"falcon",
|
"falcon",
|
||||||
"ferret",
|
"ferret",
|
||||||
"finch",
|
"finch",
|
||||||
"fish",
|
"fish",
|
||||||
"flamingo",
|
"flamingo",
|
||||||
"flounder",
|
"flounder",
|
||||||
"fly",
|
"fly",
|
||||||
"fossa",
|
"fossa",
|
||||||
"fox",
|
"fox",
|
||||||
"frigatebird",
|
"frigatebird",
|
||||||
"frog",
|
"frog",
|
||||||
"galago",
|
"galago",
|
||||||
"gar",
|
"gar",
|
||||||
"gaur",
|
"gaur",
|
||||||
"gazelle",
|
"gazelle",
|
||||||
"gecko",
|
"gecko",
|
||||||
"gerbil",
|
"gerbil",
|
||||||
"gharial",
|
"gharial",
|
||||||
"gibbon",
|
"gibbon",
|
||||||
"giraffe",
|
"giraffe",
|
||||||
"gnat",
|
"gnat",
|
||||||
"gnu",
|
"gnu",
|
||||||
"goat",
|
"goat",
|
||||||
"goldfinch",
|
"goldfinch",
|
||||||
"goldfish",
|
"goldfish",
|
||||||
"goose",
|
"goose",
|
||||||
"gopher",
|
"gopher",
|
||||||
"gorilla",
|
"gorilla",
|
||||||
"goshawk",
|
"goshawk",
|
||||||
"grasshopper",
|
"grasshopper",
|
||||||
"greyhound",
|
"greyhound",
|
||||||
"grouse",
|
"grouse",
|
||||||
"guanaco",
|
"guanaco",
|
||||||
"gull",
|
"gull",
|
||||||
"guppy",
|
"guppy",
|
||||||
"hamster",
|
"hamster",
|
||||||
"hare",
|
"hare",
|
||||||
"harrier",
|
"harrier",
|
||||||
"havanese",
|
"havanese",
|
||||||
"hawk",
|
"hawk",
|
||||||
"hedgehog",
|
"hedgehog",
|
||||||
"heron",
|
"heron",
|
||||||
"herring",
|
"herring",
|
||||||
"himalayan",
|
"himalayan",
|
||||||
"hippopotamus",
|
"hippopotamus",
|
||||||
"hornet",
|
"hornet",
|
||||||
"horse",
|
"horse",
|
||||||
"human",
|
"human",
|
||||||
"hummingbird",
|
"hummingbird",
|
||||||
"hyena",
|
"hyena",
|
||||||
"ibis",
|
"ibis",
|
||||||
"iguana",
|
"iguana",
|
||||||
"impala",
|
"impala",
|
||||||
"indri",
|
"indri",
|
||||||
"insect",
|
"insect",
|
||||||
"jackal",
|
"jackal",
|
||||||
"jaguar",
|
"jaguar",
|
||||||
"javanese",
|
"javanese",
|
||||||
"jay",
|
"jay",
|
||||||
"jellyfish",
|
"jellyfish",
|
||||||
"kakapo",
|
"kakapo",
|
||||||
"kangaroo",
|
"kangaroo",
|
||||||
"kingfisher",
|
"kingfisher",
|
||||||
"kiwi",
|
"kiwi",
|
||||||
"koala",
|
"koala",
|
||||||
"kouprey",
|
"kouprey",
|
||||||
"kudu",
|
"kudu",
|
||||||
"labradoodle",
|
"labradoodle",
|
||||||
"ladybird",
|
"ladybird",
|
||||||
"lapwing",
|
"lapwing",
|
||||||
"lark",
|
"lark",
|
||||||
"lemming",
|
"lemming",
|
||||||
"lemur",
|
"lemur",
|
||||||
"leopard",
|
"leopard",
|
||||||
"liger",
|
"liger",
|
||||||
"lion",
|
"lion",
|
||||||
"lionfish",
|
"lionfish",
|
||||||
"lizard",
|
"lizard",
|
||||||
"llama",
|
"llama",
|
||||||
"lobster",
|
"lobster",
|
||||||
"locust",
|
"locust",
|
||||||
"loris",
|
"loris",
|
||||||
"louse",
|
"louse",
|
||||||
"lynx",
|
"lynx",
|
||||||
"lyrebird",
|
"lyrebird",
|
||||||
"macaw",
|
"macaw",
|
||||||
"magpie",
|
"magpie",
|
||||||
"mallard",
|
"mallard",
|
||||||
"maltese",
|
"maltese",
|
||||||
"manatee",
|
"manatee",
|
||||||
"mandrill",
|
"mandrill",
|
||||||
"markhor",
|
"markhor",
|
||||||
"marten",
|
"marten",
|
||||||
"mastiff",
|
"mastiff",
|
||||||
"mayfly",
|
"mayfly",
|
||||||
"meerkat",
|
"meerkat",
|
||||||
"millipede",
|
"millipede",
|
||||||
"mink",
|
"mink",
|
||||||
"mole",
|
"mole",
|
||||||
"molly",
|
"molly",
|
||||||
"mongoose",
|
"mongoose",
|
||||||
"mongrel",
|
"mongrel",
|
||||||
"monkey",
|
"monkey",
|
||||||
"moorhen",
|
"moorhen",
|
||||||
"moose",
|
"moose",
|
||||||
"mosquito",
|
"mosquito",
|
||||||
"moth",
|
"moth",
|
||||||
"mouse",
|
"mouse",
|
||||||
"mule",
|
"mule",
|
||||||
"narwhal",
|
"narwhal",
|
||||||
"neanderthal",
|
"neanderthal",
|
||||||
"newfoundland",
|
"newfoundland",
|
||||||
"newt",
|
"newt",
|
||||||
"nightingale",
|
"nightingale",
|
||||||
"numbat",
|
"numbat",
|
||||||
"ocelot",
|
"ocelot",
|
||||||
"octopus",
|
"octopus",
|
||||||
"okapi",
|
"okapi",
|
||||||
"olm",
|
"olm",
|
||||||
"opossum",
|
"opossum",
|
||||||
"orangutan",
|
"orangutan",
|
||||||
"oryx",
|
"oryx",
|
||||||
"ostrich",
|
"ostrich",
|
||||||
"otter",
|
"otter",
|
||||||
"owl",
|
"owl",
|
||||||
"ox",
|
"ox",
|
||||||
"oyster",
|
"oyster",
|
||||||
"pademelon",
|
"pademelon",
|
||||||
"panther",
|
"panther",
|
||||||
"parrot",
|
"parrot",
|
||||||
"partridge",
|
"partridge",
|
||||||
"peacock",
|
"peacock",
|
||||||
"peafowl",
|
"peafowl",
|
||||||
"pekingese",
|
"pekingese",
|
||||||
"pelican",
|
"pelican",
|
||||||
"penguin",
|
"penguin",
|
||||||
"persian",
|
"persian",
|
||||||
"pheasant",
|
"pheasant",
|
||||||
"pig",
|
"pig",
|
||||||
"pigeon",
|
"pigeon",
|
||||||
"pika",
|
"pika",
|
||||||
"pike",
|
"pike",
|
||||||
"piranha",
|
"piranha",
|
||||||
"platypus",
|
"platypus",
|
||||||
"pointer",
|
"pointer",
|
||||||
"pony",
|
"pony",
|
||||||
"poodle",
|
"poodle",
|
||||||
"porcupine",
|
"porcupine",
|
||||||
"porpoise",
|
"porpoise",
|
||||||
"possum",
|
"possum",
|
||||||
"prawn",
|
"prawn",
|
||||||
"puffin",
|
"puffin",
|
||||||
"pug",
|
"pug",
|
||||||
"puma",
|
"puma",
|
||||||
"quail",
|
"quail",
|
||||||
"quelea",
|
"quelea",
|
||||||
"quetzal",
|
"quetzal",
|
||||||
"quokka",
|
"quokka",
|
||||||
"quoll",
|
"quoll",
|
||||||
"rabbit",
|
"rabbit",
|
||||||
"raccoon",
|
"raccoon",
|
||||||
"ragdoll",
|
"ragdoll",
|
||||||
"rail",
|
"rail",
|
||||||
"ram",
|
"ram",
|
||||||
"rat",
|
"rat",
|
||||||
"rattlesnake",
|
"rattlesnake",
|
||||||
"raven",
|
"raven",
|
||||||
"reindeer",
|
"reindeer",
|
||||||
"rhinoceros",
|
"rhinoceros",
|
||||||
"robin",
|
"robin",
|
||||||
"rook",
|
"rook",
|
||||||
"rottweiler",
|
"rottweiler",
|
||||||
"ruff",
|
"ruff",
|
||||||
"salamander",
|
"salamander",
|
||||||
"salmon",
|
"salmon",
|
||||||
"sandpiper",
|
"sandpiper",
|
||||||
"saola",
|
"saola",
|
||||||
"sardine",
|
"sardine",
|
||||||
"scorpion",
|
"scorpion",
|
||||||
"seahorse",
|
"seahorse",
|
||||||
"seal",
|
"seal",
|
||||||
"serval",
|
"serval",
|
||||||
"shark",
|
"shark",
|
||||||
"sheep",
|
"sheep",
|
||||||
"shrew",
|
"shrew",
|
||||||
"shrimp",
|
"shrimp",
|
||||||
"siamese",
|
"siamese",
|
||||||
"siberian",
|
"siberian",
|
||||||
"skunk",
|
"skunk",
|
||||||
"sloth",
|
"sloth",
|
||||||
"snail",
|
"snail",
|
||||||
"snake",
|
"snake",
|
||||||
"snowshoe",
|
"snowshoe",
|
||||||
"somali",
|
"somali",
|
||||||
"sparrow",
|
"sparrow",
|
||||||
"spider",
|
"spider",
|
||||||
"sponge",
|
"sponge",
|
||||||
"squid",
|
"squid",
|
||||||
"squirrel",
|
"squirrel",
|
||||||
"starfish",
|
"starfish",
|
||||||
"starling",
|
"starling",
|
||||||
"stingray",
|
"stingray",
|
||||||
"stinkbug",
|
"stinkbug",
|
||||||
"stoat",
|
"stoat",
|
||||||
"stork",
|
"stork",
|
||||||
"swallow",
|
"swallow",
|
||||||
"swan",
|
"swan",
|
||||||
"tang",
|
"tang",
|
||||||
"tapir",
|
"tapir",
|
||||||
"tarsier",
|
"tarsier",
|
||||||
"termite",
|
"termite",
|
||||||
"tetra",
|
"tetra",
|
||||||
"tiffany",
|
"tiffany",
|
||||||
"tiger",
|
"tiger",
|
||||||
"toad",
|
"toad",
|
||||||
"tortoise",
|
"tortoise",
|
||||||
"toucan",
|
"toucan",
|
||||||
"tropicbird",
|
"tropicbird",
|
||||||
"trout",
|
"trout",
|
||||||
"tuatara",
|
"tuatara",
|
||||||
"turkey",
|
"turkey",
|
||||||
"turtle",
|
"turtle",
|
||||||
"uakari",
|
"uakari",
|
||||||
"uguisu",
|
"uguisu",
|
||||||
"umbrellabird",
|
"umbrellabird",
|
||||||
"viper",
|
"viper",
|
||||||
"vulture",
|
"vulture",
|
||||||
"wallaby",
|
"wallaby",
|
||||||
"walrus",
|
"walrus",
|
||||||
"warthog",
|
"warthog",
|
||||||
"wasp",
|
"wasp",
|
||||||
"weasel",
|
"weasel",
|
||||||
"whale",
|
"whale",
|
||||||
"whippet",
|
"whippet",
|
||||||
"wildebeest",
|
"wildebeest",
|
||||||
"wolf",
|
"wolf",
|
||||||
"wolverine",
|
"wolverine",
|
||||||
"wombat",
|
"wombat",
|
||||||
"woodcock",
|
"woodcock",
|
||||||
"woodlouse",
|
"woodlouse",
|
||||||
"woodpecker",
|
"woodpecker",
|
||||||
"worm",
|
"worm",
|
||||||
"wrasse",
|
"wrasse",
|
||||||
"wren",
|
"wren",
|
||||||
"yak",
|
"yak",
|
||||||
"zebra",
|
"zebra",
|
||||||
"zebu",
|
"zebu",
|
||||||
"zonkey",
|
"zonkey",
|
||||||
"zorse",
|
"zorse",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetRandomName(retry int) string {
|
func GetRandomName(retry int) string {
|
||||||
name := fmt.Sprintf("%s_%s_%s", left[rand.Intn(len(left))], left[rand.Intn(len(left))], right[rand.Intn(len(right))])
|
name := fmt.Sprintf("%s_%s_%s", left[rand.Intn(len(left))], left[rand.Intn(len(left))], right[rand.Intn(len(right))])
|
||||||
if retry > 0 {
|
if retry > 0 {
|
||||||
name = fmt.Sprintf("%s_%d", name, rand.Intn(10))
|
name = fmt.Sprintf("%s_%d", name, rand.Intn(10))
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|||||||
175
core/room.go
175
core/room.go
@@ -1,140 +1,139 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/Akilan1999/remotegameplay/config"
|
||||||
"io/ioutil"
|
"github.com/gorilla/websocket"
|
||||||
"laplace/config"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Room struct {
|
type Room struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Sessions map[string]*StreamSession
|
Sessions map[string]*StreamSession
|
||||||
CallerConn *websocket.Conn
|
CallerConn *websocket.Conn
|
||||||
BarrierSession *Barrier
|
BarrierSession *Barrier
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamSession struct {
|
type StreamSession struct {
|
||||||
ID string
|
ID string
|
||||||
Offer string
|
Offer string
|
||||||
Answer string
|
Answer string
|
||||||
CallerIceCandidates []string
|
CallerIceCandidates []string
|
||||||
CalleeIceCandidates []string
|
CalleeIceCandidates []string
|
||||||
CallerConn *websocket.Conn
|
CallerConn *websocket.Conn
|
||||||
CalleeConn *websocket.Conn
|
CalleeConn *websocket.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
var roomMap = make(map[string]*Room)
|
var roomMap = make(map[string]*Room)
|
||||||
|
|
||||||
func GetRoom(id string) *Room {
|
func GetRoom(id string) *Room {
|
||||||
return roomMap[id]
|
return roomMap[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRoom(callerConn *websocket.Conn) *Room {
|
func NewRoom(callerConn *websocket.Conn) *Room {
|
||||||
room := Room{
|
room := Room{
|
||||||
ID: newRoomID(),
|
ID: newRoomID(),
|
||||||
Sessions: make(map[string]*StreamSession),
|
Sessions: make(map[string]*StreamSession),
|
||||||
CallerConn: callerConn,
|
CallerConn: callerConn,
|
||||||
}
|
}
|
||||||
roomMap[room.ID] = &room
|
roomMap[room.ID] = &room
|
||||||
|
|
||||||
err := room.writeToFile()
|
err := room.writeToFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err)
|
println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &room
|
return &room
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRoomID() string {
|
func newRoomID() string {
|
||||||
id := GetRandomName(0)
|
id := GetRandomName(0)
|
||||||
for GetRoom(id) != nil {
|
for GetRoom(id) != nil {
|
||||||
id = GetRandomName(0)
|
id = GetRandomName(0)
|
||||||
}
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveRoom(id string) {
|
func RemoveRoom(id string) {
|
||||||
roomMap[id] = nil
|
roomMap[id] = nil
|
||||||
// Writes nil to the file
|
// Writes nil to the file
|
||||||
roomMap[id].writeToFile()
|
roomMap[id].writeToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (room *Room) GetSession(id string) *StreamSession {
|
func (room *Room) GetSession(id string) *StreamSession {
|
||||||
return room.Sessions[id]
|
return room.Sessions[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (room *Room) NewSession(calleeConn *websocket.Conn) *StreamSession {
|
func (room *Room) NewSession(calleeConn *websocket.Conn) *StreamSession {
|
||||||
session := StreamSession{
|
session := StreamSession{
|
||||||
ID: room.newSessionID(),
|
ID: room.newSessionID(),
|
||||||
CallerIceCandidates: []string{},
|
CallerIceCandidates: []string{},
|
||||||
CalleeIceCandidates: []string{},
|
CalleeIceCandidates: []string{},
|
||||||
CallerConn: room.CallerConn,
|
CallerConn: room.CallerConn,
|
||||||
CalleeConn: calleeConn,
|
CalleeConn: calleeConn,
|
||||||
}
|
}
|
||||||
|
|
||||||
room.Sessions[session.ID] = &session
|
room.Sessions[session.ID] = &session
|
||||||
|
|
||||||
return &session
|
return &session
|
||||||
}
|
}
|
||||||
|
|
||||||
func (room *Room) newSessionID() string {
|
func (room *Room) newSessionID() string {
|
||||||
id := fmt.Sprintf("%s$%s", room.ID, GetRandomName(0))
|
id := fmt.Sprintf("%s$%s", room.ID, GetRandomName(0))
|
||||||
for GetRoom(id) != nil {
|
for GetRoom(id) != nil {
|
||||||
id = fmt.Sprintf("%s$%s", room.ID, GetRandomName(0))
|
id = fmt.Sprintf("%s$%s", room.ID, GetRandomName(0))
|
||||||
}
|
}
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to rooms.json file
|
// Write to rooms.json file
|
||||||
func (room *Room)writeToFile() error {
|
func (room *Room) writeToFile() error {
|
||||||
file, err := json.MarshalIndent(room, "", " ")
|
file, err := json.MarshalIndent(room, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Path from config
|
// Get Path from config
|
||||||
config, err := config.ConfigInit()
|
config, err := config.ConfigInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write room struct to json file
|
// Write room struct to json file
|
||||||
err = ioutil.WriteFile(config.Rooms, file, 0644)
|
err = ioutil.WriteFile(config.Rooms, file, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadRoomsFile Reads rooms file and return struct room id
|
// ReadRoomsFile Reads rooms file and return struct room id
|
||||||
func ReadRoomsFile() (*Room, error) {
|
func ReadRoomsFile() (*Room, error) {
|
||||||
config, err := config.ConfigInit()
|
config, err := config.ConfigInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil,err
|
return nil, err
|
||||||
}
|
}
|
||||||
jsonFile, err := os.Open(config.Rooms)
|
jsonFile, err := os.Open(config.Rooms)
|
||||||
// if we os.Open returns an error then handle it
|
// if we os.Open returns an error then handle it
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil,err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defer the closing of our jsonFile so that we can parse it later on
|
||||||
|
defer jsonFile.Close()
|
||||||
|
|
||||||
// defer the closing of our jsonFile so that we can parse it later on
|
// read our opened xmlFile as a byte array.
|
||||||
defer jsonFile.Close()
|
byteValue, _ := ioutil.ReadAll(jsonFile)
|
||||||
|
|
||||||
// read our opened xmlFile as a byte array.
|
// we initialize our Users array
|
||||||
byteValue, _ := ioutil.ReadAll(jsonFile)
|
var rooms *Room
|
||||||
|
|
||||||
// we initialize our Users array
|
// we unmarshal our byteArray which contains our
|
||||||
var rooms *Room
|
// jsonFile's content into 'users' which we defined above
|
||||||
|
json.Unmarshal(byteValue, &rooms)
|
||||||
|
|
||||||
// we unmarshal our byteArray which contains our
|
return rooms, nil
|
||||||
// jsonFile's content into 'users' which we defined above
|
|
||||||
json.Unmarshal(byteValue, &rooms)
|
|
||||||
|
|
||||||
return rooms, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
336
core/signal.go
336
core/signal.go
@@ -1,210 +1,210 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/Akilan1999/remotegameplay/config"
|
||||||
"laplace/config"
|
"github.com/gorilla/websocket"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WSMessage struct {
|
type WSMessage struct {
|
||||||
SessionID string
|
SessionID string
|
||||||
Type string
|
Type string
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
var upgrader = websocket.Upgrader{
|
var upgrader = websocket.Upgrader{
|
||||||
ReadBufferSize: 1024,
|
ReadBufferSize: 1024,
|
||||||
WriteBufferSize: 1024,
|
WriteBufferSize: 1024,
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendHeartBeatWS(ticker *time.Ticker, conn *websocket.Conn, quit chan struct{}) {
|
func sendHeartBeatWS(ticker *time.Ticker, conn *websocket.Conn, quit chan struct{}) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <- ticker.C:
|
case <-ticker.C:
|
||||||
_ = conn.WriteJSON(WSMessage{
|
_ = conn.WriteJSON(WSMessage{
|
||||||
Type: "beat",
|
Type: "beat",
|
||||||
})
|
})
|
||||||
case <- quit:
|
case <-quit:
|
||||||
log.Println("heartbeat stopped")
|
log.Println("heartbeat stopped")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetHttp() *http.ServeMux {
|
func GetHttp() *http.ServeMux {
|
||||||
server := http.NewServeMux()
|
server := http.NewServeMux()
|
||||||
|
|
||||||
server.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("files/static"))))
|
server.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("files/static"))))
|
||||||
|
|
||||||
server.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
server.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.ServeFile(w, r, "files/main.html")
|
http.ServeFile(w, r, "files/main.html")
|
||||||
})
|
})
|
||||||
|
|
||||||
//Get hostname of the current machine
|
//Get hostname of the current machine
|
||||||
server.HandleFunc("/hostname", func(w http.ResponseWriter, r *http.Request) {
|
server.HandleFunc("/hostname", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Read hostname from config file
|
// Read hostname from config file
|
||||||
configResp, err := config.ConfigInit()
|
configResp, err := config.ConfigInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
print(err)
|
print(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, configResp.SystemUsername)
|
fmt.Fprintf(w, configResp.SystemUsername)
|
||||||
})
|
})
|
||||||
|
|
||||||
//Get SSH password of the current machine
|
//Get SSH password of the current machine
|
||||||
server.HandleFunc("/SSHPassword", func(w http.ResponseWriter, r *http.Request) {
|
server.HandleFunc("/SSHPassword", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Read hostname from config file
|
// Read hostname from config file
|
||||||
configResp, err := config.ConfigInit()
|
configResp, err := config.ConfigInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
print(err)
|
print(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, configResp.SSHPassword)
|
fmt.Fprintf(w, configResp.SSHPassword)
|
||||||
})
|
})
|
||||||
|
|
||||||
server.HandleFunc("/ws_serve", func(writer http.ResponseWriter, request *http.Request) {
|
server.HandleFunc("/ws_serve", func(writer http.ResponseWriter, request *http.Request) {
|
||||||
conn, _ := upgrader.Upgrade(writer, request, nil)
|
conn, _ := upgrader.Upgrade(writer, request, nil)
|
||||||
room := NewRoom(conn)
|
room := NewRoom(conn)
|
||||||
if err := conn.WriteJSON(WSMessage{
|
if err := conn.WriteJSON(WSMessage{
|
||||||
SessionID: "",
|
SessionID: "",
|
||||||
Type: "newRoom",
|
Type: "newRoom",
|
||||||
Value: room.ID,
|
Value: room.ID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Println("newSessionWriteJsonError.", err)
|
log.Println("newSessionWriteJsonError.", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func(r *Room) {
|
go func(r *Room) {
|
||||||
ticker := time.NewTicker(10 * time.Second)
|
ticker := time.NewTicker(10 * time.Second)
|
||||||
quit := make(chan struct{})
|
quit := make(chan struct{})
|
||||||
defer func() {
|
defer func() {
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
_ = room.CallerConn.Close()
|
_ = room.CallerConn.Close()
|
||||||
close(quit)
|
close(quit)
|
||||||
RemoveRoom(r.ID)
|
RemoveRoom(r.ID)
|
||||||
|
|
||||||
// Close the barrier session
|
// Close the barrier session
|
||||||
if r.BarrierSession != nil {
|
if r.BarrierSession != nil {
|
||||||
r.BarrierSession.DeleteBarrierSession()
|
r.BarrierSession.DeleteBarrierSession()
|
||||||
}
|
}
|
||||||
|
|
||||||
for sID, s := range r.Sessions {
|
for sID, s := range r.Sessions {
|
||||||
_ = s.CalleeConn.WriteJSON(WSMessage{
|
_ = s.CalleeConn.WriteJSON(WSMessage{
|
||||||
Type: "roomClosed",
|
Type: "roomClosed",
|
||||||
SessionID: sID,
|
SessionID: sID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go sendHeartBeatWS(ticker, conn, quit)
|
go sendHeartBeatWS(ticker, conn, quit)
|
||||||
|
|
||||||
//noinspection ALL
|
//noinspection ALL
|
||||||
defer room.CallerConn.Close()
|
defer room.CallerConn.Close()
|
||||||
for {
|
for {
|
||||||
var msg WSMessage
|
var msg WSMessage
|
||||||
if err := room.CallerConn.ReadJSON(&msg); err != nil {
|
if err := room.CallerConn.ReadJSON(&msg); err != nil {
|
||||||
log.Println("websocketError.", err)
|
log.Println("websocketError.", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//log.Println(msg)
|
//log.Println(msg)
|
||||||
s := room.GetSession(msg.SessionID)
|
s := room.GetSession(msg.SessionID)
|
||||||
if s == nil {
|
if s == nil {
|
||||||
log.Println("session nil.", msg.SessionID)
|
log.Println("session nil.", msg.SessionID)
|
||||||
}
|
}
|
||||||
if msg.Type == "addCallerIceCandidate" {
|
if msg.Type == "addCallerIceCandidate" {
|
||||||
s.CallerIceCandidates = append(s.CallerIceCandidates, msg.Value)
|
s.CallerIceCandidates = append(s.CallerIceCandidates, msg.Value)
|
||||||
} else if msg.Type == "gotOffer" {
|
} else if msg.Type == "gotOffer" {
|
||||||
s.Offer = msg.Value
|
s.Offer = msg.Value
|
||||||
}
|
}
|
||||||
if err := s.CalleeConn.WriteJSON(msg); err != nil {
|
if err := s.CalleeConn.WriteJSON(msg); err != nil {
|
||||||
log.Println("serveEchoWriteJsonError.", err)
|
log.Println("serveEchoWriteJsonError.", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(room)
|
}(room)
|
||||||
})
|
})
|
||||||
|
|
||||||
server.HandleFunc("/ws_connect", func(writer http.ResponseWriter, request *http.Request) {
|
server.HandleFunc("/ws_connect", func(writer http.ResponseWriter, request *http.Request) {
|
||||||
conn, _ := upgrader.Upgrade(writer, request, nil)
|
conn, _ := upgrader.Upgrade(writer, request, nil)
|
||||||
|
|
||||||
ids, ok := request.URL.Query()["id"]
|
ids, ok := request.URL.Query()["id"]
|
||||||
|
|
||||||
if !ok || ids[0] == "" {
|
if !ok || ids[0] == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
room := GetRoom(ids[0])
|
room := GetRoom(ids[0])
|
||||||
|
|
||||||
ip, ok := request.URL.Query()["barrierip"]
|
ip, ok := request.URL.Query()["barrierip"]
|
||||||
|
|
||||||
if ok && ip[0] != "" {
|
if ok && ip[0] != "" {
|
||||||
//Declaring struct
|
//Declaring struct
|
||||||
var barriersession Barrier
|
var barriersession Barrier
|
||||||
barriersession.IPAddress = ip[0]
|
barriersession.IPAddress = ip[0]
|
||||||
room.BarrierSession = &barriersession
|
room.BarrierSession = &barriersession
|
||||||
// Creates a barrier session
|
// Creates a barrier session
|
||||||
err := room.BarrierSession.CreateBarrierSession()
|
err := room.BarrierSession.CreateBarrierSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if room == nil {
|
if room == nil {
|
||||||
_ = conn.WriteJSON(WSMessage{
|
_ = conn.WriteJSON(WSMessage{
|
||||||
Type: "roomNotFound",
|
Type: "roomNotFound",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
session := room.NewSession(conn)
|
session := room.NewSession(conn)
|
||||||
|
|
||||||
if err := room.CallerConn.WriteJSON(WSMessage{
|
if err := room.CallerConn.WriteJSON(WSMessage{
|
||||||
SessionID: session.ID,
|
SessionID: session.ID,
|
||||||
Type: "newSession",
|
Type: "newSession",
|
||||||
Value: session.ID,
|
Value: session.ID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Println("callerWriteJsonError.", err)
|
log.Println("callerWriteJsonError.", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := conn.WriteJSON(WSMessage{
|
if err := conn.WriteJSON(WSMessage{
|
||||||
SessionID: session.ID,
|
SessionID: session.ID,
|
||||||
Type: "newSession",
|
Type: "newSession",
|
||||||
Value: session.ID,
|
Value: session.ID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Println("calleeWriteJsonError.", err)
|
log.Println("calleeWriteJsonError.", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go func(s *StreamSession) {
|
go func(s *StreamSession) {
|
||||||
//noinspection ALL
|
//noinspection ALL
|
||||||
defer s.CalleeConn.Close()
|
defer s.CalleeConn.Close()
|
||||||
for {
|
for {
|
||||||
var msg WSMessage
|
var msg WSMessage
|
||||||
if err := conn.ReadJSON(&msg); err != nil {
|
if err := conn.ReadJSON(&msg); err != nil {
|
||||||
log.Println("websocketError.", err)
|
log.Println("websocketError.", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//log.Println(msg)
|
//log.Println(msg)
|
||||||
if msg.SessionID == s.ID {
|
if msg.SessionID == s.ID {
|
||||||
if msg.Type == "addCalleeIceCandidate" {
|
if msg.Type == "addCalleeIceCandidate" {
|
||||||
s.CalleeIceCandidates = append(s.CalleeIceCandidates, msg.Value)
|
s.CalleeIceCandidates = append(s.CalleeIceCandidates, msg.Value)
|
||||||
} else if msg.Type == "gotAnswer" {
|
} else if msg.Type == "gotAnswer" {
|
||||||
s.Answer = msg.Value
|
s.Answer = msg.Value
|
||||||
}
|
}
|
||||||
if err := s.CallerConn.WriteJSON(msg); err != nil {
|
if err := s.CallerConn.WriteJSON(msg); err != nil {
|
||||||
log.Println("connectEchoWriteJsonError.", err)
|
log.Println("connectEchoWriteJsonError.", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(session)
|
}(session)
|
||||||
})
|
})
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,20 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<title>Laplace</title>
|
<title>RemoteGamePlay</title>
|
||||||
<link rel="stylesheet" href="/static/bootstrap.min.css">
|
<link rel="stylesheet" href="/static/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="/static/main.css?v=0.0.5">
|
<link rel="stylesheet" href="/static/main.css?v=0.0.5">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<nav class="navbar">
|
<nav class="navbar">
|
||||||
<a class="navbar-brand text-dark" href="/">Laplace</a>
|
<a class="navbar-brand text-dark" href="/">RemoteGamePlay</a>
|
||||||
<span class="navbar-brand header-room" id="room-text"></span>
|
<span class="navbar-brand header-room" id="room-text"></span>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="panel" id="panel">
|
<div class="panel" id="panel">
|
||||||
|
<p> based on the open source project Laplace </p>
|
||||||
<p class="help-text">
|
<p class="help-text">
|
||||||
<b>Laplace</b> is an open-source project to enable screen sharing directly via browser.
|
<b>Laplace</b> is an open-source project to enable screen sharing directly via browser.
|
||||||
Made possible using WebRTC for low latency peer-to-peer connections,
|
Made possible using WebRTC for low latency peer-to-peer connections,
|
||||||
@@ -45,18 +46,18 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input id="inputRoomID" type="text" class="form-control form-control-lg text-center" placeholder="Enter room ID" required>
|
<input id="inputRoomID" type="text" class="form-control form-control-lg text-center" placeholder="Enter room ID" required>
|
||||||
</div>
|
</div>
|
||||||
<!-- <h4>Connect to Barrier KVM (Beta)</h4>-->
|
<h4>Connect to Barrier KVM (Beta)</h4>
|
||||||
<!-- <p class="help-text">-->
|
<p class="help-text">
|
||||||
<!-- This is a feature is still on beta testing. This feature will ensure that you can share the keyboard-->
|
This is a feature is still on beta testing. This feature will ensure that you can share the keyboard
|
||||||
<!-- and mouse of the server machine.-->
|
and mouse of the server machine.
|
||||||
<!-- <br>-->
|
<br>
|
||||||
<!-- <span class="text-success font-weight-bold"> Note: This only works if the laplace server has barrierc installed and the room name you are connecting-->
|
<span class="text-success font-weight-bold"> Note: This only works if the laplace server has Barrierc installed and the room name you are connecting
|
||||||
<!-- too belongs to the server.</span>-->
|
too belongs to the server.</span>
|
||||||
<!-- </p>-->
|
</p>
|
||||||
<!-- <h6>Host Name: <span id="hostname"> Not detected </span></h6>-->
|
<h6>Host Name: <span id="hostname"> Not detected </span></h6>
|
||||||
<!-- <div class="form-group">-->
|
<div class="form-group">
|
||||||
<!-- <input id="barrierIP" type="text" class="form-control form-control-lg text-center" placeholder="IPV6 or IPV4 address">-->
|
<input id="barrierIP" type="text" class="form-control form-control-lg text-center" placeholder="IPV6 or IPV4 address">
|
||||||
<!-- </div>-->
|
</div>
|
||||||
<button type="submit" class="btn btn-dark btn-block" value="submit">Join</button>
|
<button type="submit" class="btn btn-dark btn-block" value="submit">Join</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -181,8 +182,8 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<hr>
|
<hr>
|
||||||
<div class="text-center small" id="footer">
|
<div class="text-center small" id="footer">
|
||||||
<span>Laplace Project by Adam Jordan.</span>
|
<span><a href="https://github.com/Akilan1999/remotegameplay">RemoteGamePlay</a> Project by <a href="https://akilan.io">Akilan Selvacoumar</a> based on the fork
|
||||||
<a href="https://github.com/adamyordan/laplace">Source Code</a>
|
of <a href="https://github.com/Akilan1999/laplace/tree/keyboard_mouse">Laplace</a>.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,4 +1,4 @@
|
|||||||
module laplace
|
module github.com/Akilan1999/remotegameplay
|
||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
|
|||||||
19
main.go
19
main.go
@@ -4,8 +4,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"laplace/config"
|
"github.com/Akilan1999/remotegameplay/config"
|
||||||
"laplace/core"
|
"github.com/Akilan1999/remotegameplay/core"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
addr := flag.String("addr", "0.0.0.0:443", "Listen address")
|
addr := flag.String("addr", "0.0.0.0:443", "Listen address")
|
||||||
|
port := flag.String("port", "8888", "port for running the server")
|
||||||
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")
|
||||||
@@ -23,7 +24,7 @@ func main() {
|
|||||||
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")
|
||||||
BinaryToExcute := flag.String("BinaryToExecute","","Providing path (i.e Absolute path) of binary to execute")
|
BinaryToExcute := flag.String("BinaryToExecute", "", "Providing path (i.e Absolute path) of binary to execute")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -47,7 +48,6 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Running in headless mode
|
// Running in headless mode
|
||||||
if *headless {
|
if *headless {
|
||||||
Config, err := config.ConfigInit()
|
Config, err := config.ConfigInit()
|
||||||
@@ -75,7 +75,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Starting screen share headless
|
// Starting screen share headless
|
||||||
cmd := exec.Command("chromium-browser" ,"--no-sandbox","--auto-select-desktop-capture-source=Entire screen","--url","https://" + Addr + ":8888/?mode=headless","--ignore-certificate-errors")
|
cmd := exec.Command("chromium-browser", "--no-sandbox", "--auto-select-desktop-capture-source=Entire screen", "--url", "https://"+Addr+":"+*port+"/?mode=headless", "--ignore-certificate-errors")
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
@@ -96,22 +96,21 @@ func main() {
|
|||||||
|
|
||||||
// kills laplace server
|
// kills laplace server
|
||||||
if *killServer {
|
if *killServer {
|
||||||
cmd := exec.Command("pkill" ,"laplace")
|
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 *tls {
|
if *tls {
|
||||||
log.Println("Listening on TLS:", *addr)
|
log.Println("Listening on TLS:", *addr)
|
||||||
if err := http.ListenAndServeTLS(*addr, *certFile, *keyFile, server); err != nil {
|
if err := http.ListenAndServeTLS(*addr, *certFile, *keyFile, server); err != nil {
|
||||||
@@ -155,7 +154,7 @@ func Ip4or6(s string) string {
|
|||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
10
run.sh
10
run.sh
@@ -1,11 +1,11 @@
|
|||||||
# Starts server and runs it silently (i.e no output in the terminal)
|
# Starts server and runs it silently (i.e no output in the terminal)
|
||||||
./laplace -tls -addr 0.0.0.0:8888 > /dev/null 2>&1 &
|
./remotegameplay -tls -addr 0.0.0.0:${2} > /dev/null 2>&1 &
|
||||||
# Starts chromium browser and runs it silently (i.e no output in the terminal)
|
# Starts chromium browser and runs it silently (i.e no output in the terminal)
|
||||||
./laplace -headless -addr ${1} > /dev/null 2>&1 &
|
./remotegameplay -headless -addr ${1} -port ${2} > /dev/null 2>&1 &
|
||||||
# Lets the script sleep for 2 seconds
|
# Lets the script sleep for 2 seconds
|
||||||
sleep 2
|
sleep 2
|
||||||
# Gets roomInfo and stores in the tmp directory as JSON
|
# Gets roomInfo and stores in the tmp directory as JSON
|
||||||
./laplace -headless -roomInfo > /tmp/output.txt
|
./remotegameplay -headless -roomInfo > /tmp/output.txt
|
||||||
# Gets the room ID from the JSON file and outputs to tmp directory as text
|
# Gets the room ID from the JSON file and outputs to tmp directory as text
|
||||||
jq .id /tmp/output.txt > /tmp/test.txt
|
jq .id /tmp/output.txt > /tmp/test.txt
|
||||||
# Gets roomID from tmp directory as text
|
# Gets roomID from tmp directory as text
|
||||||
@@ -15,9 +15,9 @@ roomID=$(echo "$roomID" | tr -d '"')
|
|||||||
|
|
||||||
# Checks if the IP address is a IPV6 or IPV4 address
|
# Checks if the IP address is a IPV6 or IPV4 address
|
||||||
if [ "$1" != "${1#*[0-9].[0-9]}" ]; then
|
if [ "$1" != "${1#*[0-9].[0-9]}" ]; then
|
||||||
echo "https://"${1}":8888/?roomID="${roomID}
|
echo "https://"${1}":${2}/?roomID="${roomID}
|
||||||
elif [ "$1" != "${1#*:[0-9a-fA-F]}" ]; then
|
elif [ "$1" != "${1#*:[0-9a-fA-F]}" ]; then
|
||||||
echo "https://["${1}"]:8888/?roomID="${roomID}
|
echo "https://["${1}"]:${2}/?roomID="${roomID}
|
||||||
else
|
else
|
||||||
echo "Unrecognized IP format '$1'"
|
echo "Unrecognized IP format '$1'"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user