package server import ( "log" "net" "go.rctt.net/solec/core" ) type RemoteServer struct { Name string Conn net.Conn } func NewRemoteServer(name string, conn net.Conn) RemoteServer { return RemoteServer{name, conn} } func (s *Server) handleServerConn(conn net.Conn) { defer conn.Close() name, err := s.performServerAuth(conn) if err != nil { log.Println("server auth error:", err) return } s.serversMu.RLock() if _, ok := s.servers[name]; ok { log.Println("server already connected") return } s.serversMu.RUnlock() rs := NewRemoteServer(name, conn) s.serversMu.Lock() s.servers[name] = rs s.serversMu.Unlock() log.Println("connection from server:", name) defer func() { s.serversMu.Lock() log.Println("server disconnected: ", rs.Name) delete(s.servers, rs.Name) s.serversMu.Unlock() }() if err := s.readInput(conn); err != nil { log.Println(err) } } func (s *Server) performServerAuth(conn net.Conn) (string, error) { payload, err := core.Decode(conn) if err != nil { return "", err } auth, ok := payload.(core.ServerAuth) if !ok { return "", core.ErrUnexpectedPayloadType } if err := core.Send(conn, core.Success{}); err != nil { return "", err } return auth.Name, nil } func (s *Server) getRemote(name string) (RemoteServer, error) { s.serversMu.RLock() remote, ok := s.servers[name] s.serversMu.RUnlock() if ok { return remote, nil } conn, err := s.initRemoteConn(name) if err != nil { return RemoteServer{}, err } rs := NewRemoteServer(name, conn) s.serversMu.Lock() s.servers[name] = rs s.serversMu.Unlock() log.Println("connected to server:", name) return rs, nil } func (s *Server) initRemoteConn(name string) (net.Conn, error) { conn, err := net.Dial("tcp", name+":9999") if err != nil { return conn, err } hs := core.Handshake{0, 1, core.ConnTypeServer} if err := core.Send(conn, hs); err != nil { conn.Close() return conn, err } auth := core.ServerAuth{Name: s.name} if err := core.Send(conn, auth); err != nil { conn.Close() return conn, err } return conn, nil }