account_traffic_ws.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package service
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. openaiwsv2 "github.com/Wei-Shaw/sub2api/internal/service/openai_ws_v2"
  7. coderws "github.com/coder/websocket"
  8. "github.com/tidwall/gjson"
  9. )
  10. // Passthrough may carry many independent response.create turns. Count each
  11. // turn, release at its terminal event, and do not charge session.update/pings.
  12. type accountTrafficFrameConn struct {
  13. inner openaiwsv2.FrameConn
  14. control *AccountTrafficService
  15. plan AccountTrafficPlan
  16. ctx context.Context
  17. mu sync.Mutex
  18. permit *AccountTrafficPermit
  19. }
  20. func (c *accountTrafficFrameConn) finish(status int) {
  21. c.mu.Lock()
  22. p := c.permit
  23. c.permit = nil
  24. c.mu.Unlock()
  25. p.Finish(status)
  26. }
  27. func (c *accountTrafficFrameConn) ReadFrame(ctx context.Context) (coderws.MessageType, []byte, error) {
  28. kind, payload, err := c.inner.ReadFrame(ctx)
  29. if err != nil {
  30. c.finish(0)
  31. return kind, payload, err
  32. }
  33. if status, terminal := accountTrafficEventStatus(payload); terminal {
  34. c.finish(status)
  35. }
  36. return kind, payload, nil
  37. }
  38. func (c *accountTrafficFrameConn) WriteFrame(ctx context.Context, kind coderws.MessageType, payload []byte) error {
  39. if gjson.GetBytes(payload, "type").String() != "response.create" {
  40. return c.inner.WriteFrame(ctx, kind, payload)
  41. }
  42. c.mu.Lock()
  43. if c.permit != nil {
  44. c.mu.Unlock()
  45. return (&AccountTrafficLimitError{Reason: "上一轮请求尚未结束,请等待后重试", RetryAfter: time.Second}).FailoverError()
  46. }
  47. _, p, err := c.control.Begin(c.ctx, c.plan, func() { _ = c.inner.Close() })
  48. if err != nil {
  49. c.mu.Unlock()
  50. if failure := AccountTrafficFailover(err); failure != nil {
  51. return failure
  52. }
  53. return err
  54. }
  55. c.permit = p
  56. c.mu.Unlock()
  57. err = c.inner.WriteFrame(ctx, kind, payload)
  58. if err != nil {
  59. c.finish(0)
  60. }
  61. return err
  62. }
  63. func (c *accountTrafficFrameConn) Close() error { c.finish(0); return c.inner.Close() }
  64. func wrapAccountTrafficFrameConn(ctx context.Context, upstream HTTPUpstream, a *Account, inner openaiwsv2.FrameConn) (openaiwsv2.FrameConn, error) {
  65. plan, err := AccountTrafficPlanFor(a)
  66. if err != nil {
  67. return nil, err
  68. }
  69. if !plan.Policy.Enabled() {
  70. return inner, nil
  71. }
  72. return &accountTrafficFrameConn{inner: inner, control: accountTrafficController(upstream), plan: plan, ctx: ctx}, nil
  73. }