connected remotegameprivate and backend
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -4,6 +4,10 @@ remotegameplay
|
||||
room.json
|
||||
laplace
|
||||
scripts/
|
||||
server/
|
||||
server/docker/
|
||||
client/
|
||||
p2p/
|
||||
# Ignore SQLite database created
|
||||
xplane11-webRTC.db
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ type Config struct {
|
||||
SSHPassword string
|
||||
NATEscapeServerPort string
|
||||
NATEscapeBarrierPort string
|
||||
BackendURL string
|
||||
Rate float64
|
||||
}
|
||||
|
||||
// Exists reports whether the named file or directory exists.
|
||||
@@ -63,6 +65,8 @@ func SetDefaults() error {
|
||||
defaults["Rooms"] = defaultPath + "room.json"
|
||||
defaults["ScriptToExecute"] = ""
|
||||
defaults["SSHPassword"] = ""
|
||||
defaults["Rate"] = 0.0
|
||||
defaults["BackendURL"] = "https://xplane-webrtc.akilan.io"
|
||||
|
||||
//Paths to search for config file
|
||||
configPaths = append(configPaths, defaultPath)
|
||||
|
||||
129
core/core.go
Normal file
129
core/core.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/Akilan1999/p2p-rendering-computation/server"
|
||||
"github.com/Akilan1999/remotegameplay/config"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GameSession A single Game session. In the following implementation
|
||||
// the server can have only 1 user occupying it por session.
|
||||
type GameSession struct {
|
||||
Link string `json:"LinkID"`
|
||||
Rate float64 `json:"Rate"`
|
||||
Server *server.SysInfo `json:"ServerInformation"`
|
||||
}
|
||||
|
||||
// BroadcastServerToBackend Broadcasts server information for the backend
|
||||
func BroadcastServerToBackend() error {
|
||||
// Get server specs
|
||||
serverInfo := server.ServerInfo()
|
||||
|
||||
// Get information from the config file
|
||||
config, err := config.ConfigInit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var gameSession GameSession
|
||||
|
||||
respIpv4orIPv6 := Ip4or6(config.IPAddress)
|
||||
|
||||
// Adding game session information
|
||||
respIpv4orIPv6 = "https://" + respIpv4orIPv6
|
||||
|
||||
// Get room information
|
||||
_, err = ReadRoomsFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Game session url
|
||||
//+ file.ID
|
||||
gameSession.Link = respIpv4orIPv6 + ":" + config.NATEscapeServerPort + "/?id="
|
||||
// Rate for the game session
|
||||
gameSession.Rate = config.Rate
|
||||
// Server specs to struct GameSession
|
||||
// De-referencing server info
|
||||
gameSession.Server = serverInfo
|
||||
// convert Struct to JSON string
|
||||
gameSessionString, err := StringPrettyPrint(gameSession)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Printing the entire game session string to ensure the session
|
||||
// is running
|
||||
fmt.Println(gameSessionString)
|
||||
|
||||
form := url.Values{}
|
||||
form.Add("Link", gameSession.Link)
|
||||
form.Add("Rate", strconv.FormatFloat(gameSession.Rate, 'E', -1, 64))
|
||||
form.Add("HostName", gameSession.Server.Hostname)
|
||||
form.Add("Platform", gameSession.Server.Platform)
|
||||
form.Add("RAM", strconv.Itoa(int(gameSession.Server.RAM)))
|
||||
form.Add("Disk", strconv.Itoa(int(gameSession.Server.Disk)))
|
||||
form.Add("GPU", gameSession.Server.GPU.Gpu.GpuName)
|
||||
form.Add("CPU", gameSession.Server.CPU)
|
||||
|
||||
req, err := http.NewRequest("POST", config.BackendURL+"AddGameSession", strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
// Sending request to the backend server
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Getting the response
|
||||
response, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Checking if the response succeeded
|
||||
if string(response) != "success" {
|
||||
return errors.New(string(response))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StringPrettyPrint print the contents of the obj (
|
||||
// Reference: https://stackoverflow.com/questions/24512112/how-to-print-struct-variables-in-console
|
||||
func StringPrettyPrint(data interface{}) (string, error) {
|
||||
var p []byte
|
||||
// var err := error
|
||||
p, err := json.MarshalIndent(data, "", "\t")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%s \n", p), nil
|
||||
}
|
||||
|
||||
// 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 + "]"
|
||||
|
||||
}
|
||||
6
go.mod
6
go.mod
@@ -7,7 +7,13 @@ replace github.com/Akilan1999/p2p-rendering-computation => /Users/akilan/Documen
|
||||
require (
|
||||
github.com/Akilan1999/p2p-rendering-computation v0.0.0-00010101000000-000000000000
|
||||
github.com/fatedier/frp v0.47.0 // indirect
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/kataras/go-mailer v0.1.0
|
||||
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
gorm.io/driver/sqlite v1.4.4
|
||||
gorm.io/gorm v1.24.5
|
||||
)
|
||||
|
||||
21
go.sum
21
go.sum
@@ -116,7 +116,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/apenella/go-ansible v1.1.0/go.mod h1:tHqFBSwWXF9k2hkLQWfq6oxMQZHslySQqttkA2siyqE=
|
||||
@@ -325,7 +324,6 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
@@ -333,7 +331,6 @@ github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4u
|
||||
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
|
||||
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
|
||||
github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
|
||||
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
|
||||
@@ -556,6 +553,11 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
@@ -573,6 +575,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kataras/go-mailer v0.1.0 h1:KffyTZnKbaNzkRoyckaJZ4/jsUigvyUWxdrXXTTK7cY=
|
||||
github.com/kataras/go-mailer v0.1.0/go.mod h1:+js8BH5a6EFHhufrz90OBaL9vSv2OFwWyPtJuP98mGk=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
@@ -618,7 +622,6 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -629,6 +632,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
@@ -937,6 +942,8 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
@@ -1292,7 +1299,6 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1628,6 +1634,11 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc=
|
||||
gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
|
||||
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE=
|
||||
gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
|
||||
318
main.go
318
main.go
@@ -1,191 +1,219 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/Akilan1999/remotegameplay/config"
|
||||
"github.com/Akilan1999/remotegameplay/core"
|
||||
"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", "localhost", "Listen address")
|
||||
port := flag.String("port", "8888", "port for running the server")
|
||||
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")
|
||||
BinaryToExcute := flag.String("BinaryToExecute", "", "Providing path (i.e Absolute path) of binary to execute")
|
||||
addr := flag.String("addr", "localhost", "Listen address")
|
||||
port := flag.String("port", "8888", "port for running the server")
|
||||
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")
|
||||
BinaryToExcute := 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")
|
||||
|
||||
flag.Parse()
|
||||
flag.Parse()
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
server := core.GetHttp()
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
server := core.GetHttp()
|
||||
|
||||
err := config.SetDefaults()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err := config.SetDefaults()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// running implementation to escape NAT
|
||||
Server, barrireKVM, err := core.EscapeNAT(*port)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// Print out room information
|
||||
if *roomInfo {
|
||||
room, err := core.ReadRoomsFile()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
Config, err := config.ConfigInit()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
PrettyPrint(room)
|
||||
return
|
||||
}
|
||||
|
||||
Config.IPAddress = "64.227.168.102"
|
||||
Config.NATEscapeServerPort = Server
|
||||
Config.NATEscapeBarrierPort = barrireKVM
|
||||
// Running in headless mode
|
||||
if *headless {
|
||||
Config, err := config.ConfigInit()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
fmt.Println(Config)
|
||||
// Returns the URl address type
|
||||
Addr := Ip4or6(Config.IPAddress)
|
||||
|
||||
err = Config.WriteConfig()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// If address is provided
|
||||
if *addr != "" {
|
||||
Addr = *addr
|
||||
// Add brackets if the ip address is ipv6
|
||||
Addr = Ip4or6(Addr)
|
||||
}
|
||||
|
||||
// Print out room information
|
||||
if *roomInfo {
|
||||
room, err := core.ReadRoomsFile()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
var TaskExecute string
|
||||
|
||||
PrettyPrint(room)
|
||||
return
|
||||
}
|
||||
if *BinaryToExcute != "" {
|
||||
TaskExecute = *BinaryToExcute
|
||||
} else {
|
||||
// Read binary from config file
|
||||
TaskExecute = Config.ScriptToExecute
|
||||
}
|
||||
|
||||
// Running in headless mode
|
||||
if *headless {
|
||||
Config, err := config.ConfigInit()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// Starting screen share headless
|
||||
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 {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Returns the URl address type
|
||||
Addr := Ip4or6(Config.IPAddress)
|
||||
// Makes program sleep for 2 seconds to allow chromium browser to open
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// If address is provided
|
||||
if *addr != "" {
|
||||
Addr = *addr
|
||||
// Add brackets if the ip address is ipv6
|
||||
Addr = Ip4or6(Addr)
|
||||
}
|
||||
// Task to be executed
|
||||
err = RunTask(TaskExecute)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
var TaskExecute string
|
||||
return
|
||||
|
||||
if *BinaryToExcute != "" {
|
||||
TaskExecute = *BinaryToExcute
|
||||
} else {
|
||||
// Read binary from config file
|
||||
TaskExecute = Config.ScriptToExecute
|
||||
}
|
||||
}
|
||||
|
||||
// Starting screen share headless
|
||||
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 {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
// Makes program sleep for 2 seconds to allow chromium browser to open
|
||||
time.Sleep(3 * time.Second)
|
||||
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{})
|
||||
|
||||
// Task to be executed
|
||||
err = RunTask(TaskExecute)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
if *GameServer {
|
||||
gameserver.Server(*port)
|
||||
} else {
|
||||
if *tls {
|
||||
log.Println("Listening on TLS:", *addr+":"+*port)
|
||||
if err := http.ListenAndServeTLS(*addr+":"+*port, *certFile, *keyFile, server); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
} else {
|
||||
log.Println("Listening:", *addr+":"+*port)
|
||||
if err := http.ListenAndServe(*addr+":"+*port, server); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// running implementation to escape NAT
|
||||
Server, barrireKVM, err := core.EscapeNAT(*port)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
Config, err := config.ConfigInit()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if *tls {
|
||||
log.Println("Listening on TLS:", *addr+":"+*port)
|
||||
if err := http.ListenAndServeTLS(*addr+":"+*port, *certFile, *keyFile, server); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
} else {
|
||||
log.Println("Listening:", *addr+":"+*port)
|
||||
if err := http.ListenAndServe(*addr+":"+*port, server); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
Config.IPAddress = "64.227.168.102"
|
||||
Config.NATEscapeServerPort = Server
|
||||
Config.NATEscapeBarrierPort = barrireKVM
|
||||
|
||||
// Start P2PRC server
|
||||
//_, err = abstractions.Start()
|
||||
//if err != nil {
|
||||
// return
|
||||
//}
|
||||
err = Config.WriteConfig()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
err = core.BroadcastServerToBackend()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
fmt.Println("success broadcasting to game server")
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
16
server/auth/auth.go
Normal file
16
server/auth/auth.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
)
|
||||
|
||||
|
||||
// HashPassword Hash password passed through the
|
||||
// parameter
|
||||
func HashPassword(Password string) (string, error) {
|
||||
data := []byte(Password)
|
||||
hash := sha256.Sum256(data)
|
||||
// returning hash as a string
|
||||
return string(hash[:]), nil
|
||||
}
|
||||
|
||||
17
server/auth/auth_test.go
Normal file
17
server/auth/auth_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Function to test if the password is hashed
|
||||
func TestHashPassword(t *testing.T) {
|
||||
Password, err := HashPassword("AKILAN1999")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
fmt.Println("Password Hash")
|
||||
fmt.Println(Password)
|
||||
}
|
||||
15
server/connection.go
Normal file
15
server/connection.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Connect Connection to the Sqlite database
|
||||
func Connect() (*gorm.DB, error) {
|
||||
db, err := gorm.Open(sqlite.Open("xplane11-webRTC.db"), &gorm.Config{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return db, nil
|
||||
}
|
||||
16
server/connection_test.go
Normal file
16
server/connection_test.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Testing connection to the Database
|
||||
func TestConnect(t *testing.T) {
|
||||
// Connect to database created
|
||||
_, err := Connect()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
26
server/login.go
Normal file
26
server/login.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/Akilan1999/remotegameplay/server/auth"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func AuthLogin(db *gorm.DB, user *Users) (string, error) {
|
||||
// Generate Hash from password
|
||||
password, err := auth.HashPassword(user.Password)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
match, err := CheckIfEmailAndPasswordMatch(db, user.EmailID, password)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if match == "success" {
|
||||
return "success", nil
|
||||
}
|
||||
|
||||
return "", errors.New("Something is wrong with from our side. Email us: me@akilan.io to find out more. ")
|
||||
}
|
||||
44
server/mailServer.go
Normal file
44
server/mailServer.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package server
|
||||
|
||||
// MailerSend This function sends an automated email to the
|
||||
// person requesting it
|
||||
func MailerSend(subject, email, message string) error {
|
||||
// Load email credentials from the configuration file
|
||||
//Config, err := config.ConfigInit()
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
// sender configuration.
|
||||
//config := mailer.Config{
|
||||
// Host: Config.EmailHost,
|
||||
// Username: Config.EmailID,
|
||||
// Password: Config.EmailPassword,
|
||||
// FromAddr: Config.EmailID,
|
||||
// Port: Config.EmailPort,
|
||||
// // Enable UseCommand to support sendmail unix command,
|
||||
// // if this field is true then Host, Username, Password and Port are not required,
|
||||
// // because this info already exists in your local sendmail configuration.
|
||||
// //
|
||||
// // Defaults to false.
|
||||
// UseCommand: false,
|
||||
//}
|
||||
|
||||
// initialize a new mail sender service.
|
||||
//sender := mailer.New(config)
|
||||
//
|
||||
//// the rich message body.
|
||||
//content := message
|
||||
//
|
||||
//// the recipient(s).
|
||||
//to := []string{email}
|
||||
//
|
||||
//// send the e-mail.
|
||||
//err = sender.Send(subject, content, to...)
|
||||
//
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
return nil
|
||||
}
|
||||
14
server/mailServer_test.go
Normal file
14
server/mailServer_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMailerSend(t *testing.T) {
|
||||
err := MailerSend("Test", "akilanselva@hotmail.com", "Welcome from Xplane=WebRTC")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
341
server/models.go
Normal file
341
server/models.go
Normal file
@@ -0,0 +1,341 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/Akilan1999/remotegameplay/server/auth"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
//var users []User = []User{
|
||||
// User{Username: "foobar", FirstName: "Foo", LastName: "Bar", Salary: 200},
|
||||
// User{Username: "helloworld", FirstName: "Hello", LastName: "World", Salary: 200},
|
||||
// User{Username: "john", FirstName: "John", Salary: 200},
|
||||
//}
|
||||
|
||||
// LoginSession Storing information of the login session
|
||||
type LoginSession struct {
|
||||
SessionKey string `json:"SessionKey"`
|
||||
UserID string `json:"UserID"`
|
||||
User Users `gorm:"foreignKey:UserID;references:UserID" json:"Users"`
|
||||
}
|
||||
|
||||
// Users This struct focuses on storing user
|
||||
// information
|
||||
type Users struct {
|
||||
UserID string `json:"userID"`
|
||||
Name string `form:"Name" json:"Name"`
|
||||
Password string `form:"Password" binding:"required" json:"Password"`
|
||||
EmailID string `form:"EmailID" binding:"required" json:"EmailID"`
|
||||
}
|
||||
|
||||
// GameSession A single Game session. In the following implementation
|
||||
// the server can have only 1 user occupying it por session.
|
||||
type GameSession struct {
|
||||
GameSessionID string `json:"GameSessionID"`
|
||||
// Link of the stream started for gameplay
|
||||
Link string `form:"Link" binding:"required" json:"LinkID"`
|
||||
ServerID string `json:"ServerID"`
|
||||
Rate float64 `form:"Rate" binding:"required" json:"Rate"`
|
||||
Server ServerSpecs `gorm:"foreignKey:ID;references:ServerID" json:"ServerInformation"`
|
||||
// State of the server if it's in use
|
||||
// or free
|
||||
State bool
|
||||
UserID string `json:"UserID"`
|
||||
User Users `gorm:"foreignKey:UserID;references:UserID" json:"ServerInformation"`
|
||||
}
|
||||
|
||||
// ServerSpecs Server specs information
|
||||
type ServerSpecs struct {
|
||||
ID string `bson: ID`
|
||||
Hostname string `form:"Hostname" binding:"required" bson:hostname`
|
||||
Platform string `form:"Platform" binding:"required" bson:platform`
|
||||
CPU string `form:"CPU" binding:"required" bson:cpu`
|
||||
RAM string `form:"RAM" binding:"required" bson:ram`
|
||||
Disk string `form:"Disk" binding:"required" bson:disk`
|
||||
GPU string `form:"GPU" binding:"required" bson:GPU`
|
||||
}
|
||||
|
||||
// CreateTables CreateDB Add tables to the database
|
||||
func CreateTables(db *gorm.DB) (*gorm.DB, error) {
|
||||
// Creates table to store login sessions
|
||||
db.AutoMigrate(LoginSession{})
|
||||
// Creates table to store user information
|
||||
db.AutoMigrate(Users{})
|
||||
// Creates table of type GameSessions
|
||||
db.AutoMigrate(GameSession{})
|
||||
// Creates table of type ServerSpecs
|
||||
db.AutoMigrate(ServerSpecs{})
|
||||
// returns variable DB of type *gorm.DB and error
|
||||
// which is nil at the current moment
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// RemoveTableGameSession Removes table of type
|
||||
func RemoveTableGameSession(db *gorm.DB) (*gorm.DB, error) {
|
||||
var gameSession GameSession
|
||||
// Creates table of type GameSessions
|
||||
db.Delete(gameSession)
|
||||
// returns variable DB of type *gorm.DB and error
|
||||
// which is nil at the current moment
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// DisplayGameSessions Returns all the rows of all the game session information
|
||||
// to display
|
||||
func DisplayGameSessions(db *gorm.DB) ([]*GameSession, error) {
|
||||
// select * from GameSessions
|
||||
rows, err := db.Model(&GameSession{}).Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Variable to store information of all game sessions
|
||||
var GameSessions []*GameSession
|
||||
|
||||
// Iterates through all game session rows
|
||||
for rows.Next() {
|
||||
var gameSession GameSession
|
||||
err := db.ScanRows(rows, &gameSession)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetServerSpecs based on ServerSpecs ID
|
||||
// derived from the game session
|
||||
specs, err := GetSeverSpecs(db, gameSession.ServerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Add server information to the struct Game session
|
||||
gameSession.Server = *specs
|
||||
|
||||
// Append game result to the array
|
||||
GameSessions = append(GameSessions, &gameSession)
|
||||
}
|
||||
|
||||
return GameSessions, nil
|
||||
}
|
||||
|
||||
// GetSeverSpecs Get server specs information based on the ID provided
|
||||
func GetSeverSpecs(db *gorm.DB, ID string) (*ServerSpecs, error) {
|
||||
// query to get server specs to that game session
|
||||
ServerSpecsRows, err := db.Model(&ServerSpecs{}).Where("ID = ?", ID).Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer ServerSpecsRows.Close()
|
||||
|
||||
// Variable to store server specs
|
||||
var serverSpecs ServerSpecs
|
||||
|
||||
// iterate thought the game session available in that server
|
||||
for ServerSpecsRows.Next() {
|
||||
err := db.ScanRows(ServerSpecsRows, &serverSpecs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &serverSpecs, nil
|
||||
}
|
||||
|
||||
// AddServerSpecs Add server specs
|
||||
func AddServerSpecs(db *gorm.DB, gameSession *GameSession) error {
|
||||
// Generate Random UUID for Game Session and server specs
|
||||
gameSessionID, err := uuid.NewUUID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
serverSpecsID, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Create for entry for server specs because
|
||||
// the game session foreign relies on the
|
||||
// server specs primary key
|
||||
gameSession.Server.ID = serverSpecsID.String()
|
||||
|
||||
// Adding the IDs for both the game session and
|
||||
// the foreign key for server specs
|
||||
gameSession.GameSessionID = gameSessionID.String()
|
||||
gameSession.ServerID = serverSpecsID.String()
|
||||
|
||||
// Create Game Session
|
||||
db.Create(gameSession)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckIfEmailExits Function to check if the username has been taken already or not
|
||||
func CheckIfEmailExits(db *gorm.DB, Email string) error {
|
||||
UserRows, err := db.Model(&Users{}).Where("email_id = ?", Email).Rows()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer UserRows.Close()
|
||||
|
||||
if UserRows.Next() {
|
||||
return errors.New("Email already taken. ")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterUser Function to insert new user information
|
||||
func RegisterUser(db *gorm.DB, UserInformation *Users) error {
|
||||
// Check if the username is already taken
|
||||
err := CheckIfEmailExits(db, UserInformation.EmailID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate UserID using UUID
|
||||
id := uuid.New()
|
||||
UserInformation.UserID = id.String()
|
||||
|
||||
// Generate Hash for the plaintext password
|
||||
password, err := auth.HashPassword(UserInformation.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
UserInformation.Password = password
|
||||
// Insert the record to the database
|
||||
db.Create(UserInformation)
|
||||
|
||||
// Send email to the user that the user is successfully created
|
||||
//err = MailerSend("Xplane 11 WebRTC", UserInformation.EmailID, `<h1>Welcome to Xplane 11 WebRTC ! `+UserInformation.Name+`</h1>`)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckIfEmailAndPasswordMatch Check email and password information for login
|
||||
func CheckIfEmailAndPasswordMatch(db *gorm.DB, emailID string, Password string) (string, error) {
|
||||
UserRows, err := db.Model(&Users{}).Where("email_id = ? AND password = ?", emailID, Password).Rows()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer UserRows.Close()
|
||||
|
||||
if UserRows.Next() {
|
||||
return "success", nil
|
||||
}
|
||||
|
||||
return "", errors.New("Wrong login email or password ")
|
||||
}
|
||||
|
||||
// GetUserID Gets userID based on the EmailID
|
||||
func GetUserID(db *gorm.DB, emailID string) (string, error) {
|
||||
UserRows, err := db.Model(&Users{}).Where("email_id = ? ", emailID).Rows()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer UserRows.Close()
|
||||
|
||||
// Variable to store user information
|
||||
var users Users
|
||||
|
||||
for UserRows.Next() {
|
||||
err = db.ScanRows(UserRows, &users)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return users.UserID, nil
|
||||
}
|
||||
|
||||
return "", errors.New("User not found. ")
|
||||
}
|
||||
|
||||
// getUserInformation Gets user information based on the user ID provided
|
||||
func getUserInformation(db *gorm.DB, ID string) (*Users, error) {
|
||||
UserRows, err := db.Model(&Users{}).Where("user_id = ? ", ID).Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer UserRows.Close()
|
||||
|
||||
// Variable to store user information
|
||||
var users Users
|
||||
|
||||
for UserRows.Next() {
|
||||
err = db.ScanRows(UserRows, &users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &users, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("User not found. ")
|
||||
}
|
||||
|
||||
// CreateLoginSession function to create login session and setting expiry time
|
||||
// for the login session
|
||||
func CreateLoginSession(db *gorm.DB, user *Users) (*LoginSession, error) {
|
||||
// Get userID to be added to the session
|
||||
userID, err := GetUserID(db, user.EmailID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Generating Session ID
|
||||
newUUID, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create login session
|
||||
var loginSession LoginSession
|
||||
// Adding UUID key as session ID
|
||||
loginSession.SessionKey = newUUID.String()
|
||||
// Adding User ID to link to the user information
|
||||
loginSession.UserID = userID
|
||||
|
||||
// Add session information to the table sessions
|
||||
db.Create(loginSession)
|
||||
|
||||
return &loginSession, nil
|
||||
}
|
||||
|
||||
// RemoveLoginSession Removes session from the database based on the session ID provided
|
||||
func RemoveLoginSession(db *gorm.DB, SessionID string) error {
|
||||
// Delete session from the database
|
||||
err := db.Where("session_key = ?", SessionID).Delete(LoginSession{})
|
||||
if err != nil {
|
||||
return err.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUserInformation Gets the user information based on the session ID provided
|
||||
func GetUserInformation(db *gorm.DB, SessionID string) (*Users, error) {
|
||||
// Gets user ID from Session ID
|
||||
// select * from LoginSessions where session_key = <session key>
|
||||
rows, err := db.Model(&LoginSession{}).Where("session_key = ?", SessionID).Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Iterates through all game session rows
|
||||
for rows.Next() {
|
||||
var loginSession LoginSession
|
||||
err := db.ScanRows(rows, &loginSession)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get User information based on the User ID
|
||||
user, err := getUserInformation(db, loginSession.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Ensure the password field is empty
|
||||
user.Password = ""
|
||||
// return struct user
|
||||
return user, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("Session not found. ")
|
||||
}
|
||||
209
server/models_test.go
Normal file
209
server/models_test.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// helper functions: These functions are designed
|
||||
// to reduce repetitive steps
|
||||
func CreateAndInsertData() (*gorm.DB,error) {
|
||||
// Connect to database created
|
||||
DB , err := Connect()
|
||||
if err != nil {
|
||||
return nil,err
|
||||
}
|
||||
|
||||
// Create the appropriate table
|
||||
DB, err = CreateTables(DB)
|
||||
if err != nil {
|
||||
return nil,err
|
||||
}
|
||||
|
||||
DB.Scan(&GameSession{})
|
||||
|
||||
// Setting dummy data for the game session
|
||||
var Session GameSession
|
||||
Session.Link = "Test"
|
||||
Session.ServerID = "1"
|
||||
Session.GameSessionID = "1"
|
||||
|
||||
Session.Server = ServerSpecs{ID: "1",Hostname : "Test",GPU: "Nvidia GTX1080ti"}
|
||||
|
||||
// Insert test rows
|
||||
DB.Model(GameSession{}).Create(&Session)
|
||||
|
||||
res := DB.Scan(GameSession{})
|
||||
fmt.Println(res.Error)
|
||||
// prints row count
|
||||
fmt.Println(res.RowsAffected)
|
||||
|
||||
return DB,nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// To Ensure GameSession table is created
|
||||
func TestCreateTableGameSession(t *testing.T) {
|
||||
// Connect to database created
|
||||
DB , err := Connect()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
DB, err = CreateTables(DB)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
DB.Scan(&GameSession{})
|
||||
|
||||
}
|
||||
|
||||
// To ensure the GameSession table is removed
|
||||
func TestRemoveTableGameSession(t *testing.T) {
|
||||
// Connect to database created
|
||||
DB , err := Connect()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
DB, err = RemoveTableGameSession(DB)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
DB.Scan(&GameSession{})
|
||||
}
|
||||
|
||||
// Testing Insert rows
|
||||
func TestInsertAndDeleteRows(t *testing.T) {
|
||||
// Connect to database created
|
||||
DB , err := Connect()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// Create the appropriate table
|
||||
DB, err = CreateTables(DB)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
DB.Scan(&GameSession{})
|
||||
|
||||
// Setting dummy data for the game session
|
||||
var Session GameSession
|
||||
Session.Link = "https://2.49.230.55:8888/?id=fervent_quizzical_whippet"
|
||||
Session.ServerID = "1"
|
||||
Session.GameSessionID = "1"
|
||||
|
||||
Session.Server = ServerSpecs{ID: "1",Hostname: "akilan-Swift-SF514-54GT",GPU: "NvidiaGT 775m", RAM: 8000, CPU: "Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz" }
|
||||
|
||||
// Insert test rows
|
||||
DB.Model(GameSession{}).Create(&Session)
|
||||
|
||||
res := DB.Scan(GameSession{})
|
||||
fmt.Println(res.Error)
|
||||
// prints row count
|
||||
fmt.Println(res.RowsAffected)
|
||||
|
||||
// remove rows from the table created
|
||||
// Delete the row from the server specs table
|
||||
//DB.Delete(&ServerSpecs{}, 1)
|
||||
// Delete table from GameSession Table
|
||||
//DB.Delete(&GameSession{}, 1)
|
||||
}
|
||||
|
||||
// Test function to display all rows of the game
|
||||
// session
|
||||
func TestDisplayGameSessions(t *testing.T) {
|
||||
// Creates a test game session table and
|
||||
// inserts dummy data
|
||||
DB, err := CreateAndInsertData()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
// Gets information about all the rows
|
||||
Result , err := DisplayGameSessions(DB)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
PrettyPrint(Result)
|
||||
|
||||
//defer rows.Close()
|
||||
|
||||
//var gameSession GameSession
|
||||
//
|
||||
//// prints out the results
|
||||
//for rows.Next() {
|
||||
// DB.ScanRows(rows, &gameSession)
|
||||
// fmt.Println(gameSession.ServerID)
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
// Function to check if the user information is
|
||||
// getting successfully inserted into the database
|
||||
func TestRegisterUser(t *testing.T) {
|
||||
// Create a database connection
|
||||
connect, err := Connect()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
// Setting test registration information
|
||||
users := Users{Password: "Test123", EmailID: "akilanselva@hotmail.com"}
|
||||
|
||||
err = RegisterUser(connect, &users)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Tests to see the game session and server specs are
|
||||
// added
|
||||
func TestAddServerSpecs(t *testing.T) {
|
||||
// Create a database connection
|
||||
connect, err := Connect()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
// Setting dummy data for the game session
|
||||
var Session GameSession
|
||||
Session.Link = "Test"
|
||||
|
||||
Session.Server = ServerSpecs{Hostname : "Test",GPU: "Nvidia GTX1080ti"}
|
||||
|
||||
// Calling server session
|
||||
err = AddServerSpecs(connect, &Session)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
188
server/server.go
Normal file
188
server/server.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Server Starts the server for the client side
|
||||
func Server(port string) error {
|
||||
|
||||
r := gin.Default()
|
||||
|
||||
r.Static("/assets", "./templates/assets")
|
||||
|
||||
r.LoadHTMLGlob("./templates/*.html")
|
||||
// htmlRender.TemplatesDir = "templates/" // default
|
||||
// htmlRender.Ext = ".html" // default
|
||||
|
||||
// Tell gin to use our html render
|
||||
|
||||
// Initialise connection to Sqlite DB
|
||||
connect, err := Connect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Gets default information about the game sessions
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
// Get client session ID
|
||||
session, err := c.Cookie("SessionID")
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/login")
|
||||
}
|
||||
|
||||
// User information based on session ID
|
||||
User, err := GetUserInformation(connect, session)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/login")
|
||||
}
|
||||
|
||||
// Get information of all game sessions available
|
||||
GameSessions, err := DisplayGameSessions(connect)
|
||||
if err != nil {
|
||||
c.String(http.StatusOK, fmt.Sprint(err))
|
||||
}
|
||||
c.HTML(http.StatusOK, "index.html", gin.H{
|
||||
"title": "Xplane11-WebRTC",
|
||||
"GameSessions": GameSessions,
|
||||
"User": User,
|
||||
})
|
||||
})
|
||||
|
||||
// Opens the forgot password page
|
||||
r.GET("/forgotpassword", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "forgotpassword.html", gin.H{
|
||||
"title": "Xplane11-WebRTC",
|
||||
})
|
||||
})
|
||||
|
||||
// Opens the login page
|
||||
r.GET("/login", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "login.html", gin.H{
|
||||
"title": "Xplane11-WebRTC",
|
||||
})
|
||||
})
|
||||
|
||||
// Validate login information
|
||||
r.POST("/login", func(c *gin.Context) {
|
||||
// you can bind multipart form with explicit binding declaration:
|
||||
// c.ShouldBindWith(&form, binding.Form)
|
||||
// or you can simply use autobinding with ShouldBind method:
|
||||
// source: https://github.com/gin-gonic/gin#multiparturlencoded-binding
|
||||
var users Users
|
||||
// in this case proper binding will be automatically selected
|
||||
if err := c.ShouldBind(&users); err != nil {
|
||||
c.String(http.StatusBadRequest, "bad request")
|
||||
}
|
||||
|
||||
result, err := AuthLogin(connect, &users)
|
||||
if err != nil {
|
||||
c.String(http.StatusOK, fmt.Sprint(err))
|
||||
} else {
|
||||
if result == "success" {
|
||||
// Create Login session
|
||||
session, err := CreateLoginSession(connect, &users)
|
||||
if err != nil {
|
||||
c.String(http.StatusExpectationFailed, "error")
|
||||
}
|
||||
// TODO redirect to homepage
|
||||
// Set client Cookie as Session ID
|
||||
// To be changed when we use HTTPS
|
||||
c.SetCookie("SessionID", session.SessionKey, 3600, "/", "localhost", false, true)
|
||||
// redirects to the home page
|
||||
//c.Redirect(http.StatusFound, "/")
|
||||
|
||||
// Sends message success. which then redirects back to the home page
|
||||
c.String(http.StatusOK, "Success!")
|
||||
} else {
|
||||
c.String(http.StatusOK, "Something is wrong with from our side. Email us: me@akilan.io to find out more. ")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Route for logout
|
||||
r.GET("/logout", func(c *gin.Context) {
|
||||
// Get client session ID
|
||||
session, err := c.Cookie("SessionID")
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusFound, "/login")
|
||||
}
|
||||
|
||||
// Remove Session ID from the database
|
||||
RemoveLoginSession(connect, session)
|
||||
|
||||
// redirect to the login page
|
||||
c.Redirect(http.StatusFound, "/login")
|
||||
})
|
||||
|
||||
// Opens the registration page
|
||||
r.GET("/register", func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "registration.html", gin.H{
|
||||
"title": "Xplane11-WebRTC",
|
||||
})
|
||||
})
|
||||
|
||||
// Register user information required
|
||||
r.POST("/register", func(c *gin.Context) {
|
||||
// you can bind multipart form with explicit binding declaration:
|
||||
// c.ShouldBindWith(&form, binding.Form)
|
||||
// or you can simply use autobinding with ShouldBind method:
|
||||
// source: https://github.com/gin-gonic/gin#multiparturlencoded-binding
|
||||
var users Users
|
||||
// in this case proper binding will be automatically selected
|
||||
if err := c.ShouldBind(&users); err != nil {
|
||||
c.String(http.StatusBadRequest, "bad request")
|
||||
}
|
||||
|
||||
err = RegisterUser(connect, &users)
|
||||
if err != nil {
|
||||
c.String(http.StatusOK, fmt.Sprint(err))
|
||||
} else {
|
||||
c.String(http.StatusOK, "Success! Head back to the login page")
|
||||
}
|
||||
})
|
||||
|
||||
// Add new server information
|
||||
r.POST("/AddGameSession", func(c *gin.Context) {
|
||||
|
||||
// TODO: Binding
|
||||
// you can bind multipart form with explicit binding declaration:
|
||||
// c.ShouldBindWith(&form, binding.Form)
|
||||
// or you can simply use autobinding with ShouldBind method:
|
||||
// source: https://github.com/gin-gonic/gin#multiparturlencoded-binding
|
||||
var gameSession GameSession
|
||||
|
||||
gameSession.Rate, _ = strconv.ParseFloat(c.PostForm("Rate"), 8)
|
||||
gameSession.Server.GPU = c.PostForm("GPU")
|
||||
gameSession.Link = c.PostForm("Link")
|
||||
gameSession.Server.CPU = c.PostForm("CPU")
|
||||
gameSession.Server.GPU = c.PostForm("GPU")
|
||||
gameSession.Server.Platform = c.PostForm("Platform")
|
||||
gameSession.Server.Hostname = c.PostForm("HostName")
|
||||
gameSession.Server.RAM = c.PostForm("RAM")
|
||||
gameSession.Server.Disk = c.PostForm("Disk")
|
||||
|
||||
// in this case proper binding will be automatically selected
|
||||
//if err := c.ShouldBind(&gameSession); err != nil {
|
||||
// c.String(http.StatusBadRequest, "bad request")
|
||||
//}
|
||||
|
||||
err = AddServerSpecs(connect, &gameSession)
|
||||
if err != nil {
|
||||
c.String(http.StatusOK, fmt.Sprint(err))
|
||||
} else {
|
||||
c.String(http.StatusOK, "Success")
|
||||
}
|
||||
})
|
||||
|
||||
// Run gin server on the specified port
|
||||
err = r.Run(":" + port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
81
templates/addgamesession.html
Normal file
81
templates/addgamesession.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Admin - Free Bulma template</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,700" rel="stylesheet">
|
||||
<!-- Bulma Version 0.9.0-->
|
||||
<link rel="stylesheet" href="https://unpkg.com/bulma@0.9.0/css/bulma.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="assets/css/admin.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- START NAV -->
|
||||
<nav class="navbar is-white">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item brand-text" href="index.html">
|
||||
XPlane11-WebRTC
|
||||
</a>
|
||||
<div class="navbar-burger burger" data-target="navMenu">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="navMenu" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item" href="admin.html">
|
||||
Home
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- END NAV -->
|
||||
<div class="container">
|
||||
<div class="">
|
||||
<div class="">
|
||||
<section class="hero is-info welcome is-small">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">
|
||||
Hello, User.
|
||||
</h1>
|
||||
<h2 class="subtitle">
|
||||
I hope you are having a great day!
|
||||
</h2>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="info-tiles">
|
||||
<div class="tile is-ancestor has-text-centered row columns is-multiline">
|
||||
{{ range .GameSessions }}
|
||||
<div class="column is-4 tile is-parent">
|
||||
<article class="tile is-child box">
|
||||
<p class="title">{{ .Server.GPU }}</p>
|
||||
<p style="color: #8F99A3; margin-top:-1.25rem; font-weight: 300; font-size: 1.25rem">RAM: {{ .Server.RAM }}</p>
|
||||
<p style="color: #8F99A3; font-weight: 300; font-size: 1.25rem">Rate: 1$/hr </p>
|
||||
<p style="color: #8F99A3; font-weight: 300; font-size: 1.25rem">CPU: {{ .Server.CPU }} </p>
|
||||
<p style="color: #8F99A3; font-weight: 300; font-size: 1.25rem">Disk: {{ .Server.Disk }} </p>
|
||||
<br>
|
||||
<a href="{{ .Link }}" class="button is-block is-success is-fullwidth is-medium">Play</a>
|
||||
</article>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script async type="text/javascript" src="assets/js/bulma.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
82
templates/assets/css/admin.css
Normal file
82
templates/assets/css/admin.css
Normal file
@@ -0,0 +1,82 @@
|
||||
html, body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
height: 100%;
|
||||
background: #ECF0F3;
|
||||
}
|
||||
nav.navbar {
|
||||
border-top: 4px solid #276cda;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.navbar-item.brand-text {
|
||||
font-weight: 300;
|
||||
}
|
||||
.navbar-item, .navbar-link {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.columns {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
.menu-label {
|
||||
color: #8F99A3;
|
||||
letter-spacing: 1.3;
|
||||
font-weight: 700;
|
||||
}
|
||||
.menu-list a {
|
||||
color: #0F1D38;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.menu-list a:hover {
|
||||
background-color: transparent;
|
||||
color: #276cda;
|
||||
}
|
||||
.menu-list a.is-active {
|
||||
background-color: transparent;
|
||||
color: #276cda;
|
||||
font-weight: 700;
|
||||
}
|
||||
.card {
|
||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.18);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.card-header-title {
|
||||
color: #8F99A3;
|
||||
font-weight: 400;
|
||||
}
|
||||
.info-tiles {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.info-tiles .subtitle {
|
||||
font-weight: 300;
|
||||
color: #8F99A3;
|
||||
}
|
||||
.hero.welcome.is-info {
|
||||
background: #36D1DC;
|
||||
background: -webkit-linear-gradient(to right, #5B86E5, #36D1DC);
|
||||
background: linear-gradient(to right, #5B86E5, #36D1DC);
|
||||
}
|
||||
.hero.welcome .title, .hero.welcome .subtitle {
|
||||
color: hsl(192, 17%, 99%);
|
||||
}
|
||||
.card .content {
|
||||
font-size: 14px;
|
||||
}
|
||||
.card-footer-item {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #8F99A3;
|
||||
}
|
||||
.card-footer-item:hover {
|
||||
}
|
||||
.card-table .table {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.events-card .card-table {
|
||||
max-height: 250px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
4
templates/assets/css/register.css
Normal file
4
templates/assets/css/register.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.va {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
10
templates/assets/js/bulma.js
Normal file
10
templates/assets/js/bulma.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// The following code is based off a toggle menu by @Bradcomp
|
||||
// source: https://gist.github.com/Bradcomp/a9ef2ef322a8e8017443b626208999c1
|
||||
(function() {
|
||||
var burger = document.querySelector('.burger');
|
||||
var menu = document.querySelector('#'+burger.dataset.target);
|
||||
burger.addEventListener('click', function() {
|
||||
burger.classList.toggle('is-active');
|
||||
menu.classList.toggle('is-active');
|
||||
});
|
||||
})();
|
||||
153
templates/forgotpassword.html
Normal file
153
templates/forgotpassword.html
Normal file
@@ -0,0 +1,153 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Register - Free Bulma template</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<script src="https://kit.fontawesome.com/15181efa86.js" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/bulma@0.9.0/css/bulma.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="assets/css/register.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section class="container">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-8 is-offset-2 register">
|
||||
<div class="columns">
|
||||
<div class="column left">
|
||||
<h1 class="title is-1">Xplane 11 WebRTC</h1>
|
||||
<br>
|
||||
<h2 class="subtitle is-4">Enjoy the XPlane 11 gameplay performance without any setup</h2>
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="column right has-text-centered">
|
||||
<h1 class="title is-4">Forgot password</h1>
|
||||
<p class="description">We will send a reset password link to your email</p>
|
||||
<form>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="email" placeholder="Email">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="button is-block is-success is-fullwidth is-medium">Send reset password link</button>
|
||||
<br>
|
||||
<a href="/register" >Create a new account</a>
|
||||
<br>
|
||||
<a href="/login" >Already have an account ?</a>
|
||||
<br/>
|
||||
<small><em></em></small>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-8 is-offset-2">
|
||||
<br>
|
||||
<nav class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<span class="icon">
|
||||
<i class="fab fa-github"></i>
|
||||
</span>  
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<small class="level-item" style="color: var(--textLight)">
|
||||
© Super Cool Website. All Rights Reserved.
|
||||
</small>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
<style>
|
||||
:root {
|
||||
--brandColor: hsl(166, 67%, 51%);
|
||||
--background: rgb(247, 247, 247);
|
||||
--textDark: hsla(0, 0%, 0%, 0.66);
|
||||
--textLight: hsla(0, 0%, 0%, 0.33);
|
||||
}
|
||||
|
||||
body {
|
||||
background: url('https://forums.x-plane.org/screenshots/monthly_2017_07/b738_21.png.5ba5bcaca689d85705396affb04473ce.png');
|
||||
background-size: cover; /* <------ */
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
height: 100vh;
|
||||
color: var(--textDark);
|
||||
}
|
||||
|
||||
.field:not(:last-child) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.register {
|
||||
margin-top: 10rem;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.left,
|
||||
.right {
|
||||
padding: 4.5rem;
|
||||
}
|
||||
|
||||
.left {
|
||||
border-right: 5px solid var(--background);
|
||||
}
|
||||
|
||||
.left .title {
|
||||
font-weight: 800;
|
||||
letter-spacing: -2px;
|
||||
}
|
||||
|
||||
.left .colored {
|
||||
color: var(--brandColor);
|
||||
font-weight: 500;
|
||||
margin-top: 1rem !important;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.left p {
|
||||
color: var(--textLight);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.right .title {
|
||||
font-weight: 800;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.right .description {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem !important;
|
||||
color: var(--textLight);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.right small {
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border-color: var(--brandColor) !important;
|
||||
box-shadow: 0 0 0 1px var(--brandColor) !important;
|
||||
}
|
||||
|
||||
.fab,
|
||||
.fas {
|
||||
color: var(--textLight);
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</html>
|
||||
85
templates/index.html
Normal file
85
templates/index.html
Normal file
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Admin - Free Bulma template</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,700" rel="stylesheet">
|
||||
<!-- Bulma Version 0.9.0-->
|
||||
<link rel="stylesheet" href="https://unpkg.com/bulma@0.9.0/css/bulma.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="assets/css/admin.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- START NAV -->
|
||||
<nav class="navbar is-white">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item brand-text" href="/">
|
||||
XPlane11-WebRTC
|
||||
</a>
|
||||
<div class="navbar-burger burger" data-target="navMenu">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="navMenu" class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item" href="/">
|
||||
Home
|
||||
</a>
|
||||
<a class="navbar-item" href="/logout">
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- END NAV -->
|
||||
<div class="container">
|
||||
<div class="">
|
||||
<div class="">
|
||||
<section class="hero is-info welcome is-small">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title">
|
||||
Hello, {{ .User.Name }}
|
||||
</h1>
|
||||
<h2 class="subtitle">
|
||||
I hope you are having a great day!
|
||||
</h2>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="info-tiles">
|
||||
<div class="tile is-ancestor has-text-centered row columns is-multiline">
|
||||
{{ range .GameSessions }}
|
||||
<div class="column is-4 tile is-parent">
|
||||
<article class="tile is-child box">
|
||||
<p class="title">{{ .Server.GPU }}</p>
|
||||
<p style="color: #8F99A3; margin-top:-1.25rem; font-weight: 300; font-size: 1.25rem">RAM: {{ .Server.RAM }} MB</p>
|
||||
<p style="color: #8F99A3; font-weight: 300; font-size: 1.25rem">Rate: {{ .Rate }}$/hr </p>
|
||||
<p style="color: #8F99A3; font-weight: 300; font-size: 1.25rem">CPU: {{ .Server.CPU }} </p>
|
||||
<p style="color: #8F99A3; font-weight: 300; font-size: 1.25rem">Disk: {{ .Server.Disk }} MB</p>
|
||||
<p style="color: #8F99A3; font-weight: 300; font-size: 1.25rem">Platform: {{ .Server.Platform }}</p>
|
||||
<br>
|
||||
<a href="{{ .Link }}" class="button is-block is-success is-fullwidth is-medium">Play</a>
|
||||
</article>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script async type="text/javascript" src="assets/js/bulma.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
218
templates/login.html
Normal file
218
templates/login.html
Normal file
@@ -0,0 +1,218 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Register - Free Bulma template</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<script src="https://kit.fontawesome.com/15181efa86.js" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/bulma@0.9.0/css/bulma.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="assets/css/register.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section class="container">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-8 is-offset-2 register">
|
||||
<div class="columns">
|
||||
<div class="column left">
|
||||
<h1 class="title is-1">Xplane 11 WebRTC</h1>
|
||||
<br>
|
||||
<h2 class="subtitle is-4">Enjoy the XPlane 11 gameplay performance without any setup</h2>
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="column right has-text-centered">
|
||||
<h1 class="title is-4">Login</h1>
|
||||
<p class="description">We cool so long as your computer supports a browser</p>
|
||||
<form>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="email" placeholder="Email" id="EmailID">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="password" placeholder="Password" id="Password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<p id="EmailIDError"></p>
|
||||
<p id="PasswordError"></p>
|
||||
<p id="ResponseText"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="button is-block is-success is-fullwidth is-medium" onclick="LoginSubmit();return false;">Login</button>
|
||||
<br>
|
||||
<a href="/register" >Create a new account</a>
|
||||
<br>
|
||||
<a href="/forgotpassword">Forgot password ?</a>
|
||||
<br/>
|
||||
<small><em></em></small>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-8 is-offset-2">
|
||||
<br>
|
||||
<nav class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<span class="icon">
|
||||
<i class="fab fa-github"></i>
|
||||
</span>  
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<small class="level-item" style="color: var(--textLight)">
|
||||
© Super Cool Website. All Rights Reserved.
|
||||
</small>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
<script>
|
||||
// The function is called on OnClick action
|
||||
function LoginSubmit() {
|
||||
// Getting element information of all the fields
|
||||
// required for registration
|
||||
var EmailID = document.getElementById("EmailID").value
|
||||
var Password = document.getElementById("Password").value
|
||||
|
||||
|
||||
// When EmailID is not entered
|
||||
if (EmailID == "") {
|
||||
document.getElementById("EmailIDError").innerHTML = "Enter EmailID"
|
||||
return
|
||||
}
|
||||
|
||||
// When EmailID is entered
|
||||
if (EmailID != "") {
|
||||
document.getElementById("EmailIDError").innerHTML = ""
|
||||
}
|
||||
|
||||
// When password and confirm password don't match
|
||||
if (Password != "") {
|
||||
document.getElementById("PasswordError").innerHTML = ""
|
||||
}
|
||||
// When the password matches then clear the field
|
||||
if (Password == "") {
|
||||
document.getElementById("PasswordError").innerHTML = "Enter password"
|
||||
return
|
||||
}
|
||||
|
||||
// binding data to uri encoded string
|
||||
uriencoded = "EmailID=" + EmailID + "&Password=" + Password
|
||||
|
||||
// Submitting the registration information
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/login", true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
xhr.send(uriencoded);
|
||||
|
||||
xhr.onload = function () {
|
||||
console.log(xhr.responseText)
|
||||
// Outputting response text
|
||||
document.getElementById("ResponseText").innerHTML = xhr.responseText
|
||||
// Create Sessions browser
|
||||
// if response is success then redirect
|
||||
if (xhr.responseText == "Success!") {
|
||||
window.location.replace("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
:root {
|
||||
--brandColor: hsl(166, 67%, 51%);
|
||||
--background: rgb(247, 247, 247);
|
||||
--textDark: hsla(0, 0%, 0%, 0.66);
|
||||
--textLight: hsla(0, 0%, 0%, 0.33);
|
||||
}
|
||||
|
||||
body {
|
||||
background: url('https://forums.x-plane.org/screenshots/monthly_2017_07/b738_21.png.5ba5bcaca689d85705396affb04473ce.png');
|
||||
background-size: cover; /* <------ */
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
height: 100vh;
|
||||
color: var(--textDark);
|
||||
}
|
||||
|
||||
.field:not(:last-child) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.register {
|
||||
margin-top: 10rem;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.left,
|
||||
.right {
|
||||
padding: 4.5rem;
|
||||
}
|
||||
|
||||
.left {
|
||||
border-right: 5px solid var(--background);
|
||||
}
|
||||
|
||||
.left .title {
|
||||
font-weight: 800;
|
||||
letter-spacing: -2px;
|
||||
}
|
||||
|
||||
.left .colored {
|
||||
color: var(--brandColor);
|
||||
font-weight: 500;
|
||||
margin-top: 1rem !important;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.left p {
|
||||
color: var(--textLight);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.right .title {
|
||||
font-weight: 800;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.right .description {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem !important;
|
||||
color: var(--textLight);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.right small {
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border-color: var(--brandColor) !important;
|
||||
box-shadow: 0 0 0 1px var(--brandColor) !important;
|
||||
}
|
||||
|
||||
.fab,
|
||||
.fas {
|
||||
color: var(--textLight);
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</html>
|
||||
249
templates/registration.html
Normal file
249
templates/registration.html
Normal file
@@ -0,0 +1,249 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Register - Free Bulma template</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<script src="https://kit.fontawesome.com/15181efa86.js" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/bulma@0.9.0/css/bulma.min.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="assets/css/register.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section class="container">
|
||||
<div class="columns is-multiline">
|
||||
<div class="column is-8 is-offset-2 register">
|
||||
<div class="columns">
|
||||
<div class="column left">
|
||||
<h1 class="title is-1">Xplane 11 WebRTC</h1>
|
||||
<br>
|
||||
<h2 class="subtitle is-4">Enjoy the XPlane 11 gameplay performance without any setup</h2>
|
||||
<p></p>
|
||||
</div>
|
||||
<div class="column right has-text-centered">
|
||||
<h1 class="title is-4">Sign up today</h1>
|
||||
<p class="description">We cool so long as your computer supports a browser</p>
|
||||
<form>
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="text" id="Name" placeholder="Name" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="email" id="EmailID" placeholder="Email" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="password" id="Password" placeholder="Password" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input class="input is-medium" type="password" id="ConfirmPassword" placeholder="Confirm password" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<p id="NameError"></p>
|
||||
<p id="EmailIDError"></p>
|
||||
<p id="ConfirmPasswordError"></p>
|
||||
<p id="ResponseText"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="button is-block is-success is-fullwidth is-medium" onclick="RegisterSubmit();return false;">Submit</button>
|
||||
<br>
|
||||
<a href="/login" >Already have an account ?</a>
|
||||
<br>
|
||||
<a href="/forgotpassword">Forgot password ?</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<small><em></em></small>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-8 is-offset-2">
|
||||
<br>
|
||||
<nav class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<span class="icon">
|
||||
<i class="fab fa-github"></i>
|
||||
</span>  
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<small class="level-item" style="color: var(--textLight)">
|
||||
© Super Cool Website. All Rights Reserved.
|
||||
</small>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
<!-- The following script handles communicating with the server for registration -->
|
||||
<script>
|
||||
// The function is called on OnClick action
|
||||
function RegisterSubmit() {
|
||||
// Getting element information of all the fields
|
||||
// required for registration
|
||||
var EmailID = document.getElementById("EmailID").value
|
||||
var Name = document.getElementById("Name").value
|
||||
var Password = document.getElementById("Password").value
|
||||
var ConfirmPassword = document.getElementById("ConfirmPassword").value
|
||||
|
||||
// When Name is not entered
|
||||
if (Name == "") {
|
||||
document.getElementById("Name").innerHTML = "Enter Name"
|
||||
return
|
||||
}
|
||||
|
||||
// When Name is entered
|
||||
if (Name != "") {
|
||||
document.getElementById("Name").innerHTML = ""
|
||||
}
|
||||
|
||||
// When EmailID is not entered
|
||||
if (EmailID == "") {
|
||||
document.getElementById("EmailIDError").innerHTML = "Enter EmailID"
|
||||
return
|
||||
}
|
||||
|
||||
// When EmailID is entered
|
||||
if (EmailID != "") {
|
||||
document.getElementById("EmailIDError").innerHTML = ""
|
||||
}
|
||||
|
||||
// When password and confirm password don't match
|
||||
if (Password != ConfirmPassword) {
|
||||
document.getElementById("ConfirmPasswordError").innerHTML = "Password and confirm password don't match"
|
||||
return
|
||||
}
|
||||
// When the password matches then clear the field
|
||||
if (Password == ConfirmPassword){
|
||||
document.getElementById("ConfirmPasswordError").innerHTML = ""
|
||||
}
|
||||
|
||||
// binding data to uri encoded string
|
||||
uriencoded = "Name=" + Name + "&EmailID=" + EmailID + "&Password=" + Password
|
||||
|
||||
// Submitting the registration information
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/register", true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
xhr.send(uriencoded);
|
||||
|
||||
xhr.onload = function() {
|
||||
// Outputting response text
|
||||
document.getElementById("ResponseText").innerHTML = xhr.responseText
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// comparing strings
|
||||
function strcmp(a, b)
|
||||
{
|
||||
return (a<b?-1:(a>b?1:0));
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
:root {
|
||||
--brandColor: hsl(166, 67%, 51%);
|
||||
--background: rgb(247, 247, 247);
|
||||
--textDark: hsla(0, 0%, 0%, 0.66);
|
||||
--textLight: hsla(0, 0%, 0%, 0.33);
|
||||
}
|
||||
|
||||
body {
|
||||
background: url('https://forums.x-plane.org/screenshots/monthly_2017_07/b738_21.png.5ba5bcaca689d85705396affb04473ce.png');
|
||||
background-size: cover; /* <------ */
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
height: 100vh;
|
||||
color: var(--textDark);
|
||||
}
|
||||
|
||||
.field:not(:last-child) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.register {
|
||||
margin-top: 10rem;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.left,
|
||||
.right {
|
||||
padding: 4.5rem;
|
||||
}
|
||||
|
||||
.left {
|
||||
border-right: 5px solid var(--background);
|
||||
}
|
||||
|
||||
.left .title {
|
||||
font-weight: 800;
|
||||
letter-spacing: -2px;
|
||||
}
|
||||
|
||||
.left .colored {
|
||||
color: var(--brandColor);
|
||||
font-weight: 500;
|
||||
margin-top: 1rem !important;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.left p {
|
||||
color: var(--textLight);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.right .title {
|
||||
font-weight: 800;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.right .description {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem !important;
|
||||
color: var(--textLight);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.right small {
|
||||
color: var(--textLight);
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border-color: var(--brandColor) !important;
|
||||
box-shadow: 0 0 0 1px var(--brandColor) !important;
|
||||
}
|
||||
|
||||
.fab,
|
||||
.fas {
|
||||
color: var(--textLight);
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user