nng-ruby 0.1.1 → 0.1.2

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,374 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Protocol Buffers + NNG 示例
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
+ # 1. 定义 Protobuf 消息格式
17
+ # ============================================================================
18
+
19
+ puts "1. 定义 Protobuf 消息格式"
20
+ puts "-" * 70
21
+
22
+ # 定义请求消息
23
+ Google::Protobuf::DescriptorPool.generated_pool.build do
24
+ add_file("request.proto", syntax: :proto3) do
25
+ add_message "Request" do
26
+ optional :id, :int32, 1
27
+ optional :method, :string, 2
28
+ optional :params, :string, 3
29
+ optional :timestamp, :int64, 4
30
+ end
31
+ end
32
+ end
33
+
34
+ # 定义响应消息
35
+ Google::Protobuf::DescriptorPool.generated_pool.build do
36
+ add_file("response.proto", syntax: :proto3) do
37
+ add_message "Response" do
38
+ optional :id, :int32, 1
39
+ optional :status, :int32, 2
40
+ optional :message, :string, 3
41
+ optional :data, :string, 4
42
+ end
43
+ end
44
+ end
45
+
46
+ Request = Google::Protobuf::DescriptorPool.generated_pool.lookup("Request").msgclass
47
+ Response = Google::Protobuf::DescriptorPool.generated_pool.lookup("Response").msgclass
48
+
49
+ puts "✅ Protobuf 消息定义完成"
50
+ puts " - Request: id, method, params, timestamp"
51
+ puts " - Response: id, status, message, data"
52
+ puts
53
+
54
+ # ============================================================================
55
+ # 2. 启动服务器线程
56
+ # ============================================================================
57
+
58
+ puts "2. 启动 NNG 服务器 (Pair1 协议)"
59
+ puts "-" * 70
60
+
61
+ server_url = "tcp://127.0.0.1:15555"
62
+ server_ready = false
63
+
64
+ server_thread = Thread.new do
65
+ server = NNG::Socket.new(:pair1)
66
+ server.listen(server_url)
67
+ server_ready = true
68
+ puts "✅ 服务器监听: #{server_url}"
69
+ puts
70
+
71
+ # 接收请求
72
+ request_data = server.recv
73
+ request = Request.decode(request_data)
74
+
75
+ puts "📥 服务器收到请求:"
76
+ puts " ID: #{request.id}"
77
+ puts " Method: #{request.method}"
78
+ puts " Params: #{request.params}"
79
+ puts " Timestamp: #{Time.at(request.timestamp)}"
80
+ puts
81
+
82
+ # 处理请求并构建响应
83
+ response = Response.new(
84
+ id: request.id,
85
+ status: 200,
86
+ message: "Success",
87
+ data: "Hello from server! Processed: #{request.method}"
88
+ )
89
+
90
+ # 序列化并发送响应
91
+ response_data = Response.encode(response)
92
+ server.send(response_data)
93
+
94
+ puts "📤 服务器发送响应:"
95
+ puts " Status: #{response.status}"
96
+ puts " Message: #{response.message}"
97
+ puts " Data: #{response.data}"
98
+ puts
99
+
100
+ server.close
101
+ end
102
+
103
+ # 等待服务器准备好
104
+ sleep 0.1 until server_ready
105
+
106
+ # ============================================================================
107
+ # 3. 客户端发送请求
108
+ # ============================================================================
109
+
110
+ puts "3. 启动 NNG 客户端 (Pair1 协议)"
111
+ puts "-" * 70
112
+
113
+ client = NNG::Socket.new(:pair1)
114
+ client.dial(server_url)
115
+ puts "✅ 客户端连接: #{server_url}"
116
+ puts
117
+
118
+ # 构建请求
119
+ request = Request.new(
120
+ id: 12345,
121
+ method: "getUserInfo",
122
+ params: '{"user_id": 888}',
123
+ timestamp: Time.now.to_i
124
+ )
125
+
126
+ puts "📤 客户端发送请求:"
127
+ puts " ID: #{request.id}"
128
+ puts " Method: #{request.method}"
129
+ puts " Params: #{request.params}"
130
+ puts
131
+
132
+ # 序列化并发送
133
+ request_data = Request.encode(request)
134
+ puts " 序列化后大小: #{request_data.bytesize} bytes"
135
+ puts
136
+
137
+ client.send(request_data)
138
+
139
+ # 接收响应
140
+ response_data = client.recv
141
+ response = Response.decode(response_data)
142
+
143
+ puts "📥 客户端收到响应:"
144
+ puts " ID: #{response.id}"
145
+ puts " Status: #{response.status}"
146
+ puts " Message: #{response.message}"
147
+ puts " Data: #{response.data}"
148
+ puts
149
+
150
+ client.close
151
+
152
+ # 等待服务器线程结束
153
+ server_thread.join
154
+
155
+ # ============================================================================
156
+ # 4. 高级示例:使用嵌套消息
157
+ # ============================================================================
158
+
159
+ puts "=" * 70
160
+ puts "4. 高级示例:嵌套 Protobuf 消息"
161
+ puts "=" * 70
162
+ puts
163
+
164
+ # 定义复杂的嵌套消息
165
+ Google::Protobuf::DescriptorPool.generated_pool.build do
166
+ add_file("user.proto", syntax: :proto3) do
167
+ add_message "User" do
168
+ optional :id, :int32, 1
169
+ optional :name, :string, 2
170
+ optional :email, :string, 3
171
+ repeated :tags, :string, 4
172
+ end
173
+
174
+ add_message "UserRequest" do
175
+ optional :action, :string, 1
176
+ optional :user, :message, 2, "User"
177
+ end
178
+
179
+ add_message "UserResponse" do
180
+ optional :success, :bool, 1
181
+ optional :user, :message, 2, "User"
182
+ optional :error, :string, 3
183
+ end
184
+ end
185
+ end
186
+
187
+ User = Google::Protobuf::DescriptorPool.generated_pool.lookup("User").msgclass
188
+ UserRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("UserRequest").msgclass
189
+ UserResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("UserResponse").msgclass
190
+
191
+ # 创建复杂消息
192
+ user = User.new(
193
+ id: 1001,
194
+ name: "张三",
195
+ email: "zhangsan@example.com",
196
+ tags: ["VIP", "早期用户", "活跃"]
197
+ )
198
+
199
+ user_request = UserRequest.new(
200
+ action: "create",
201
+ user: user
202
+ )
203
+
204
+ puts "创建嵌套消息:"
205
+ puts " Action: #{user_request.action}"
206
+ puts " User:"
207
+ puts " ID: #{user_request.user.id}"
208
+ puts " Name: #{user_request.user.name}"
209
+ puts " Email: #{user_request.user.email}"
210
+ puts " Tags: #{user_request.user.tags.join(', ')}"
211
+ puts
212
+
213
+ # 序列化
214
+ serialized = UserRequest.encode(user_request)
215
+ puts "序列化后大小: #{serialized.bytesize} bytes"
216
+ puts
217
+
218
+ # 反序列化
219
+ deserialized = UserRequest.decode(serialized)
220
+ puts "反序列化成功:"
221
+ puts " User Name: #{deserialized.user.name}"
222
+ puts " User Tags: #{deserialized.user.tags.join(', ')}"
223
+ puts
224
+
225
+ # ============================================================================
226
+ # 5. 实际应用:RPC 调用示例
227
+ # ============================================================================
228
+
229
+ puts "=" * 70
230
+ puts "5. 实际应用:完整 RPC 调用"
231
+ puts "=" * 70
232
+ puts
233
+
234
+ # 定义 RPC 消息
235
+ Google::Protobuf::DescriptorPool.generated_pool.build do
236
+ add_file("rpc.proto", syntax: :proto3) do
237
+ add_message "RpcRequest" do
238
+ optional :func_code, :int32, 1
239
+ optional :data, :bytes, 2
240
+ end
241
+
242
+ add_message "RpcResponse" do
243
+ optional :status, :int32, 1
244
+ optional :data, :bytes, 2
245
+ optional :error_msg, :string, 3
246
+ end
247
+ end
248
+ end
249
+
250
+ RpcRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcRequest").msgclass
251
+ RpcResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcResponse").msgclass
252
+
253
+ # 模拟 RPC 服务器
254
+ rpc_url = "tcp://127.0.0.1:15556"
255
+ rpc_server_ready = false
256
+
257
+ rpc_server = Thread.new do
258
+ server = NNG::Socket.new(:pair1)
259
+ server.listen(rpc_url)
260
+ rpc_server_ready = true
261
+
262
+ # 接收 RPC 请求
263
+ request_data = server.recv
264
+ rpc_request = RpcRequest.decode(request_data)
265
+
266
+ puts "🔧 RPC 服务器收到调用:"
267
+ puts " Function Code: 0x#{rpc_request.func_code.to_s(16)}"
268
+ puts " Data Size: #{rpc_request.data.bytesize} bytes"
269
+ puts
270
+
271
+ # 解析嵌套的用户数据
272
+ user_data = User.decode(rpc_request.data)
273
+ puts " 解析用户数据:"
274
+ puts " Name: #{user_data.name}"
275
+ puts " Email: #{user_data.email}"
276
+ puts
277
+
278
+ # 构建响应
279
+ result_user = User.new(
280
+ id: user_data.id,
281
+ name: user_data.name,
282
+ email: user_data.email,
283
+ tags: user_data.tags + ["已处理"]
284
+ )
285
+
286
+ rpc_response = RpcResponse.new(
287
+ status: 0,
288
+ data: User.encode(result_user),
289
+ error_msg: ""
290
+ )
291
+
292
+ # 发送响应
293
+ server.send(RpcResponse.encode(rpc_response))
294
+ puts "✅ RPC 响应已发送"
295
+ puts
296
+
297
+ server.close
298
+ end
299
+
300
+ sleep 0.1 until rpc_server_ready
301
+
302
+ # RPC 客户端
303
+ puts "📞 RPC 客户端发起调用..."
304
+ puts
305
+
306
+ client = NNG::Socket.new(:pair1)
307
+ client.dial(rpc_url)
308
+
309
+ # 准备调用参数
310
+ call_user = User.new(
311
+ id: 2001,
312
+ name: "李四",
313
+ email: "lisi@example.com",
314
+ tags: ["新用户"]
315
+ )
316
+
317
+ # 构建 RPC 请求
318
+ rpc_request = RpcRequest.new(
319
+ func_code: 0x10, # 假设 0x10 是 getUserInfo 的功能码
320
+ data: User.encode(call_user)
321
+ )
322
+
323
+ # 发送请求
324
+ client.send(RpcRequest.encode(rpc_request))
325
+
326
+ # 接收响应
327
+ response_data = client.recv
328
+ rpc_response = RpcResponse.decode(response_data)
329
+
330
+ puts "📥 RPC 客户端收到响应:"
331
+ puts " Status: #{rpc_response.status}"
332
+
333
+ if rpc_response.status == 0
334
+ result_user = User.decode(rpc_response.data)
335
+ puts " 结果:"
336
+ puts " Name: #{result_user.name}"
337
+ puts " Email: #{result_user.email}"
338
+ puts " Tags: #{result_user.tags.join(', ')}"
339
+ else
340
+ puts " Error: #{rpc_response.error_msg}"
341
+ end
342
+ puts
343
+
344
+ client.close
345
+ rpc_server.join
346
+
347
+ # ============================================================================
348
+ # 总结
349
+ # ============================================================================
350
+
351
+ puts "=" * 70
352
+ puts "✅ 示例完成"
353
+ puts "=" * 70
354
+ puts
355
+ puts "关键要点:"
356
+ puts " 1. ✅ 使用 Protobuf 定义消息格式"
357
+ puts " 2. ✅ 使用 encode 序列化消息"
358
+ puts " 3. ✅ 使用 NNG 发送二进制数据"
359
+ puts " 4. ✅ 使用 NNG 接收二进制数据"
360
+ puts " 5. ✅ 使用 decode 反序列化消息"
361
+ puts
362
+ puts "优势:"
363
+ puts " • 类型安全的消息格式"
364
+ puts " • 高效的二进制序列化"
365
+ puts " • 跨语言兼容"
366
+ puts " • 版本演进支持"
367
+ puts " • 自动代码生成"
368
+ puts
369
+ puts "适用场景:"
370
+ puts " • 微服务 RPC 通信"
371
+ puts " • 分布式系统消息传递"
372
+ puts " • 高性能数据交换"
373
+ puts " • 跨语言服务集成"
374
+ puts
@@ -0,0 +1,191 @@
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
+ # 1. 定义 Protobuf 消息格式
17
+ # ============================================================================
18
+
19
+ puts "步骤 1: 定义 Protobuf 消息"
20
+ puts "-" * 70
21
+
22
+ # 定义请求消息
23
+ Google::Protobuf::DescriptorPool.generated_pool.build do
24
+ add_file("request.proto", syntax: :proto3) do
25
+ add_message "Request" do
26
+ optional :id, :int32, 1
27
+ optional :rpc_method, :string, 2
28
+ optional :params, :string, 3
29
+ end
30
+ end
31
+ end
32
+
33
+ # 定义响应消息
34
+ Google::Protobuf::DescriptorPool.generated_pool.build do
35
+ add_file("response.proto", syntax: :proto3) do
36
+ add_message "Response" do
37
+ optional :id, :int32, 1
38
+ optional :status, :int32, 2
39
+ optional :message, :string, 3
40
+ end
41
+ end
42
+ end
43
+
44
+ Request = Google::Protobuf::DescriptorPool.generated_pool.lookup("Request").msgclass
45
+ Response = Google::Protobuf::DescriptorPool.generated_pool.lookup("Response").msgclass
46
+
47
+ puts "✅ Protobuf 消息定义完成"
48
+ puts
49
+
50
+ # ============================================================================
51
+ # 2. 序列化和反序列化测试
52
+ # ============================================================================
53
+
54
+ puts "步骤 2: 测试 Protobuf 序列化"
55
+ puts "-" * 70
56
+
57
+ # 创建请求对象
58
+ request = Request.new(
59
+ id: 12345,
60
+ rpc_method: "getUserInfo",
61
+ params: '{"user_id": 888}'
62
+ )
63
+
64
+ puts "原始请求对象:"
65
+ puts " ID: #{request.id}"
66
+ puts " Method: #{request.rpc_method}"
67
+ puts " Params: #{request.params}"
68
+ puts
69
+
70
+ # 序列化为二进制
71
+ binary_data = Request.encode(request)
72
+ puts "序列化结果:"
73
+ puts " 大小: #{binary_data.bytesize} bytes"
74
+ puts " 十六进制: #{binary_data.unpack('H*').first}"
75
+ puts
76
+
77
+ # 反序列化
78
+ decoded_request = Request.decode(binary_data)
79
+ puts "反序列化结果:"
80
+ puts " ID: #{decoded_request.id}"
81
+ puts " Method: #{decoded_request.rpc_method}"
82
+ puts " Params: #{decoded_request.params}"
83
+ puts
84
+
85
+ # ============================================================================
86
+ # 3. 使用进程模拟客户端-服务器通信
87
+ # ============================================================================
88
+
89
+ puts "步骤 3: NNG + Protobuf 通信演示"
90
+ puts "-" * 70
91
+
92
+ url = "tcp://127.0.0.1:15557"
93
+
94
+ # 创建服务器进程
95
+ server_pid = fork do
96
+ begin
97
+ server = NNG::Socket.new(:pair1)
98
+ server.listen(url)
99
+ puts "[服务器] 监听: #{url}"
100
+
101
+ # 接收请求
102
+ request_data = server.recv
103
+ puts "[服务器] 收到 #{request_data.bytesize} bytes 数据"
104
+
105
+ # 反序列化请求
106
+ request = Request.decode(request_data)
107
+ puts "[服务器] 解析请求:"
108
+ puts "[服务器] ID: #{request.id}"
109
+ puts "[服务器] Method: #{request.rpc_method}"
110
+ puts "[服务器] Params: #{request.params}"
111
+
112
+ # 创建响应
113
+ response = Response.new(
114
+ id: request.id,
115
+ status: 200,
116
+ message: "处理成功: #{request.rpc_method}"
117
+ )
118
+
119
+ # 序列化并发送
120
+ response_data = Response.encode(response)
121
+ server.send(response_data)
122
+ puts "[服务器] 发送响应 #{response_data.bytesize} bytes"
123
+
124
+ server.close
125
+ rescue => e
126
+ puts "[服务器] 错误: #{e.message}"
127
+ end
128
+ end
129
+
130
+ # 等待服务器启动
131
+ sleep 0.5
132
+
133
+ # 客户端
134
+ begin
135
+ client = NNG::Socket.new(:pair1)
136
+ client.dial(url)
137
+ puts "[客户端] 连接: #{url}"
138
+
139
+ # 创建请求
140
+ request = Request.new(
141
+ id: 99999,
142
+ rpc_method: "getContacts",
143
+ params: '{"limit": 100}'
144
+ )
145
+
146
+ # 序列化并发送
147
+ request_data = Request.encode(request)
148
+ puts "[客户端] 发送请求 #{request_data.bytesize} bytes"
149
+ client.send(request_data)
150
+
151
+ # 接收响应
152
+ response_data = client.recv
153
+ puts "[客户端] 收到响应 #{response_data.bytesize} bytes"
154
+
155
+ # 反序列化
156
+ response = Response.decode(response_data)
157
+ puts "[客户端] 解析响应:"
158
+ puts "[客户端] ID: #{response.id}"
159
+ puts "[客户端] Status: #{response.status}"
160
+ puts "[客户端] Message: #{response.message}"
161
+
162
+ client.close
163
+ rescue => e
164
+ puts "[客户端] 错误: #{e.message}"
165
+ puts e.backtrace.first(3)
166
+ end
167
+
168
+ # 等待服务器进程结束
169
+ Process.wait(server_pid)
170
+
171
+ puts
172
+ puts "=" * 70
173
+ puts "✅ 示例完成"
174
+ puts "=" * 70
175
+ puts
176
+ puts "关键代码:"
177
+ puts
178
+ puts " # 序列化"
179
+ puts " binary_data = Request.encode(request)"
180
+ puts " socket.send(binary_data)"
181
+ puts
182
+ puts " # 反序列化"
183
+ puts " binary_data = socket.recv"
184
+ puts " request = Request.decode(binary_data)"
185
+ puts
186
+ puts "优势:"
187
+ puts " ✅ 类型安全的消息定义"
188
+ puts " ✅ 高效的二进制序列化 (~50% 比 JSON 小)"
189
+ puts " ✅ 跨语言兼容 (Python, Java, Go, C++ 等)"
190
+ puts " ✅ 向后兼容的版本演进"
191
+ puts