Match best worker based on latency + Experiment with Singapore Host (#60)

* Add echo endpoint

* Fix async

* Use latency map

* Only start webRTC after worker match

* Experiment with Singapore server

* Update comments
This commit is contained in:
giongto35 2019-06-21 03:47:35 +08:00 committed by GitHub
parent e33126c67c
commit fafae16756
7 changed files with 74 additions and 22 deletions

2
README.md vendored
View file

@ -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.

View file

@ -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)
}
}

View file

@ -159,6 +159,7 @@ func (c *Client) Listen() {
err = json.Unmarshal(rawMsg, &wspacket)
if err != nil {
log.Println("Warn: error decoding", rawMsg)
continue
}

View file

@ -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
}

2
run_local_docker.sh vendored
View file

@ -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"

2
static/game.html vendored
View file

@ -94,7 +94,7 @@
<script src="/static/js/gesture_keyboard.js?1"></script>
<script src="/static/js/gesture_touch.js?1"></script>
<script src="/static/js/gesture_joystick.js?1"></script>
<script src="/static/js/ws.js?2"></script>
<script src="/static/js/ws.js?4"></script>
<script src="/static/js/init.js?1"></script>

63
static/js/ws.js vendored
View file

@ -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)