144 lines
2.6 KiB
Go
144 lines
2.6 KiB
Go
package proxy
|
|
|
|
import (
|
|
"errors"
|
|
"log"
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/anon55555/mt"
|
|
"github.com/anon55555/mt/rudp"
|
|
)
|
|
|
|
// A ServerConn is a connection to a minetest server.
|
|
type ServerConn struct {
|
|
mt.Peer
|
|
clt *ClientConn
|
|
mu sync.RWMutex
|
|
|
|
logger *log.Logger
|
|
|
|
cstate clientState
|
|
cstateMu sync.RWMutex
|
|
name string
|
|
initCh chan struct{}
|
|
|
|
auth struct {
|
|
method mt.AuthMethods
|
|
salt, srpA, a, srpK []byte
|
|
}
|
|
|
|
mediaPool string
|
|
|
|
inv mt.Inv
|
|
detachedInvs []string
|
|
|
|
aos map[mt.AOID]struct{}
|
|
particleSpawners map[mt.ParticleSpawnerID]struct{}
|
|
|
|
sounds map[mt.SoundID]struct{}
|
|
|
|
huds map[mt.HUDID]mt.HUDType
|
|
|
|
playerList map[string]struct{}
|
|
}
|
|
|
|
func (sc *ServerConn) client() *ClientConn {
|
|
sc.mu.RLock()
|
|
defer sc.mu.RUnlock()
|
|
|
|
return sc.clt
|
|
}
|
|
|
|
func (sc *ServerConn) state() clientState {
|
|
sc.cstateMu.RLock()
|
|
defer sc.cstateMu.RUnlock()
|
|
|
|
return sc.cstate
|
|
}
|
|
|
|
func (sc *ServerConn) setState(state clientState) {
|
|
sc.cstateMu.Lock()
|
|
defer sc.cstateMu.Unlock()
|
|
|
|
sc.cstate = state
|
|
}
|
|
|
|
// Init returns a channel that is closed
|
|
// when the ServerConn enters the csActive state.
|
|
func (sc *ServerConn) Init() <-chan struct{} { return sc.initCh }
|
|
|
|
// Log logs an interaction with the ServerConn.
|
|
// dir indicates the direction of the interaction.
|
|
func (sc *ServerConn) Log(dir string, v ...interface{}) {
|
|
sc.logger.Println(append([]interface{}{dir}, v...)...)
|
|
}
|
|
|
|
func handleSrv(sc *ServerConn) {
|
|
go func() {
|
|
init := make(chan struct{})
|
|
defer close(init)
|
|
|
|
go func(init <-chan struct{}) {
|
|
select {
|
|
case <-init:
|
|
case <-time.After(10 * time.Second):
|
|
sc.Log("->", "timeout")
|
|
sc.Close()
|
|
}
|
|
}(init)
|
|
|
|
for sc.state() == csCreated && sc.client() != nil {
|
|
sc.SendCmd(&mt.ToSrvInit{
|
|
SerializeVer: serializeVer,
|
|
MinProtoVer: protoVer,
|
|
MaxProtoVer: protoVer,
|
|
PlayerName: sc.client().Name(),
|
|
})
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
}()
|
|
|
|
for {
|
|
pkt, err := sc.Recv()
|
|
if err != nil {
|
|
if errors.Is(err, net.ErrClosed) {
|
|
if errors.Is(sc.WhyClosed(), rudp.ErrTimedOut) {
|
|
sc.Log("<->", "timeout")
|
|
} else {
|
|
sc.Log("<->", "disconnect")
|
|
}
|
|
|
|
if sc.client() != nil {
|
|
ack, _ := sc.client().SendCmd(&mt.ToCltKick{
|
|
Reason: mt.Custom,
|
|
Custom: "Server connection closed unexpectedly.",
|
|
})
|
|
|
|
select {
|
|
case <-sc.client().Closed():
|
|
case <-ack:
|
|
sc.client().Close()
|
|
|
|
sc.client().mu.Lock()
|
|
sc.client().srv = nil
|
|
sc.client().mu.Unlock()
|
|
|
|
sc.mu.Lock()
|
|
sc.clt = nil
|
|
sc.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
break
|
|
}
|
|
|
|
sc.Log("<-", err)
|
|
continue
|
|
}
|
|
|
|
sc.process(pkt)
|
|
}
|
|
}
|