nng-ruby 0.1.2 → 1.0.1

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.
@@ -1,236 +1,236 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # NNG + Protocol Buffers 示例 (使用线程)
5
- # 演示 NNG 与 Protobuf 配合使用
6
-
7
- require 'nng'
8
- require 'google/protobuf'
9
-
10
- puts "=" * 70
11
- puts "NNG + Protocol Buffers 完整示例"
12
- puts "=" * 70
13
- puts
14
-
15
- # ============================================================================
16
- # 定义 Protobuf 消息
17
- # ============================================================================
18
-
19
- Google::Protobuf::DescriptorPool.generated_pool.build do
20
- add_file("rpc.proto", syntax: :proto3) do
21
- # RPC 请求
22
- add_message "RpcRequest" do
23
- optional :func_code, :int32, 1
24
- optional :data, :bytes, 2
25
- optional :request_id, :string, 3
26
- end
27
-
28
- # RPC 响应
29
- add_message "RpcResponse" do
30
- optional :status, :int32, 1
31
- optional :data, :bytes, 2
32
- optional :error_msg, :string, 3
33
- end
34
-
35
- # 联系人
36
- add_message "Contact" do
37
- optional :wxid, :string, 1
38
- optional :name, :string, 2
39
- end
40
-
41
- # 联系人列表
42
- add_message "ContactList" do
43
- repeated :contacts, :message, 1, "Contact"
44
- end
45
- end
46
- end
47
-
48
- RpcRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcRequest").msgclass
49
- RpcResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcResponse").msgclass
50
- Contact = Google::Protobuf::DescriptorPool.generated_pool.lookup("Contact").msgclass
51
- ContactList = Google::Protobuf::DescriptorPool.generated_pool.lookup("ContactList").msgclass
52
-
53
- puts "✅ Protobuf 消息定义完成"
54
- puts
55
-
56
- # ============================================================================
57
- # 示例: 获取联系人列表 (使用嵌套的 Protobuf 消息)
58
- # ============================================================================
59
-
60
- puts "示例: RPC 调用 - 获取联系人列表"
61
- puts "=" * 70
62
- puts
63
-
64
- url = "inproc://contacts_demo" # 使用 inproc 避免端口冲突
65
-
66
- # 创建 server socket (必须在 client 之前)
67
- server_socket = NNG::Socket.new(:pair1)
68
- server_socket.listen(url)
69
- server_ready = true
70
- puts "✅ 服务器监听: #{url}"
71
- puts
72
-
73
- # 服务器线程
74
- server_thread = Thread.new do
75
- begin
76
- # 接收 RPC 请求
77
- request_data = server_socket.recv
78
- puts "📥 [服务器] 收到请求 (#{request_data.bytesize} bytes)"
79
-
80
- # 反序列化 RPC 请求
81
- rpc_request = RpcRequest.decode(request_data)
82
- puts "📋 [服务器] 解析 RPC 请求:"
83
- puts " Function Code: 0x#{rpc_request.func_code.to_s(16)}"
84
- puts " Request ID: #{rpc_request.request_id}"
85
- puts
86
-
87
- # 构建联系人列表 (嵌套消息)
88
- contacts = ContactList.new(
89
- contacts: [
90
- Contact.new(wxid: "wxid_001", name: "张三"),
91
- Contact.new(wxid: "wxid_002", name: "李四"),
92
- Contact.new(wxid: "wxid_003", name: "王五"),
93
- Contact.new(wxid: "chatroom_001", name: "技术交流群")
94
- ]
95
- )
96
-
97
- puts "🏗️ [服务器] 构建联系人列表:"
98
- puts " 联系人数量: #{contacts.contacts.size}"
99
- contacts.contacts.each_with_index do |contact, i|
100
- puts " #{i + 1}. #{contact.name} (#{contact.wxid})"
101
- end
102
- puts
103
-
104
- # 序列化联系人列表 (内层)
105
- contacts_data = ContactList.encode(contacts)
106
- puts "📦 [服务器] 序列化联系人列表: #{contacts_data.bytesize} bytes"
107
-
108
- # 构建 RPC 响应 (外层)
109
- rpc_response = RpcResponse.new(
110
- status: 0,
111
- data: contacts_data,
112
- error_msg: ""
113
- )
114
-
115
- # 序列化 RPC 响应
116
- response_data = RpcResponse.encode(rpc_response)
117
- puts "📦 [服务器] 序列化 RPC 响应: #{response_data.bytesize} bytes"
118
-
119
- # 发送响应
120
- server_socket.send(response_data)
121
- puts "📤 [服务器] 响应已发送"
122
- puts
123
-
124
- rescue => e
125
- puts "❌ [服务器] 错误: #{e.message}"
126
- end
127
- end
128
-
129
- # 等待服务器准备好
130
- sleep 0.1
131
-
132
- # ============================================================================
133
- # 客户端
134
- # ============================================================================
135
-
136
- puts "📞 [客户端] 发起 RPC 调用..."
137
- puts
138
-
139
- begin
140
- # 创建 client socket
141
- client_socket = NNG::Socket.new(:pair1)
142
- client_socket.dial(url)
143
- puts "✅ [客户端] 连接: #{url}"
144
- puts
145
-
146
- # 构建 RPC 请求
147
- rpc_request = RpcRequest.new(
148
- func_code: 0x12, # 假设 0x12 = FUNC_GET_CONTACTS
149
- data: "", # 本例无需参数
150
- request_id: "req_#{Time.now.to_i}"
151
- )
152
-
153
- puts "🏗️ [客户端] 构建 RPC 请求:"
154
- puts " Function Code: 0x#{rpc_request.func_code.to_s(16)}"
155
- puts " Request ID: #{rpc_request.request_id}"
156
- puts
157
-
158
- # 序列化并发送
159
- request_data = RpcRequest.encode(rpc_request)
160
- puts "📦 [客户端] 序列化请求: #{request_data.bytesize} bytes"
161
- client_socket.send(request_data)
162
- puts "📤 [客户端] 请求已发送"
163
- puts
164
-
165
- # 接收响应
166
- response_data = client_socket.recv
167
- puts "📥 [客户端] 收到响应 (#{response_data.bytesize} bytes)"
168
-
169
- # 反序列化 RPC 响应 (外层)
170
- rpc_response = RpcResponse.decode(response_data)
171
- puts "📋 [客户端] 解析 RPC 响应:"
172
- puts " Status: #{rpc_response.status}"
173
- puts " Error: #{rpc_response.error_msg}" unless rpc_response.error_msg.empty?
174
- puts
175
-
176
- if rpc_response.status == 0
177
- # 反序列化联系人列表 (内层)
178
- contacts = ContactList.decode(rpc_response.data)
179
- puts "📋 [客户端] 解析联系人列表:"
180
- puts " 总数: #{contacts.contacts.size}"
181
- puts
182
-
183
- contacts.contacts.each_with_index do |contact, i|
184
- puts " #{i + 1}. #{contact.name}"
185
- puts " WXID: #{contact.wxid}"
186
- end
187
- else
188
- puts "❌ [客户端] RPC 调用失败: #{rpc_response.error_msg}"
189
- end
190
-
191
- # 关闭
192
- client_socket.close
193
-
194
- rescue => e
195
- puts "❌ [客户端] 错误: #{e.message}"
196
- puts e.backtrace.first(3)
197
- end
198
-
199
- # 等待服务器线程完成
200
- server_thread.join
201
- server_socket.close
202
-
203
- puts
204
- puts "=" * 70
205
- puts "✅ 示例完成"
206
- puts "=" * 70
207
- puts
208
- puts "技术要点:"
209
- puts
210
- puts "1. 消息嵌套:"
211
- puts " RpcRequest/Response 包含 bytes 类型的 data 字段"
212
- puts " data 字段可以存储任意 Protobuf 消息的序列化结果"
213
- puts
214
- puts "2. 序列化过程:"
215
- puts " 内层: contacts → ContactList.encode → bytes"
216
- puts " 外层: RpcRequest { data: bytes } → RpcRequest.encode → bytes"
217
- puts " 发送: bytes → NNG socket.send"
218
- puts
219
- puts "3. 反序列化过程:"
220
- puts " 接收: NNG socket.recv → bytes"
221
- puts " 外层: bytes → RpcResponse.decode → RpcResponse"
222
- puts " 内层: RpcResponse.data → ContactList.decode → contacts"
223
- puts
224
- puts "4. 优势:"
225
- puts " • 类型安全 - 编译时检查消息结构"
226
- puts " • 高效序列化 - 比 JSON 小 50%+"
227
- puts " • 跨语言 - Python/Java/Go/C++ 互通"
228
- puts " • 向后兼容 - 可安全添加字段"
229
- puts " • 自动文档 - .proto 文件即文档"
230
- puts
231
- puts "5. 实际应用:"
232
- puts " • 微服务 RPC 通信"
233
- puts " • 分布式系统消息传递"
234
- puts " • 客户端-服务器协议"
235
- puts " • 消息队列数据格式"
236
- puts
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # NNG + Protocol Buffers 示例 (使用线程)
5
+ # 演示 NNG 与 Protobuf 配合使用
6
+
7
+ require 'nng'
8
+ require 'google/protobuf'
9
+
10
+ puts "=" * 70
11
+ puts "NNG + Protocol Buffers 完整示例"
12
+ puts "=" * 70
13
+ puts
14
+
15
+ # ============================================================================
16
+ # 定义 Protobuf 消息
17
+ # ============================================================================
18
+
19
+ Google::Protobuf::DescriptorPool.generated_pool.build do
20
+ add_file("rpc.proto", syntax: :proto3) do
21
+ # RPC 请求
22
+ add_message "RpcRequest" do
23
+ optional :func_code, :int32, 1
24
+ optional :data, :bytes, 2
25
+ optional :request_id, :string, 3
26
+ end
27
+
28
+ # RPC 响应
29
+ add_message "RpcResponse" do
30
+ optional :status, :int32, 1
31
+ optional :data, :bytes, 2
32
+ optional :error_msg, :string, 3
33
+ end
34
+
35
+ # 联系人
36
+ add_message "Contact" do
37
+ optional :wxid, :string, 1
38
+ optional :name, :string, 2
39
+ end
40
+
41
+ # 联系人列表
42
+ add_message "ContactList" do
43
+ repeated :contacts, :message, 1, "Contact"
44
+ end
45
+ end
46
+ end
47
+
48
+ RpcRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcRequest").msgclass
49
+ RpcResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcResponse").msgclass
50
+ Contact = Google::Protobuf::DescriptorPool.generated_pool.lookup("Contact").msgclass
51
+ ContactList = Google::Protobuf::DescriptorPool.generated_pool.lookup("ContactList").msgclass
52
+
53
+ puts "✅ Protobuf 消息定义完成"
54
+ puts
55
+
56
+ # ============================================================================
57
+ # 示例: 获取联系人列表 (使用嵌套的 Protobuf 消息)
58
+ # ============================================================================
59
+
60
+ puts "示例: RPC 调用 - 获取联系人列表"
61
+ puts "=" * 70
62
+ puts
63
+
64
+ url = "inproc://contacts_demo" # 使用 inproc 避免端口冲突
65
+
66
+ # 创建 server socket (必须在 client 之前)
67
+ server_socket = NNG::Socket.new(:pair1)
68
+ server_socket.listen(url)
69
+ server_ready = true
70
+ puts "✅ 服务器监听: #{url}"
71
+ puts
72
+
73
+ # 服务器线程
74
+ server_thread = Thread.new do
75
+ begin
76
+ # 接收 RPC 请求
77
+ request_data = server_socket.recv
78
+ puts "📥 [服务器] 收到请求 (#{request_data.bytesize} bytes)"
79
+
80
+ # 反序列化 RPC 请求
81
+ rpc_request = RpcRequest.decode(request_data)
82
+ puts "📋 [服务器] 解析 RPC 请求:"
83
+ puts " Function Code: 0x#{rpc_request.func_code.to_s(16)}"
84
+ puts " Request ID: #{rpc_request.request_id}"
85
+ puts
86
+
87
+ # 构建联系人列表 (嵌套消息)
88
+ contacts = ContactList.new(
89
+ contacts: [
90
+ Contact.new(wxid: "wxid_001", name: "张三"),
91
+ Contact.new(wxid: "wxid_002", name: "李四"),
92
+ Contact.new(wxid: "wxid_003", name: "王五"),
93
+ Contact.new(wxid: "chatroom_001", name: "技术交流群")
94
+ ]
95
+ )
96
+
97
+ puts "🏗️ [服务器] 构建联系人列表:"
98
+ puts " 联系人数量: #{contacts.contacts.size}"
99
+ contacts.contacts.each_with_index do |contact, i|
100
+ puts " #{i + 1}. #{contact.name} (#{contact.wxid})"
101
+ end
102
+ puts
103
+
104
+ # 序列化联系人列表 (内层)
105
+ contacts_data = ContactList.encode(contacts)
106
+ puts "📦 [服务器] 序列化联系人列表: #{contacts_data.bytesize} bytes"
107
+
108
+ # 构建 RPC 响应 (外层)
109
+ rpc_response = RpcResponse.new(
110
+ status: 0,
111
+ data: contacts_data,
112
+ error_msg: ""
113
+ )
114
+
115
+ # 序列化 RPC 响应
116
+ response_data = RpcResponse.encode(rpc_response)
117
+ puts "📦 [服务器] 序列化 RPC 响应: #{response_data.bytesize} bytes"
118
+
119
+ # 发送响应
120
+ server_socket.send(response_data)
121
+ puts "📤 [服务器] 响应已发送"
122
+ puts
123
+
124
+ rescue => e
125
+ puts "❌ [服务器] 错误: #{e.message}"
126
+ end
127
+ end
128
+
129
+ # 等待服务器准备好
130
+ sleep 0.1
131
+
132
+ # ============================================================================
133
+ # 客户端
134
+ # ============================================================================
135
+
136
+ puts "📞 [客户端] 发起 RPC 调用..."
137
+ puts
138
+
139
+ begin
140
+ # 创建 client socket
141
+ client_socket = NNG::Socket.new(:pair1)
142
+ client_socket.dial(url)
143
+ puts "✅ [客户端] 连接: #{url}"
144
+ puts
145
+
146
+ # 构建 RPC 请求
147
+ rpc_request = RpcRequest.new(
148
+ func_code: 0x12, # 假设 0x12 = FUNC_GET_CONTACTS
149
+ data: "", # 本例无需参数
150
+ request_id: "req_#{Time.now.to_i}"
151
+ )
152
+
153
+ puts "🏗️ [客户端] 构建 RPC 请求:"
154
+ puts " Function Code: 0x#{rpc_request.func_code.to_s(16)}"
155
+ puts " Request ID: #{rpc_request.request_id}"
156
+ puts
157
+
158
+ # 序列化并发送
159
+ request_data = RpcRequest.encode(rpc_request)
160
+ puts "📦 [客户端] 序列化请求: #{request_data.bytesize} bytes"
161
+ client_socket.send(request_data)
162
+ puts "📤 [客户端] 请求已发送"
163
+ puts
164
+
165
+ # 接收响应
166
+ response_data = client_socket.recv
167
+ puts "📥 [客户端] 收到响应 (#{response_data.bytesize} bytes)"
168
+
169
+ # 反序列化 RPC 响应 (外层)
170
+ rpc_response = RpcResponse.decode(response_data)
171
+ puts "📋 [客户端] 解析 RPC 响应:"
172
+ puts " Status: #{rpc_response.status}"
173
+ puts " Error: #{rpc_response.error_msg}" unless rpc_response.error_msg.empty?
174
+ puts
175
+
176
+ if rpc_response.status == 0
177
+ # 反序列化联系人列表 (内层)
178
+ contacts = ContactList.decode(rpc_response.data)
179
+ puts "📋 [客户端] 解析联系人列表:"
180
+ puts " 总数: #{contacts.contacts.size}"
181
+ puts
182
+
183
+ contacts.contacts.each_with_index do |contact, i|
184
+ puts " #{i + 1}. #{contact.name}"
185
+ puts " WXID: #{contact.wxid}"
186
+ end
187
+ else
188
+ puts "❌ [客户端] RPC 调用失败: #{rpc_response.error_msg}"
189
+ end
190
+
191
+ # 关闭
192
+ client_socket.close
193
+
194
+ rescue => e
195
+ puts "❌ [客户端] 错误: #{e.message}"
196
+ puts e.backtrace.first(3)
197
+ end
198
+
199
+ # 等待服务器线程完成
200
+ server_thread.join
201
+ server_socket.close
202
+
203
+ puts
204
+ puts "=" * 70
205
+ puts "✅ 示例完成"
206
+ puts "=" * 70
207
+ puts
208
+ puts "技术要点:"
209
+ puts
210
+ puts "1. 消息嵌套:"
211
+ puts " RpcRequest/Response 包含 bytes 类型的 data 字段"
212
+ puts " data 字段可以存储任意 Protobuf 消息的序列化结果"
213
+ puts
214
+ puts "2. 序列化过程:"
215
+ puts " 内层: contacts → ContactList.encode → bytes"
216
+ puts " 外层: RpcRequest { data: bytes } → RpcRequest.encode → bytes"
217
+ puts " 发送: bytes → NNG socket.send"
218
+ puts
219
+ puts "3. 反序列化过程:"
220
+ puts " 接收: NNG socket.recv → bytes"
221
+ puts " 外层: bytes → RpcResponse.decode → RpcResponse"
222
+ puts " 内层: RpcResponse.data → ContactList.decode → contacts"
223
+ puts
224
+ puts "4. 优势:"
225
+ puts " • 类型安全 - 编译时检查消息结构"
226
+ puts " • 高效序列化 - 比 JSON 小 50%+"
227
+ puts " • 跨语言 - Python/Java/Go/C++ 互通"
228
+ puts " • 向后兼容 - 可安全添加字段"
229
+ puts " • 自动文档 - .proto 文件即文档"
230
+ puts
231
+ puts "5. 实际应用:"
232
+ puts " • 微服务 RPC 通信"
233
+ puts " • 分布式系统消息传递"
234
+ puts " • 客户端-服务器协议"
235
+ puts " • 消息队列数据格式"
236
+ puts
data/examples/pubsub.rb CHANGED
@@ -1,51 +1,51 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require_relative '../lib/nng'
5
-
6
- # Example: Publish/Subscribe protocol
7
-
8
- puts "NNG Publish/Subscribe Protocol Example"
9
- puts "=" * 50
10
-
11
- # Create publisher socket
12
- pub = NNG::Socket.new(:pub)
13
- pub.listen("tcp://127.0.0.1:5557")
14
- puts "Publisher listening on tcp://127.0.0.1:5557"
15
-
16
- # Create subscribers in threads
17
- sub_threads = 3.times.map do |i|
18
- Thread.new do
19
- sleep 0.5 # Give publisher time to start
20
- sub = NNG::Socket.new(:sub)
21
- sub.dial("tcp://127.0.0.1:5557")
22
- sub.set_option("sub:subscribe", "") # Subscribe to all topics
23
- puts "Subscriber #{i + 1} connected"
24
-
25
- # Receive 5 messages
26
- 5.times do
27
- msg = sub.recv
28
- puts "Subscriber #{i + 1} received: #{msg}"
29
- end
30
-
31
- sub.close
32
- end
33
- end
34
-
35
- # Publisher sends 5 messages
36
- sleep 1 # Give subscribers time to connect
37
- 5.times do |i|
38
- message = "Broadcast message #{i + 1}"
39
- pub.send(message)
40
- puts "Publisher sent: #{message}"
41
- sleep 0.2
42
- end
43
-
44
- # Wait for all subscribers
45
- sub_threads.each(&:join)
46
-
47
- # Cleanup
48
- pub.close
49
-
50
- puts "=" * 50
51
- puts "Example completed!"
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/nng'
5
+
6
+ # Example: Publish/Subscribe protocol
7
+
8
+ puts "NNG Publish/Subscribe Protocol Example"
9
+ puts "=" * 50
10
+
11
+ # Create publisher socket
12
+ pub = NNG::Socket.new(:pub)
13
+ pub.listen("tcp://127.0.0.1:5557")
14
+ puts "Publisher listening on tcp://127.0.0.1:5557"
15
+
16
+ # Create subscribers in threads
17
+ sub_threads = 3.times.map do |i|
18
+ Thread.new do
19
+ sleep 0.5 # Give publisher time to start
20
+ sub = NNG::Socket.new(:sub)
21
+ sub.dial("tcp://127.0.0.1:5557")
22
+ sub.set_option("sub:subscribe", "") # Subscribe to all topics
23
+ puts "Subscriber #{i + 1} connected"
24
+
25
+ # Receive 5 messages
26
+ 5.times do
27
+ msg = sub.recv
28
+ puts "Subscriber #{i + 1} received: #{msg}"
29
+ end
30
+
31
+ sub.close
32
+ end
33
+ end
34
+
35
+ # Publisher sends 5 messages
36
+ sleep 1 # Give subscribers time to connect
37
+ 5.times do |i|
38
+ message = "Broadcast message #{i + 1}"
39
+ pub.send(message)
40
+ puts "Publisher sent: #{message}"
41
+ sleep 0.2
42
+ end
43
+
44
+ # Wait for all subscribers
45
+ sub_threads.each(&:join)
46
+
47
+ # Cleanup
48
+ pub.close
49
+
50
+ puts "=" * 50
51
+ puts "Example completed!"