plusui-native-core 0.1.55 β 0.1.56
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.
- package/Core/CMakeLists.txt +1 -1
- package/package.json +1 -1
- package/Core/Features/Connection/ARCHITECTURE.md +0 -369
- package/Core/Features/Connection/examples/simple_tags_example.hpp +0 -130
- package/Core/Features/Connection/examples/simple_tags_example.ts +0 -247
- package/Core/generated/bridge.hpp +0 -302
package/Core/CMakeLists.txt
CHANGED
package/package.json
CHANGED
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
# Connection Feature Architecture
|
|
2
|
-
|
|
3
|
-
## ποΈ System Overview
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
7
|
-
β PlusUI Connection Feature β
|
|
8
|
-
β Unified Frontend β Backend Communication β
|
|
9
|
-
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
10
|
-
|
|
11
|
-
ββββββββββββββββββββ ββββββββββββββββββββ
|
|
12
|
-
β Frontend (TS) β β Backend (C++) β
|
|
13
|
-
β β β β
|
|
14
|
-
β ββββββββββββββ β β ββββββββββββββ β
|
|
15
|
-
β β connect.* β β β β Bindings β β
|
|
16
|
-
β β API β β β β Class β β
|
|
17
|
-
β βββββββ¬βββββββ β β βββββββ¬βββββββ β
|
|
18
|
-
β β β β β β
|
|
19
|
-
β βββββββΌβββββββ β βββββββββββββββ β βββββββΌβββββββ β
|
|
20
|
-
β βConnection ββββΌββββΊβ WebView2 ββββββββββΌββΊβConnection β β
|
|
21
|
-
β β Client β β β IPC Layer β β β Protocol β β
|
|
22
|
-
β ββββββββββββββ β βββββββββββββββ β ββββββββββββββ β
|
|
23
|
-
β β β β
|
|
24
|
-
ββββββββββββββββββββ ββββββββββββββββββββ
|
|
25
|
-
|
|
26
|
-
βββββββββββββββββββ
|
|
27
|
-
β Schema File β
|
|
28
|
-
β connection. β
|
|
29
|
-
β schema β
|
|
30
|
-
ββββββββββ¬βββββββββ
|
|
31
|
-
β
|
|
32
|
-
ββββββββββΌβββββββββ
|
|
33
|
-
β Bindgen β
|
|
34
|
-
β Generator β
|
|
35
|
-
ββββββββββ¬βββββββββ
|
|
36
|
-
β
|
|
37
|
-
ββββββββββββββ΄βββββββββββββ
|
|
38
|
-
β β
|
|
39
|
-
ββββββββΌββββββ ββββββββΌβββββββ
|
|
40
|
-
βbindings.ts β βbindings.hpp β
|
|
41
|
-
β(Generated) β β (Generated) β
|
|
42
|
-
ββββββββββββββ βββββββββββββββ
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## π Communication Flow
|
|
46
|
-
|
|
47
|
-
### CALL Pattern (Request/Response)
|
|
48
|
-
```
|
|
49
|
-
Frontend Backend
|
|
50
|
-
β β
|
|
51
|
-
βββ[1] call(name, args)βββββΊβ
|
|
52
|
-
β β
|
|
53
|
-
β [2] handle_*
|
|
54
|
-
β β
|
|
55
|
-
ββββ[3] result ββββββββββββββ
|
|
56
|
-
β β
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### FIRE Pattern (One-way)
|
|
60
|
-
```
|
|
61
|
-
Frontend Backend
|
|
62
|
-
β β
|
|
63
|
-
βββ[1] fire(name, args)βββββΊβ
|
|
64
|
-
β β
|
|
65
|
-
β [2] handle_*
|
|
66
|
-
β β
|
|
67
|
-
β (no response) β
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### EVENT Pattern (Backend β Frontend)
|
|
71
|
-
```
|
|
72
|
-
Frontend Backend
|
|
73
|
-
β β
|
|
74
|
-
β [1] on(name, callback) β
|
|
75
|
-
β β
|
|
76
|
-
β β [2] emit_*
|
|
77
|
-
ββββ[3] event data ββββββββββ
|
|
78
|
-
β β
|
|
79
|
-
β [4] callback(data) β
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### STREAM Pattern (Continuous Data)
|
|
83
|
-
```
|
|
84
|
-
Frontend Backend
|
|
85
|
-
β β
|
|
86
|
-
β [1] stream.subscribe(cb) β
|
|
87
|
-
β β
|
|
88
|
-
β β [2] emit_* (repeated)
|
|
89
|
-
ββββ[3] data ββββββββββββββββ
|
|
90
|
-
ββββ[4] data ββββββββββββββββ
|
|
91
|
-
ββββ[5] data ββββββββββββββββ
|
|
92
|
-
β β
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### CHANNEL Pattern (Bidirectional Pub/Sub)
|
|
96
|
-
```
|
|
97
|
-
Frontend Backend
|
|
98
|
-
β β
|
|
99
|
-
βββ[1] channel.publish()ββββΊβ [2] handle_*_publish
|
|
100
|
-
β β
|
|
101
|
-
β [3] channel.subscribe() β
|
|
102
|
-
β β
|
|
103
|
-
ββββ[4] emit_* ββββββββββββββ
|
|
104
|
-
β β
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## π Build & Generation Flow
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
1. Developer writes schema
|
|
111
|
-
βββΊ connection.schema
|
|
112
|
-
|
|
113
|
-
2. Run connect generator tool
|
|
114
|
-
βββΊ node Tools/plusui-connector/src/connect.js
|
|
115
|
-
|
|
116
|
-
3. Parser reads schema
|
|
117
|
-
βββΊ Parses connect definitions
|
|
118
|
-
βββΊ Validates syntax
|
|
119
|
-
βββΊ Creates method definitions
|
|
120
|
-
|
|
121
|
-
4. Generator creates TypeScript
|
|
122
|
-
βββΊ Type definitions (GreetIn, GreetOut, etc.)
|
|
123
|
-
βββΊ connect.* API functions
|
|
124
|
-
βββΊ Typed callbacks
|
|
125
|
-
|
|
126
|
-
5. Generator creates C++
|
|
127
|
-
βββΊ Struct definitions with JSON converters
|
|
128
|
-
βββΊ Virtual handler methods
|
|
129
|
-
βββΊ Emit helper methods
|
|
130
|
-
βββΊ Message dispatcher
|
|
131
|
-
|
|
132
|
-
6. Files written
|
|
133
|
-
βββΊ Core/Features/Connection/generated/bindings.ts
|
|
134
|
-
βββΊ Core/Features/Connection/generated/bindings.hpp
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## π¦ Component Architecture
|
|
138
|
-
|
|
139
|
-
### TypeScript Side
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
143
|
-
β Generated API (bindings.ts) β
|
|
144
|
-
β ββββββββββββββββββββββββββββββββββ β
|
|
145
|
-
β β export const connect = { β β
|
|
146
|
-
β β greet: (args) => ..., β β
|
|
147
|
-
β β onResize: (cb) => ..., β β
|
|
148
|
-
β β cpuUsage: { subscribe }, β β
|
|
149
|
-
β β logBus: { subscribe, pub }, β β
|
|
150
|
-
β β } β β
|
|
151
|
-
β ββββββββββββββ¬ββββββββββββββββββββ β
|
|
152
|
-
βββββββββββββββββΌβββββββββββββββββββββββ
|
|
153
|
-
β uses
|
|
154
|
-
βΌ
|
|
155
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
156
|
-
β Core Connection (connection.ts) β
|
|
157
|
-
β ββββββββββββββββββββββββββββββββββ β
|
|
158
|
-
β β class ConnectionClient { β β
|
|
159
|
-
β β call(name, args) β β
|
|
160
|
-
β β fire(name, args) β β
|
|
161
|
-
β β on(name, callback) β β
|
|
162
|
-
β β stream(name) β β
|
|
163
|
-
β β channel(name) β β
|
|
164
|
-
β β } β β
|
|
165
|
-
β ββββββββββββββ¬ββββββββββββββββββββ β
|
|
166
|
-
βββββββββββββββββΌβββββββββββββββββββββββ
|
|
167
|
-
β sends/receives
|
|
168
|
-
βΌ
|
|
169
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
170
|
-
β Message Protocol β
|
|
171
|
-
β { β
|
|
172
|
-
β kind: "call" | "fire" | ..., β
|
|
173
|
-
β id: "...", β
|
|
174
|
-
β name: "methodName", β
|
|
175
|
-
β payload: { ... } β
|
|
176
|
-
β } β
|
|
177
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### C++ Side
|
|
181
|
-
|
|
182
|
-
```
|
|
183
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
184
|
-
β User Implementation β
|
|
185
|
-
β ββββββββββββββββββββββββββββββββββ β
|
|
186
|
-
β β class MyApp : public β β
|
|
187
|
-
β β plusui::connect::Bindings β β
|
|
188
|
-
β β { β β
|
|
189
|
-
β β GreetOut handle_greet(...) β β
|
|
190
|
-
β β void handle_log(...) β β
|
|
191
|
-
β β β β
|
|
192
|
-
β β void emitUpdate() { β β
|
|
193
|
-
β β emit_onResize({...}); β β
|
|
194
|
-
β β } β β
|
|
195
|
-
β β } β β
|
|
196
|
-
β ββββββββββββββ¬ββββββββββββββββββββ β
|
|
197
|
-
βββββββββββββββββΌβββββββββββββββββββββββ
|
|
198
|
-
β inherits
|
|
199
|
-
βΌ
|
|
200
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
201
|
-
β Generated Base (bindings.hpp) β
|
|
202
|
-
β ββββββββββββββββββββββββββββββββββ β
|
|
203
|
-
β β class Bindings : public β β
|
|
204
|
-
β β Connection { β β
|
|
205
|
-
β β β β
|
|
206
|
-
β β // Virtual handlers β β
|
|
207
|
-
β β virtual GreetOut handle_* β β
|
|
208
|
-
β β β β
|
|
209
|
-
β β // Emit methods β β
|
|
210
|
-
β β void emit_onResize(...) β β
|
|
211
|
-
β β β β
|
|
212
|
-
β β // Message dispatcher β β
|
|
213
|
-
β β void handleMessage(Envelope) β β
|
|
214
|
-
β β } β β
|
|
215
|
-
β ββββββββββββββ¬ββββββββββββββββββββ β
|
|
216
|
-
βββββββββββββββββΌβββββββββββββββββββββββ
|
|
217
|
-
β uses
|
|
218
|
-
βΌ
|
|
219
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
220
|
-
β Core Connect (connect.hpp) β
|
|
221
|
-
β ββββββββββββββββββββββββββββββββββ β
|
|
222
|
-
β β class Connection { β β
|
|
223
|
-
β β void send(Envelope) β β
|
|
224
|
-
β β void call(...) β β
|
|
225
|
-
β β void fire(...) β β
|
|
226
|
-
β β void event(...) β β
|
|
227
|
-
β β } β β
|
|
228
|
-
β ββββββββββββββββββββββββββββββββββ β
|
|
229
|
-
ββββββββββββββββββββββββββββββββββββββββ
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
## π Key Design Decisions
|
|
233
|
-
|
|
234
|
-
### 1. Schema-Driven
|
|
235
|
-
- **Why**: Single source of truth, prevents TS/C++ drift
|
|
236
|
-
- **Benefit**: Auto-generated types, less manual work
|
|
237
|
-
|
|
238
|
-
### 2. Strongly Typed
|
|
239
|
-
- **Why**: Catch errors at compile time
|
|
240
|
-
- **Benefit**: Better IDE support, safer code
|
|
241
|
-
|
|
242
|
-
### 3. Pattern-Based
|
|
243
|
-
- **Why**: Different use cases need different semantics
|
|
244
|
-
- **Benefit**: Clear intent, optimized for each pattern
|
|
245
|
-
|
|
246
|
-
### 4. Code Generation
|
|
247
|
-
- **Why**: Boilerplate is tedious and error-prone
|
|
248
|
-
- **Benefit**: Consistent, maintainable, fast development
|
|
249
|
-
|
|
250
|
-
### 5. Struct-Based (not JSON)
|
|
251
|
-
- **Why**: Type safety in C++
|
|
252
|
-
- **Benefit**: Compiler checks, clear interfaces
|
|
253
|
-
|
|
254
|
-
## π― Design Principles
|
|
255
|
-
|
|
256
|
-
1. **Simple Developer Experience**
|
|
257
|
-
- Minimal boilerplate
|
|
258
|
-
- Intuitive API
|
|
259
|
-
- Clear patterns
|
|
260
|
-
|
|
261
|
-
2. **Type Safety**
|
|
262
|
-
- End-to-end type checking
|
|
263
|
-
- Auto-generated types
|
|
264
|
-
- Compile-time validation
|
|
265
|
-
|
|
266
|
-
3. **Unified System**
|
|
267
|
-
- Single API for all patterns
|
|
268
|
-
- Consistent naming
|
|
269
|
-
- One import
|
|
270
|
-
|
|
271
|
-
4. **Framework Agnostic**
|
|
272
|
-
- Works with React, Vue, Svelte
|
|
273
|
-
- No framework lock-in
|
|
274
|
-
- Plain TypeScript/JavaScript
|
|
275
|
-
|
|
276
|
-
5. **Performance**
|
|
277
|
-
- Minimal overhead
|
|
278
|
-
- Efficient serialization
|
|
279
|
-
- Direct dispatch
|
|
280
|
-
|
|
281
|
-
## π Message Protocol
|
|
282
|
-
|
|
283
|
-
### Envelope Structure
|
|
284
|
-
```typescript
|
|
285
|
-
{
|
|
286
|
-
kind: "call" | "fire" | "result" | "event" | "stream" |
|
|
287
|
-
"sub" | "unsub" | "publish" | "error",
|
|
288
|
-
id?: string, // Request ID (for calls)
|
|
289
|
-
name: string, // Method/event name
|
|
290
|
-
payload: unknown, // Data
|
|
291
|
-
error?: string // Error message (if kind="error")
|
|
292
|
-
}
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### Message Kinds
|
|
296
|
-
- **call**: Request (needs response)
|
|
297
|
-
- **fire**: One-way command
|
|
298
|
-
- **result**: Response to call
|
|
299
|
-
- **event**: Backend notification
|
|
300
|
-
- **stream**: Continuous data
|
|
301
|
-
- **sub**: Subscribe to stream
|
|
302
|
-
- **unsub**: Unsubscribe from stream
|
|
303
|
-
- **publish**: Channel message
|
|
304
|
-
- **error**: Error response
|
|
305
|
-
|
|
306
|
-
## π Type Safety Flow
|
|
307
|
-
|
|
308
|
-
```
|
|
309
|
-
Schema Definition
|
|
310
|
-
β
|
|
311
|
-
Bindgen
|
|
312
|
-
β
|
|
313
|
-
ββββββββββββββββ
|
|
314
|
-
β TypeScript β
|
|
315
|
-
β - GreetIn β
|
|
316
|
-
β - GreetOut β
|
|
317
|
-
ββββββββββββββββ
|
|
318
|
-
β
|
|
319
|
-
Frontend Code
|
|
320
|
-
await connect.greet({ name: "..." })
|
|
321
|
-
β Type checked!
|
|
322
|
-
β
|
|
323
|
-
{ message: "..." }
|
|
324
|
-
β Type checked!
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
```
|
|
328
|
-
Schema Definition
|
|
329
|
-
β
|
|
330
|
-
Bindgen
|
|
331
|
-
β
|
|
332
|
-
ββββββββββββββββ
|
|
333
|
-
β C++ β
|
|
334
|
-
β - GreetIn β
|
|
335
|
-
β - GreetOut β
|
|
336
|
-
ββββββββββββββββ
|
|
337
|
-
β
|
|
338
|
-
Backend Code
|
|
339
|
-
GreetOut handle_greet(const GreetIn& args)
|
|
340
|
-
β Type checked!
|
|
341
|
-
return { "Hello" }
|
|
342
|
-
β Type checked!
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
## π Performance Characteristics
|
|
346
|
-
|
|
347
|
-
- **Call latency**: ~1-2ms (depends on WebView2)
|
|
348
|
-
- **Fire latency**: <1ms (fire-and-forget)
|
|
349
|
-
- **Event dispatch**: <0.1ms (in-process)
|
|
350
|
-
- **Serialization**: O(n) for payload size
|
|
351
|
-
- **Memory**: Minimal (shared memory for IPC)
|
|
352
|
-
|
|
353
|
-
## π§ Extension Points
|
|
354
|
-
|
|
355
|
-
Future enhancements:
|
|
356
|
-
- State synchronization (synced properties)
|
|
357
|
-
- Binary protocol option (faster than JSON)
|
|
358
|
-
- Compression for large payloads
|
|
359
|
-
- Message batching
|
|
360
|
-
- Request cancellation
|
|
361
|
-
- Middleware/interceptors
|
|
362
|
-
- RPC versioning
|
|
363
|
-
|
|
364
|
-
---
|
|
365
|
-
|
|
366
|
-
**See Also:**
|
|
367
|
-
- [README.md](README.md) - Complete guide
|
|
368
|
-
- [QUICK_REFERENCE.md](QUICK_REFERENCE.md) - Cheat sheet
|
|
369
|
-
- [MIGRATION.md](MIGRATION.md) - Migration from old system
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example: Simple Tag-Based Connection (C++ Backend)
|
|
3
|
-
*
|
|
4
|
-
* No schema file needed! Just tag your methods and bindgen does the rest.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
#pragma once
|
|
8
|
-
#include <plusui/connect.hpp>
|
|
9
|
-
#include <string>
|
|
10
|
-
|
|
11
|
-
namespace example {
|
|
12
|
-
|
|
13
|
-
class SimpleApp : public plusui::Connect {
|
|
14
|
-
public:
|
|
15
|
-
|
|
16
|
-
// ============================================
|
|
17
|
-
// CONNECT_CALL: Request/Response
|
|
18
|
-
// Frontend can await the result
|
|
19
|
-
// ============================================
|
|
20
|
-
|
|
21
|
-
// Simple call with one parameter
|
|
22
|
-
CONNECT_CALL(greet, std::string, std::string name)
|
|
23
|
-
std::string greet(const std::string& name) {
|
|
24
|
-
return "Hello, " + name + "!";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Call with multiple parameters β returns object
|
|
28
|
-
CONNECT_CALL(calculate, double, double a, double b)
|
|
29
|
-
double calculate(double a, double b) {
|
|
30
|
-
return a + b;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Call with complex return (auto-generates struct)
|
|
34
|
-
CONNECT_CALL(getUser, {int id, std::string name, std::string email}, int userId)
|
|
35
|
-
auto getUser(int userId) {
|
|
36
|
-
struct Result { int id; std::string name; std::string email; };
|
|
37
|
-
return Result{ userId, "John Doe", "john@example.com" };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// ============================================
|
|
41
|
-
// CONNECT_FIRE: One-way to Backend
|
|
42
|
-
// No response expected
|
|
43
|
-
// ============================================
|
|
44
|
-
|
|
45
|
-
CONNECT_FIRE(minimize, void)
|
|
46
|
-
void minimize() {
|
|
47
|
-
// Minimize window
|
|
48
|
-
std::cout << "Minimizing..." << std::endl;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
CONNECT_FIRE(log, void, std::string level, std::string message)
|
|
52
|
-
void log(const std::string& level, const std::string& message) {
|
|
53
|
-
std::cout << "[" << level << "] " << message << std::endl;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ============================================
|
|
57
|
-
// CONNECT_EVENT: Backend β Frontend
|
|
58
|
-
// Backend emits, frontend listens
|
|
59
|
-
// ============================================
|
|
60
|
-
|
|
61
|
-
CONNECT_EVENT(onResize, int width, int height)
|
|
62
|
-
void emitResize(int width, int height) {
|
|
63
|
-
// Auto-generated emit method
|
|
64
|
-
emit_onResize(width, height);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
CONNECT_EVENT(onFileDrop, std::vector<std::string> files)
|
|
68
|
-
void emitFileDrop(const std::vector<std::string>& files) {
|
|
69
|
-
emit_onFileDrop(files);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// ============================================
|
|
73
|
-
// CONNECT_STREAM: Continuous Data
|
|
74
|
-
// Backend streams, frontend subscribes
|
|
75
|
-
// ============================================
|
|
76
|
-
|
|
77
|
-
CONNECT_STREAM(cpuUsage, double percent)
|
|
78
|
-
void startMonitoring() {
|
|
79
|
-
// Stream CPU usage continuously
|
|
80
|
-
std::thread([this]() {
|
|
81
|
-
while (running) {
|
|
82
|
-
double cpu = getCpuUsage();
|
|
83
|
-
emit_cpuUsage(cpu);
|
|
84
|
-
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
85
|
-
}
|
|
86
|
-
}).detach();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ============================================
|
|
90
|
-
// CONNECT_CHANNEL: Bidirectional
|
|
91
|
-
// Both sides can send and receive
|
|
92
|
-
// ============================================
|
|
93
|
-
|
|
94
|
-
CONNECT_CHANNEL(logBus, std::string level, std::string line)
|
|
95
|
-
|
|
96
|
-
// Receive from frontend
|
|
97
|
-
void onLogFromFrontend(const std::string& level, const std::string& line) {
|
|
98
|
-
std::cout << "[Frontend] " << level << ": " << line << std::endl;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Send to frontend
|
|
102
|
-
void sendLogToFrontend(const std::string& level, const std::string& line) {
|
|
103
|
-
emit_logBus(level, line);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private:
|
|
107
|
-
bool running = true;
|
|
108
|
-
|
|
109
|
-
double getCpuUsage() {
|
|
110
|
-
return 50.0 + (rand() % 30);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
} // namespace example
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* This example shows how simple it is:
|
|
118
|
-
*
|
|
119
|
-
* 1. Tag your methods with CONNECT_* macros
|
|
120
|
-
* 2. Run: npm run bindgen
|
|
121
|
-
* 3. Use in TypeScript:
|
|
122
|
-
*
|
|
123
|
-
* const result = await connect.greet({ name: 'World' });
|
|
124
|
-
* connect.minimize();
|
|
125
|
-
* connect.onResize((w, h) => updateUI(w, h));
|
|
126
|
-
* connect.cpuUsage.subscribe((cpu) => showCpu(cpu));
|
|
127
|
-
* connect.logBus.publish({ level: 'info', line: 'msg' });
|
|
128
|
-
*
|
|
129
|
-
* That's it! No separate schema file, no manual typing.
|
|
130
|
-
*/
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Example: Simple Tag-Based Connection (TypeScript Frontend)
|
|
3
|
-
*
|
|
4
|
-
* After running bindgen, use the auto-generated connect API
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { connect } from '../generated/bindings';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* All these methods are auto-generated from C++ CONNECT_* tags!
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// ============================================
|
|
14
|
-
// CALL - Request/Response
|
|
15
|
-
// ============================================
|
|
16
|
-
|
|
17
|
-
async function callExamples() {
|
|
18
|
-
// Simple call
|
|
19
|
-
const greeting = await connect.greet({ name: 'PlusUI' });
|
|
20
|
-
console.log(greeting); // "Hello, PlusUI!"
|
|
21
|
-
|
|
22
|
-
// Call with multiple params
|
|
23
|
-
const sum = await connect.calculate({ a: 10, b: 20 });
|
|
24
|
-
console.log(sum); // 30
|
|
25
|
-
|
|
26
|
-
// Complex return type
|
|
27
|
-
const user = await connect.getUser({ userId: 123 });
|
|
28
|
-
console.log(user.name, user.email);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// ============================================
|
|
32
|
-
// FIRE - One-way to Backend
|
|
33
|
-
// ============================================
|
|
34
|
-
|
|
35
|
-
function fireExamples() {
|
|
36
|
-
// Fire with no params
|
|
37
|
-
connect.minimize();
|
|
38
|
-
|
|
39
|
-
// Fire with params
|
|
40
|
-
connect.log({
|
|
41
|
-
level: 'info',
|
|
42
|
-
message: 'User clicked button'
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Fire and forget - doesn't wait
|
|
46
|
-
connect.log({ level: 'debug', message: 'Debug info' });
|
|
47
|
-
doSomethingElse(); // Runs immediately
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// ============================================
|
|
51
|
-
// EVENT - Listen to Backend
|
|
52
|
-
// ============================================
|
|
53
|
-
|
|
54
|
-
function eventExamples() {
|
|
55
|
-
// Listen for resize events
|
|
56
|
-
const unsubResize = connect.onResize((data) => {
|
|
57
|
-
console.log(`Window: ${data.width}x${data.height}`);
|
|
58
|
-
updateLayout(data.width, data.height);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Listen for file drops
|
|
62
|
-
connect.onFileDrop((data) => {
|
|
63
|
-
console.log('Files dropped:', data.files);
|
|
64
|
-
data.files.forEach(file => processFile(file));
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
// Clean up when done
|
|
68
|
-
// unsubResize();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ============================================
|
|
72
|
-
// STREAM - Subscribe to Continuous Data
|
|
73
|
-
// ============================================
|
|
74
|
-
|
|
75
|
-
function streamExamples() {
|
|
76
|
-
// Subscribe to CPU usage stream
|
|
77
|
-
const unsub = connect.cpuUsage.subscribe((data) => {
|
|
78
|
-
updateCpuChart(data.percent);
|
|
79
|
-
|
|
80
|
-
if (data.percent > 90) {
|
|
81
|
-
showWarning('High CPU!');
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// Unsubscribe when component unmounts
|
|
86
|
-
return unsub;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// ============================================
|
|
90
|
-
// CHANNEL - Bidirectional Communication
|
|
91
|
-
// ============================================
|
|
92
|
-
|
|
93
|
-
function channelExamples() {
|
|
94
|
-
// Subscribe to receive from backend
|
|
95
|
-
connect.logBus.subscribe((msg) => {
|
|
96
|
-
const color = msg.level === 'error' ? 'red' : 'gray';
|
|
97
|
-
console.log(`%c[${msg.level}] ${msg.line}`, `color: ${color}`);
|
|
98
|
-
addToLogView(msg);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Publish to backend
|
|
102
|
-
connect.logBus.publish({
|
|
103
|
-
level: 'info',
|
|
104
|
-
line: 'Frontend initialized'
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Both sides can communicate freely
|
|
108
|
-
document.onclick = () => {
|
|
109
|
-
connect.logBus.publish({
|
|
110
|
-
level: 'debug',
|
|
111
|
-
line: 'User clicked somewhere'
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// ============================================
|
|
117
|
-
// React Component Example
|
|
118
|
-
// ============================================
|
|
119
|
-
|
|
120
|
-
function ReactExample() {
|
|
121
|
-
const [greeting, setGreeting] = React.useState('');
|
|
122
|
-
const [cpu, setCpu] = React.useState(0);
|
|
123
|
-
|
|
124
|
-
React.useEffect(() => {
|
|
125
|
-
// Call on mount
|
|
126
|
-
connect.greet({ name: 'React' })
|
|
127
|
-
.then(result => setGreeting(result));
|
|
128
|
-
|
|
129
|
-
// Subscribe to events
|
|
130
|
-
const unsubResize = connect.onResize((data) => {
|
|
131
|
-
console.log('Resize:', data);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// Subscribe to stream
|
|
135
|
-
const unsubCpu = connect.cpuUsage.subscribe((data) => {
|
|
136
|
-
setCpu(data.percent);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// Subscribe to channel
|
|
140
|
-
const unsubLog = connect.logBus.subscribe((msg) => {
|
|
141
|
-
console.log(msg);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
// Cleanup all subscriptions
|
|
145
|
-
return () => {
|
|
146
|
-
unsubResize();
|
|
147
|
-
unsubCpu();
|
|
148
|
-
unsubLog();
|
|
149
|
-
};
|
|
150
|
-
}, []);
|
|
151
|
-
|
|
152
|
-
const handleMinimize = () => {
|
|
153
|
-
connect.minimize();
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const handleLog = () => {
|
|
157
|
-
connect.log({
|
|
158
|
-
level: 'info',
|
|
159
|
-
message: 'Button clicked!'
|
|
160
|
-
});
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
return (
|
|
164
|
-
<div>
|
|
165
|
-
<h1>{greeting}</h1>
|
|
166
|
-
<div>CPU: {cpu.toFixed(1)}%</div>
|
|
167
|
-
<button onClick={handleMinimize}>Minimize</button>
|
|
168
|
-
<button onClick={handleLog}>Log Message</button>
|
|
169
|
-
</div>
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// ============================================
|
|
174
|
-
// Vue Composition API Example
|
|
175
|
-
// ============================================
|
|
176
|
-
|
|
177
|
-
function vueExample() {
|
|
178
|
-
const greeting = ref('');
|
|
179
|
-
const cpu = ref(0);
|
|
180
|
-
|
|
181
|
-
onMounted(async () => {
|
|
182
|
-
// Call backend
|
|
183
|
-
const result = await connect.greet({ name: 'Vue' });
|
|
184
|
-
greeting.value = result;
|
|
185
|
-
|
|
186
|
-
// Subscribe to stream
|
|
187
|
-
const unsub = connect.cpuUsage.subscribe((data) => {
|
|
188
|
-
cpu.value = data.percent;
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
onUnmounted(() => {
|
|
192
|
-
unsub();
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
greeting,
|
|
198
|
-
cpu,
|
|
199
|
-
minimize: () => connect.minimize(),
|
|
200
|
-
log: (msg: string) => connect.log({ level: 'info', message: msg }),
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// ============================================
|
|
205
|
-
// Helper Functions
|
|
206
|
-
// ============================================
|
|
207
|
-
|
|
208
|
-
function updateLayout(width: number, height: number) {
|
|
209
|
-
// Update UI layout
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function processFile(file: string) {
|
|
213
|
-
// Process dropped file
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function updateCpuChart(percent: number) {
|
|
217
|
-
// Update chart
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function showWarning(msg: string) {
|
|
221
|
-
// Show warning toast
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function addToLogView(msg: any) {
|
|
225
|
-
// Add to log view
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function doSomethingElse() {
|
|
229
|
-
// Continue execution
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* THAT'S IT!
|
|
234
|
-
*
|
|
235
|
-
* No schema file needed.
|
|
236
|
-
* No manual type definitions.
|
|
237
|
-
* Just tag your C++ methods and use them in TypeScript.
|
|
238
|
-
*
|
|
239
|
-
* Bindgen automatically:
|
|
240
|
-
* - Finds all CONNECT_* tags
|
|
241
|
-
* - Generates TypeScript types
|
|
242
|
-
* - Creates the connect.* API
|
|
243
|
-
* - Handles all serialization
|
|
244
|
-
* - Manages subscriptions
|
|
245
|
-
*
|
|
246
|
-
* Perfect developer experience! π
|
|
247
|
-
*/
|
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-generated by plusui-bindgen
|
|
3
|
-
* DO NOT EDIT - Changes will be overwritten
|
|
4
|
-
* Generated from: connect.schema
|
|
5
|
-
*/
|
|
6
|
-
#pragma once
|
|
7
|
-
#include <plusui/connect.hpp>
|
|
8
|
-
#include <string>
|
|
9
|
-
#include <vector>
|
|
10
|
-
|
|
11
|
-
namespace plusui {
|
|
12
|
-
namespace connect {
|
|
13
|
-
|
|
14
|
-
// ============================================
|
|
15
|
-
// Type Definitions
|
|
16
|
-
// ============================================
|
|
17
|
-
|
|
18
|
-
struct GreetIn {
|
|
19
|
-
std::string name;
|
|
20
|
-
|
|
21
|
-
static GreetIn from_json(const nlohmann::json& j) {
|
|
22
|
-
GreetIn result;
|
|
23
|
-
if (j.contains("name")) { result.name = j["name"]; }
|
|
24
|
-
return result;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
nlohmann::json to_json() const {
|
|
28
|
-
nlohmann::json j;
|
|
29
|
-
j["name"] = name;
|
|
30
|
-
return j;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
struct GreetOut {
|
|
35
|
-
std::string message;
|
|
36
|
-
|
|
37
|
-
static GreetOut from_json(const nlohmann::json& j) {
|
|
38
|
-
GreetOut result;
|
|
39
|
-
if (j.contains("message")) { result.message = j["message"]; }
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
nlohmann::json to_json() const {
|
|
44
|
-
nlohmann::json j;
|
|
45
|
-
j["message"] = message;
|
|
46
|
-
return j;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
struct LogIn {
|
|
51
|
-
std::string msg;
|
|
52
|
-
|
|
53
|
-
static LogIn from_json(const nlohmann::json& j) {
|
|
54
|
-
LogIn result;
|
|
55
|
-
if (j.contains("msg")) { result.msg = j["msg"]; }
|
|
56
|
-
return result;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
nlohmann::json to_json() const {
|
|
60
|
-
nlohmann::json j;
|
|
61
|
-
j["msg"] = msg;
|
|
62
|
-
return j;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
struct OnResizeIn {
|
|
67
|
-
double width;
|
|
68
|
-
double height;
|
|
69
|
-
|
|
70
|
-
static OnResizeIn from_json(const nlohmann::json& j) {
|
|
71
|
-
OnResizeIn result;
|
|
72
|
-
if (j.contains("width")) { result.width = j["width"]; }
|
|
73
|
-
if (j.contains("height")) { result.height = j["height"]; }
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
nlohmann::json to_json() const {
|
|
78
|
-
nlohmann::json j;
|
|
79
|
-
j["width"] = width;
|
|
80
|
-
j["height"] = height;
|
|
81
|
-
return j;
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
struct OnResizeData {
|
|
86
|
-
double width;
|
|
87
|
-
double height;
|
|
88
|
-
|
|
89
|
-
static OnResizeData from_json(const nlohmann::json& j) {
|
|
90
|
-
OnResizeData result;
|
|
91
|
-
if (j.contains("width")) { result.width = j["width"]; }
|
|
92
|
-
if (j.contains("height")) { result.height = j["height"]; }
|
|
93
|
-
return result;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
nlohmann::json to_json() const {
|
|
97
|
-
nlohmann::json j;
|
|
98
|
-
j["width"] = width;
|
|
99
|
-
j["height"] = height;
|
|
100
|
-
return j;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
struct OnFileDropIn {
|
|
105
|
-
nlohmann::json files;
|
|
106
|
-
|
|
107
|
-
static OnFileDropIn from_json(const nlohmann::json& j) {
|
|
108
|
-
OnFileDropIn result;
|
|
109
|
-
if (j.contains("files")) { result.files = j["files"]; }
|
|
110
|
-
return result;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
nlohmann::json to_json() const {
|
|
114
|
-
nlohmann::json j;
|
|
115
|
-
j["files"] = files;
|
|
116
|
-
return j;
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
struct OnFileDropData {
|
|
121
|
-
nlohmann::json files;
|
|
122
|
-
|
|
123
|
-
static OnFileDropData from_json(const nlohmann::json& j) {
|
|
124
|
-
OnFileDropData result;
|
|
125
|
-
if (j.contains("files")) { result.files = j["files"]; }
|
|
126
|
-
return result;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
nlohmann::json to_json() const {
|
|
130
|
-
nlohmann::json j;
|
|
131
|
-
j["files"] = files;
|
|
132
|
-
return j;
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
struct CpuUsageIn {
|
|
137
|
-
double percent;
|
|
138
|
-
|
|
139
|
-
static CpuUsageIn from_json(const nlohmann::json& j) {
|
|
140
|
-
CpuUsageIn result;
|
|
141
|
-
if (j.contains("percent")) { result.percent = j["percent"]; }
|
|
142
|
-
return result;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
nlohmann::json to_json() const {
|
|
146
|
-
nlohmann::json j;
|
|
147
|
-
j["percent"] = percent;
|
|
148
|
-
return j;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
struct CpuUsageData {
|
|
153
|
-
double percent;
|
|
154
|
-
|
|
155
|
-
static CpuUsageData from_json(const nlohmann::json& j) {
|
|
156
|
-
CpuUsageData result;
|
|
157
|
-
if (j.contains("percent")) { result.percent = j["percent"]; }
|
|
158
|
-
return result;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
nlohmann::json to_json() const {
|
|
162
|
-
nlohmann::json j;
|
|
163
|
-
j["percent"] = percent;
|
|
164
|
-
return j;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
struct LogBusIn {
|
|
169
|
-
std::string level;
|
|
170
|
-
std::string line;
|
|
171
|
-
|
|
172
|
-
static LogBusIn from_json(const nlohmann::json& j) {
|
|
173
|
-
LogBusIn result;
|
|
174
|
-
if (j.contains("level")) { result.level = j["level"]; }
|
|
175
|
-
if (j.contains("line")) { result.line = j["line"]; }
|
|
176
|
-
return result;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
nlohmann::json to_json() const {
|
|
180
|
-
nlohmann::json j;
|
|
181
|
-
j["level"] = level;
|
|
182
|
-
j["line"] = line;
|
|
183
|
-
return j;
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
struct LogBusData {
|
|
188
|
-
std::string level;
|
|
189
|
-
std::string line;
|
|
190
|
-
|
|
191
|
-
static LogBusData from_json(const nlohmann::json& j) {
|
|
192
|
-
LogBusData result;
|
|
193
|
-
if (j.contains("level")) { result.level = j["level"]; }
|
|
194
|
-
if (j.contains("line")) { result.line = j["line"]; }
|
|
195
|
-
return result;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
nlohmann::json to_json() const {
|
|
199
|
-
nlohmann::json j;
|
|
200
|
-
j["level"] = level;
|
|
201
|
-
j["line"] = line;
|
|
202
|
-
return j;
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// ============================================
|
|
207
|
-
// Generated Bindings Base Class
|
|
208
|
-
// ============================================
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Auto-generated connection bindings
|
|
212
|
-
* Inherit from this class and implement the handler methods
|
|
213
|
-
*/
|
|
214
|
-
class Bindings : public Connection {
|
|
215
|
-
public:
|
|
216
|
-
|
|
217
|
-
// ========================================
|
|
218
|
-
// Handler Methods (implement these)
|
|
219
|
-
// ========================================
|
|
220
|
-
|
|
221
|
-
/** [CALL] greet - Request/response handler */
|
|
222
|
-
virtual GreetOut handle_greet(const GreetIn& args) = 0;
|
|
223
|
-
|
|
224
|
-
/** [FIRE] log - One-way handler */
|
|
225
|
-
virtual void handle_log(const LogIn& args) = 0;
|
|
226
|
-
|
|
227
|
-
/** [FIRE] minimize - One-way handler */
|
|
228
|
-
virtual void handle_minimize() = 0;
|
|
229
|
-
|
|
230
|
-
/** [CHANNEL] logBus - Publish handler */
|
|
231
|
-
virtual void handle_logBus_publish(const LogBusData& data) = 0;
|
|
232
|
-
|
|
233
|
-
// ========================================
|
|
234
|
-
// Emit Methods (call these to send to frontend)
|
|
235
|
-
// ========================================
|
|
236
|
-
|
|
237
|
-
/** [EVENT] onResize - Emit to frontend */
|
|
238
|
-
void emit_onResize(const OnResizeData& data) {
|
|
239
|
-
auto payload = data.to_json();
|
|
240
|
-
event("onResize", payload);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/** [EVENT] onFileDrop - Emit to frontend */
|
|
244
|
-
void emit_onFileDrop(const OnFileDropData& data) {
|
|
245
|
-
auto payload = data.to_json();
|
|
246
|
-
event("onFileDrop", payload);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/** [STREAM] cpuUsage - Emit to frontend */
|
|
250
|
-
void emit_cpuUsage(const CpuUsageData& data) {
|
|
251
|
-
auto payload = data.to_json();
|
|
252
|
-
stream("cpuUsage", payload);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/** [CHANNEL] logBus - Emit to frontend */
|
|
256
|
-
void emit_logBus(const LogBusData& data) {
|
|
257
|
-
auto payload = data.to_json();
|
|
258
|
-
publish("logBus", payload);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
protected:
|
|
262
|
-
// ========================================
|
|
263
|
-
// Message Dispatcher (auto-generated)
|
|
264
|
-
// ========================================
|
|
265
|
-
|
|
266
|
-
void handleMessage(const std::string &name, const nlohmann::json &payload) override {
|
|
267
|
-
try {
|
|
268
|
-
// TODO: Update bindgen to generate simplified handlers
|
|
269
|
-
// For now, all messages are treated as events
|
|
270
|
-
|
|
271
|
-
if (name == "greet") {
|
|
272
|
-
auto args = GreetIn::from_json(payload);
|
|
273
|
-
auto res = handle_greet(args);
|
|
274
|
-
emit("greetResult", res.to_json());
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (name == "log") {
|
|
279
|
-
auto args = LogIn::from_json(payload);
|
|
280
|
-
handle_log(args);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (name == "minimize") {
|
|
285
|
-
handle_minimize();
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
if (name == "logBus") {
|
|
290
|
-
auto data = LogBusData::from_json(payload);
|
|
291
|
-
handle_logBus_publish(data);
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
} catch (const std::exception& e) {
|
|
295
|
-
// Error handling simplified - just log or ignore
|
|
296
|
-
// sendError(env.id, env.name, std::string("Handler error: ") + e.what());
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
} // namespace connect
|
|
302
|
-
} // namespace plusui
|