mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-22 17:47:11 +00:00
WIP
This commit is contained in:
parent
81cdf27acc
commit
dd415f1cce
6 changed files with 191 additions and 142 deletions
74
cmd/main.go
74
cmd/main.go
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"strings"
|
||||
|
|
@ -29,6 +28,47 @@ var writeWait = 30 * time.Second
|
|||
var IsOverlord = false
|
||||
var upgrader = websocket.Upgrader{}
|
||||
|
||||
// initilizeOverlord setup an overlord server
|
||||
func initilizeOverlord() {
|
||||
overlord := overlord.NewServer()
|
||||
|
||||
log.Println("http://localhost:9000")
|
||||
|
||||
// Can consider Overlord works as server but it is complicated
|
||||
http.HandleFunc("/wso", overlord.WSO)
|
||||
http.ListenAndServe(":9000", nil)
|
||||
}
|
||||
|
||||
func createOverlordConnection() (*websocket.Conn, error) {
|
||||
c, _, err := websocket.DefaultDialer.Dial(*config.OverlordHost, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// initializeServer setup a server
|
||||
func initializeServer() {
|
||||
conn, err := createOverlordConnection()
|
||||
if err != nil {
|
||||
log.Println("Cannot connect to overlord")
|
||||
log.Println("Run as a single server")
|
||||
}
|
||||
|
||||
handler := handler.NewHandler(conn)
|
||||
|
||||
// ignore origin
|
||||
upgrader.CheckOrigin = func(r *http.Request) bool { return true }
|
||||
|
||||
http.HandleFunc("/", handler.GetWeb)
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
|
||||
http.HandleFunc("/ws", handler.WS)
|
||||
|
||||
log.Println("http://localhost:" + *config.Port)
|
||||
http.ListenAndServe(":"+*config.Port, nil)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
log.Println("Usage: ./game [debug]")
|
||||
|
|
@ -40,6 +80,7 @@ func main() {
|
|||
|
||||
if *config.OverlordHost == "overlord" {
|
||||
log.Println("Running as overlord ")
|
||||
initilizeOverlord()
|
||||
IsOverlord = true
|
||||
} else {
|
||||
if strings.HasPrefix(*config.OverlordHost, "ws") && !strings.HasSuffix(*config.OverlordHost, "wso") {
|
||||
|
|
@ -48,35 +89,4 @@ func main() {
|
|||
log.Println("Running as slave ")
|
||||
IsOverlord = false
|
||||
}
|
||||
|
||||
handler, err := handler.NewHandler(IsOverlord)
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
|
||||
// ignore origin
|
||||
upgrader.CheckOrigin = func(r *http.Request) bool { return true }
|
||||
|
||||
http.HandleFunc("/", handler.GetWeb)
|
||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
|
||||
http.HandleFunc("/ws", handler.WS)
|
||||
|
||||
if !IsOverlord {
|
||||
conn, err := createOverlordConnection()
|
||||
if err != nil {
|
||||
log.Println("Cannot connect to overlord")
|
||||
log.Println("Run as a single server")
|
||||
oclient = nil
|
||||
} else {
|
||||
oclient = NewOverlordClient(conn)
|
||||
}
|
||||
}
|
||||
|
||||
if !IsOverlord {
|
||||
log.Println("http://localhost:" + *config.Port)
|
||||
http.ListenAndServe(":"+*config.Port, nil)
|
||||
} else {
|
||||
log.Println("http://localhost:9000")
|
||||
// Overlord expose one more path for handle overlord connections
|
||||
http.HandleFunc("/wso", overlord.WSO)
|
||||
http.ListenAndServe(":9000", nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/giongto35/cloud-game/cws"
|
||||
"github.com/giongto35/cloud-game/handler"
|
||||
"github.com/giongto35/cloud-game/overlord"
|
||||
gamertc "github.com/giongto35/cloud-game/webrtc"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pion/webrtc"
|
||||
|
|
@ -17,26 +20,36 @@ var host = "http://localhost:8000"
|
|||
var webrtcconfig = webrtc.Configuration{ICEServers: []webrtc.ICEServer{{URLs: []string{"stun:stun.l.google.com:19302"}}}}
|
||||
|
||||
func initOverlord() *httptest.Server {
|
||||
overlord := httptest.NewServer(http.HandlerFunc(wso))
|
||||
server := overlord.NewServer()
|
||||
overlord := httptest.NewServer(http.HandlerFunc(server.WSO))
|
||||
return overlord
|
||||
}
|
||||
|
||||
func initServer(t *testing.T, overlordURL string) *httptest.Server {
|
||||
if overlordURL == "" {
|
||||
oclient = nil
|
||||
} else {
|
||||
u := "ws" + strings.TrimPrefix(overlordURL, "http")
|
||||
fmt.Println("connecting to overlord: ", u)
|
||||
func initServer(t *testing.T, oclient *handler.OverlordClient) *httptest.Server {
|
||||
conn := connectTestOverlordServer()
|
||||
handler, err := handler.NewHandler(oclient)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
server := httptest.NewServer(http.HandlerFunc(handler.WS))
|
||||
return server
|
||||
}
|
||||
|
||||
oconn, _, err := websocket.DefaultDialer.Dial(u, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
oclient = NewOverlordClient(oconn)
|
||||
func connectTestOverlordServer(t *testing.T, overlordURL string) *handler.OverlordClient {
|
||||
if overlordURL == "" {
|
||||
return nil
|
||||
} else {
|
||||
overlordURL = "ws" + strings.TrimPrefix(overlordURL, "http")
|
||||
fmt.Println("connecting to overlord: ", overlordURL)
|
||||
}
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(ws))
|
||||
return server
|
||||
oconn, _, err := websocket.DefaultDialer.Dial(overlordURL, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
defer oconn.Close()
|
||||
|
||||
return oconn
|
||||
}
|
||||
|
||||
func initClient(t *testing.T, host string) {
|
||||
|
|
@ -69,17 +82,17 @@ func initClient(t *testing.T, host string) {
|
|||
}
|
||||
|
||||
// Send offer to server
|
||||
client := NewClient(ws)
|
||||
go client.listen()
|
||||
client := cws.NewClient(ws)
|
||||
go client.Listen()
|
||||
|
||||
fmt.Println("Sending offer...")
|
||||
client.send(WSPacket{
|
||||
client.Send(cws.WSPacket{
|
||||
ID: "initwebrtc",
|
||||
Data: gamertc.Encode(offer),
|
||||
}, nil)
|
||||
fmt.Println("Waiting sdp...")
|
||||
|
||||
client.receive("sdp", func(resp WSPacket) WSPacket {
|
||||
client.Receive("sdp", func(resp cws.WSPacket) cws.WSPacket {
|
||||
fmt.Println("received", resp.Data)
|
||||
answer := webrtc.SessionDescription{}
|
||||
gamertc.Decode(resp.Data, &answer)
|
||||
|
|
@ -89,19 +102,19 @@ func initClient(t *testing.T, host string) {
|
|||
panic(err)
|
||||
}
|
||||
|
||||
return EmptyPacket
|
||||
return cws.EmptyPacket
|
||||
})
|
||||
|
||||
time.Sleep(time.Second * 3)
|
||||
fmt.Println("Sending start...")
|
||||
|
||||
roomID := make(chan string)
|
||||
client.send(WSPacket{
|
||||
client.Send(cws.WSPacket{
|
||||
ID: "start",
|
||||
Data: "Contra.nes",
|
||||
RoomID: "",
|
||||
PlayerIndex: 1,
|
||||
}, func(resp WSPacket) {
|
||||
}, func(resp cws.WSPacket) {
|
||||
fmt.Println("Received response")
|
||||
fmt.Println("RoomID:", resp.RoomID)
|
||||
roomID <- resp.RoomID
|
||||
|
|
@ -119,8 +132,7 @@ func initClient(t *testing.T, host string) {
|
|||
|
||||
func TestSingleServerNoOverlord(t *testing.T) {
|
||||
// Init slave server
|
||||
oclient = nil
|
||||
s := initServer(t, "")
|
||||
s := initServer(t, nil)
|
||||
defer s.Close()
|
||||
|
||||
initClient(t, s.URL)
|
||||
|
|
@ -129,12 +141,13 @@ func TestSingleServerNoOverlord(t *testing.T) {
|
|||
func TestSingleServerOneOverlord(t *testing.T) {
|
||||
o := initOverlord()
|
||||
defer o.Close()
|
||||
|
||||
oconn := connectOverlord(t, o.URL)
|
||||
// Init slave server
|
||||
s := initServer(t, o.URL)
|
||||
s := initServer(t, oconn)
|
||||
defer s.Close()
|
||||
|
||||
initClient(t, s.URL)
|
||||
oclient.conn.Close()
|
||||
}
|
||||
|
||||
//func TestTwoServerOneOverlord(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -22,33 +22,8 @@ type BrowserClient struct {
|
|||
playerIndex int
|
||||
}
|
||||
|
||||
// NewOverlordClient returns a client connecting to browser. This connection exchanges information between clients and server
|
||||
func NewBrowserClient(c *websocket.Conn, overlordClient *OverlordClient) *BrowserClient {
|
||||
roomID := ""
|
||||
gameName := ""
|
||||
playerIndex := 0
|
||||
// Create connection to overlord
|
||||
browserClient := &BrowserClient{
|
||||
Client: cws.NewClient(c),
|
||||
gameName: "",
|
||||
roomID: "",
|
||||
playerIndex: 0,
|
||||
}
|
||||
|
||||
//sessionID := strconv.Itoa(rand.Int())
|
||||
sessionID := uuid.Must(uuid.NewV4()).String()
|
||||
|
||||
wssession := &Session{
|
||||
BrowserClient: browserClient,
|
||||
OverlordClient: overlordClient,
|
||||
peerconnection: webrtc.NewWebRTC(),
|
||||
// The server session is maintaining
|
||||
}
|
||||
|
||||
browserClient.Send(cws.WSPacket{
|
||||
ID: "gamelist",
|
||||
Data: gamelist.GetEncodedGameList(),
|
||||
}, nil)
|
||||
func (s *Session) RegisterBrowserClient() {
|
||||
browserClient := s.BrowserClient
|
||||
|
||||
browserClient.Receive("heartbeat", func(resp cws.WSPacket) cws.WSPacket {
|
||||
return resp
|
||||
|
|
@ -56,7 +31,7 @@ func NewBrowserClient(c *websocket.Conn, overlordClient *OverlordClient) *Browse
|
|||
|
||||
browserClient.Receive("initwebrtc", func(resp cws.WSPacket) cws.WSPacket {
|
||||
log.Println("Received user SDP")
|
||||
localSession, err := wssession.peerconnection.StartClient(resp.Data, config.Width, config.Height)
|
||||
localSession, err := s.peerconnection.StartClient(resp.Data, config.Width, config.Height)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
|
@ -64,7 +39,7 @@ func NewBrowserClient(c *websocket.Conn, overlordClient *OverlordClient) *Browse
|
|||
return cws.WSPacket{
|
||||
ID: "sdp",
|
||||
Data: localSession,
|
||||
SessionID: sessionID,
|
||||
SessionID: s.SessionID,
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -152,5 +127,34 @@ func NewBrowserClient(c *websocket.Conn, overlordClient *OverlordClient) *Browse
|
|||
return req
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// NewOverlordClient returns a client connecting to browser. This connection exchanges information between clients and server
|
||||
func NewBrowserClient(c *websocket.Conn, overlordClient *OverlordClient) *BrowserClient {
|
||||
roomID := ""
|
||||
gameName := ""
|
||||
playerIndex := 0
|
||||
// Create connection to overlord
|
||||
browserClient := &BrowserClient{
|
||||
Client: cws.NewClient(c),
|
||||
gameName: "",
|
||||
roomID: "",
|
||||
playerIndex: 0,
|
||||
}
|
||||
|
||||
//sessionID := strconv.Itoa(rand.Int())
|
||||
sessionID := uuid.Must(uuid.NewV4()).String()
|
||||
|
||||
wssession := &Session{
|
||||
BrowserClient: browserClient,
|
||||
OverlordClient: overlordClient,
|
||||
peerconnection: webrtc.NewWebRTC(),
|
||||
// The server session is maintaining
|
||||
}
|
||||
|
||||
browserClient.Send(cws.WSPacket{
|
||||
ID: "gamelist",
|
||||
Data: gamelist.GetEncodedGameList(),
|
||||
}, nil)
|
||||
return browserClient
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ var upgrader = websocket.Upgrader{}
|
|||
|
||||
// ID to peerconnection
|
||||
//var peerconnections = map[string]*webrtc.WebRTC{}
|
||||
var oclient *OverlordClient
|
||||
//var oclient *OverlordClient
|
||||
|
||||
type Handler struct {
|
||||
oClient *OverlordClient
|
||||
|
|
@ -38,18 +38,21 @@ type Handler struct {
|
|||
serverID string
|
||||
// ID to peerconnection
|
||||
peerconnections map[string]*webrtc.WebRTC
|
||||
// Session
|
||||
wssession Session
|
||||
}
|
||||
|
||||
func NewHandler() (*Handler, error) {
|
||||
conn, err := createOverlordConnection()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// NewHandler returns a new server
|
||||
func NewHandler(overlordConn *websocket.Conn) *Handler {
|
||||
//conn, err := createOverlordConnection()
|
||||
//if err != nil {
|
||||
//return nil, err
|
||||
//}
|
||||
return &Handler{
|
||||
oClient: NewOverlordClient(conn),
|
||||
oClient: NewOverlordClient(overlordConn),
|
||||
rooms: map[string]*Room{},
|
||||
peerconnections: map[string]*webrtc.WebRTC{},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetWeb returns web frontend
|
||||
|
|
@ -61,7 +64,7 @@ func (h *Handler) GetWeb(w http.ResponseWriter, r *http.Request) {
|
|||
w.Write(bs)
|
||||
}
|
||||
|
||||
// Handle normal traffic (from browser to host)
|
||||
// WS handles normal traffic (from browser to host)
|
||||
func (h *Handler) WS(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func NewOverlordClient(oc *websocket.Conn) *OverlordClient {
|
|||
return oclient
|
||||
}
|
||||
|
||||
func (h *Handler) Register(oclient *OverlordClient) {
|
||||
func (h *Handler) RegisterOverlordClient(oclient *OverlordClient) {
|
||||
|
||||
// Received from overlord the serverID
|
||||
oclient.Receive(
|
||||
|
|
|
|||
|
|
@ -8,16 +8,26 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/giongto35/cloud-game/cws"
|
||||
"github.com/giongto35/cloud-game/webrtc"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
var roomToServer = map[string]string{}
|
||||
type Server struct {
|
||||
roomToServer map[string]string
|
||||
// servers are the map serverID to server Client
|
||||
servers map[string]*cws.Client
|
||||
}
|
||||
|
||||
// servers are the map serverID to server Client
|
||||
var servers = map[string]*cws.Client{}
|
||||
var upgrader = websocket.Upgrader{}
|
||||
|
||||
func NewServer() *Server {
|
||||
return &Server{
|
||||
servers: map[string]*cws.Client{},
|
||||
roomToServer: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
// If it's overlord, handle overlord connection (from host to overlord)
|
||||
func WSO(w http.ResponseWriter, r *http.Request) {
|
||||
func (o *Server) WSO(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("Connected")
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
|
|
@ -26,51 +36,58 @@ func WSO(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
defer c.Close()
|
||||
|
||||
// register new server
|
||||
// Register new server
|
||||
serverID := strconv.Itoa(rand.Int())
|
||||
log.Println("A new server connected ", serverID)
|
||||
|
||||
client := NewClient(c)
|
||||
servers[serverID] = client
|
||||
// Register to servers map the client connection
|
||||
client := cws.NewClient(c)
|
||||
o.servers[serverID] = client
|
||||
|
||||
wssession := &Session{
|
||||
client: client,
|
||||
peerconnection: webrtc.NewWebRTC(),
|
||||
// The server session is maintaining
|
||||
}
|
||||
//wssession := &Session{
|
||||
//client: client,
|
||||
//peerconnection: webrtc.NewWebRTC(),
|
||||
//// The server session is maintaining
|
||||
//}
|
||||
|
||||
client.send(
|
||||
WSPacket{
|
||||
// Sendback the ID to server
|
||||
client.Send(
|
||||
cws.WSPacket{
|
||||
ID: "serverID",
|
||||
Data: serverID,
|
||||
},
|
||||
nil,
|
||||
)
|
||||
|
||||
client.receive("registerRoom", func(resp WSPacket) WSPacket {
|
||||
// registerRoom event from a server, when server created a new room.
|
||||
// RoomID is global so it is managed by overlord.
|
||||
client.Receive("registerRoom", func(resp cws.WSPacket) cws.WSPacket {
|
||||
log.Println("Received registerRoom ", resp.Data, serverID)
|
||||
roomToServer[resp.Data] = serverID
|
||||
return WSPacket{
|
||||
o.roomToServer[resp.Data] = serverID
|
||||
return cws.WSPacket{
|
||||
ID: "registerRoom",
|
||||
}
|
||||
})
|
||||
|
||||
client.receive("getRoom", func(resp WSPacket) WSPacket {
|
||||
// getRoom returns the server ID based on requested roomID.
|
||||
client.Receive("getRoom", func(resp cws.WSPacket) cws.WSPacket {
|
||||
log.Println("Received a getroom request")
|
||||
return WSPacket{
|
||||
return cws.WSPacket{
|
||||
ID: "getRoom",
|
||||
Data: roomToServer[resp.Data],
|
||||
Data: o.roomToServer[resp.Data],
|
||||
}
|
||||
})
|
||||
|
||||
client.receive("initwebrtc", func(resp WSPacket) WSPacket {
|
||||
// Relay message from server to other target server
|
||||
// TODO: Generalize
|
||||
client.Receive("initwebrtc", func(resp cws.WSPacket) cws.WSPacket {
|
||||
log.Println("Received a relay sdp request from a host")
|
||||
// TODO: Abstract
|
||||
if resp.TargetHostID != serverID {
|
||||
log.Println("sending relay sdp to target host", resp)
|
||||
// relay SDP to target host and get back sdp
|
||||
// TODO: Async
|
||||
sdp := servers[resp.TargetHostID].syncSend(
|
||||
sdp := o.servers[resp.TargetHostID].SyncSend(
|
||||
resp,
|
||||
)
|
||||
|
||||
|
|
@ -79,46 +96,48 @@ func WSO(w http.ResponseWriter, r *http.Request) {
|
|||
log.Println("Target host is overlord itself: start peerconnection")
|
||||
// If the target is in master
|
||||
// start by its old
|
||||
localSession, err := wssession.peerconnection.StartClient(resp.Data, width, height)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
//localSession, err := wssession.peerconnection.StartClient(resp.Data, width, height)
|
||||
//if err != nil {
|
||||
//log.Fatalln(err)
|
||||
//}
|
||||
|
||||
return WSPacket{
|
||||
ID: "sdp",
|
||||
Data: localSession,
|
||||
}
|
||||
//return cws.WSPacket{
|
||||
//ID: "sdp",
|
||||
//Data: localSession,
|
||||
//}
|
||||
return cws.EmptyPacket
|
||||
})
|
||||
|
||||
// TODO: use relay ID type
|
||||
// TODO: Merge sdp and start
|
||||
client.receive("start", func(resp WSPacket) WSPacket {
|
||||
client.Receive("start", func(resp cws.WSPacket) cws.WSPacket {
|
||||
log.Println("Received a relay start request from a host")
|
||||
// TODO: Abstract
|
||||
if resp.TargetHostID != serverID {
|
||||
// relay SDP to target host and get back sdp
|
||||
// TODO: Async
|
||||
resp := servers[resp.TargetHostID].syncSend(
|
||||
resp := o.servers[resp.TargetHostID].SyncSend(
|
||||
resp,
|
||||
)
|
||||
|
||||
return resp
|
||||
}
|
||||
log.Println("Target host is overlord itself: start game")
|
||||
// If the target is in master
|
||||
// start by its old
|
||||
roomID, isNewRoom := startSession(wssession.peerconnection, resp.Data, resp.RoomID, resp.PlayerIndex)
|
||||
// Bridge always access to old room
|
||||
// TODO: log warn
|
||||
if isNewRoom == true {
|
||||
log.Fatal("Bridge should not spawn new room")
|
||||
}
|
||||
//// If the target is in master
|
||||
//// start by its old
|
||||
//roomID, isNewRoom := startSession(wssession.peerconnection, resp.Data, resp.RoomID, resp.PlayerIndex)
|
||||
//// Bridge always access to old room
|
||||
//// TODO: log warn
|
||||
//if isNewRoom == true {
|
||||
//log.Fatal("Bridge should not spawn new room")
|
||||
//}
|
||||
|
||||
return WSPacket{
|
||||
ID: "start",
|
||||
RoomID: roomID,
|
||||
}
|
||||
//return cws.WSPacket{
|
||||
//ID: "start",
|
||||
//RoomID: roomID,
|
||||
//}
|
||||
return cws.EmptyPacket
|
||||
})
|
||||
|
||||
client.listeồi
|
||||
client.Listen()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue