From 3a34fab09816b030b7a828fbfc010118c532fb34 Mon Sep 17 00:00:00 2001 From: giongto35 Date: Sat, 20 Apr 2019 04:24:13 +0800 Subject: [PATCH] Register server IP --- main.go | 190 +++++++++++++++++++++++++++++----------------------- overlord.go | 57 ++++++++++++++++ ws.go | 35 ++++++++-- 3 files changed, 191 insertions(+), 91 deletions(-) create mode 100644 overlord.go diff --git a/main.go b/main.go index 71f830b0..96fff91b 100644 --- a/main.go +++ b/main.go @@ -145,13 +145,14 @@ func isRoomRunning(roomID string) bool { } // startSession handles one session call -func startSession(webRTC *webrtc.WebRTC, gameName string, roomID string, playerIndex int) string { +func startSession(webRTC *webrtc.WebRTC, gameName string, roomID string, playerIndex int) (rRoomID string, isNewRoom bool) { cleanSession(webRTC) // If the roomID is empty, // or the roomID doesn't have any running sessions (room was closed) // we spawn a new room if roomID == "" || !isRoomRunning(roomID) { roomID = initRoom(roomID, gameName) + isNewRoom = true } // TODO: Might have race condition @@ -161,40 +162,14 @@ func startSession(webRTC *webrtc.WebRTC, gameName string, roomID string, playerI webRTC.AttachRoomID(roomID) go startWebRTCSession(room, webRTC, playerIndex) - return roomID + return roomID, false } -// If it's overlord, handle overlord connection (from host to overlord) -func wso(w http.ResponseWriter, r *http.Request) { - fmt.Println("Connected") - c, err := upgrader.Upgrade(w, r, nil) - if err != nil { - log.Print("[!] WS upgrade:", err) - return - } - defer c.Close() - - client := NewClient(c, webrtc.NewWebRTC()) - - client.syncReceive("ping", func(req WSPacket) WSPacket { - log.Println("received Ping, sending Pong") - return WSPacket{ - ID: "pong", - } - }) - client.listen() -} - -const overlordHost = "ws://localhost:9000/wso" - -func createOverlordClient() (*websocket.Conn, error) { - c, _, err := websocket.DefaultDialer.Dial(overlordHost, nil) - if err != nil { - log.Fatal("dial:", err) - return nil, err - } - - return c, nil +// Session represents a session connected from the browser to the current server +type Session struct { + client *Client + oclient *Client + ServerID string } // Handle normal traffic (from browser to host) @@ -209,11 +184,22 @@ func ws(w http.ResponseWriter, r *http.Request) { var roomID string var playerIndex int + var oclient *Client + // Create connection to overlord client := NewClient(c, webrtc.NewWebRTC()) - client.syncReceive("initwebrtc", func(req WSPacket) WSPacket { + wssession := Session{ + client: client, + // The server session is maintaining + } + + if !IsOverlord { + wssession.NewOverlordClient() + } + + client.syncReceive("initwebrtc", func(resp WSPacket) WSPacket { log.Println("Received user SDP") - localSession, err := client.peerconnection.StartClient(req.Data, width, height) + localSession, err := client.peerconnection.StartClient(resp.Data, width, height) if err != nil { log.Fatalln(err) } @@ -224,84 +210,75 @@ func ws(w http.ResponseWriter, r *http.Request) { } }) - client.syncReceive("save", func(req WSPacket) (res WSPacket) { + client.syncReceive("save", func(resp WSPacket) (req WSPacket) { log.Println("Saving game state") - res.ID = "save" - res.Data = "ok" + req.ID = "save" + req.Data = "ok" if roomID != "" { err = rooms[roomID].director.SaveGame() if err != nil { log.Println("[!] Cannot save game state: ", err) - res.Data = "error" + req.Data = "error" } } else { - res.Data = "error" + req.Data = "error" } - return res + return req }) - client.syncReceive("load", func(req WSPacket) (res WSPacket) { + client.syncReceive("load", func(resp WSPacket) (req WSPacket) { log.Println("Loading game state") - res.ID = "load" - res.Data = "ok" + req.ID = "load" + req.Data = "ok" if roomID != "" { err = rooms[roomID].director.LoadGame() if err != nil { log.Println("[!] Cannot load game state: ", err) - res.Data = "error" + req.Data = "error" } } else { - res.Data = "error" + req.Data = "error" } - return res + return req }) - client.syncReceive("start", func(req WSPacket) (res WSPacket) { - gameName = req.Data - roomID = req.RoomID - playerIndex = req.PlayerIndex + client.syncReceive("start", func(resp WSPacket) (req WSPacket) { + gameName = resp.Data + roomID = resp.RoomID + playerIndex = resp.PlayerIndex + isNewRoom := false //log.Println("Ping from server with game:", gameName) //res.ID = "pong" log.Println("Starting game") - roomID = startSession(client.peerconnection, gameName, roomID, playerIndex) - res.ID = "start" - res.RoomID = roomID + roomID, isNewRoom = startSession(client.peerconnection, gameName, roomID, playerIndex) + if isNewRoom { + oclient.send(WSPacket{ + ID: "RegisterRoom", + Data: roomID, + }) + } + req.ID = "start" + req.RoomID = roomID - return res + return req }) - client.syncReceive("candidate", func(req WSPacket) (res WSPacket) { + client.syncReceive("candidate", func(resp WSPacket) (req WSPacket) { // Unuse code hi := pionRTC.ICECandidateInit{} - err = json.Unmarshal([]byte(req.Data), &hi) + err = json.Unmarshal([]byte(resp.Data), &hi) if err != nil { log.Println("[!] Cannot parse candidate: ", err) } else { // webRTC.AddCandidate(hi) } - res.ID = "candidate" + req.ID = "candidate" - return res + return req }) - // Create connection to overlord - if !IsOverlord { - oc, err := createOverlordClient() - if err != nil { - log.Println("Cannot connect to overlord") - } - oclient := NewClient(oc, webrtc.NewWebRTC()) - oclient.syncSend(WSPacket{ - ID: "ping", - }, - func(resp WSPacket) { - log.Println("pong") - }, - ) - } - client.listen() } @@ -398,12 +375,57 @@ func removeSession(w *webrtc.WebRTC, room *Room) { } } -//func (o *Overlord) isRemoteRoom(roomID string) bool { -//err := c.WriteMessage(websocket.TextMessage, []byte(stRes)) -//o.ws.WriteMessage() -//_, message, err := o.ws.ReadMessage() -//if message == "isRemoteRoom" { -//return true -//} -//return false -//} +func GetServerIDOfRoom(oc Client, roomID string) chan string { + res := make(chan string) + + oc.syncSend(WSPacket{ + ID: "getRoom", + }, func(resp WSPacket) { + res <- resp.Data + }) + return res +} + +const overlordHost = "ws://localhost:9000/wso" + +func createOverlordConnection() (*websocket.Conn, error) { + c, _, err := websocket.DefaultDialer.Dial(overlordHost, nil) + if err != nil { + log.Fatal("dial:", err) + return nil, err + } + + return c, nil +} + +func (s *Session) NewOverlordClient() { + oc, err := createOverlordConnection() + if err != nil { + log.Println("Cannot connect to overlord") + } + oclient := NewClient(oc, webrtc.NewWebRTC()) + oclient.syncSend( + WSPacket{ + ID: "ping", + }, + func(resp WSPacket) { + log.Println("Received pong full flow") + }, + ) + + // Received from overlord the serverID + oclient.syncReceive( + "serverID", + func(response WSPacket) (request WSPacket) { + // Stick session with serverID got from overlord + log.Println("Received serverID ", response.Data) + s.ServerID = response.Data + + return EmptyPacket + }, + ) + + go oclient.listen() + + return +} diff --git a/overlord.go b/overlord.go new file mode 100644 index 00000000..8ab29130 --- /dev/null +++ b/overlord.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + "log" + "math/rand" + "net/http" + "strconv" + + "github.com/giongto35/cloud-game/webrtc" +) + +var overlordRooms = map[string]string{} + +// servers are the map serverID to server Client +var servers = map[string]Client{} + +// If it's overlord, handle overlord connection (from host to overlord) +func wso(w http.ResponseWriter, r *http.Request) { + fmt.Println("Connected") + c, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Print("[!] WS upgrade:", err) + return + } + defer c.Close() + + // register new server + serverID := strconv.Itoa(rand.Int()) + log.Println("A new server connected ", serverID) + + client := NewClient(c, webrtc.NewWebRTC()) + + client.send( + WSPacket{ + ID: "serverID", + Data: serverID, + }, + ) + + client.syncReceive("ping", func(resp WSPacket) WSPacket { + log.Println("received Ping, sending Pong") + return WSPacket{ + ID: "pong", + } + }) + + client.syncReceive("registerRoom", func(resp WSPacket) WSPacket { + log.Println("received registerRoom") + overlordRooms[resp.Data] = serverID + return WSPacket{ + ID: "registerRoom", + } + }) + + client.listen() +} diff --git a/ws.go b/ws.go index a529047e..57898684 100644 --- a/ws.go +++ b/ws.go @@ -3,6 +3,8 @@ package main import ( "encoding/json" "log" + "math/rand" + "strconv" "time" "github.com/giongto35/cloud-game/webrtc" @@ -31,6 +33,8 @@ type WSPacket struct { PacketID string } +var EmptyPacket = WSPacket{} + func NewClient(conn *websocket.Conn, webrtc *webrtc.WebRTC) *Client { sendCallback := map[string]func(WSPacket){} recvCallback := map[string]func(WSPacket){} @@ -43,22 +47,39 @@ func NewClient(conn *websocket.Conn, webrtc *webrtc.WebRTC) *Client { } } -// syncSend sends a packet and trigger callback when the packet comes back -func (c *Client) syncSend(packet WSPacket, callback func(msg WSPacket)) { - data, err := json.Marshal(packet) +// send sends a normal packet +func (c *Client) send(request WSPacket) { + data, err := json.Marshal(request) if err != nil { return } c.conn.WriteMessage(websocket.TextMessage, data) - c.sendCallback[packet.PacketID] = callback +} + +// syncSend sends a packet and trigger callback when the packet comes back +func (c *Client) syncSend(request WSPacket, callback func(response WSPacket)) { + request.PacketID = strconv.Itoa(rand.Int()) + data, err := json.Marshal(request) + if err != nil { + return + } + + c.conn.WriteMessage(websocket.TextMessage, data) + c.sendCallback[request.PacketID] = callback } // syncReceive receive and response back -func (c *Client) syncReceive(id string, f func(request WSPacket) (response WSPacket)) { - c.recvCallback[id] = func(request WSPacket) { - packet := f(request) +func (c *Client) syncReceive(id string, f func(response WSPacket) (request WSPacket)) { + c.recvCallback[id] = func(response WSPacket) { + packet := f(response) + // Add Meta data + packet.PacketID = response.PacketID + // Skip rqeuest if it is EmptyPacket + if packet == EmptyPacket { + return + } resp, err := json.Marshal(packet) if err != nil { log.Println("[!] json marshal error:", err)