mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-08-01 22:34:02 +00:00
Setup HTTPS using autocert (#149)
* Add HTTPS WSS * Update https * HTTPS * Add https * Add HTTPS worker * Add HTTPS * add https * Add pingserver to worker * add https * Add public domain whitelist * Not fatal when there existing echo server
This commit is contained in:
parent
4b9dc14c11
commit
a1ac8f272a
12 changed files with 280 additions and 45 deletions
9
go.mod
vendored
9
go.mod
vendored
|
|
@ -7,10 +7,19 @@ require (
|
|||
github.com/gen2brain/x264-go v0.0.0-20180306035800-58f586137654
|
||||
github.com/gofrs/uuid v3.2.0+incompatible
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/pion/webrtc/v2 v2.1.16
|
||||
github.com/prometheus/client_golang v1.1.0
|
||||
github.com/spf13/pflag v1.0.3
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
|
||||
golang.org/x/sys v0.0.0-20191218084908-4a24b4065292 // indirect
|
||||
golang.org/x/tools v0.0.0-20191218191756-61f5e7d2990e // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
||||
gopkg.in/hraban/opus.v2 v2.0.0-20180426093920-0f2e0b4fc6cd
|
||||
)
|
||||
|
|
|
|||
14
go.sum
vendored
14
go.sum
vendored
|
|
@ -51,6 +51,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
|
|||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
|
|
@ -176,9 +178,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4=
|
||||
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0=
|
||||
|
|
@ -191,6 +196,7 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
|
|||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -209,6 +215,8 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8
|
|||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss=
|
||||
golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
|
|
@ -218,6 +226,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -236,6 +245,8 @@ golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3 h1:4y9KwBHBgBNwDbtu44R5o1fdO
|
|||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE=
|
||||
golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191218084908-4a24b4065292 h1:Y8q0zsdcgAd+JU8VUA8p8Qv2YhuY9zevDG2ORt5qBUI=
|
||||
golang.org/x/sys v0.0.0-20191218084908-4a24b4065292/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
|
|
@ -252,6 +263,9 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn
|
|||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191218191756-61f5e7d2990e/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ var StunTurnTemplate = `[{"urls":"stun:stun.l.google.com:19302"},{"urls":"stun:%
|
|||
var WSWait = 20 * time.Second
|
||||
var MatchWorkerRandom = false
|
||||
var ProdEnv = "prod"
|
||||
var StagingEnv = "staging"
|
||||
|
||||
const NumKeys = 10
|
||||
|
||||
|
|
|
|||
|
|
@ -6,16 +6,18 @@ import (
|
|||
)
|
||||
|
||||
type Config struct {
|
||||
Port int
|
||||
URLPrefix string
|
||||
DebugHost string
|
||||
Port int
|
||||
PublicDomain string
|
||||
URLPrefix string
|
||||
DebugHost string
|
||||
|
||||
MonitoringConfig monitoring.ServerMonitoringConfig
|
||||
}
|
||||
|
||||
func NewDefaultConfig() Config {
|
||||
return Config{
|
||||
Port: 8800,
|
||||
Port: 8800,
|
||||
PublicDomain: "http://localhost:8000",
|
||||
|
||||
MonitoringConfig: monitoring.ServerMonitoringConfig{
|
||||
Port: 6601,
|
||||
|
|
@ -34,6 +36,7 @@ func (c *Config) AddFlags(fs *pflag.FlagSet) *Config {
|
|||
fs.IntVarP(&c.MonitoringConfig.Port, "monitoring.port", "", c.MonitoringConfig.Port, "Monitoring server port")
|
||||
fs.StringVarP(&c.MonitoringConfig.URLPrefix, "monitoring.prefix", "", c.MonitoringConfig.URLPrefix, "Monitoring server url prefix")
|
||||
fs.StringVarP(&c.DebugHost, "debughost", "d", "", "Specify the server want to connect directly to debug")
|
||||
fs.StringVarP(&c.PublicDomain, "domain", "n", c.PublicDomain, "Specify the server want to connect directly to debug")
|
||||
|
||||
return c
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ type Server struct {
|
|||
workerClients map[string]*WorkerClient
|
||||
}
|
||||
|
||||
const pingServerTemp = "https://%s.%s/echo"
|
||||
const devPingServer = "http://localhost:9000/echo"
|
||||
|
||||
var upgrader = websocket.Upgrader{}
|
||||
var errNotFound = errors.New("Not found")
|
||||
|
||||
|
|
@ -65,6 +68,16 @@ func (o *Server) GetWeb(w http.ResponseWriter, r *http.Request) {
|
|||
tmpl.Execute(w, data)
|
||||
}
|
||||
|
||||
// getPingServer returns the server for latency check of a zone. In latency check to find best worker step, we use this server to find the closest worker.
|
||||
func (o *Server) getPingServer(zone string) string {
|
||||
if *config.Mode == config.ProdEnv || *config.Mode == config.StagingEnv {
|
||||
return fmt.Sprintf(pingServerTemp, zone, o.cfg.PublicDomain)
|
||||
}
|
||||
|
||||
// If not Prod or Staging, return dev environment
|
||||
return devPingServer
|
||||
}
|
||||
|
||||
// WSO handles all connections from a new worker to overlord
|
||||
func (o *Server) WSO(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("Connected")
|
||||
|
|
@ -82,8 +95,11 @@ func (o *Server) WSO(w http.ResponseWriter, r *http.Request) {
|
|||
// Zone of the worker
|
||||
zone := r.URL.Query().Get("zone")
|
||||
|
||||
pingServer := o.getPingServer(zone)
|
||||
|
||||
fmt.Printf("Is public: %v zone: %v\n", util.IsPublicIP(address), zone)
|
||||
|
||||
// In case worker and overlord in the same host
|
||||
if !util.IsPublicIP(address) && *config.Mode == config.ProdEnv {
|
||||
// Don't accept private IP for worker's address in prod mode
|
||||
// However, if the worker in the same host with overlord, we can get public IP of worker
|
||||
|
|
@ -95,7 +111,7 @@ func (o *Server) WSO(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
}
|
||||
client := NewWorkerClient(c, serverID, address, fmt.Sprintf(config.StunTurnTemplate, address, address), zone)
|
||||
client := NewWorkerClient(c, serverID, address, fmt.Sprintf(config.StunTurnTemplate, address, address), zone, pingServer)
|
||||
o.workerClients[serverID] = client
|
||||
defer o.cleanConnection(client, serverID)
|
||||
|
||||
|
|
@ -213,7 +229,7 @@ func (o *Server) getBestWorkerClient(client *BrowserClient, zone string) (*Worke
|
|||
|
||||
workerClients := o.getAvailableWorkers()
|
||||
|
||||
serverID, err := findBestServerFromBrowser(workerClients, client, zone)
|
||||
serverID, err := o.findBestServerFromBrowser(workerClients, client, zone)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
|
|
@ -247,13 +263,13 @@ func (o *Server) getWorkerFromAddress(address string) *WorkerClient {
|
|||
|
||||
// findBestServerFromBrowser returns the best server for a session
|
||||
// All workers addresses are sent to user and user will ping to get latency
|
||||
func findBestServerFromBrowser(workerClients map[string]*WorkerClient, client *BrowserClient, zone string) (string, error) {
|
||||
func (o *Server) findBestServerFromBrowser(workerClients map[string]*WorkerClient, client *BrowserClient, zone string) (string, error) {
|
||||
// TODO: Find best Server by latency, currently return by ping
|
||||
if len(workerClients) == 0 {
|
||||
return "", errors.New("No server found")
|
||||
}
|
||||
|
||||
latencies := getLatencyMapFromBrowser(workerClients, client)
|
||||
latencies := o.getLatencyMapFromBrowser(workerClients, client)
|
||||
log.Println("Latency map", latencies)
|
||||
|
||||
if len(latencies) == 0 {
|
||||
|
|
@ -280,16 +296,15 @@ func findBestServerFromBrowser(workerClients map[string]*WorkerClient, client *B
|
|||
}
|
||||
|
||||
// getLatencyMapFromBrowser get all latencies from worker to user
|
||||
func getLatencyMapFromBrowser(workerClients map[string]*WorkerClient, client *BrowserClient) map[*WorkerClient]int64 {
|
||||
func (o *Server) getLatencyMapFromBrowser(workerClients map[string]*WorkerClient, client *BrowserClient) map[*WorkerClient]int64 {
|
||||
workersList := []*WorkerClient{}
|
||||
|
||||
addressList := []string{}
|
||||
latencyMap := map[*WorkerClient]int64{}
|
||||
|
||||
// addressList is the list of worker addresses
|
||||
addressList := []string{}
|
||||
for _, workerClient := range workerClients {
|
||||
workersList = append(workersList, workerClient)
|
||||
addressList = append(addressList, workerClient.Address)
|
||||
addressList = append(addressList, workerClient.PingServer)
|
||||
}
|
||||
|
||||
// send this address to user and get back latency
|
||||
|
|
@ -307,7 +322,7 @@ func getLatencyMapFromBrowser(workerClients map[string]*WorkerClient, client *Br
|
|||
}
|
||||
|
||||
for _, workerClient := range workersList {
|
||||
if latency, ok := respLatency[workerClient.Address]; ok {
|
||||
if latency, ok := respLatency[workerClient.PingServer]; ok {
|
||||
latencyMap[workerClient] = latency
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,23 @@ package overlord
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/giongto35/cloud-game/pkg/config"
|
||||
"github.com/giongto35/cloud-game/pkg/monitoring"
|
||||
"github.com/golang/glog"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"golang.org/x/crypto/acme"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
const stagingLEURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
|
||||
type Overlord struct {
|
||||
ctx context.Context
|
||||
cfg Config
|
||||
|
|
@ -45,24 +55,97 @@ func (o *Overlord) Shutdown() {
|
|||
}
|
||||
}
|
||||
|
||||
func makeServerFromMux(mux *http.ServeMux) *http.Server {
|
||||
// set timeouts so that a slow or malicious client doesn't
|
||||
// hold resources forever
|
||||
return &http.Server{
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
Handler: mux,
|
||||
}
|
||||
}
|
||||
|
||||
func makeHTTPServer(server *Server) *http.Server {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", server.GetWeb)
|
||||
r.HandleFunc("/ws", server.WS)
|
||||
r.HandleFunc("/wso", server.WSO)
|
||||
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./web"))))
|
||||
|
||||
svmux := &http.ServeMux{}
|
||||
svmux.Handle("/", r)
|
||||
|
||||
return makeServerFromMux(svmux)
|
||||
}
|
||||
|
||||
func makeHTTPToHTTPSRedirectServer(server *Server) *http.Server {
|
||||
handleRedirect := func(w http.ResponseWriter, r *http.Request) {
|
||||
newURI := "https://" + r.Host + r.URL.String()
|
||||
http.Redirect(w, r, newURI, http.StatusFound)
|
||||
}
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", handleRedirect)
|
||||
r.HandleFunc("/ws", handleRedirect)
|
||||
r.HandleFunc("/wso", handleRedirect)
|
||||
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./web"))))
|
||||
|
||||
svmux := &http.ServeMux{}
|
||||
svmux.Handle("/", r)
|
||||
|
||||
return makeServerFromMux(svmux)
|
||||
}
|
||||
|
||||
// initializeOverlord setup an overlord server
|
||||
func (o *Overlord) initializeOverlord() {
|
||||
overlord := NewServer(o.cfg)
|
||||
|
||||
http.HandleFunc("/", overlord.GetWeb)
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./web"))))
|
||||
var certManager *autocert.Manager
|
||||
var httpsSrv *http.Server
|
||||
|
||||
// browser facing port
|
||||
go func() {
|
||||
http.HandleFunc("/ws", overlord.WS)
|
||||
}()
|
||||
log.Println("Initializing Overlord Server")
|
||||
if *config.Mode == config.ProdEnv || *config.Mode == config.StagingEnv {
|
||||
var leurl string
|
||||
if *config.Mode == config.StagingEnv {
|
||||
leurl = stagingLEURL
|
||||
} else {
|
||||
leurl = acme.LetsEncryptURL
|
||||
}
|
||||
|
||||
// worker facing port
|
||||
http.HandleFunc("/wso", overlord.WSO)
|
||||
log.Println("Listening at port: localhost:8000")
|
||||
err := http.ListenAndServe(":8000", nil)
|
||||
// Print err if overlord cannot launch
|
||||
certManager = &autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist(o.cfg.PublicDomain),
|
||||
Cache: autocert.DirCache("assets/cache"),
|
||||
Client: &acme.Client{DirectoryURL: leurl},
|
||||
}
|
||||
|
||||
httpsSrv = makeHTTPServer(overlord)
|
||||
httpsSrv.Addr = ":443"
|
||||
httpsSrv.TLSConfig = &tls.Config{GetCertificate: certManager.GetCertificate}
|
||||
|
||||
go func() {
|
||||
fmt.Printf("Starting HTTPS server on %s\n", httpsSrv.Addr)
|
||||
err := httpsSrv.ListenAndServeTLS("", "")
|
||||
if err != nil {
|
||||
log.Fatalf("httpsSrv.ListendAndServeTLS() failed with %s", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var httpSrv *http.Server
|
||||
if *config.Mode == config.ProdEnv || *config.Mode == config.StagingEnv {
|
||||
httpSrv = makeHTTPToHTTPSRedirectServer(overlord)
|
||||
} else {
|
||||
httpSrv = makeHTTPServer(overlord)
|
||||
}
|
||||
|
||||
if certManager != nil {
|
||||
httpSrv.Handler = certManager.HTTPHandler(httpSrv.Handler)
|
||||
}
|
||||
|
||||
httpSrv.Addr = ":8000"
|
||||
err := httpSrv.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Fatalf("httpSrv.ListenAndServe() failed with %s", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,14 @@ import (
|
|||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const pingServer = "%s://%s/echo"
|
||||
|
||||
type WorkerClient struct {
|
||||
*cws.Client
|
||||
ServerID string
|
||||
Address string
|
||||
ServerID string
|
||||
Address string // ip address of worker
|
||||
// public server used for ping check (Cannot use worker address because they are not publicly exposed)
|
||||
PingServer string
|
||||
StunTurnServer string
|
||||
IsAvailable bool
|
||||
Zone string
|
||||
|
|
@ -57,10 +61,11 @@ func (o *Server) RouteWorker(workerClient *WorkerClient) {
|
|||
}
|
||||
|
||||
// NewWorkerClient returns a client connecting to worker. This connection exchanges information between workers and server
|
||||
func NewWorkerClient(c *websocket.Conn, serverID string, address string, stunturn string, zone string) *WorkerClient {
|
||||
func NewWorkerClient(c *websocket.Conn, serverID string, address string, stunturn string, zone, pingServer string) *WorkerClient {
|
||||
return &WorkerClient{
|
||||
Client: cws.NewClient(c),
|
||||
ServerID: serverID,
|
||||
PingServer: pingServer,
|
||||
Address: address,
|
||||
StunTurnServer: stunturn,
|
||||
IsAvailable: true,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/giongto35/cloud-game/pkg/config"
|
||||
"github.com/giongto35/cloud-game/pkg/config/worker"
|
||||
|
||||
"github.com/giongto35/cloud-game/pkg/util"
|
||||
|
|
@ -61,13 +63,13 @@ func (h *Handler) Run() {
|
|||
for {
|
||||
oClient, err := setupOverlordConnection(h.overlordHost, h.cfg.Zone)
|
||||
if err != nil {
|
||||
log.Println("Cannot connect to overlord. Retrying...")
|
||||
log.Printf("Cannot connect to overlord. %v Retrying...", err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
h.oClient = oClient
|
||||
log.Println("Connected to overlord successfully.")
|
||||
log.Println("Connected to overlord successfully.", oClient, err)
|
||||
go h.oClient.Heartbeat()
|
||||
h.RouteOverlord()
|
||||
h.oClient.Listen()
|
||||
|
|
@ -76,28 +78,43 @@ func (h *Handler) Run() {
|
|||
}
|
||||
|
||||
func setupOverlordConnection(ohost string, zone string) (*OverlordClient, error) {
|
||||
var scheme string
|
||||
|
||||
if *config.Mode == config.ProdEnv || *config.Mode == config.StagingEnv {
|
||||
scheme = "wss"
|
||||
} else {
|
||||
scheme = "ws"
|
||||
}
|
||||
|
||||
overlordURL := url.URL{
|
||||
Scheme: "ws",
|
||||
Scheme: scheme,
|
||||
Host: ohost,
|
||||
Path: "/wso",
|
||||
RawQuery: "zone=" + zone,
|
||||
}
|
||||
log.Println("Worker connecting to overlord:", overlordURL.String())
|
||||
|
||||
conn, err := createOverlordConnection(overlordURL.String())
|
||||
conn, err := createOverlordConnection(&overlordURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewOverlordClient(conn), nil
|
||||
}
|
||||
|
||||
func createOverlordConnection(ohost string) (*websocket.Conn, error) {
|
||||
c, _, err := websocket.DefaultDialer.Dial(ohost, nil)
|
||||
func createOverlordConnection(ourl *url.URL) (*websocket.Conn, error) {
|
||||
var d websocket.Dialer
|
||||
if ourl.Scheme == "wss" {
|
||||
d = websocket.Dialer{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
|
||||
} else {
|
||||
d = websocket.Dialer{}
|
||||
}
|
||||
|
||||
ws, _, err := d.Dial(ourl.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
return ws, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetOverlordClient() *OverlordClient {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,18 @@ package worker
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/giongto35/cloud-game/pkg/config"
|
||||
"github.com/giongto35/cloud-game/pkg/config/worker"
|
||||
"golang.org/x/crypto/acme"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
|
||||
"github.com/giongto35/cloud-game/pkg/monitoring"
|
||||
"github.com/golang/glog"
|
||||
|
|
@ -21,6 +26,8 @@ type OverWorker struct {
|
|||
monitoringServer *monitoring.ServerMonitoring
|
||||
}
|
||||
|
||||
const stagingLEURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
|
||||
func New(ctx context.Context, cfg worker.Config) *OverWorker {
|
||||
return &OverWorker{
|
||||
ctx: ctx,
|
||||
|
|
@ -50,6 +57,87 @@ func (o *OverWorker) Shutdown() {
|
|||
}
|
||||
}
|
||||
|
||||
func makeServerFromMux(mux *http.ServeMux) *http.Server {
|
||||
// set timeouts so that a slow or malicious client doesn't
|
||||
// hold resources forever
|
||||
return &http.Server{
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
IdleTimeout: 120 * time.Second,
|
||||
Handler: mux,
|
||||
}
|
||||
}
|
||||
|
||||
func makeHTTPServer() *http.Server {
|
||||
mux := &http.ServeMux{}
|
||||
mux.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
log.Println(w, "echo")
|
||||
})
|
||||
|
||||
return makeServerFromMux(mux)
|
||||
}
|
||||
|
||||
func makeHTTPToHTTPSRedirectServer() *http.Server {
|
||||
handleRedirect := func(w http.ResponseWriter, r *http.Request) {
|
||||
newURI := "https://" + r.Host + r.URL.String()
|
||||
http.Redirect(w, r, newURI, http.StatusFound)
|
||||
}
|
||||
mux := &http.ServeMux{}
|
||||
mux.HandleFunc("/", handleRedirect)
|
||||
|
||||
return makeServerFromMux(mux)
|
||||
}
|
||||
|
||||
func (o *OverWorker) spawnServer(port int) {
|
||||
var certManager *autocert.Manager
|
||||
var httpsSrv *http.Server
|
||||
|
||||
if *config.Mode == config.ProdEnv || *config.Mode == config.StagingEnv {
|
||||
var leurl string
|
||||
if *config.Mode == config.StagingEnv {
|
||||
leurl = stagingLEURL
|
||||
} else {
|
||||
leurl = acme.LetsEncryptURL
|
||||
}
|
||||
|
||||
certManager = &autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
Cache: autocert.DirCache("assets/cache"),
|
||||
Client: &acme.Client{DirectoryURL: leurl},
|
||||
}
|
||||
|
||||
httpsSrv = makeHTTPServer()
|
||||
httpsSrv.Addr = ":443"
|
||||
httpsSrv.TLSConfig = &tls.Config{GetCertificate: certManager.GetCertificate}
|
||||
|
||||
go func() {
|
||||
fmt.Printf("Starting HTTPS server on %s\n", httpsSrv.Addr)
|
||||
err := httpsSrv.ListenAndServeTLS("", "")
|
||||
if err != nil {
|
||||
log.Printf("httpsSrv.ListendAndServeTLS() failed with %s", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var httpSrv *http.Server
|
||||
if *config.Mode == config.ProdEnv || *config.Mode == config.StagingEnv {
|
||||
httpSrv = makeHTTPToHTTPSRedirectServer()
|
||||
} else {
|
||||
httpSrv = makeHTTPServer()
|
||||
}
|
||||
|
||||
if certManager != nil {
|
||||
httpSrv.Handler = certManager.HTTPHandler(httpSrv.Handler)
|
||||
}
|
||||
|
||||
httpSrv.Addr = ":" + strconv.Itoa(port)
|
||||
err := httpSrv.ListenAndServe()
|
||||
if err != nil {
|
||||
log.Printf("httpSrv.ListenAndServe() failed with %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// initializeWorker setup a worker
|
||||
func (o *OverWorker) initializeWorker() {
|
||||
worker := NewHandler(o.cfg)
|
||||
|
|
@ -77,12 +165,6 @@ func (o *OverWorker) initializeWorker() {
|
|||
|
||||
l.Close()
|
||||
|
||||
// echo endpoint is where user will request to test latency
|
||||
http.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
fmt.Fprintf(w, "echo")
|
||||
})
|
||||
|
||||
http.ListenAndServe(":"+strconv.Itoa(port), nil)
|
||||
o.spawnServer(port)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
web/game.html
vendored
2
web/game.html
vendored
|
|
@ -99,7 +99,7 @@
|
|||
<script src="/static/js/input/input.js?v=1"></script>
|
||||
<script src="/static/js/gameList.js?v=1"></script>
|
||||
<script src="/static/js/room.js?v=1"></script>
|
||||
<script src="/static/js/controller.js?v=1"></script>
|
||||
<script src="/static/js/controller.js?v=2"></script>
|
||||
<script src="/static/js/input/keyboard.js?v=1"></script>
|
||||
<script src="/static/js/input/touch.js?v=1"></script>
|
||||
<script src="/static/js/input/joystick.js?v=1"></script>
|
||||
|
|
|
|||
2
web/js/controller.js
vendored
2
web/js/controller.js
vendored
|
|
@ -50,7 +50,7 @@
|
|||
|
||||
Promise.all((data.addresses || []).map(address => {
|
||||
let beforeTime = Date.now();
|
||||
return ajax.fetch(`http://${address}:9000/echo?_=${beforeTime}`, {}, timeoutMs)
|
||||
return ajax.fetch(`${address}?_=${beforeTime}`, {method: "GET", redirect: "follow"}, timeoutMs)
|
||||
.then(() => ({[address]: Date.now() - beforeTime}), () => ({[address]: maxTimeoutMs}));
|
||||
})).then(results => {
|
||||
// const latencies = Object.assign({}, ...results);
|
||||
|
|
|
|||
8
web/js/network/socket.js
vendored
8
web/js/network/socket.js
vendored
|
|
@ -14,7 +14,13 @@ const socket = (() => {
|
|||
const init = (roomId, zone) => {
|
||||
const paramString = new URLSearchParams({room_id: roomId, zone: zone})
|
||||
|
||||
conn = new WebSocket(`ws://${location.host}/ws?${paramString.toString()}`);
|
||||
// if localhost
|
||||
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
|
||||
scheme = "ws"
|
||||
} else {
|
||||
scheme = "wss"
|
||||
}
|
||||
conn = new WebSocket(`${scheme}://${location.host}/ws?${paramString.toString()}`);
|
||||
|
||||
// Clear old roomID
|
||||
conn.onopen = () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue