mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-01-23 18:46:11 +00:00
182 lines
5 KiB
Go
182 lines
5 KiB
Go
package worker
|
|
|
|
import (
|
|
"net/url"
|
|
|
|
"github.com/giongto35/cloud-game/v3/pkg/api"
|
|
"github.com/giongto35/cloud-game/v3/pkg/com"
|
|
"github.com/giongto35/cloud-game/v3/pkg/config"
|
|
"github.com/giongto35/cloud-game/v3/pkg/logger"
|
|
"github.com/giongto35/cloud-game/v3/pkg/network/webrtc"
|
|
)
|
|
|
|
type Connection interface {
|
|
Disconnect()
|
|
Id() com.Uid
|
|
ProcessPackets(func(api.In[com.Uid]) error) chan struct{}
|
|
SetErrorHandler(func(error))
|
|
|
|
Send(api.PT, any) ([]byte, error)
|
|
Notify(api.PT, any)
|
|
Route(api.In[com.Uid], *api.Out)
|
|
}
|
|
|
|
type coordinator struct {
|
|
Connection
|
|
log *logger.Logger
|
|
}
|
|
|
|
var connector com.Client
|
|
|
|
func newCoordinatorConnection(host string, conf config.Worker, addr string, log *logger.Logger) (*coordinator, error) {
|
|
scheme := "ws"
|
|
if conf.Network.Secure {
|
|
scheme = "wss"
|
|
}
|
|
address := url.URL{Scheme: scheme, Host: host, Path: conf.Network.Endpoint}
|
|
|
|
log.Debug().
|
|
Str(logger.ClientField, "c").
|
|
Str(logger.DirectionField, logger.MarkOut).
|
|
Msgf("Handshake %s", address.String())
|
|
|
|
id := com.NewUid()
|
|
req, err := buildConnQuery(id, conf, addr)
|
|
if req != "" && err == nil {
|
|
address.RawQuery = "data=" + req
|
|
} else {
|
|
return nil, err
|
|
}
|
|
|
|
conn, err := connector.Connect(address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
clog := log.Extend(log.With().Str(logger.ClientField, "c"))
|
|
client := com.NewConnection[api.PT, api.In[com.Uid], api.Out, *api.Out](conn, id, clog)
|
|
|
|
return &coordinator{
|
|
Connection: client,
|
|
log: log.Extend(log.With().Str("cid", client.Id().Short())),
|
|
}, nil
|
|
}
|
|
|
|
func (c *coordinator) HandleRequests(w *Worker) chan struct{} {
|
|
ap, err := webrtc.NewApiFactory(w.conf.Webrtc, c.log, nil)
|
|
if err != nil {
|
|
c.log.Panic().Err(err).Msg("WebRTC API creation has been failed")
|
|
}
|
|
skipped := api.Out{}
|
|
|
|
return c.ProcessPackets(func(x api.In[com.Uid]) (err error) {
|
|
var out api.Out
|
|
switch x.T {
|
|
case api.WebrtcInit:
|
|
if dat := api.Unwrap[api.WebrtcInitRequest[com.Uid]](x.Payload); dat == nil {
|
|
err, out = api.ErrMalformed, api.EmptyPacket
|
|
} else {
|
|
out = c.HandleWebrtcInit(*dat, w, ap)
|
|
}
|
|
case api.WebrtcAnswer:
|
|
dat := api.Unwrap[api.WebrtcAnswerRequest[com.Uid]](x.Payload)
|
|
if dat == nil {
|
|
return api.ErrMalformed
|
|
}
|
|
c.HandleWebrtcAnswer(*dat, w)
|
|
case api.WebrtcIce:
|
|
dat := api.Unwrap[api.WebrtcIceCandidateRequest[com.Uid]](x.Payload)
|
|
if dat == nil {
|
|
return api.ErrMalformed
|
|
}
|
|
c.HandleWebrtcIceCandidate(*dat, w)
|
|
case api.StartGame:
|
|
if dat := api.Unwrap[api.StartGameRequest[com.Uid]](x.Payload); dat == nil {
|
|
err, out = api.ErrMalformed, api.EmptyPacket
|
|
} else {
|
|
out = c.HandleGameStart(*dat, w)
|
|
}
|
|
case api.TerminateSession:
|
|
dat := api.Unwrap[api.TerminateSessionRequest[com.Uid]](x.Payload)
|
|
if dat == nil {
|
|
return api.ErrMalformed
|
|
}
|
|
c.HandleTerminateSession(*dat, w)
|
|
case api.QuitGame:
|
|
dat := api.Unwrap[api.GameQuitRequest[com.Uid]](x.Payload)
|
|
if dat == nil {
|
|
return api.ErrMalformed
|
|
}
|
|
c.HandleQuitGame(*dat, w)
|
|
case api.SaveGame:
|
|
if dat := api.Unwrap[api.SaveGameRequest[com.Uid]](x.Payload); dat == nil {
|
|
err, out = api.ErrMalformed, api.EmptyPacket
|
|
} else {
|
|
out = c.HandleSaveGame(*dat, w)
|
|
}
|
|
case api.LoadGame:
|
|
if dat := api.Unwrap[api.LoadGameRequest[com.Uid]](x.Payload); dat == nil {
|
|
err, out = api.ErrMalformed, api.EmptyPacket
|
|
} else {
|
|
out = c.HandleLoadGame(*dat, w)
|
|
}
|
|
case api.ChangePlayer:
|
|
if dat := api.Unwrap[api.ChangePlayerRequest[com.Uid]](x.Payload); dat == nil {
|
|
err, out = api.ErrMalformed, api.EmptyPacket
|
|
} else {
|
|
out = c.HandleChangePlayer(*dat, w)
|
|
}
|
|
case api.ResetGame:
|
|
dat := api.Unwrap[api.ResetGameRequest[com.Uid]](x.Payload)
|
|
if dat == nil {
|
|
return api.ErrMalformed
|
|
}
|
|
c.HandleResetGame(*dat, w)
|
|
case api.RecordGame:
|
|
if dat := api.Unwrap[api.RecordGameRequest[com.Uid]](x.Payload); dat == nil {
|
|
err, out = api.ErrMalformed, api.EmptyPacket
|
|
} else {
|
|
out = c.HandleRecordGame(*dat, w)
|
|
}
|
|
default:
|
|
c.log.Warn().Msgf("unhandled packet type %v", x.T)
|
|
}
|
|
if out != skipped {
|
|
w.cord.Route(x, &out)
|
|
}
|
|
return err
|
|
})
|
|
}
|
|
|
|
func (c *coordinator) RegisterRoom(id string) { c.Notify(api.RegisterRoom, id) }
|
|
|
|
// CloseRoom sends a signal to coordinator which will remove that room from its list.
|
|
func (c *coordinator) CloseRoom(id string) { c.Notify(api.CloseRoom, id) }
|
|
func (c *coordinator) IceCandidate(candidate string, sessionId com.Uid) {
|
|
c.Notify(api.WebrtcIce, api.WebrtcIceCandidateRequest[com.Uid]{Stateful: api.Stateful[com.Uid]{Id: sessionId}, Candidate: candidate})
|
|
}
|
|
|
|
func (c *coordinator) SendLibrary(w *Worker) {
|
|
g := w.lib.GetAll()
|
|
|
|
var gg = make([]api.GameInfo, len(g))
|
|
for i, g := range g {
|
|
gg[i] = api.GameInfo(g)
|
|
}
|
|
|
|
c.Notify(api.LibNewGameList, api.LibGameListInfo{T: 1, List: gg})
|
|
}
|
|
|
|
func (c *coordinator) SendPrevSessions(w *Worker) {
|
|
sessions := w.lib.Sessions()
|
|
|
|
// extract ids from save states, i.e. sessions
|
|
var ids []string
|
|
|
|
for _, id := range sessions {
|
|
x, _ := api.ExplodeDeepLink(id)
|
|
ids = append(ids, x)
|
|
}
|
|
|
|
c.Notify(api.PrevSessions, api.PrevSessionInfo{List: ids})
|
|
}
|