diff --git a/README.md b/README.md index 557fd6c5..3d5ddc9b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Klog, Web-based Cloud Gaming Service - **US West (San Francisco)**: [http://usw.cloud.webgame2d.com](http://usw.cloud.webgame2d.com) - **US East(New York)**: [http://use.cloud.webgame2d.com](http://use.cloud.webgame2d.com) -- **Singapore**: [http://sg.cloud.webgame2d.com](http://sg.cloud.webgame2d.com) - **Europe (London)**: [http://eu.cloud.webgame2d.com](http://eu.cloud.webgame2d.com) +- **Singapore**: [http://cloud.webgame2d.com](http://sg.cloud.webgame2d.com) - **Europe (London)**: [http://eu.cloud.webgame2d.com](http://eu.cloud.webgame2d.com) - [**Game Instruction**](document/instruction/) For the best gaming experience, please select the closest region to you. diff --git a/cmd/main.go b/cmd/main.go index 7209e05a..a8ac70ab 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -2,6 +2,7 @@ package main import ( "flag" + "fmt" "log" "math/rand" "net" @@ -77,6 +78,12 @@ func initializeWorker() { http.Handle("/metrics", promhttp.Handler()) } + // 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) } } diff --git a/cws/cws.go b/cws/cws.go index 2a5abebb..47e3dc78 100644 --- a/cws/cws.go +++ b/cws/cws.go @@ -159,6 +159,7 @@ func (c *Client) Listen() { err = json.Unmarshal(rawMsg, &wspacket) if err != nil { + log.Println("Warn: error decoding", rawMsg) continue } diff --git a/overlord/handlers.go b/overlord/handlers.go index 34a404c2..7869495a 100644 --- a/overlord/handlers.go +++ b/overlord/handlers.go @@ -1,6 +1,7 @@ package overlord import ( + "encoding/json" "errors" "fmt" "html/template" @@ -8,7 +9,6 @@ import ( "math" "math/rand" "net/http" - "strconv" "strings" "github.com/giongto35/cloud-game/config" @@ -232,13 +232,18 @@ func (o *Server) getLatencyMapFromBrowser(client *BrowserClient) map[*WorkerClie ID: "checkLatency", Data: strings.Join(addressList, ","), }) - log.Println("Received latency list:", data.Data) - latencies := strings.Split(data.Data, ",") - log.Println("Received latency list:", latencies) - for i, workerClient := range workersList { - il, _ := strconv.Atoi(latencies[i]) - latencyMap[workerClient] = int64(il) + respLatency := map[string]int64{} + err := json.Unmarshal([]byte(data.Data), &respLatency) + if err != nil { + log.Println(err) + return latencyMap + } + + for _, workerClient := range workersList { + if latency, ok := respLatency[workerClient.Address]; ok { + latencyMap[workerClient] = latency + } } return latencyMap } diff --git a/run_local_docker.sh b/run_local_docker.sh index d4874e0f..999da164 100755 --- a/run_local_docker.sh +++ b/run_local_docker.sh @@ -3,4 +3,4 @@ docker build . -t cloud-game-local docker stop cloud-game-local docker rm cloud-game-local # Overlord and worker should be run separately. Local is for demo purpose -docker run --privileged -d --name cloud-game-local -p 8000:8000 cloud-game-local bash -c "cmd -overlordhost ws://localhost:8000/wso & cmd -overlordhost overlord" +docker run --privileged -d --name cloud-game-local -p 8000:8000 -p 9000:9000 cloud-game-local bash -c "cmd -overlordhost ws://localhost:8000/wso & cmd -overlordhost overlord" diff --git a/static/game.html b/static/game.html index 9523ee19..c3232865 100644 --- a/static/game.html +++ b/static/game.html @@ -94,7 +94,7 @@ - + diff --git a/static/js/ws.js b/static/js/ws.js index 6a99564b..b3682fed 100644 --- a/static/js/ws.js +++ b/static/js/ws.js @@ -10,7 +10,6 @@ conn.onopen = () => { log("Send ping pong frequently") pingpongTimer = setInterval(sendPing, 1000 / PINGPONGPS) - startWebRTC(); } conn.onerror = error => { @@ -90,24 +89,63 @@ conn.onmessage = e => { var s = d["data"]; var latencyList = []; curPacketID = d["packet_id"]; + latencyPacketID = curPacketID; addrs = s.split(",") + + var latenciesMap = {}; + var cntResp = 0; + beforeTime = Date.now(); for (const addr of addrs) { - beforeTime = Date.now(); + var sumLatency = 0 + // TODO: Clean code, use async var xmlHttp = new XMLHttpRequest(); - xmlHttp.open( "GET", addr+"/echo", false ); // false for synchronous request - xmlHttp.send( null ); + xmlHttp.open( "GET", "http://"+addr+":9000/echo?_=" + beforeTime, true ); // false for synchronous request, add date to not calling cache + xmlHttp.timeout = 1000 + xmlHttp.ontimeout = () => { + cntResp++; + afterTime = Date.now(); + //sumLatency += afterTime - beforeTime + latenciesMap[addr] = afterTime - beforeTime + if (cntResp == addrs.length) { + log(`Send latency list ${latenciesMap}`) + log(curPacketID) - resp = xmlHttp.responseText - afterTime = Date.now(); - latencyList.push(afterTime - beforeTime) + conn.send(JSON.stringify({"id": "checkLatency", "data": JSON.stringify(latenciesMap), "packet_id": latencyPacketID})); + startWebRTC(); + } + } + xmlHttp.onload = () => { + cntResp++; + afterTime = Date.now(); + //sumLatency += afterTime - beforeTime + latenciesMap[addr] = afterTime - beforeTime + if (cntResp == addrs.length) { + log(`Send latency list ${latenciesMap}`) + log(curPacketID) + + //conn.send(JSON.stringify({"id": "checkLatency", "data": latenciesMap, "packet_id": latencyPacketID})); + conn.send(JSON.stringify({"id": "checkLatency", "data": JSON.stringify(latenciesMap), "packet_id": latencyPacketID})); + startWebRTC(); + } + } + xmlHttp.send( null ); } - log(`Send latency list ${latencyList.join()}`) - log(curPacketID) - conn.send(JSON.stringify({"id": "checkLatency", "data": latencyList.join(), "packet_id": curPacketID})); } } +function updateLatencies(beforeTime, addr, latenciesMap, cntResp, curPacketID) { + afterTime = Date.now(); + //sumLatency += afterTime - beforeTime + latenciesMap[addr] = afterTime - beforeTime + if (cntResp == addrs.length) { + log(`Send latency list ${latenciesMap}`) + log(curPacketID) + + conn.send(JSON.stringify({"id": "checkLatency", "data": latenciesMap, "packet_id": curPacketID})); + } +} + function sendPing() { // TODO: format the package with time conn.send(JSON.stringify({"id": "heartbeat", "data": Date.now().toString()})); @@ -256,7 +294,8 @@ function startWebRTC() { session = btoa(JSON.stringify(pc.localDescription)); log("Send SDP to remote peer"); // TODO: Fix curPacketID - conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID})); + //conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID})); + conn.send(JSON.stringify({"id": "initwebrtc", "data": session})); iceSent = true } } else { @@ -267,7 +306,7 @@ function startWebRTC() { if (!iceSent) { log("Ice gathering timeout, send anyway") session = btoa(JSON.stringify(pc.localDescription)); - conn.send(JSON.stringify({"id": "initwebrtc", "data": session, "packet_id": curPacketID})); + conn.send(JSON.stringify({"id": "initwebrtc", "data": session})); iceSent = true; } }, ICE_TIMEOUT)