Add persistent fabric session client

This commit is contained in:
2026-05-16 00:38:28 +03:00
parent b5a29d692e
commit ce6b9beb6b
4 changed files with 226 additions and 46 deletions
+78 -17
View File
@@ -20,10 +20,17 @@ type Client struct {
}
type FabricSessionDialOptions struct {
Token string
Header http.Header
Dialer *websocket.Dialer
Timeout time.Duration
Token string
Header http.Header
Dialer *websocket.Dialer
Timeout time.Duration
MaxPayload int
}
type FabricSessionClient struct {
conn *websocket.Conn
timeout time.Duration
maxPayload int
}
func NewClient(baseURL string) Client {
@@ -142,35 +149,89 @@ func (c Client) DialFabricSession(ctx context.Context, opts FabricSessionDialOpt
return dialer.DialContext(ctx, target, header)
}
func (c Client) SendFabricSessionFrame(ctx context.Context, opts FabricSessionDialOptions, frame fabricproto.Frame) (fabricproto.Frame, error) {
func (c Client) OpenFabricSession(ctx context.Context, opts FabricSessionDialOptions) (*FabricSessionClient, *http.Response, error) {
conn, resp, err := c.DialFabricSession(ctx, opts)
if err != nil {
if resp != nil {
return fabricproto.Frame{}, fmt.Errorf("fabric session websocket rejected with status %d: %w", resp.StatusCode, err)
return nil, resp, fmt.Errorf("fabric session websocket rejected with status %d: %w", resp.StatusCode, err)
}
return fabricproto.Frame{}, err
return nil, resp, err
}
defer conn.Close()
payload, err := fabricproto.MarshalFrame(frame)
maxPayload := opts.MaxPayload
if maxPayload <= 0 {
maxPayload = fabricproto.DefaultMaxPayload
}
return &FabricSessionClient{
conn: conn,
timeout: opts.Timeout,
maxPayload: maxPayload,
}, resp, nil
}
func (c Client) SendFabricSessionFrame(ctx context.Context, opts FabricSessionDialOptions, frame fabricproto.Frame) (fabricproto.Frame, error) {
session, _, err := c.OpenFabricSession(ctx, opts)
if err != nil {
return fabricproto.Frame{}, err
}
if err := conn.WriteMessage(websocket.BinaryMessage, payload); err != nil {
return fabricproto.Frame{}, err
defer session.Close()
return session.RoundTrip(ctx, frame)
}
func (c *FabricSessionClient) Close() error {
if c == nil || c.conn == nil {
return nil
}
if deadline, ok := ctx.Deadline(); ok {
_ = conn.SetReadDeadline(deadline)
} else if opts.Timeout > 0 {
_ = conn.SetReadDeadline(time.Now().Add(opts.Timeout))
return c.conn.Close()
}
func (c *FabricSessionClient) WriteFrame(ctx context.Context, frame fabricproto.Frame) error {
if c == nil || c.conn == nil {
return fmt.Errorf("fabric session client is closed")
}
messageType, responsePayload, err := conn.ReadMessage()
payload, err := fabricproto.MarshalFrame(frame)
if err != nil {
return err
}
c.applyWriteDeadline(ctx)
return c.conn.WriteMessage(websocket.BinaryMessage, payload)
}
func (c *FabricSessionClient) ReadFrame(ctx context.Context) (fabricproto.Frame, error) {
if c == nil || c.conn == nil {
return fabricproto.Frame{}, fmt.Errorf("fabric session client is closed")
}
c.applyReadDeadline(ctx)
messageType, responsePayload, err := c.conn.ReadMessage()
if err != nil {
return fabricproto.Frame{}, err
}
if messageType != websocket.BinaryMessage {
return fabricproto.Frame{}, fmt.Errorf("fabric session websocket returned non-binary message type %d", messageType)
}
return fabricproto.UnmarshalFrame(responsePayload, fabricproto.DefaultMaxPayload)
return fabricproto.UnmarshalFrame(responsePayload, c.maxPayload)
}
func (c *FabricSessionClient) RoundTrip(ctx context.Context, frame fabricproto.Frame) (fabricproto.Frame, error) {
if err := c.WriteFrame(ctx, frame); err != nil {
return fabricproto.Frame{}, err
}
return c.ReadFrame(ctx)
}
func (c *FabricSessionClient) applyReadDeadline(ctx context.Context) {
if deadline, ok := ctx.Deadline(); ok {
_ = c.conn.SetReadDeadline(deadline)
} else if c.timeout > 0 {
_ = c.conn.SetReadDeadline(time.Now().Add(c.timeout))
}
}
func (c *FabricSessionClient) applyWriteDeadline(ctx context.Context) {
if deadline, ok := ctx.Deadline(); ok {
_ = c.conn.SetWriteDeadline(deadline)
} else if c.timeout > 0 {
_ = c.conn.SetWriteDeadline(time.Now().Add(c.timeout))
}
}
func (c Client) fabricSessionWebSocketURL() (string, error) {