diff options
author | Himbeer <himbeer@disroot.org> | 2024-11-17 17:03:18 +0100 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-11-17 17:21:02 +0100 |
commit | 7b69e587118c299d1601680ef70241283f30a009 (patch) | |
tree | f80204e2e750d82c53d2be34201ab81dbb6052f2 | |
parent | 3b344731fff17f3c5255f278f8f14879e7610f7d (diff) |
Allow plugins to handle player join and leave events
This includes the ability to kick a client on join for reasons other
than banning.
Closes #156.
-rw-r--r-- | client_conn.go | 4 | ||||
-rw-r--r-- | plugin_join_leave.go | 82 | ||||
-rw-r--r-- | process.go | 1 |
3 files changed, 87 insertions, 0 deletions
diff --git a/client_conn.go b/client_conn.go index 9753147..1a16d94 100644 --- a/client_conn.go +++ b/client_conn.go @@ -123,6 +123,10 @@ func handleClt(cc *ClientConn) { pkt, err := cc.Recv() if err != nil { if errors.Is(err, net.ErrClosed) { + if cc.state() == csActive { + handleLeave(cc) + } + if errors.Is(cc.WhyClosed(), rudp.ErrTimedOut) { cc.Log("<->", "timeout") } else { diff --git a/plugin_join_leave.go b/plugin_join_leave.go new file mode 100644 index 0000000..baa4ba3 --- /dev/null +++ b/plugin_join_leave.go @@ -0,0 +1,82 @@ +package proxy + +import "sync" + +var ( + onJoin []func(*ClientConn) string + onJoinMu sync.Mutex + onJoinOnce sync.Once +) + +var ( + onLeave []func(*ClientConn) + onLeaveMu sync.Mutex + onLeaveOnce sync.Once +) + +// RegisterOnJoin registers a handler that is called +// when a client finishes connecting to the proxy (TOSERVER_CLIENT_READY packet) +// but before it is connected to an upstream server. +// If any handler returns a non-empty string, the client is kicked +// with that message. +// Handlers are run sequentially and block the client's connection +// and packet handling procedure. +func RegisterOnJoin(handler func(*ClientConn) string) { + initOnJoin() + + onJoinMu.Lock() + defer onJoinMu.Unlock() + + onJoin = append(onJoin, handler) +} + +// RegisterOnLeave registers a handler that is called +// when a client disconnects for any reason after reaching the ready stage. +// Handlers are run sequentially. +func RegisterOnLeave(handler func(*ClientConn)) { + initOnLeave() + + onLeaveMu.Lock() + defer onLeaveMu.Unlock() + + onLeave = append(onLeave, handler) +} + +func handleJoin(cc *ClientConn) { + onJoinMu.Lock() + defer onJoinMu.Unlock() + + for _, handler := range onJoin { + if msg := handler(cc); msg != "" { + cc.Kick(msg) + break + } + } +} + +func handleLeave(cc *ClientConn) { + onLeaveMu.Lock() + defer onLeaveMu.Unlock() + + for _, handler := range onLeave { + handler(cc) + } +} + +func initOnJoin() { + onJoinOnce.Do(func() { + onJoinMu.Lock() + defer onJoinMu.Unlock() + + onJoin = make([]func(*ClientConn) string, 0) + }) +} + +func initOnLeave() { + onLeaveOnce.Do(func() { + onLeaveMu.Lock() + defer onLeaveMu.Unlock() + + onLeave = make([]func(*ClientConn), 0) + }) +} @@ -435,6 +435,7 @@ func (cc *ClientConn) process(pkt mt.Pkt) { cc.formspecVer = cmd.Formspec cc.setState(csActive) + handleJoin(cc) close(cc.initCh) return |