| 236 | } |
| 237 | |
| 238 | func (p *PsyNetRPC) sendRequestAsync(ctx context.Context, service string, data interface{}) (<-chan *PsyResponse, error) { |
| 239 | if !p.IsConnected() { |
| 240 | return nil, fmt.Errorf("websocket connection not established") |
| 241 | } |
| 242 | |
| 243 | requestID := p.requestID.getID() |
| 244 | p.logger.Debug("sending websocket request", slog.String("requestID", requestID), slog.String("service", service), slog.Any("data", data)) |
| 245 | |
| 246 | respCh := make(chan *PsyResponse, 1) |
| 247 | |
| 248 | headers := map[string]string{ |
| 249 | "PsyService": service, |
| 250 | "PsyRequestID": requestID, |
| 251 | } |
| 252 | message, err := p.buildMessage(headers, data) |
| 253 | if err != nil { |
| 254 | return nil, fmt.Errorf("failed to buildm message: %w", err) |
| 255 | } |
| 256 | |
| 257 | p.mu.Lock() |
| 258 | if !p.connected || p.wsConn == nil { |
| 259 | p.mu.Unlock() |
| 260 | return nil, fmt.Errorf("connection lost while preparing to send") |
| 261 | } |
| 262 | |
| 263 | p.pendingReqs[requestID] = respCh |
| 264 | err = p.wsConn.WriteMessage(websocket.TextMessage, []byte(message)) |
| 265 | if err != nil { |
| 266 | delete(p.pendingReqs, requestID) |
| 267 | p.mu.Unlock() |
| 268 | return nil, fmt.Errorf("failed to send request: %w", err) |
| 269 | } |
| 270 | |
| 271 | p.mu.Unlock() |
| 272 | |
| 273 | go func() { |
| 274 | <-ctx.Done() |
| 275 | p.mu.Lock() |
| 276 | ch := p.pendingReqs[requestID] |
| 277 | delete(p.pendingReqs, requestID) |
| 278 | p.mu.Unlock() |
| 279 | |
| 280 | if ch != nil { |
| 281 | close(ch) |
| 282 | } |
| 283 | }() |
| 284 | |
| 285 | return respCh, nil |
| 286 | } |
| 287 | |
| 288 | func (p *PsyNetRPC) awaitResponse(ctx context.Context, respCh <-chan *PsyResponse, result interface{}) error { |
| 289 | select { |