package server import ( "errors" "log" "net" "sync" "go.rctt.net/solec/core" ) type Server struct { listenAddr string name string users map[string]User servers map[string]RemoteServer usersMu sync.RWMutex serversMu sync.RWMutex } func NewServer(listenAddr string, name string) *Server { return &Server{ listenAddr: listenAddr, name: name, users: make(map[string]User), servers: make(map[string]RemoteServer), } } func (s *Server) Start() error { ln, err := net.Listen("tcp", s.listenAddr) if err != nil { return err } for { conn, err := ln.Accept() if err != nil { log.Println("cannot listen:", err) continue } log.Println("client connected:", conn.RemoteAddr()) go s.handleConn(conn) } } func (s *Server) handleConn(conn net.Conn) { defer conn.Close() cType, err := s.performHandshake(conn) if err != nil { log.Println("handshake error:", err) return } switch cType { case core.ConnTypeUnknown: log.Println("invalid connection type") case core.ConnTypeUser: s.handleUserConn(conn) case core.ConnTypeServer: s.handleServerConn(conn) } } func (s *Server) performHandshake(conn net.Conn) (core.ConnType, error) { serverHs := core.Handshake{0, 2, core.ConnTypeServer} if err := core.Send(conn, serverHs); err != nil { return core.ConnTypeUnknown, err } clientPayload, err := core.Decode(conn) if err != nil { return core.ConnTypeUnknown, err } clientHs, ok := clientPayload.(core.Handshake) if !ok { return core.ConnTypeUnknown, core.ErrUnexpectedPayloadType } if serverHs.Major != clientHs.Major { return clientHs.ConnType, errors.New("server and client are using different protocol version") } return clientHs.ConnType, nil } func (s *Server) readInput(conn net.Conn) error { for { payload, err := core.Decode(conn) if err != nil { return err } if err := s.handlePayload(payload); err != nil { log.Print("handler error: ", err) } } } func (s *Server) handlePayload(payload any) error { switch v := payload.(type) { case core.Message: return s.handleMessage(v) default: return core.ErrUnexpectedPayloadType } }