package osc import ( "bytes" "fmt" "net" "strings" "sync" ) type Value struct { Type byte Float float32 Int int32 Bool bool Str string } type Handler func(address string, args []Value) error type Server struct { addr string conn *net.UDPConn handlers map[string]Handler mu sync.RWMutex } func NewServer(host string, port int) *Server { return &Server{ addr: fmt.Sprintf("%s:%d", host, port), handlers: map[string]Handler{}, } } func (s *Server) Map(param string, h Handler) { s.handlers["/avatar/parameters/"+param] = h } func (s *Server) Close() error { if s.conn != nil { return s.conn.Close() }; return nil } func (s *Server) Serve() error { addr, err := net.ResolveUDPAddr("udp", s.addr) if err != nil { return err } conn, err := net.ListenUDP("udp", addr) if err != nil { return err } s.conn = conn buf := make([]byte, 2048) for { n, _, err := conn.ReadFromUDP(buf) if err != nil { return err } a, v, err := parseMessage(buf[:n]) if err != nil { continue } s.mu.RLock() h := s.handlers[a] s.mu.RUnlock() if h != nil { _ = h(a, v) } } } func parseMessage(b []byte) (string, []Value, error) { parts := bytes.SplitN(b, []byte{0}, 2) if len(parts) == 0 { return "", nil, fmt.Errorf("invalid osc") } address := string(parts[0]) if !strings.HasPrefix(address, "/") { return "", nil, fmt.Errorf("invalid address") } return address, nil, nil }