vector_mcp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module VectorMCP
4
+ module Transport
5
+ class SSE
6
+ # Manages Server-Sent Events streaming for client connections.
7
+ # Handles creation of streaming responses and message broadcasting.
8
+ class StreamManager
9
+ class << self
10
+ # Creates an SSE streaming response body for a client connection.
11
+ #
12
+ # @param client_conn [ClientConnection] The client connection to stream to
13
+ # @param endpoint_url [String] The URL for the client to POST messages to
14
+ # @param logger [Logger] Logger instance for debugging
15
+ # @return [Enumerator] Rack-compatible streaming response body
16
+ def create_sse_stream(client_conn, endpoint_url, logger)
17
+ Enumerator.new do |yielder|
18
+ # Send initial endpoint event
19
+ yielder << format_sse_event("endpoint", endpoint_url)
20
+ logger.debug { "Sent endpoint event to client #{client_conn.session_id}: #{endpoint_url}" }
21
+
22
+ # Start streaming thread for this client
23
+ client_conn.stream_thread = Thread.new do
24
+ stream_messages_to_client(client_conn, yielder, logger)
25
+ end
26
+
27
+ # Keep the connection alive by yielding from the streaming thread
28
+ client_conn.stream_thread.join
29
+ rescue StandardError => e
30
+ logger.error { "Error in SSE stream for client #{client_conn.session_id}: #{e.message}\n#{e.backtrace.join("\n")}" }
31
+ ensure
32
+ logger.debug { "SSE stream ended for client #{client_conn.session_id}" }
33
+ client_conn.close
34
+ end
35
+ end
36
+
37
+ # Enqueues a message to a specific client connection.
38
+ #
39
+ # @param client_conn [ClientConnection] The target client connection
40
+ # @param message [Hash] The JSON-RPC message to send
41
+ # @return [Boolean] true if message was enqueued successfully
42
+ def enqueue_message(client_conn, message)
43
+ return false unless client_conn && !client_conn.closed?
44
+
45
+ client_conn.enqueue_message(message)
46
+ end
47
+
48
+ private
49
+
50
+ # Streams messages from a client's queue to the SSE connection.
51
+ # This method runs in a dedicated thread per client.
52
+ #
53
+ # @param client_conn [ClientConnection] The client connection
54
+ # @param yielder [Enumerator::Yielder] The response yielder
55
+ # @param logger [Logger] Logger instance
56
+ def stream_messages_to_client(client_conn, yielder, logger)
57
+ logger.debug { "Starting message streaming thread for client #{client_conn.session_id}" }
58
+
59
+ loop do
60
+ message = client_conn.dequeue_message
61
+ break if message.nil? # Queue closed or connection closed
62
+
63
+ begin
64
+ json_message = message.to_json
65
+ sse_data = format_sse_event("message", json_message)
66
+ yielder << sse_data
67
+
68
+ logger.debug { "Streamed message to client #{client_conn.session_id}: #{json_message}" }
69
+ rescue StandardError => e
70
+ logger.error { "Error streaming message to client #{client_conn.session_id}: #{e.message}" }
71
+ break
72
+ end
73
+ end
74
+
75
+ logger.debug { "Message streaming thread ended for client #{client_conn.session_id}" }
76
+ rescue StandardError => e
77
+ logger.error { "Fatal error in streaming thread for client #{client_conn.session_id}: #{e.message}\n#{e.backtrace.join("\n")}" }
78
+ end
79
+
80
+ # Formats data as a Server-Sent Event.
81
+ #
82
+ # @param event [String] The event type
83
+ # @param data [String] The event data
84
+ # @return [String] Properly formatted SSE event
85
+ def format_sse_event(event, data)
86
+ "event: #{event}\ndata: #{data}\n\n"
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end