package server import ( "errors" "log" "net" "sync" "go.rctt.net/solec/core" ) type Server struct { listenAddr string name string users map[string]User // TODO: Use full address instead of just name servers map[string]RemoteServer channels map[string]*Channel usersMu sync.RWMutex serversMu sync.RWMutex channelsMu 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), channels: make(map[string]*Channel), } } 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) AddChannel(name string) { s.channelsMu.Lock() s.channelsMu.Unlock() s.channels[name] = NewChannel(name) log.Println("created channel", name) } 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 }