diff options
author | Himbeer <himbeer@disroot.org> | 2024-12-06 20:39:47 +0100 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-12-07 11:22:54 +0100 |
commit | 162faad9f636263cc27413358af18de725db66d9 (patch) | |
tree | b8de1a5559fee82ba93edb37898a3edfcff4b1ed | |
parent | fed47e8f13cf051c2f09b08112c513deb08b47a1 (diff) |
Implement modchannel plugin API between clients and proxy
-rw-r--r-- | plugin_modchan.go | 96 | ||||
-rw-r--r-- | process.go | 16 |
2 files changed, 112 insertions, 0 deletions
diff --git a/plugin_modchan.go b/plugin_modchan.go new file mode 100644 index 0000000..446a37f --- /dev/null +++ b/plugin_modchan.go @@ -0,0 +1,96 @@ +package proxy + +import ( + "sync" + + "github.com/HimbeerserverDE/mt" +) + +var ( + modChanSubscribers map[string][]*ClientConn + modChanSubscriberMu sync.RWMutex +) + +var ( + onCltModChanMsg []func(string, *ClientConn, string) bool + onCltModChanMsgMu sync.RWMutex + onCltModChanMsgOnce sync.Once +) + +// SendModChanMsg sends a message to all subscribed clients on a modchannel. +func SendModChanMsg(channel, msg string) { + modChanSubscriberMu.RLock() + defer modChanSubscriberMu.RUnlock() + + subs, _ := modChanSubscribers[channel] + for _, cc := range subs { + cc.SendCmd(&mt.ToCltModChanMsg{ + Channel: channel, + Msg: msg, + }) + } +} + +// RegisterOnCltModChanMsg registers a handler that is called +// when a client sends a message on a modchannel. +// If any handler returns true, the message is not forwarded +// to the upstream server. +func RegisterOnCltModChanMsg(handler func(string, *ClientConn, string) bool) { + onCltModChanMsgMu.Lock() + defer onCltModChanMsgMu.Unlock() + + onCltModChanMsg = append(onCltModChanMsg, handler) +} + +func cltLeaveModChan(cc *ClientConn, channel string) { + modChanSubscriberMu.Lock() + defer modChanSubscriberMu.Unlock() + + for i, sub := range modChanSubscribers[channel] { + if sub == cc { + modChanSubscribers[channel] = append(modChanSubscribers[channel][:i], modChanSubscribers[channel][i+1:]...) + break + } + } +} + +func cltLeaveModChans(cc *ClientConn) { + modChanSubscriberMu.Lock() + defer modChanSubscriberMu.Unlock() + + for ch := range modChanSubscribers { + for i, sub := range modChanSubscribers[ch] { + if sub == cc { + modChanSubscribers[ch] = append(modChanSubscribers[ch][:i], modChanSubscribers[ch][i+1:]...) + break + } + } + } +} + +func handleCltModChanMsg(cc *ClientConn, cmd *mt.ToSrvMsgModChan) bool { + onCltModChanMsgMu.RLock() + defer onCltModChanMsgMu.RUnlock() + + subs, _ := modChanSubscribers[cmd.Channel] + for _, sub := range subs { + sub.SendCmd(&mt.ToCltModChanMsg{ + Channel: cmd.Channel, + Sender: cc.Name(), + Msg: cmd.Msg, + }) + } + + drop := false + for _, handler := range onCltModChanMsg { + if handler(cmd.Channel, cc, cmd.Msg) { + drop = true + } + } + + return drop +} + +func init() { + modChanSubscribers = make(map[string][]*ClientConn) +} @@ -12,6 +12,10 @@ import ( ) func (cc *ClientConn) process(pkt mt.Pkt) { + defer func() { + cltLeaveModChans(cc) + }() + srv := cc.server() forward := func(pkt mt.Pkt) { @@ -484,6 +488,18 @@ func (cc *ClientConn) process(pkt mt.Pkt) { if handleOnPlayerReceiveFields(cc, cmd) { return } + case *mt.ToSrvJoinModChan: + modChanSubscriberMu.Lock() + defer modChanSubscriberMu.Unlock() + + subs, _ := modChanSubscribers[cmd.Channel] + modChanSubscribers[cmd.Channel] = append(subs, cc) + case *mt.ToSrvLeaveModChan: + cltLeaveModChan(cc, cmd.Channel) + case *mt.ToSrvMsgModChan: + if handleCltModChanMsg(cc, cmd) { + return + } } forward(pkt) |