From 95580544491e7373e47aae5467dbef20389e7afb Mon Sep 17 00:00:00 2001 From: giongto35 Date: Fri, 20 Mar 2020 00:50:29 +0800 Subject: [PATCH] Rename --- Makefile | 16 +++--- cmd/overlord/main.go | 14 +++--- cmd/{overworker => worker}/main.go | 0 docs/designdoc/README.md | 16 +++--- docs/designdoc/implementation/README.md | 16 +++--- docs/img/overlord.png | Bin 54345 -> 0 bytes pkg/config/worker/config.go | 20 ++++---- pkg/{overlord => coordinator}/browser.go | 38 +++++++-------- pkg/{overlord => coordinator}/config.go | 6 +-- .../coordinator.go} | 32 ++++++------ pkg/{overlord => coordinator}/handlers.go | 18 +++---- pkg/{overlord => coordinator}/session.go | 8 +-- pkg/{overlord => coordinator}/worker.go | 14 +++--- pkg/worker/{overlord.go => coordinator.go} | 46 +++++++++--------- pkg/worker/handlers.go | 46 +++++++++--------- pkg/worker/session.go | 4 +- pkg/worker/{overworker.go => worker.go} | 0 tests/e2e/main_test.go | 26 +++++----- 18 files changed, 160 insertions(+), 160 deletions(-) rename cmd/{overworker => worker}/main.go (100%) delete mode 100644 docs/img/overlord.png rename pkg/{overlord => coordinator}/browser.go (65%) rename pkg/{overlord => coordinator}/config.go (91%) rename pkg/{overlord/overlord.go => coordinator/coordinator.go} (82%) rename pkg/{overlord => coordinator}/handlers.go (94%) rename pkg/{overlord => coordinator}/session.go (74%) rename pkg/{overlord => coordinator}/worker.go (81%) rename pkg/worker/{overlord.go => coordinator.go} (80%) rename pkg/worker/{overworker.go => worker.go} (100%) diff --git a/Makefile b/Makefile index 3a4c04e9..0b4408c8 100644 --- a/Makefile +++ b/Makefile @@ -24,9 +24,9 @@ dep: # NOTE: there is problem with go mod vendor when it delete github.com/gen2brain/x264-go/x264c causing unable to build. https://github.com/golang/go/issues/26366 #build.cross: build -# CGO_ENABLED=1 GOOS=darwin GOARC=amd64 go build --ldflags '-linkmode external -extldflags "-static"' -o bin/overlord-darwin ./cmd/overlord +# CGO_ENABLED=1 GOOS=darwin GOARC=amd64 go build --ldflags '-linkmode external -extldflags "-static"' -o bin/coordinator-darwin ./cmd/coordinator # CGO_ENABLED=1 GOOS=darwin GOARC=amd64 go build --ldflags '-linkmode external -extldflags "-static"' -o bin/overworker-darwin ./cmd/overworker -# CC=arm-linux-musleabihf-gcc GOOS=linux GOARC=amd64 CGO_ENABLED=1 go build --ldflags '-linkmode external -extldflags "-static"' -o bin/overlord-linu ./cmd/overlord +# CC=arm-linux-musleabihf-gcc GOOS=linux GOARC=amd64 CGO_ENABLED=1 go build --ldflags '-linkmode external -extldflags "-static"' -o bin/coordinator-linu ./cmd/coordinator # CC=arm-linux-musleabihf-gcc GOOS=linux GOARC=amd64 CGO_ENABLED=1 go build --ldflags '-linkmode external -extldflags "-static"' -o bin/overworker-linux ./cmd/overworker # A user can invoke tests in different ways: @@ -64,20 +64,20 @@ dev.tools: ./hack/scripts/install_tools.sh dev.build: compile - go build -a -tags netgo -ldflags '-w' -o bin/overlord ./cmd/overlord + go build -a -tags netgo -ldflags '-w' -o bin/coordinator ./cmd/coordinator go build -a -tags netgo -ldflags '-w' -o bin/overworker ./cmd/overworker dev.build-local: - go build -o bin/overlord ./cmd/overlord + go build -o bin/coordinator ./cmd/coordinator go build -o bin/overworker ./cmd/overworker dev.run: dev.build-local - ./bin/overlord --v=5 & - ./bin/overworker --overlordhost localhost:8000 + ./bin/coordinator --v=5 & + ./bin/overworker --coordinatorhost localhost:8000 dev.run-docker: docker build . -t cloud-game-local docker stop cloud-game-local || true docker rm cloud-game-local || true - # Overlord and worker should be run separately. - docker run --privileged -v $PWD/games:/cloud-game/games -d --name cloud-game-local -p 8000:8000 -p 9000:9000 cloud-game-local bash -c "overlord --v=5 & overworker --overlordhost localhost:8000" + # Coordinator and worker should be run separately. + docker run --privileged -v $PWD/games:/cloud-game/games -d --name cloud-game-local -p 8000:8000 -p 9000:9000 cloud-game-local bash -c "coordinator --v=5 & overworker --coordinatorhost localhost:8000" diff --git a/cmd/overlord/main.go b/cmd/overlord/main.go index 066861ec..de4b74be 100644 --- a/cmd/overlord/main.go +++ b/cmd/overlord/main.go @@ -7,7 +7,7 @@ import ( "os/signal" "time" - "github.com/giongto35/cloud-game/pkg/overlord" + "github.com/giongto35/cloud-game/pkg/coordinator" "github.com/giongto35/cloud-game/pkg/util/logging" "github.com/golang/glog" "github.com/spf13/pflag" @@ -16,7 +16,7 @@ import ( func main() { rand.Seed(time.Now().UTC().UnixNano()) - cfg := overlord.NewDefaultConfig() + cfg := coordinator.NewDefaultConfig() cfg.AddFlags(pflag.CommandLine) logging.Init() @@ -24,11 +24,11 @@ func main() { ctx, cancelCtx := context.WithCancel(context.Background()) - glog.Infof("Initializing overlord server") - glog.V(4).Infof("Overlord configs %v", cfg) - o := overlord.New(ctx, cfg) + glog.Infof("Initializing coordinator server") + glog.V(4).Infof("Coordinator configs %v", cfg) + o := coordinator.New(ctx, cfg) if err := o.Run(); err != nil { - glog.Errorf("Failed to run overlord server, reason %v", err) + glog.Errorf("Failed to run coordinator server, reason %v", err) os.Exit(1) } @@ -36,7 +36,7 @@ func main() { signal.Notify(stop, os.Interrupt) select { case <-stop: - glog.Infoln("Received SIGTERM, Quiting Overlord") + glog.Infoln("Received SIGTERM, Quiting Coordinator") o.Shutdown() cancelCtx() } diff --git a/cmd/overworker/main.go b/cmd/worker/main.go similarity index 100% rename from cmd/overworker/main.go rename to cmd/worker/main.go diff --git a/docs/designdoc/README.md b/docs/designdoc/README.md index ad3f48ab..b15cd503 100644 --- a/docs/designdoc/README.md +++ b/docs/designdoc/README.md @@ -1,6 +1,6 @@ # Web-based Cloud Gaming Service Design Document -Web-based Cloud Gaming Service contains multiple workers for gaming stream and a coordinator (Overlord) for distributing traffic and pairing up connection. +Web-based Cloud Gaming Service contains multiple workers for gaming stream and a coordinator (Coordinator) for distributing traffic and pairing up connection. ## Worker @@ -12,14 +12,14 @@ Worker is responsible for streaming game to frontend - On the other hand, input from users is sent to workers over WebRTC DataChannel. Game logic on the emulator will be updated based on the input stream. - Game state is stored in cloud storage, so all workers can collaborate and keep the same understanding with each other. It allows user can continue from the saved state in the next time. -## Overlord +## Coordinator -Overlord is loadbalancer and coordinator, which is in charge of picking the most suitable workers for a user. Every time a user connects to Overlord, it will collect all the metric from all workers, i.e free CPU resources and latency from worker to user. Overlord will decide the best candidate based on the metric and setup peer-to-peer connection between worker and user based on WebRTC protocol +Coordinator is loadbalancer and coordinator, which is in charge of picking the most suitable workers for a user. Every time a user connects to Coordinator, it will collect all the metric from all workers, i.e free CPU resources and latency from worker to user. Coordinator will decide the best candidate based on the metric and setup peer-to-peer connection between worker and user based on WebRTC protocol -![Architecture](../img/overlord.png) +![Architecture](../img/coordinator.png) -1. A user connected to Overlord . -2. Overlord will find the most suitable worker to serve the user. -3. Overlord collects all latencies from workers to users as well as CPU usage on each machine. -4. Overlord setup peer-to-peer handshake between worker and user by exchanging Session Description Protocol. +1. A user connected to Coordinator . +2. Coordinator will find the most suitable worker to serve the user. +3. Coordinator collects all latencies from workers to users as well as CPU usage on each machine. +4. Coordinator setup peer-to-peer handshake between worker and user by exchanging Session Description Protocol. 5. A game is hosted on worker and streamed to the user. diff --git a/docs/designdoc/implementation/README.md b/docs/designdoc/implementation/README.md index ce52ecf1..17626a35 100644 --- a/docs/designdoc/implementation/README.md +++ b/docs/designdoc/implementation/README.md @@ -4,14 +4,14 @@ ``` . ├── cmd: service entrypoint -│ ├── main.go: Spawn overlord or worker based on flag +│ ├── main.go: Spawn coordinator or worker based on flag │ └── main_test.go ├── static: static file for front end │ ├── js │ │ └── ws.js: client logic │ ├── game.html: frontend with gameboy ui │ └── index_ws.html: raw frontend without ui -├── overlord: coordinator +├── coordinator: coordinator │ ├── handlers.go: coordinator entrypoint │ ├── browser.go: router listening to browser │ └── worker.go: router listening to worker @@ -21,7 +21,7 @@ │ │ ├── room.go: room logic │ │ └── media.go: video + audio encoding │ ├── handlers.go: worker entrypoint -│ └── overlord.go: router listening to overlord +│ └── coordinator.go: router listening to coordinator ├── emulator: emulator internal │ ├── nes: NES device internal │ ├── director.go: coordinator of views @@ -35,9 +35,9 @@ Room is a fundamental part of the system. Each user session will spawn a room with a game running inside. There is a pipeline to encode images and audio and stream them out from emulator to user. The pipeline also listens to all input and streams to the emulator. ## Worker -Worker is an instance that can be provisioned to scale up the traffic. There are multiple rooms inside a worker. Worker will listen to overlord events in `overlord.go`. +Worker is an instance that can be provisioned to scale up the traffic. There are multiple rooms inside a worker. Worker will listen to coordinator events in `coordinator.go`. -## Overlord -Overlord is the coordinator, which handles all communication with workers and frontend. -Overlord will pair up a worker and a user for peer streaming. In WebRTC handshaking, two peers need to exchange their signature (Session Description Protocol) to initiate a peerconnection. -Events come from frontend will be handled in `overlord/browser.go`. Events come from worker will be handled in `overlord/worker.go`. Overlord stays in the middle and relays handshake packages between workers and user. +## Coordinator +Coordinator is the coordinator, which handles all communication with workers and frontend. +Coordinator will pair up a worker and a user for peer streaming. In WebRTC handshaking, two peers need to exchange their signature (Session Description Protocol) to initiate a peerconnection. +Events come from frontend will be handled in `coordinator/browser.go`. Events come from worker will be handled in `coordinator/worker.go`. Coordinator stays in the middle and relays handshake packages between workers and user. diff --git a/docs/img/overlord.png b/docs/img/overlord.png deleted file mode 100644 index 9eb927bea3c9d72b87c4ced6160e71e9f171921c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54345 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 Room rooms map[string]*room.Room // ID of the current server globalwise @@ -50,34 +50,34 @@ func NewHandler(cfg worker.Config) *Handler { // Init online storage onlineStorage := storage.NewInitClient() return &Handler{ - rooms: map[string]*room.Room{}, - sessions: map[string]*Session{}, - overlordHost: cfg.OverlordAddress, - cfg: cfg, - onlineStorage: onlineStorage, + rooms: map[string]*room.Room{}, + sessions: map[string]*Session{}, + coordinatorHost: cfg.CoordinatorAddress, + cfg: cfg, + onlineStorage: onlineStorage, } } // Run starts a Handler running logic func (h *Handler) Run() { for { - oClient, err := setupOverlordConnection(h.overlordHost, h.cfg.Zone) + oClient, err := setupCoordinatorConnection(h.coordinatorHost, h.cfg.Zone) if err != nil { - log.Printf("Cannot connect to overlord. %v Retrying...", err) + log.Printf("Cannot connect to coordinator. %v Retrying...", err) time.Sleep(time.Second) continue } h.oClient = oClient - log.Println("Connected to overlord successfully.", oClient, err) + log.Println("Connected to coordinator successfully.", oClient, err) go h.oClient.Heartbeat() - h.RouteOverlord() + h.RouteCoordinator() h.oClient.Listen() - // If cannot listen, reconnect to overlord + // If cannot listen, reconnect to coordinator } } -func setupOverlordConnection(ohost string, zone string) (*OverlordClient, error) { +func setupCoordinatorConnection(ohost string, zone string) (*CoordinatorClient, error) { var scheme string if *config.Mode == config.ProdEnv || *config.Mode == config.StagingEnv { @@ -86,22 +86,22 @@ func setupOverlordConnection(ohost string, zone string) (*OverlordClient, error) scheme = "ws" } - overlordURL := url.URL{ + coordinatorURL := url.URL{ Scheme: scheme, Host: ohost, Path: "/wso", RawQuery: "zone=" + zone, } - log.Println("Worker connecting to overlord:", overlordURL.String()) + log.Println("Worker connecting to coordinator:", coordinatorURL.String()) - conn, err := createOverlordConnection(&overlordURL) + conn, err := createCoordinatorConnection(&coordinatorURL) if err != nil { return nil, err } - return NewOverlordClient(conn), nil + return NewCoordinatorClient(conn), nil } -func createOverlordConnection(ourl *url.URL) (*websocket.Conn, error) { +func createCoordinatorConnection(ourl *url.URL) (*websocket.Conn, error) { var d websocket.Dialer if ourl.Scheme == "wss" { d = websocket.Dialer{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} @@ -117,7 +117,7 @@ func createOverlordConnection(ourl *url.URL) (*websocket.Conn, error) { return ws, nil } -func (h *Handler) GetOverlordClient() *OverlordClient { +func (h *Handler) GetCoordinatorClient() *CoordinatorClient { return h.oClient } diff --git a/pkg/worker/session.go b/pkg/worker/session.go index 6a1e9856..0dad3e47 100644 --- a/pkg/worker/session.go +++ b/pkg/worker/session.go @@ -3,8 +3,8 @@ package worker import "github.com/giongto35/cloud-game/pkg/webrtc" // Session represents a session connected from the browser to the current server -// It requires one connection to browser and one connection to the overlord -// connection to browser is 1-1. connection to overlord is n - 1 +// It requires one connection to browser and one connection to the coordinator +// connection to browser is 1-1. connection to coordinator is n - 1 // Peerconnection can be from other server to ensure better latency type Session struct { ID string diff --git a/pkg/worker/overworker.go b/pkg/worker/worker.go similarity index 100% rename from pkg/worker/overworker.go rename to pkg/worker/worker.go diff --git a/tests/e2e/main_test.go b/tests/e2e/main_test.go index df42f071..fb282df9 100644 --- a/tests/e2e/main_test.go +++ b/tests/e2e/main_test.go @@ -27,7 +27,7 @@ package e2e // URLs: []string{"stun:stun.l.google.com:19302"}, // }}} // -// func initOverlord() (*httptest.Server, *httptest.Server) { +// func initCoordinator() (*httptest.Server, *httptest.Server) { // server := overlord.NewServer() // overlordWorker := httptest.NewServer(http.HandlerFunc(server.WSO)) // overlordBrowser := httptest.NewServer(http.HandlerFunc(server.WS)) @@ -137,7 +137,7 @@ package e2e // // If receive roomID, the server is running correctly // } // -// func TestSingleServerOneOverlord(t *testing.T) { +// func TestSingleServerOneCoordinator(t *testing.T) { // /* // Case scenario: // - A server X are initilized @@ -146,7 +146,7 @@ package e2e // - Room received not empty. // */ // -// oworker, obrowser := initOverlord() +// oworker, obrowser := initCoordinator() // defer obrowser.Close() // defer oworker.Close() // @@ -178,7 +178,7 @@ package e2e // fmt.Println("Done") // } // -// func TestTwoServerOneOverlord(t *testing.T) { +// func TestTwoServerOneCoordinator(t *testing.T) { // /* // Case scenario: // - Two server X, Y are initilized @@ -190,7 +190,7 @@ package e2e // - Client B can join a room hosted on A // */ // -// oworker, obrowser := initOverlord() +// oworker, obrowser := initCoordinator() // defer obrowser.Close() // defer oworker.Close() // @@ -277,7 +277,7 @@ package e2e // TODO: Current test just make sure the game is running, not check if the game is the same // */ // -// oworker, obrowser := initOverlord() +// oworker, obrowser := initCoordinator() // defer obrowser.Close() // defer oworker.Close() // @@ -306,7 +306,7 @@ package e2e // // log.Println("Closing room and server") // client.Close() -// worker.GetOverlordClient().Close() +// worker.GetCoordinatorClient().Close() // worker.Close() // // // Close server and reconnect @@ -356,7 +356,7 @@ package e2e // */ // // This test only run if GCP storage is set // -// oworker, obrowser := initOverlord() +// oworker, obrowser := initCoordinator() // defer obrowser.Close() // defer oworker.Close() // @@ -390,7 +390,7 @@ package e2e // // log.Println("Closing room and server") // client.Close() -// worker.GetOverlordClient().Close() +// worker.GetCoordinatorClient().Close() // worker.Close() // // Remove room on local // path := util.GetSavePath(saveRoomID) @@ -429,7 +429,7 @@ package e2e // fmt.Println("Done") // } -//func TestRejoinNoOverlordMultiple(t *testing.T) { +//func TestRejoinNoCoordinatorMultiple(t *testing.T) { //[> //Case scenario: //- A server X without connecting to overlord @@ -470,7 +470,7 @@ package e2e //} -//func TestRejoinWithOverlordMultiple(t *testing.T) { +//func TestRejoinWithCoordinatorMultiple(t *testing.T) { //[> //Case scenario: //- A server X is initialized connecting to overlord @@ -480,10 +480,10 @@ package e2e //*/ //// Init slave server -//o := initOverlord() +//o := initCoordinator() //defer o.Close() -//oconn := connectTestOverlordServer(t, o.URL) +//oconn := connectTestCoordinatorServer(t, o.URL) //// Init slave server //s := initServer(t, oconn) //defer s.Close()