package com import "github.com/giongto35/cloud-game/v3/pkg/logger" type stringer interface { comparable String() string } type NetClient[K stringer] interface { Disconnect() Id() K } type NetMap[K stringer, T NetClient[K]] struct{ Map[K, T] } func NewNetMap[K stringer, T NetClient[K]]() NetMap[K, T] { return NetMap[K, T]{Map: Map[K, T]{m: make(map[K]T, 10)}} } func (m *NetMap[K, T]) Add(client T) bool { return m.Put(client.Id(), client) } func (m *NetMap[K, T]) Empty() bool { return m.Map.Len() == 0 } func (m *NetMap[K, T]) Remove(client T) { m.Map.Remove(client.Id()) } func (m *NetMap[K, T]) RemoveL(client T) int { return m.Map.RemoveL(client.Id()) } func (m *NetMap[K, T]) Reset() { m.Map = Map[K, T]{m: make(map[K]T, 10)} } func (m *NetMap[K, T]) RemoveDisconnect(client T) { client.Disconnect(); m.Remove(client) } func (m *NetMap[K, T]) Find(id string) T { v, _ := m.Map.FindBy(func(v T) bool { return v.Id().String() == id }) return v } type SocketClient[T ~uint8, P Packet[T], X any, P2 Packet2[X]] struct { id Uid rpc *RPC[T, P] sock *Connection log *logger.Logger // a special logger for showing x -> y directions } func NewConnection[T ~uint8, P Packet[T], X any, P2 Packet2[X]](conn *Connection, id Uid, log *logger.Logger) *SocketClient[T, P, X, P2] { if id.IsNil() { id = NewUid() } dir := logger.MarkOut if conn.IsServer() { dir = logger.MarkIn } dirClLog := log.Extend(log.With(). Str("cid", id.Short()). Str(logger.DirectionField, dir), ) dirClLog.Debug().Msg("Connect") return &SocketClient[T, P, X, P2]{sock: conn, id: id, log: dirClLog} } func (c *SocketClient[T, P, _, _]) ProcessPackets(fn func(in P) error) chan struct{} { c.rpc = NewRPC[T, P]() c.rpc.Handler = func(p P) { c.log.Debug().Str(logger.DirectionField, logger.MarkIn).Msgf("%v", p.GetType()) if err := fn(p); err != nil { // 3rd handler c.log.Error().Err(err).Send() } } c.sock.conn.SetMessageHandler(c.handleMessage) // 1st handler return c.sock.conn.Listen() } func (c *SocketClient[T, P, X, P2]) SetErrorHandler(h func(error)) { c.sock.conn.SetErrorHandler(h) } func (c *SocketClient[T, P, X, P2]) SetMaxMessageSize(s int64) { c.sock.conn.SetMaxMessageSize(s) } func (c *SocketClient[_, _, _, _]) handleMessage(message []byte, err error) { if err != nil { c.log.Error().Err(err).Send() return } if err = c.rpc.handleMessage(message); err != nil { // 2nd handler c.log.Error().Err(err).Send() return } } func (c *SocketClient[_, P, X, P2]) Route(in P, out P2) { rq := P2(new(X)) rq.SetId(in.GetId().String()) rq.SetType(uint8(in.GetType())) rq.SetPayload(out.GetPayload()) if err := c.rpc.Send(c.sock.conn, rq); err != nil { c.log.Error().Err(err).Msgf("message route fail") } } // Send makes a blocking call. func (c *SocketClient[T, P, X, P2]) Send(t T, data any) ([]byte, error) { c.log.Debug().Str(logger.DirectionField, logger.MarkOut).Msgf("ᵇ%v", t) rq := P2(new(X)) rq.SetType(uint8(t)) rq.SetPayload(data) return c.rpc.Call(c.sock.conn, rq) } // Notify just sends a message and goes further. func (c *SocketClient[T, P, X, P2]) Notify(t T, data any) { c.log.Debug().Str(logger.DirectionField, logger.MarkOut).Msgf("%v", t) rq := P2(new(X)) rq.SetType(uint8(t)) rq.SetPayload(data) if err := c.rpc.Send(c.sock.conn, rq); err != nil { c.log.Error().Err(err).Msgf("notify fail") } } func (c *SocketClient[_, _, _, _]) Disconnect() { c.sock.conn.Close() c.rpc.Cleanup() c.log.Debug().Str(logger.DirectionField, logger.MarkCross).Msg("Close") } func (c *SocketClient[_, _, _, _]) Id() Uid { return c.id } func (c *SocketClient[_, _, _, _]) String() string { return c.Id().String() }