114 lines
3.1 KiB
Go
114 lines
3.1 KiB
Go
package wire
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
"google.golang.org/protobuf/proto"
|
|
"nhooyr.io/websocket"
|
|
|
|
iop "iop/proto/gen/iop"
|
|
proto_socket "git.toki-labs.com/toki/proto-socket/go"
|
|
)
|
|
|
|
// PortalServer wraps the proto-socket WebSocket server for Portal-Control Plane communication.
|
|
type PortalServer struct {
|
|
server *proto_socket.WsServer
|
|
logger *zap.Logger
|
|
host string
|
|
port int
|
|
}
|
|
|
|
// NewPortalServer creates a new PortalServer instance listening on the specified address.
|
|
func NewPortalServer(listenAddr string, logger *zap.Logger) (*PortalServer, error) {
|
|
host, portStr, err := net.SplitHostPort(listenAddr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid listen address %q: %w", listenAddr, err)
|
|
}
|
|
port, err := strconv.Atoi(portStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid port in listen address %q: %w", listenAddr, err)
|
|
}
|
|
|
|
parserMap := proto_socket.ParserMap{
|
|
proto_socket.TypeNameOf(&iop.PortalHelloRequest{}): func(b []byte) (proto.Message, error) {
|
|
req := &iop.PortalHelloRequest{}
|
|
return req, proto.Unmarshal(b, req)
|
|
},
|
|
proto_socket.TypeNameOf(&iop.PortalHelloResponse{}): func(b []byte) (proto.Message, error) {
|
|
res := &iop.PortalHelloResponse{}
|
|
return res, proto.Unmarshal(b, res)
|
|
},
|
|
}
|
|
|
|
opts := proto_socket.WsServerOptions{
|
|
AcceptOptions: &websocket.AcceptOptions{
|
|
OriginPatterns: []string{
|
|
"localhost",
|
|
"localhost:*",
|
|
"127.0.0.1",
|
|
"127.0.0.1:*",
|
|
},
|
|
},
|
|
}
|
|
|
|
wsServer := proto_socket.NewWsServerWithOptions(host, port, "/portal", opts, func(conn *websocket.Conn) *proto_socket.WsClient {
|
|
client := proto_socket.NewWsClient(conn, proto_socket.DefaultHeartbeatIntervalSec, proto_socket.DefaultHeartbeatWaitSec, parserMap)
|
|
|
|
proto_socket.AddRequestListenerTyped(&client.Communicator, func(req *iop.PortalHelloRequest) (*iop.PortalHelloResponse, error) {
|
|
logger.Info("portal client hello request received",
|
|
zap.String("client_id", req.ClientId),
|
|
zap.String("client_version", req.ClientVersion),
|
|
)
|
|
return &iop.PortalHelloResponse{
|
|
Ready: true,
|
|
Protocol: Protocol,
|
|
ServerTimeUnixNano: time.Now().UnixNano(),
|
|
Message: "Hello from IOP Control Plane",
|
|
}, nil
|
|
})
|
|
|
|
return client
|
|
})
|
|
|
|
wsServer.OnClientConnected = func(client *proto_socket.WsClient) {
|
|
logger.Info("portal client connected via proto-socket WS")
|
|
}
|
|
|
|
return &PortalServer{
|
|
server: wsServer,
|
|
logger: logger,
|
|
host: host,
|
|
port: port,
|
|
}, nil
|
|
}
|
|
|
|
// Start starts the portal wire WebSocket server.
|
|
func (s *PortalServer) Start(ctx context.Context) error {
|
|
s.logger.Info("starting portal wire WS server",
|
|
zap.String("host", s.host),
|
|
zap.Int("port", s.port),
|
|
zap.String("path", "/portal"),
|
|
)
|
|
return s.server.Start(ctx)
|
|
}
|
|
|
|
// Stop stops the portal wire WebSocket server.
|
|
func (s *PortalServer) Stop() error {
|
|
s.logger.Info("stopping portal wire WS server")
|
|
return s.server.Stop()
|
|
}
|
|
|
|
// Host returns the host the server is listening on.
|
|
func (s *PortalServer) Host() string {
|
|
return s.host
|
|
}
|
|
|
|
// Port returns the port the server is listening on.
|
|
func (s *PortalServer) Port() int {
|
|
return s.port
|
|
}
|