package core import ( "fmt" "net" "sync" "sync/atomic" "time" ) // Handler is a byte code specific packet handler. type Handler func([]byte, *Client) // Server represents a UDP server. type Server struct { socket *net.UDPConn handlers [256]Handler clients sync.Map count atomic.Int64 } // New creates a new server. func New() *Server { timeout := 3 * time.Second interval := time.Second server := &Server{} go func() { ticker := time.NewTicker(interval) defer ticker.Stop() for range ticker.C { now := time.Now() server.clients.Range(func(key, value interface{}) bool { item := value.(*Client) if !item.lastPacket.IsZero() && now.After(item.lastPacket.Add(timeout)) { server.clients.Delete(key) server.count.Add(-1) } return true }) } }() return server } // AddHandler adds the handler for the given byte code. func (s *Server) AddHandler(code byte, handler Handler) { s.handlers[code] = handler } // Count returns the number of connected clients. func (s *Server) Count() int { return int(s.count.Load()) } // Send sends the data prefixed with the byte code to the client. func (s *Server) Send(code byte, data []byte, client *Client) { data = append([]byte{code}, data...) _, err := s.socket.WriteToUDP(data, client.address) if err != nil { fmt.Println("Error sending response:", err) } } // Run starts the server on the given port. func (s *Server) Run(port int) { s.socket = listen(port) defer s.socket.Close() s.read() } // listen creates a socket for the server and starts listening for incoming packets. func listen(port int) *net.UDPConn { addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) if err != nil { panic(err) } connection, err := net.ListenUDP("udp", addr) if err != nil { panic(err) } return connection } // read is a blocking call which will read incoming packets and handle them. func (s *Server) read() { buffer := make([]byte, 4096) for { n, addr, err := s.socket.ReadFromUDP(buffer) if err != nil { fmt.Println("Error reading from UDP connection:", err) continue } if n == 0 { continue } go s.handle(buffer[:n], addr) } } // handle deals with an incoming packet. func (s *Server) handle(data []byte, addr *net.UDPAddr) { c := s.getClient(addr) c.lastPacket = time.Now() // fmt.Printf("Received %d bytes from %s: %s\n", len(data), c, string(data)) handler := s.handlers[data[0]] if handler == nil { fmt.Printf("No callback registered for packet type %d\n", data[0]) return } handler(data[1:], c) } // getClient either returns a new or existing client for the requested address. func (s *Server) getClient(addr *net.UDPAddr) *Client { obj, exists := s.clients.Load(addr.String()) if exists { return obj.(*Client) } client := &Client{ address: addr, } s.clients.Store(addr.String(), client) s.count.Add(1) return client }