refactor Gateway out

trunk
vilmibm 2022-12-23 21:31:08 -08:00
parent 9824fecaa2
commit d006c992ec
2 changed files with 41 additions and 56 deletions

View File

@ -72,9 +72,11 @@ type gameWorldServer struct {
proto.UnimplementedGameWorldServer proto.UnimplementedGameWorldServer
db db.DB db db.DB
mu sync.Mutex // for msgRouter msgRouterMutex sync.Mutex
msgRouter map[string]func(*proto.ClientMessage) error msgRouter map[string]func(*proto.ClientMessage) error
Gateway *witch.Gateway Gateway *witch.Gateway
scripts map[int]*witch.ScriptContext
scriptsMutex sync.RWMutex
} }
func newServer() (*gameWorldServer, error) { func newServer() (*gameWorldServer, error) {
@ -95,13 +97,37 @@ func newServer() (*gameWorldServer, error) {
s := &gameWorldServer{ s := &gameWorldServer{
msgRouter: make(map[string]func(*proto.ClientMessage) error), msgRouter: make(map[string]func(*proto.ClientMessage) error),
db: db, db: db,
scripts: make(map[int]*witch.ScriptContext),
scriptsMutex: sync.RWMutex{},
} }
gw := witch.NewGateway(s.HandleCmd)
s.Gateway = gw
return s, nil return s, nil
} }
func (s *gameWorldServer) verbHandler(verb, rest string, sender, target db.Object) error {
/*
So right here is a problem: we are definitely making >1 LuaState per
goroutine. Top priority before anything else is getting a goroutine made
for the script contexts
*/
s.scriptsMutex.RLock()
sc, ok := s.scripts[target.ID]
s.scriptsMutex.RUnlock()
if !ok || sc.NeedsRefresh(target) {
sc, err := witch.NewScriptContext(target)
if err != nil {
return err
}
s.scriptsMutex.Lock()
s.scripts[target.ID] = sc
s.scriptsMutex.Unlock()
}
return sc.Handle(verb, rest, sender, target)
}
func (s *gameWorldServer) HandleCmd(verb, rest string, sender *db.Object) { func (s *gameWorldServer) HandleCmd(verb, rest string, sender *db.Object) {
// TODO // TODO
} }
@ -213,9 +239,9 @@ func (s *gameWorldServer) Ping(ctx context.Context, _ *proto.SessionInfo) (*prot
} }
func (s *gameWorldServer) Messages(si *proto.SessionInfo, stream proto.GameWorld_MessagesServer) error { func (s *gameWorldServer) Messages(si *proto.SessionInfo, stream proto.GameWorld_MessagesServer) error {
s.mu.Lock() s.msgRouterMutex.Lock()
s.msgRouter[si.SessionID] = stream.Send s.msgRouter[si.SessionID] = stream.Send
s.mu.Unlock() s.msgRouterMutex.Unlock()
// TODO this is clearly bad but it works. I should refactor this so that messages are received on a channel. // TODO this is clearly bad but it works. I should refactor this so that messages are received on a channel.
for { for {

View File

@ -1,8 +1,6 @@
package witch package witch
import ( import (
"sync"
"github.com/vilmibm/hermeticum/server/db" "github.com/vilmibm/hermeticum/server/db"
lua "github.com/yuin/gopher-lua" lua "github.com/yuin/gopher-lua"
) )
@ -15,14 +13,14 @@ import (
*/ */
type scriptContext struct { type ScriptContext struct {
script string script string
l *lua.LState l *lua.LState
incoming chan string incoming chan string
// TODO whatever is needed to support calling a Go API // TODO whatever is needed to support calling a Go API
} }
func (sc *scriptContext) NeedsRefresh(obj db.Object) bool { func (sc *ScriptContext) NeedsRefresh(obj db.Object) bool {
return sc.script != obj.Script return sc.script != obj.Script
} }
@ -62,7 +60,7 @@ end)
// - do i inject from Go or prepend some Lua code? // - do i inject from Go or prepend some Lua code?
// TODO figure out how the Lua code can affect Go and thus the database // TODO figure out how the Lua code can affect Go and thus the database
func newScriptContext(obj db.Object) (*scriptContext, error) { func NewScriptContext(obj db.Object) (*ScriptContext, error) {
l := lua.NewState() l := lua.NewState()
l.SetGlobal("has", l.NewFunction(hasWrapper(obj))) l.SetGlobal("has", l.NewFunction(hasWrapper(obj)))
@ -73,49 +71,10 @@ func newScriptContext(obj db.Object) (*scriptContext, error) {
return nil, err return nil, err
} }
return &scriptContext{}, nil return &ScriptContext{}, nil
} }
func (sc *scriptContext) Handle(verb, rest string, sender, target *db.Object) error { func (sc *ScriptContext) Handle(verb, rest string, sender, target db.Object) error {
// TODO call _handle function from the Lstate // TODO call _handle function from the Lstate
return nil return nil
} }
type Gateway struct {
// maps game object IDs to script contexts
m map[int]*scriptContext
mu sync.RWMutex
cb func(string, string, *db.Object)
}
func NewGateway(cb func(string, string, *db.Object)) *Gateway {
return &Gateway{
m: map[int]*scriptContext{},
mu: sync.RWMutex{},
// TODO use cb from scriptContext
cb: cb,
}
}
func (g *Gateway) VerbHandler(verb, rest string, sender, target db.Object) error {
var sc *scriptContext
g.mu.RLock()
sc, ok := g.m[target.ID]
g.mu.RUnlock()
if !ok || sc.NeedsRefresh(target) {
sc, err := newScriptContext(target)
if err != nil {
return err
}
g.mu.Lock()
g.m[target.ID] = sc
g.mu.Unlock()
}
sc.Handle(verb, rest, &sender, &target)
return nil
}