kubemq 1.0.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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +30 -0
  3. data/LICENSE +201 -0
  4. data/README.md +237 -0
  5. data/lib/kubemq/base_client.rb +180 -0
  6. data/lib/kubemq/cancellation_token.rb +63 -0
  7. data/lib/kubemq/channel_info.rb +84 -0
  8. data/lib/kubemq/configuration.rb +247 -0
  9. data/lib/kubemq/cq/client.rb +446 -0
  10. data/lib/kubemq/cq/command_message.rb +59 -0
  11. data/lib/kubemq/cq/command_received.rb +52 -0
  12. data/lib/kubemq/cq/command_response.rb +44 -0
  13. data/lib/kubemq/cq/command_response_message.rb +58 -0
  14. data/lib/kubemq/cq/commands_subscription.rb +45 -0
  15. data/lib/kubemq/cq/queries_subscription.rb +45 -0
  16. data/lib/kubemq/cq/query_message.rb +70 -0
  17. data/lib/kubemq/cq/query_received.rb +52 -0
  18. data/lib/kubemq/cq/query_response.rb +59 -0
  19. data/lib/kubemq/cq/query_response_message.rb +67 -0
  20. data/lib/kubemq/error_codes.rb +181 -0
  21. data/lib/kubemq/errors/error_mapper.rb +134 -0
  22. data/lib/kubemq/errors.rb +276 -0
  23. data/lib/kubemq/interceptors/auth_interceptor.rb +78 -0
  24. data/lib/kubemq/interceptors/error_mapping_interceptor.rb +75 -0
  25. data/lib/kubemq/interceptors/metrics_interceptor.rb +95 -0
  26. data/lib/kubemq/interceptors/retry_interceptor.rb +119 -0
  27. data/lib/kubemq/proto/kubemq_pb.rb +43 -0
  28. data/lib/kubemq/proto/kubemq_services_pb.rb +35 -0
  29. data/lib/kubemq/pubsub/client.rb +475 -0
  30. data/lib/kubemq/pubsub/event_message.rb +52 -0
  31. data/lib/kubemq/pubsub/event_received.rb +48 -0
  32. data/lib/kubemq/pubsub/event_send_result.rb +31 -0
  33. data/lib/kubemq/pubsub/event_sender.rb +112 -0
  34. data/lib/kubemq/pubsub/event_store_message.rb +53 -0
  35. data/lib/kubemq/pubsub/event_store_received.rb +47 -0
  36. data/lib/kubemq/pubsub/event_store_result.rb +33 -0
  37. data/lib/kubemq/pubsub/event_store_sender.rb +164 -0
  38. data/lib/kubemq/pubsub/events_store_subscription.rb +81 -0
  39. data/lib/kubemq/pubsub/events_subscription.rb +43 -0
  40. data/lib/kubemq/queues/client.rb +366 -0
  41. data/lib/kubemq/queues/downstream_receiver.rb +247 -0
  42. data/lib/kubemq/queues/queue_message.rb +99 -0
  43. data/lib/kubemq/queues/queue_message_received.rb +148 -0
  44. data/lib/kubemq/queues/queue_poll_request.rb +77 -0
  45. data/lib/kubemq/queues/queue_poll_response.rb +138 -0
  46. data/lib/kubemq/queues/queue_send_result.rb +49 -0
  47. data/lib/kubemq/queues/upstream_sender.rb +180 -0
  48. data/lib/kubemq/server_info.rb +57 -0
  49. data/lib/kubemq/subscription.rb +98 -0
  50. data/lib/kubemq/telemetry/otel.rb +64 -0
  51. data/lib/kubemq/telemetry/semconv.rb +51 -0
  52. data/lib/kubemq/transport/channel_manager.rb +212 -0
  53. data/lib/kubemq/transport/converter.rb +287 -0
  54. data/lib/kubemq/transport/grpc_transport.rb +411 -0
  55. data/lib/kubemq/transport/message_buffer.rb +105 -0
  56. data/lib/kubemq/transport/reconnect_manager.rb +111 -0
  57. data/lib/kubemq/transport/state_machine.rb +150 -0
  58. data/lib/kubemq/types.rb +80 -0
  59. data/lib/kubemq/validation/validator.rb +216 -0
  60. data/lib/kubemq/version.rb +6 -0
  61. data/lib/kubemq.rb +118 -0
  62. metadata +138 -0
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kubemq.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+
8
+ descriptor_data = "\n\x0ckubemq.proto\x12\x06kubemq\"a\n\nPingResult\x12\x0c\n\x04Host\x18\x01 \x01(\t\x12\x0f\n\x07Version\x18\x02 \x01(\t\x12\x17\n\x0fServerStartTime\x18\x03 \x01(\x03\x12\x1b\n\x13ServerUpTimeSeconds\x18\x04 \x01(\x03\"\x07\n\x05\x45mpty\"6\n\x06Result\x12\x0f\n\x07\x45ventID\x18\x01 \x01(\t\x12\x0c\n\x04Sent\x18\x02 \x01(\x08\x12\r\n\x05\x45rror\x18\x03 \x01(\t\"\xbe\x01\n\x05\x45vent\x12\x0f\n\x07\x45ventID\x18\x01 \x01(\t\x12\x10\n\x08\x43lientID\x18\x02 \x01(\t\x12\x0f\n\x07\x43hannel\x18\x03 \x01(\t\x12\x10\n\x08Metadata\x18\x04 \x01(\t\x12\x0c\n\x04\x42ody\x18\x05 \x01(\x0c\x12\r\n\x05Store\x18\x06 \x01(\x08\x12%\n\x04Tags\x18\x07 \x03(\x0b\x32\x17.kubemq.Event.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xd0\x01\n\x0c\x45ventReceive\x12\x0f\n\x07\x45ventID\x18\x01 \x01(\t\x12\x0f\n\x07\x43hannel\x18\x02 \x01(\t\x12\x10\n\x08Metadata\x18\x03 \x01(\t\x12\x0c\n\x04\x42ody\x18\x04 \x01(\x0c\x12\x11\n\tTimestamp\x18\x05 \x01(\x03\x12\x10\n\x08Sequence\x18\x06 \x01(\x04\x12,\n\x04Tags\x18\x07 \x03(\x0b\x32\x1e.kubemq.EventReceive.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xe3\x03\n\tSubscribe\x12:\n\x11SubscribeTypeData\x18\x01 \x01(\x0e\x32\x1f.kubemq.Subscribe.SubscribeType\x12\x10\n\x08\x43lientID\x18\x02 \x01(\t\x12\x0f\n\x07\x43hannel\x18\x03 \x01(\t\x12\r\n\x05Group\x18\x04 \x01(\t\x12>\n\x13\x45ventsStoreTypeData\x18\x05 \x01(\x0e\x32!.kubemq.Subscribe.EventsStoreType\x12\x1c\n\x14\x45ventsStoreTypeValue\x18\x06 \x01(\x03\"c\n\rSubscribeType\x12\x1a\n\x16SubscribeTypeUndefined\x10\x00\x12\n\n\x06\x45vents\x10\x01\x12\x0f\n\x0b\x45ventsStore\x10\x02\x12\x0c\n\x08\x43ommands\x10\x03\x12\x0b\n\x07Queries\x10\x04\"\xa4\x01\n\x0f\x45ventsStoreType\x12\x1c\n\x18\x45ventsStoreTypeUndefined\x10\x00\x12\x10\n\x0cStartNewOnly\x10\x01\x12\x12\n\x0eStartFromFirst\x10\x02\x12\x11\n\rStartFromLast\x10\x03\x12\x13\n\x0fStartAtSequence\x10\x04\x12\x0f\n\x0bStartAtTime\x10\x05\x12\x14\n\x10StartAtTimeDelta\x10\x06\"\x83\x03\n\x07Request\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12\x34\n\x0fRequestTypeData\x18\x02 \x01(\x0e\x32\x1b.kubemq.Request.RequestType\x12\x10\n\x08\x43lientID\x18\x03 \x01(\t\x12\x0f\n\x07\x43hannel\x18\x04 \x01(\t\x12\x10\n\x08Metadata\x18\x05 \x01(\t\x12\x0c\n\x04\x42ody\x18\x06 \x01(\x0c\x12\x14\n\x0cReplyChannel\x18\x07 \x01(\t\x12\x0f\n\x07Timeout\x18\x08 \x01(\x05\x12\x10\n\x08\x43\x61\x63heKey\x18\t \x01(\t\x12\x10\n\x08\x43\x61\x63heTTL\x18\n \x01(\x05\x12\x0c\n\x04Span\x18\x0b \x01(\x0c\x12\'\n\x04Tags\x18\x0c \x03(\x0b\x32\x19.kubemq.Request.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"=\n\x0bRequestType\x12\x16\n\x12RequestTypeUnknown\x10\x00\x12\x0b\n\x07\x43ommand\x10\x01\x12\t\n\x05Query\x10\x02\"\x90\x02\n\x08Response\x12\x10\n\x08\x43lientID\x18\x01 \x01(\t\x12\x11\n\tRequestID\x18\x02 \x01(\t\x12\x14\n\x0cReplyChannel\x18\x03 \x01(\t\x12\x10\n\x08Metadata\x18\x04 \x01(\t\x12\x0c\n\x04\x42ody\x18\x05 \x01(\x0c\x12\x10\n\x08\x43\x61\x63heHit\x18\x06 \x01(\x08\x12\x11\n\tTimestamp\x18\x07 \x01(\x03\x12\x10\n\x08\x45xecuted\x18\x08 \x01(\x08\x12\r\n\x05\x45rror\x18\t \x01(\t\x12\x0c\n\x04Span\x18\n \x01(\x0c\x12(\n\x04Tags\x18\x0b \x03(\x0b\x32\x1a.kubemq.Response.TagsEntry\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x9f\x02\n\x0cQueueMessage\x12\x11\n\tMessageID\x18\x01 \x01(\t\x12\x10\n\x08\x43lientID\x18\x02 \x01(\t\x12\x0f\n\x07\x43hannel\x18\x03 \x01(\t\x12\x10\n\x08Metadata\x18\x04 \x01(\t\x12\x0c\n\x04\x42ody\x18\x05 \x01(\x0c\x12,\n\x04Tags\x18\x06 \x03(\x0b\x32\x1e.kubemq.QueueMessage.TagsEntry\x12\x32\n\nAttributes\x18\x07 \x01(\x0b\x32\x1e.kubemq.QueueMessageAttributes\x12*\n\x06Policy\x18\x08 \x01(\x0b\x32\x1a.kubemq.QueueMessagePolicy\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"T\n\x19QueueMessagesBatchRequest\x12\x0f\n\x07\x42\x61tchID\x18\x01 \x01(\t\x12&\n\x08Messages\x18\x02 \x03(\x0b\x32\x14.kubemq.QueueMessage\"r\n\x1aQueueMessagesBatchResponse\x12\x0f\n\x07\x42\x61tchID\x18\x01 \x01(\t\x12/\n\x07Results\x18\x02 \x03(\x0b\x32\x1e.kubemq.SendQueueMessageResult\x12\x12\n\nHaveErrors\x18\x03 \x01(\x08\"\xbc\x01\n\x16QueueMessageAttributes\x12\x11\n\tTimestamp\x18\x01 \x01(\x03\x12\x10\n\x08Sequence\x18\x02 \x01(\x04\x12\x11\n\tMD5OfBody\x18\x03 \x01(\t\x12\x14\n\x0cReceiveCount\x18\x04 \x01(\x05\x12\x10\n\x08ReRouted\x18\x05 \x01(\x08\x12\x19\n\x11ReRoutedFromQueue\x18\x06 \x01(\t\x12\x14\n\x0c\x45xpirationAt\x18\x07 \x01(\x03\x12\x11\n\tDelayedTo\x18\x08 \x01(\x03\"w\n\x12QueueMessagePolicy\x12\x19\n\x11\x45xpirationSeconds\x18\x01 \x01(\x05\x12\x14\n\x0c\x44\x65laySeconds\x18\x02 \x01(\x05\x12\x17\n\x0fMaxReceiveCount\x18\x03 \x01(\x05\x12\x17\n\x0fMaxReceiveQueue\x18\x04 \x01(\t\"\x84\x01\n\x16SendQueueMessageResult\x12\x11\n\tMessageID\x18\x01 \x01(\t\x12\x0e\n\x06SentAt\x18\x02 \x01(\x03\x12\x14\n\x0c\x45xpirationAt\x18\x03 \x01(\x03\x12\x11\n\tDelayedTo\x18\x04 \x01(\x03\x12\x0f\n\x07IsError\x18\x05 \x01(\x08\x12\r\n\x05\x45rror\x18\x06 \x01(\t\"\x99\x01\n\x1bReceiveQueueMessagesRequest\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12\x10\n\x08\x43lientID\x18\x02 \x01(\t\x12\x0f\n\x07\x43hannel\x18\x03 \x01(\t\x12\x1b\n\x13MaxNumberOfMessages\x18\x04 \x01(\x05\x12\x17\n\x0fWaitTimeSeconds\x18\x05 \x01(\x05\x12\x0e\n\x06IsPeak\x18\x06 \x01(\x08\"\xbc\x01\n\x1cReceiveQueueMessagesResponse\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12&\n\x08Messages\x18\x02 \x03(\x0b\x32\x14.kubemq.QueueMessage\x12\x18\n\x10MessagesReceived\x18\x03 \x01(\x05\x12\x17\n\x0fMessagesExpired\x18\x04 \x01(\x05\x12\x0e\n\x06IsPeak\x18\x05 \x01(\x08\x12\x0f\n\x07IsError\x18\x06 \x01(\x08\x12\r\n\x05\x45rror\x18\x07 \x01(\t\"k\n\x1a\x41\x63kAllQueueMessagesRequest\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12\x10\n\x08\x43lientID\x18\x02 \x01(\t\x12\x0f\n\x07\x43hannel\x18\x03 \x01(\t\x12\x17\n\x0fWaitTimeSeconds\x18\x04 \x01(\x05\"j\n\x1b\x41\x63kAllQueueMessagesResponse\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12\x18\n\x10\x41\x66\x66\x65\x63tedMessages\x18\x02 \x01(\x04\x12\x0f\n\x07IsError\x18\x03 \x01(\x08\x12\r\n\x05\x45rror\x18\x04 \x01(\t\"\x84\x02\n\x1aStreamQueueMessagesRequest\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12\x10\n\x08\x43lientID\x18\x02 \x01(\t\x12\x38\n\x15StreamRequestTypeData\x18\x03 \x01(\x0e\x32\x19.kubemq.StreamRequestType\x12\x0f\n\x07\x43hannel\x18\x04 \x01(\t\x12\x19\n\x11VisibilitySeconds\x18\x05 \x01(\x05\x12\x17\n\x0fWaitTimeSeconds\x18\x06 \x01(\x05\x12\x13\n\x0bRefSequence\x18\x07 \x01(\x04\x12-\n\x0fModifiedMessage\x18\x08 \x01(\x0b\x32\x14.kubemq.QueueMessage\"\xb1\x01\n\x1bStreamQueueMessagesResponse\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12\x38\n\x15StreamRequestTypeData\x18\x02 \x01(\x0e\x32\x19.kubemq.StreamRequestType\x12%\n\x07Message\x18\x03 \x01(\x0b\x32\x14.kubemq.QueueMessage\x12\x0f\n\x07IsError\x18\x04 \x01(\x08\x12\r\n\x05\x45rror\x18\x05 \x01(\t\"R\n\x15QueuesUpstreamRequest\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12&\n\x08Messages\x18\x02 \x03(\x0b\x32\x14.kubemq.QueueMessage\"\x7f\n\x16QueuesUpstreamResponse\x12\x14\n\x0cRefRequestID\x18\x01 \x01(\t\x12/\n\x07Results\x18\x02 \x03(\x0b\x32\x1e.kubemq.SendQueueMessageResult\x12\x0f\n\x07IsError\x18\x03 \x01(\x08\x12\r\n\x05\x45rror\x18\x04 \x01(\t\"\x80\x03\n\x17QueuesDownstreamRequest\x12\x11\n\tRequestID\x18\x01 \x01(\t\x12\x10\n\x08\x43lientID\x18\x02 \x01(\t\x12<\n\x0fRequestTypeData\x18\x03 \x01(\x0e\x32#.kubemq.QueuesDownstreamRequestType\x12\x0f\n\x07\x43hannel\x18\x04 \x01(\t\x12\x10\n\x08MaxItems\x18\x05 \x01(\x05\x12\x13\n\x0bWaitTimeout\x18\x06 \x01(\x05\x12\x0f\n\x07\x41utoAck\x18\x07 \x01(\x08\x12\x16\n\x0eReQueueChannel\x18\x08 \x01(\t\x12\x15\n\rSequenceRange\x18\t \x03(\x03\x12\x18\n\x10RefTransactionId\x18\n \x01(\t\x12?\n\x08Metadata\x18\x0c \x03(\x0b\x32-.kubemq.QueuesDownstreamRequest.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xf4\x02\n\x18QueuesDownstreamResponse\x12\x15\n\rTransactionId\x18\x01 \x01(\t\x12\x14\n\x0cRefRequestId\x18\x02 \x01(\t\x12<\n\x0fRequestTypeData\x18\x03 \x01(\x0e\x32#.kubemq.QueuesDownstreamRequestType\x12&\n\x08Messages\x18\x04 \x03(\x0b\x32\x14.kubemq.QueueMessage\x12\x15\n\rActiveOffsets\x18\x05 \x03(\x03\x12\x0f\n\x07IsError\x18\x06 \x01(\x08\x12\r\n\x05\x45rror\x18\x07 \x01(\t\x12\x1b\n\x13TransactionComplete\x18\x08 \x01(\x08\x12@\n\x08Metadata\x18\t \x03(\x0b\x32..kubemq.QueuesDownstreamResponse.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01*\xaa\x01\n\x11StreamRequestType\x12\x1c\n\x18StreamRequestTypeUnknown\x10\x00\x12\x12\n\x0eReceiveMessage\x10\x01\x12\x0e\n\nAckMessage\x10\x02\x12\x11\n\rRejectMessage\x10\x03\x12\x14\n\x10ModifyVisibility\x10\x04\x12\x11\n\rResendMessage\x10\x05\x12\x17\n\x13SendModifiedMessage\x10\x06*\xea\x01\n\x1bQueuesDownstreamRequestType\x12\x1a\n\x16PollRequestTypeUnknown\x10\x00\x12\x07\n\x03Get\x10\x01\x12\n\n\x06\x41\x63kAll\x10\x02\x12\x0c\n\x08\x41\x63kRange\x10\x03\x12\x0b\n\x07NAckAll\x10\x04\x12\r\n\tNAckRange\x10\x05\x12\x0e\n\nReQueueAll\x10\x06\x12\x10\n\x0cReQueueRange\x10\x07\x12\x11\n\rActiveOffsets\x10\x08\x12\x15\n\x11TransactionStatus\x10\t\x12\x11\n\rCloseByClient\x10\n\x12\x11\n\rCloseByServer\x10\x0b\x32\x93\x08\n\x06kubemq\x12,\n\tSendEvent\x12\r.kubemq.Event\x1a\x0e.kubemq.Result\"\x00\x12\x37\n\x10SendEventsStream\x12\r.kubemq.Event\x1a\x0e.kubemq.Result\"\x00(\x01\x30\x01\x12@\n\x11SubscribeToEvents\x12\x11.kubemq.Subscribe\x1a\x14.kubemq.EventReceive\"\x00\x30\x01\x12=\n\x13SubscribeToRequests\x12\x11.kubemq.Subscribe\x1a\x0f.kubemq.Request\"\x00\x30\x01\x12\x32\n\x0bSendRequest\x12\x0f.kubemq.Request\x1a\x10.kubemq.Response\"\x00\x12\x31\n\x0cSendResponse\x12\x10.kubemq.Response\x1a\r.kubemq.Empty\"\x00\x12J\n\x10SendQueueMessage\x12\x14.kubemq.QueueMessage\x1a\x1e.kubemq.SendQueueMessageResult\"\x00\x12\x61\n\x16SendQueueMessagesBatch\x12!.kubemq.QueueMessagesBatchRequest\x1a\".kubemq.QueueMessagesBatchResponse\"\x00\x12\x63\n\x14ReceiveQueueMessages\x12#.kubemq.ReceiveQueueMessagesRequest\x1a$.kubemq.ReceiveQueueMessagesResponse\"\x00\x12\x63\n\x12StreamQueueMessage\x12\".kubemq.StreamQueueMessagesRequest\x1a#.kubemq.StreamQueueMessagesResponse\"\x00(\x01\x30\x01\x12`\n\x13\x41\x63kAllQueueMessages\x12\".kubemq.AckAllQueueMessagesRequest\x1a#.kubemq.AckAllQueueMessagesResponse\"\x00\x12+\n\x04Ping\x12\r.kubemq.Empty\x1a\x12.kubemq.PingResult\"\x00\x12[\n\x10QueuesDownstream\x12\x1f.kubemq.QueuesDownstreamRequest\x1a .kubemq.QueuesDownstreamResponse\"\x00(\x01\x30\x01\x12U\n\x0eQueuesUpstream\x12\x1d.kubemq.QueuesUpstreamRequest\x1a\x1e.kubemq.QueuesUpstreamResponse\"\x00(\x01\x30\x01\x62\x06proto3"
9
+
10
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
+ pool.add_serialized_file(descriptor_data)
12
+
13
+ module Kubemq
14
+ PingResult = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.PingResult").msgclass
15
+ Empty = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Empty").msgclass
16
+ Result = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Result").msgclass
17
+ Event = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Event").msgclass
18
+ EventReceive = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.EventReceive").msgclass
19
+ Subscribe = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Subscribe").msgclass
20
+ Subscribe::SubscribeType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Subscribe.SubscribeType").enummodule
21
+ Subscribe::EventsStoreType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Subscribe.EventsStoreType").enummodule
22
+ Request = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Request").msgclass
23
+ Request::RequestType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Request.RequestType").enummodule
24
+ Response = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.Response").msgclass
25
+ QueueMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueueMessage").msgclass
26
+ QueueMessagesBatchRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueueMessagesBatchRequest").msgclass
27
+ QueueMessagesBatchResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueueMessagesBatchResponse").msgclass
28
+ QueueMessageAttributes = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueueMessageAttributes").msgclass
29
+ QueueMessagePolicy = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueueMessagePolicy").msgclass
30
+ SendQueueMessageResult = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.SendQueueMessageResult").msgclass
31
+ ReceiveQueueMessagesRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.ReceiveQueueMessagesRequest").msgclass
32
+ ReceiveQueueMessagesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.ReceiveQueueMessagesResponse").msgclass
33
+ AckAllQueueMessagesRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.AckAllQueueMessagesRequest").msgclass
34
+ AckAllQueueMessagesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.AckAllQueueMessagesResponse").msgclass
35
+ StreamQueueMessagesRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.StreamQueueMessagesRequest").msgclass
36
+ StreamQueueMessagesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.StreamQueueMessagesResponse").msgclass
37
+ QueuesUpstreamRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueuesUpstreamRequest").msgclass
38
+ QueuesUpstreamResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueuesUpstreamResponse").msgclass
39
+ QueuesDownstreamRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueuesDownstreamRequest").msgclass
40
+ QueuesDownstreamResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueuesDownstreamResponse").msgclass
41
+ StreamRequestType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.StreamRequestType").enummodule
42
+ QueuesDownstreamRequestType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kubemq.QueuesDownstreamRequestType").enummodule
43
+ end
@@ -0,0 +1,35 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: kubemq.proto for package 'kubemq'
3
+
4
+ require 'grpc'
5
+ require_relative 'kubemq_pb'
6
+
7
+ module Kubemq
8
+ module Kubemq
9
+ class Service
10
+
11
+ include ::GRPC::GenericService
12
+
13
+ self.marshal_class_method = :encode
14
+ self.unmarshal_class_method = :decode
15
+ self.service_name = 'kubemq.kubemq'
16
+
17
+ rpc :SendEvent, ::Kubemq::Event, ::Kubemq::Result
18
+ rpc :SendEventsStream, stream(::Kubemq::Event), stream(::Kubemq::Result)
19
+ rpc :SubscribeToEvents, ::Kubemq::Subscribe, stream(::Kubemq::EventReceive)
20
+ rpc :SubscribeToRequests, ::Kubemq::Subscribe, stream(::Kubemq::Request)
21
+ rpc :SendRequest, ::Kubemq::Request, ::Kubemq::Response
22
+ rpc :SendResponse, ::Kubemq::Response, ::Kubemq::Empty
23
+ rpc :SendQueueMessage, ::Kubemq::QueueMessage, ::Kubemq::SendQueueMessageResult
24
+ rpc :SendQueueMessagesBatch, ::Kubemq::QueueMessagesBatchRequest, ::Kubemq::QueueMessagesBatchResponse
25
+ rpc :ReceiveQueueMessages, ::Kubemq::ReceiveQueueMessagesRequest, ::Kubemq::ReceiveQueueMessagesResponse
26
+ rpc :StreamQueueMessage, stream(::Kubemq::StreamQueueMessagesRequest), stream(::Kubemq::StreamQueueMessagesResponse)
27
+ rpc :AckAllQueueMessages, ::Kubemq::AckAllQueueMessagesRequest, ::Kubemq::AckAllQueueMessagesResponse
28
+ rpc :Ping, ::Kubemq::Empty, ::Kubemq::PingResult
29
+ rpc :QueuesDownstream, stream(::Kubemq::QueuesDownstreamRequest), stream(::Kubemq::QueuesDownstreamResponse)
30
+ rpc :QueuesUpstream, stream(::Kubemq::QueuesUpstreamRequest), stream(::Kubemq::QueuesUpstreamResponse)
31
+ end
32
+
33
+ Stub = Service.rpc_stub_class
34
+ end
35
+ end
@@ -0,0 +1,475 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module KubeMQ
6
+ # Client for KubeMQ pub/sub messaging — events (fire-and-forget) and
7
+ # events store (durable with replay).
8
+ #
9
+ # Inherits connection management and channel CRUD from {BaseClient}.
10
+ # Subscription methods run on background threads and accept a block for
11
+ # incoming messages.
12
+ #
13
+ # @example Send and subscribe to events
14
+ # client = KubeMQ::PubSubClient.new(address: "localhost:50000")
15
+ #
16
+ # token = KubeMQ::CancellationToken.new
17
+ # sub = KubeMQ::PubSub::EventsSubscription.new(channel: "notifications")
18
+ # client.subscribe_to_events(sub, cancellation_token: token) do |event|
19
+ # puts "Received: #{event.body}"
20
+ # end
21
+ #
22
+ # client.send_event(
23
+ # KubeMQ::PubSub::EventMessage.new(channel: "notifications", body: "hello")
24
+ # )
25
+ # sleep 1
26
+ # token.cancel
27
+ # client.close
28
+ #
29
+ # @see PubSub::EventMessage
30
+ # @see PubSub::EventsSubscription
31
+ # @see PubSub::EventsStoreSubscription
32
+ class PubSubClient < BaseClient
33
+ def initialize(**kwargs)
34
+ super
35
+ @senders = []
36
+ @senders_mutex = Mutex.new
37
+ end
38
+
39
+ # Sends a single event to a channel. Fire-and-forget semantics — the
40
+ # server does not guarantee persistence.
41
+ #
42
+ # @param message [PubSub::EventMessage] event to send
43
+ #
44
+ # @return [PubSub::EventSendResult] send confirmation with error status
45
+ #
46
+ # @raise [ValidationError] if channel name or content is invalid
47
+ # @raise [ClientClosedError] if the client has been closed
48
+ # @raise [ConnectionError] if unable to reach the broker
49
+ #
50
+ # @example
51
+ # msg = KubeMQ::PubSub::EventMessage.new(
52
+ # channel: "events.orders",
53
+ # metadata: "order-created",
54
+ # body: '{"id": 42}',
55
+ # tags: { "env" => "production" }
56
+ # )
57
+ # result = client.send_event(msg)
58
+ # puts "Sent: #{result.id}" if result.sent
59
+ #
60
+ # @see PubSub::EventMessage
61
+ # @see PubSub::EventSendResult
62
+ def send_event(message)
63
+ Validator.validate_channel!(message.channel, allow_wildcards: false)
64
+ Validator.validate_content!(message.metadata, message.body)
65
+ ensure_connected!
66
+
67
+ proto = Transport::Converter.event_to_proto(message, @config.client_id, store: false)
68
+ result = @transport.kubemq_client.send_event(proto)
69
+ hash = Transport::Converter.proto_to_event_result(result)
70
+ PubSub::EventSendResult.new(**hash)
71
+ end
72
+
73
+ # Creates a streaming event sender for high-throughput publishing.
74
+ #
75
+ # The sender holds a persistent gRPC stream open. Close it explicitly
76
+ # when finished, or it will be closed when the client is closed.
77
+ #
78
+ # @param on_error [Proc, nil] callback receiving {Error} on stream failures
79
+ #
80
+ # @return [PubSub::EventSender] streaming sender bound to this client
81
+ #
82
+ # @raise [ClientClosedError] if the client has been closed
83
+ # @raise [ConnectionError] if unable to reach the broker
84
+ #
85
+ # @see PubSub::EventSender
86
+ def create_events_sender(on_error: nil)
87
+ ensure_connected!
88
+ sender = PubSub::EventSender.new(transport: @transport, client_id: @config.client_id, on_error: on_error)
89
+ senders_mutex.synchronize { senders_list << sender }
90
+ sender
91
+ end
92
+
93
+ # Subscribes to real-time events on a channel. Runs on a background
94
+ # thread; incoming events are delivered to the provided block.
95
+ #
96
+ # The subscription automatically reconnects with exponential backoff on
97
+ # transient failures. Use the returned {Subscription} or the
98
+ # +cancellation_token+ to stop.
99
+ #
100
+ # @param subscription [PubSub::EventsSubscription] channel and group config
101
+ # @param cancellation_token [CancellationToken, nil] token for cooperative
102
+ # cancellation (auto-created if nil)
103
+ # @param on_error [Proc, nil] callback receiving {Error} on stream or
104
+ # callback failures
105
+ # @yield [event] called for each received event on a background thread
106
+ # @yieldparam event [PubSub::EventReceived] the received event
107
+ #
108
+ # @return [Subscription] handle to check status, cancel, or join
109
+ #
110
+ # @raise [ArgumentError] if no block is given
111
+ # @raise [ValidationError] if the subscription channel is invalid
112
+ # @raise [ClientClosedError] if the client has been closed
113
+ #
114
+ # @note Wildcard channels (containing +*+ or +>+) are supported for events.
115
+ #
116
+ # @example
117
+ # token = KubeMQ::CancellationToken.new
118
+ # sub_config = KubeMQ::PubSub::EventsSubscription.new(
119
+ # channel: "events.>", group: "workers"
120
+ # )
121
+ # subscription = client.subscribe_to_events(sub_config, cancellation_token: token) do |event|
122
+ # puts "#{event.channel}: #{event.body}"
123
+ # end
124
+ # # later...
125
+ # token.cancel
126
+ # subscription.wait(5)
127
+ #
128
+ # @see PubSub::EventsSubscription
129
+ # @see PubSub::EventReceived
130
+ # @see CancellationToken
131
+ # @see Subscription
132
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength -- subscription with auto-reconnect loop
133
+ def subscribe_to_events(subscription, cancellation_token: nil, on_error: nil, &block)
134
+ raise ArgumentError, 'Block required for subscribe_to_events' unless block
135
+
136
+ Validator.validate_channel!(subscription.channel, allow_wildcards: true)
137
+ ensure_connected!
138
+
139
+ cancellation_token ||= CancellationToken.new
140
+ nil
141
+
142
+ thread = Thread.new do
143
+ @transport.register_subscription(Thread.current)
144
+ Thread.current[:cancellation_token] = cancellation_token
145
+ reconnect_attempts = 0
146
+ begin
147
+ loop do
148
+ break if cancellation_token.cancelled?
149
+
150
+ begin
151
+ @transport.ensure_connected!
152
+ proto_sub = Transport::Converter.subscribe_to_proto(subscription, @config.client_id)
153
+ stream = @transport.kubemq_client.subscribe_to_events(proto_sub)
154
+ Thread.current[:grpc_call] = stream
155
+ reconnect_attempts = 0
156
+ stream.each do |event_receive|
157
+ break if cancellation_token.cancelled?
158
+
159
+ hash = Transport::Converter.proto_to_event_received(event_receive)
160
+ received = PubSub::EventReceived.new(**hash)
161
+ begin
162
+ block.call(received)
163
+ rescue StandardError => e
164
+ begin
165
+ on_error&.call(Error.new("Callback error: #{e.message}", code: ErrorCode::CALLBACK_ERROR))
166
+ rescue StandardError => nested
167
+ Kernel.warn("[kubemq] on_error callback raised: #{nested.message}")
168
+ end
169
+ end
170
+ end
171
+ rescue CancellationError
172
+ break
173
+ rescue GRPC::BadStatus, StandardError => e
174
+ @transport.on_disconnect! if e.is_a?(GRPC::Unavailable) || e.is_a?(GRPC::DeadlineExceeded)
175
+ reconnect_attempts += 1
176
+ begin
177
+ if e.is_a?(GRPC::BadStatus)
178
+ on_error&.call(ErrorMapper.map_grpc_error(e, operation: 'subscribe_events'))
179
+ else
180
+ on_error&.call(Error.new(e.message, code: ErrorCode::STREAM_BROKEN))
181
+ end
182
+ rescue StandardError => cb_err
183
+ Kernel.warn("[kubemq] on_error callback raised: #{cb_err.message}")
184
+ end
185
+ delay = [@config.reconnect_policy.base_interval *
186
+ (@config.reconnect_policy.multiplier**(reconnect_attempts - 1)),
187
+ @config.reconnect_policy.max_delay].min
188
+ sleep(delay) unless cancellation_token.cancelled?
189
+ end
190
+ end
191
+ rescue StandardError => e
192
+ Thread.current[:kubemq_subscription]&.mark_error(e)
193
+ ensure
194
+ begin; Thread.current[:grpc_call]&.cancel; rescue StandardError; end
195
+ Thread.current[:kubemq_subscription]&.mark_closed
196
+ @transport.unregister_subscription(Thread.current)
197
+ end
198
+ end
199
+
200
+ sub_wrapper = KubeMQ::Subscription.new(thread: thread, cancellation_token: cancellation_token)
201
+ thread[:kubemq_subscription] = sub_wrapper
202
+ sub_wrapper
203
+ end
204
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
205
+
206
+ # Sends a single event to a durable events store channel.
207
+ #
208
+ # Unlike {#send_event}, the broker persists events store messages and
209
+ # supports replay via {#subscribe_to_events_store}.
210
+ #
211
+ # @param message [PubSub::EventStoreMessage] event store message to send
212
+ #
213
+ # @return [PubSub::EventStoreResult] send confirmation with error status
214
+ #
215
+ # @raise [ValidationError] if channel name or content is invalid
216
+ # @raise [ClientClosedError] if the client has been closed
217
+ # @raise [ConnectionError] if unable to reach the broker
218
+ #
219
+ # @example
220
+ # msg = KubeMQ::PubSub::EventStoreMessage.new(
221
+ # channel: "orders.created",
222
+ # body: '{"id": 42}'
223
+ # )
224
+ # result = client.send_event_store(msg)
225
+ # puts "Stored: #{result.id}" if result.sent
226
+ #
227
+ # @see PubSub::EventStoreMessage
228
+ # @see PubSub::EventStoreResult
229
+ def send_event_store(message)
230
+ Validator.validate_channel!(message.channel, allow_wildcards: false)
231
+ Validator.validate_content!(message.metadata, message.body)
232
+ ensure_connected!
233
+
234
+ proto = Transport::Converter.event_to_proto(message, @config.client_id, store: true)
235
+ result = @transport.kubemq_client.send_event(proto)
236
+ hash = Transport::Converter.proto_to_event_result(result)
237
+ PubSub::EventStoreResult.new(**hash)
238
+ end
239
+
240
+ # Creates a streaming events store sender for high-throughput publishing
241
+ # with synchronous per-message confirmation.
242
+ #
243
+ # Close the sender explicitly when finished, or it will be closed when
244
+ # the client is closed.
245
+ #
246
+ # @return [PubSub::EventStoreSender] streaming sender bound to this client
247
+ #
248
+ # @raise [ClientClosedError] if the client has been closed
249
+ # @raise [ConnectionError] if unable to reach the broker
250
+ #
251
+ # @see PubSub::EventStoreSender
252
+ def create_events_store_sender
253
+ ensure_connected!
254
+ sender = PubSub::EventStoreSender.new(transport: @transport, client_id: @config.client_id)
255
+ senders_mutex.synchronize { senders_list << sender }
256
+ sender
257
+ end
258
+
259
+ # Subscribes to durable events store messages on a channel. Runs on a
260
+ # background thread; incoming events are delivered to the provided block.
261
+ #
262
+ # The subscription automatically reconnects with exponential backoff on
263
+ # transient failures. On reconnect, playback resumes from the last
264
+ # received sequence number to avoid duplicates.
265
+ #
266
+ # @param subscription [PubSub::EventsStoreSubscription] channel, group,
267
+ # and start position config
268
+ # @param cancellation_token [CancellationToken, nil] token for cooperative
269
+ # cancellation (auto-created if nil)
270
+ # @param on_error [Proc, nil] callback receiving {Error} on stream or
271
+ # callback failures
272
+ # @yield [event] called for each received event on a background thread
273
+ # @yieldparam event [PubSub::EventStoreReceived] the received event
274
+ #
275
+ # @return [Subscription] handle to check status, cancel, or join
276
+ #
277
+ # @raise [ArgumentError] if no block is given
278
+ # @raise [ValidationError] if the subscription channel or start position
279
+ # is invalid
280
+ # @raise [ClientClosedError] if the client has been closed
281
+ #
282
+ # @note On reconnect the subscription automatically resumes from the last
283
+ # received sequence number, overriding the original start position.
284
+ #
285
+ # @example Subscribe from the beginning
286
+ # sub = KubeMQ::PubSub::EventsStoreSubscription.new(
287
+ # channel: "orders",
288
+ # start_position: KubeMQ::PubSub::EventStoreStartPosition::START_FROM_FIRST
289
+ # )
290
+ # token = KubeMQ::CancellationToken.new
291
+ # client.subscribe_to_events_store(sub, cancellation_token: token) do |event|
292
+ # puts "seq=#{event.sequence}: #{event.body}"
293
+ # end
294
+ #
295
+ # @see PubSub::EventsStoreSubscription
296
+ # @see PubSub::EventStoreReceived
297
+ # @see PubSub::EventStoreStartPosition
298
+ # @see CancellationToken
299
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength -- subscription with auto-reconnect + sequence tracking
300
+ def subscribe_to_events_store(subscription, cancellation_token: nil, on_error: nil, &block)
301
+ raise ArgumentError, 'Block required for subscribe_to_events_store' unless block
302
+
303
+ Validator.validate_channel!(subscription.channel, allow_wildcards: false)
304
+ Validator.validate_events_store_subscription!(
305
+ subscription.start_position, subscription.start_position_value
306
+ )
307
+ ensure_connected!
308
+
309
+ cancellation_token ||= CancellationToken.new
310
+ nil
311
+
312
+ thread = Thread.new do
313
+ @transport.register_subscription(Thread.current)
314
+ Thread.current[:cancellation_token] = cancellation_token
315
+ last_sequence = 0
316
+ reconnect_attempts = 0
317
+ begin
318
+ loop do
319
+ break if cancellation_token.cancelled?
320
+
321
+ begin
322
+ @transport.ensure_connected!
323
+ proto_sub = Transport::Converter.subscribe_to_proto(subscription, @config.client_id)
324
+ if last_sequence.positive?
325
+ proto_sub.EventsStoreTypeData = PubSub::EventStoreStartPosition::START_AT_SEQUENCE
326
+ proto_sub.EventsStoreTypeValue = last_sequence + 1
327
+ end
328
+ stream = @transport.kubemq_client.subscribe_to_events(proto_sub)
329
+ Thread.current[:grpc_call] = stream
330
+ reconnect_attempts = 0
331
+ stream.each do |event_receive|
332
+ break if cancellation_token.cancelled?
333
+
334
+ hash = Transport::Converter.proto_to_event_received(event_receive)
335
+ received = PubSub::EventStoreReceived.new(**hash)
336
+ last_sequence = received.sequence if received.sequence.positive?
337
+ begin
338
+ block.call(received)
339
+ rescue StandardError => e
340
+ begin
341
+ on_error&.call(Error.new("Callback error: #{e.message}", code: ErrorCode::CALLBACK_ERROR))
342
+ rescue StandardError => nested
343
+ Kernel.warn("[kubemq] on_error callback raised: #{nested.message}")
344
+ end
345
+ end
346
+ end
347
+ rescue CancellationError
348
+ break
349
+ rescue GRPC::BadStatus, StandardError => e
350
+ @transport.on_disconnect! if e.is_a?(GRPC::Unavailable) || e.is_a?(GRPC::DeadlineExceeded)
351
+ reconnect_attempts += 1
352
+ begin
353
+ if e.is_a?(GRPC::BadStatus)
354
+ on_error&.call(ErrorMapper.map_grpc_error(e, operation: 'subscribe_events_store'))
355
+ else
356
+ on_error&.call(Error.new(e.message, code: ErrorCode::STREAM_BROKEN))
357
+ end
358
+ rescue StandardError => cb_err
359
+ Kernel.warn("[kubemq] on_error callback raised: #{cb_err.message}")
360
+ end
361
+ delay = [@config.reconnect_policy.base_interval *
362
+ (@config.reconnect_policy.multiplier**(reconnect_attempts - 1)),
363
+ @config.reconnect_policy.max_delay].min
364
+ sleep(delay) unless cancellation_token.cancelled?
365
+ end
366
+ end
367
+ rescue StandardError => e
368
+ Thread.current[:kubemq_subscription]&.mark_error(e)
369
+ ensure
370
+ begin; Thread.current[:grpc_call]&.cancel; rescue StandardError; end
371
+ Thread.current[:kubemq_subscription]&.mark_closed
372
+ @transport.unregister_subscription(Thread.current)
373
+ end
374
+ end
375
+
376
+ sub_wrapper = KubeMQ::Subscription.new(thread: thread, cancellation_token: cancellation_token)
377
+ thread[:kubemq_subscription] = sub_wrapper
378
+ sub_wrapper
379
+ end
380
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
381
+
382
+ # Closes the client, all open senders, and releases resources.
383
+ #
384
+ # Closes any {PubSub::EventSender} or {PubSub::EventStoreSender}
385
+ # instances created through this client before closing the transport.
386
+ # This method is idempotent.
387
+ #
388
+ # @return [void]
389
+ def close
390
+ senders_mutex.synchronize do
391
+ senders_list.each do |s|
392
+ s.close
393
+ rescue StandardError
394
+ nil
395
+ end
396
+ senders_list.clear
397
+ end
398
+ super
399
+ end
400
+
401
+ # Creates an events channel on the broker.
402
+ #
403
+ # @param channel_name [String] name for the new channel
404
+ # @return [Boolean] +true+ on success
405
+ # @raise [ClientClosedError] if the client has been closed
406
+ # @raise [ChannelError] if the broker rejects the operation
407
+ # @see BaseClient#create_channel
408
+ def create_events_channel(channel_name:)
409
+ create_channel(channel_name: channel_name, channel_type: ChannelType::EVENTS)
410
+ end
411
+
412
+ # Creates an events store channel on the broker.
413
+ #
414
+ # @param channel_name [String] name for the new channel
415
+ # @return [Boolean] +true+ on success
416
+ # @raise [ClientClosedError] if the client has been closed
417
+ # @raise [ChannelError] if the broker rejects the operation
418
+ # @see BaseClient#create_channel
419
+ def create_events_store_channel(channel_name:)
420
+ create_channel(channel_name: channel_name, channel_type: ChannelType::EVENTS_STORE)
421
+ end
422
+
423
+ # Deletes an events channel from the broker.
424
+ #
425
+ # @param channel_name [String] name of the channel to delete
426
+ # @return [Boolean] +true+ on success
427
+ # @raise [ClientClosedError] if the client has been closed
428
+ # @raise [ChannelError] if the broker rejects the operation
429
+ # @see BaseClient#delete_channel
430
+ def delete_events_channel(channel_name:)
431
+ delete_channel(channel_name: channel_name, channel_type: ChannelType::EVENTS)
432
+ end
433
+
434
+ # Deletes an events store channel from the broker.
435
+ #
436
+ # @param channel_name [String] name of the channel to delete
437
+ # @return [Boolean] +true+ on success
438
+ # @raise [ClientClosedError] if the client has been closed
439
+ # @raise [ChannelError] if the broker rejects the operation
440
+ # @see BaseClient#delete_channel
441
+ def delete_events_store_channel(channel_name:)
442
+ delete_channel(channel_name: channel_name, channel_type: ChannelType::EVENTS_STORE)
443
+ end
444
+
445
+ # Lists events channels, with optional name filtering.
446
+ #
447
+ # @param search [String, nil] substring filter for channel names
448
+ # @return [Array<ChannelInfo>] matching channels with metadata
449
+ # @raise [ClientClosedError] if the client has been closed
450
+ # @see BaseClient#list_channels
451
+ def list_events_channels(search: nil)
452
+ list_channels(channel_type: ChannelType::EVENTS, search: search)
453
+ end
454
+
455
+ # Lists events store channels, with optional name filtering.
456
+ #
457
+ # @param search [String, nil] substring filter for channel names
458
+ # @return [Array<ChannelInfo>] matching channels with metadata
459
+ # @raise [ClientClosedError] if the client has been closed
460
+ # @see BaseClient#list_channels
461
+ def list_events_store_channels(search: nil)
462
+ list_channels(channel_type: ChannelType::EVENTS_STORE, search: search)
463
+ end
464
+
465
+ private
466
+
467
+ def senders_list
468
+ @senders_list ||= []
469
+ end
470
+
471
+ def senders_mutex
472
+ @senders_mutex ||= Mutex.new
473
+ end
474
+ end
475
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module KubeMQ
6
+ module PubSub
7
+ # Outbound event message for fire-and-forget pub/sub.
8
+ #
9
+ # Construct an +EventMessage+ and pass it to {PubSubClient#send_event}
10
+ # or {PubSub::EventSender#publish}. Events are not persisted — use
11
+ # {EventStoreMessage} for durable delivery.
12
+ #
13
+ # @example
14
+ # msg = KubeMQ::PubSub::EventMessage.new(
15
+ # channel: "notifications.email",
16
+ # metadata: "user-signup",
17
+ # body: '{"user_id": 42}',
18
+ # tags: { "priority" => "high" }
19
+ # )
20
+ # result = client.send_event(msg)
21
+ #
22
+ # @see PubSubClient#send_event
23
+ # @see EventSender#publish
24
+ # @see EventStoreMessage
25
+ class EventMessage
26
+ # @!attribute [rw] id
27
+ # @return [String] unique message identifier (auto-generated UUID if not provided)
28
+ # @!attribute [rw] channel
29
+ # @return [String] target channel name
30
+ # @!attribute [rw] metadata
31
+ # @return [String, nil] arbitrary metadata string
32
+ # @!attribute [rw] body
33
+ # @return [String, nil] message payload (binary-safe)
34
+ # @!attribute [rw] tags
35
+ # @return [Hash{String => String}] user-defined key-value tags
36
+ attr_accessor :id, :channel, :metadata, :body, :tags
37
+
38
+ # @param channel [String] target channel name (required)
39
+ # @param metadata [String, nil] arbitrary metadata
40
+ # @param body [String, nil] message payload
41
+ # @param tags [Hash{String => String}, nil] key-value tags (default: +{}+)
42
+ # @param id [String, nil] message ID (default: auto-generated UUID)
43
+ def initialize(channel:, metadata: nil, body: nil, tags: nil, id: nil)
44
+ @id = id || SecureRandom.uuid
45
+ @channel = channel
46
+ @metadata = metadata
47
+ @body = body
48
+ @tags = tags || {}
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KubeMQ
4
+ module PubSub
5
+ # An event received from a pub/sub subscription.
6
+ #
7
+ # Delivered to the block passed to {PubSubClient#subscribe_to_events}.
8
+ # This is a read-only snapshot — modifying attributes has no effect
9
+ # on the broker.
10
+ #
11
+ # @see PubSubClient#subscribe_to_events
12
+ # @see EventsSubscription
13
+ class EventReceived
14
+ # @!attribute [r] id
15
+ # @return [String] unique event identifier
16
+ # @!attribute [r] channel
17
+ # @return [String] the channel the event was published to
18
+ # @!attribute [r] metadata
19
+ # @return [String] event metadata
20
+ # @!attribute [r] body
21
+ # @return [String] event payload (binary)
22
+ # @!attribute [r] timestamp
23
+ # @return [Integer] broker-assigned timestamp (Unix nanoseconds)
24
+ # @!attribute [r] sequence
25
+ # @return [Integer] broker-assigned sequence number
26
+ # @!attribute [r] tags
27
+ # @return [Hash{String => String}] user-defined key-value tags
28
+ attr_reader :id, :channel, :metadata, :body, :timestamp, :sequence, :tags
29
+
30
+ # @param id [String] event identifier
31
+ # @param channel [String] source channel name
32
+ # @param metadata [String] event metadata
33
+ # @param body [String] event payload
34
+ # @param timestamp [Integer] broker timestamp (Unix nanoseconds)
35
+ # @param sequence [Integer] broker sequence number
36
+ # @param tags [Hash{String => String}, nil] key-value tags
37
+ def initialize(id:, channel:, metadata:, body:, timestamp:, sequence:, tags:)
38
+ @id = id
39
+ @channel = channel
40
+ @metadata = metadata
41
+ @body = body
42
+ @timestamp = timestamp
43
+ @sequence = sequence
44
+ @tags = tags || {}
45
+ end
46
+ end
47
+ end
48
+ end