Paper trading readiness에서 API/worker/CLI가 같은 protobuf 계약으로 paper state를 시작하고 조회할 수 있어야 한다. Headless 운영 경로를 먼저 닫기 위해 contract, worker runtime, API forwarding, CLI scenario, client parser map과 검증 artifact를 함께 반영한다.
88 lines
3.3 KiB
Go
88 lines
3.3 KiB
Go
package socket
|
|
|
|
import (
|
|
protoSocket "git.toki-labs.com/toki/proto-socket/go"
|
|
|
|
altv1 "git.toki-labs.com/toki/alt/packages/contracts/gen/go/alt/v1"
|
|
"git.toki-labs.com/toki/alt/services/api/internal/workerclient"
|
|
)
|
|
|
|
// sessionHandler is one request-response unit attached to a freshly connected
|
|
// client communicator. Splitting registration into independent units keeps the
|
|
// api hub control-plane surface thin: later command/query handlers attach
|
|
// through the same registry instead of growing a single registration function.
|
|
type sessionHandler struct {
|
|
// requestType is the ALT protobuf request type name the handler answers.
|
|
// It lets the registry detect duplicate or missing handler coverage without
|
|
// a live socket connection.
|
|
requestType string
|
|
// register attaches the handler onto the client communicator.
|
|
register func(*protoSocket.WsClient)
|
|
}
|
|
|
|
// sessionHandlers returns the ordered set of handlers registered on every API
|
|
// client session. Hello is registered through this registry so its behaviour
|
|
// stays identical while gaining the shared registration path.
|
|
func sessionHandlers(worker workerclient.WorkerClient) []sessionHandler {
|
|
handlers := []sessionHandler{
|
|
helloHandler(worker),
|
|
}
|
|
handlers = append(handlers, marketHandlers(worker)...)
|
|
handlers = append(handlers, backtestHandlers(worker)...)
|
|
handlers = append(handlers, paperHandlers(worker)...)
|
|
return handlers
|
|
}
|
|
|
|
// registerSessionHandlers wires every session handler onto a newly connected
|
|
// client. It is the OnClientConnected entrypoint for the API socket server.
|
|
func registerSessionHandlers(worker workerclient.WorkerClient) func(*protoSocket.WsClient) {
|
|
return func(client *protoSocket.WsClient) {
|
|
registerHandlers(client, sessionHandlers(worker))
|
|
}
|
|
}
|
|
|
|
// registerHandlers attaches the given handlers onto a client. nil registrars
|
|
// are skipped so a malformed registry entry cannot panic the connection setup
|
|
// path.
|
|
func registerHandlers(client *protoSocket.WsClient, handlers []sessionHandler) {
|
|
for _, handler := range handlers {
|
|
if handler.register == nil {
|
|
continue
|
|
}
|
|
handler.register(client)
|
|
}
|
|
}
|
|
|
|
func helloHandler(worker workerclient.WorkerClient) sessionHandler {
|
|
return sessionHandler{
|
|
requestType: protoSocket.TypeNameOf(&altv1.HelloRequest{}),
|
|
register: func(client *protoSocket.WsClient) {
|
|
protoSocket.AddRequestListenerTyped[*altv1.HelloRequest, *altv1.HelloResponse](&client.Communicator, func(req *altv1.HelloRequest) (*altv1.HelloResponse, error) {
|
|
return handleHello(worker, req)
|
|
})
|
|
},
|
|
}
|
|
}
|
|
|
|
func handleHello(worker workerclient.WorkerClient, req *altv1.HelloRequest) (*altv1.HelloResponse, error) {
|
|
protocolVersion := req.GetAltProtocolVersion()
|
|
if protocolVersion == "" {
|
|
protocolVersion = defaultAltProtocolVersion
|
|
}
|
|
return &altv1.HelloResponse{
|
|
ServerName: serverName,
|
|
ServerVersion: serverVersion,
|
|
AltProtocolVersion: protocolVersion,
|
|
Capabilities: capabilitiesForSession(worker),
|
|
}, nil
|
|
}
|
|
|
|
func capabilitiesForSession(worker workerclient.WorkerClient) []string {
|
|
caps := []string{"hello", "request-response", "market-read", "market-import", "backtest-read", "backtest-start", "worker-execution", "paper-trading"}
|
|
if worker != nil && worker.IsConnected() {
|
|
caps = append(caps, "worker-available")
|
|
} else {
|
|
caps = append(caps, "worker-unavailable")
|
|
}
|
|
return caps
|
|
}
|