Luisnguyen1 commited on
Commit
fb2d702
·
1 Parent(s): 8f39e88
Files changed (11) hide show
  1. .env +710 -1
  2. .env.example +0 -15
  3. Meeting.sol +159 -134
  4. go.mod +30 -7
  5. go.sum +223 -19
  6. listenSM.html +760 -0
  7. main.go +90 -0
  8. public/index.html +2 -1
  9. public/join.html +2 -1
  10. public/js/room.js +2 -1
  11. temp/test.go +0 -1135
.env CHANGED
@@ -6,4 +6,713 @@ CLOUDFLARE_APP_ID='977c39eac9a8fc03a471d7da6a7d66e0'
6
  CLOUDFLARE_APP_SECRET='f069115dbeb5847040e7dbb7f9c79772fa923534fe1f74e3a62d54561aa12118'
7
 
8
  CLOUDFLARE_TURN_ID='4f88cf5ab3d61f069a9c7fe38502ddef'
9
- CLOUDFLARE_TURN_TOKEN='5a8acf5e87457eea45222ec73195fb560704cbfe949928946694f05b7c76f5f3'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  CLOUDFLARE_APP_SECRET='f069115dbeb5847040e7dbb7f9c79772fa923534fe1f74e3a62d54561aa12118'
7
 
8
  CLOUDFLARE_TURN_ID='4f88cf5ab3d61f069a9c7fe38502ddef'
9
+ CLOUDFLARE_TURN_TOKEN='5a8acf5e87457eea45222ec73195fb560704cbfe949928946694f05b7c76f5f3'
10
+
11
+
12
+ CONTRACT_ADDRESS = '0x887C677BFC3d9802a8fa0F324B7315B864222894'
13
+ PRIVATE_KEY = '77a38de82eccbcb54cd10c5470ec204b74337322da47bea3cf5ecaff8ff136f7'
14
+ ABI_JSON = '[
15
+ {
16
+ "inputs": [
17
+ {
18
+ "internalType": "string",
19
+ "name": "urls",
20
+ "type": "string"
21
+ },
22
+ {
23
+ "internalType": "string",
24
+ "name": "username",
25
+ "type": "string"
26
+ },
27
+ {
28
+ "internalType": "string",
29
+ "name": "credential",
30
+ "type": "string"
31
+ }
32
+ ],
33
+ "name": "addIceServer",
34
+ "outputs": [],
35
+ "stateMutability": "nonpayable",
36
+ "type": "function"
37
+ },
38
+ {
39
+ "inputs": [
40
+ {
41
+ "internalType": "string",
42
+ "name": "roomId",
43
+ "type": "string"
44
+ },
45
+ {
46
+ "internalType": "string",
47
+ "name": "name",
48
+ "type": "string"
49
+ },
50
+ {
51
+ "internalType": "string",
52
+ "name": "metadata",
53
+ "type": "string"
54
+ }
55
+ ],
56
+ "name": "createRoom",
57
+ "outputs": [],
58
+ "stateMutability": "nonpayable",
59
+ "type": "function"
60
+ },
61
+ {
62
+ "inputs": [],
63
+ "stateMutability": "nonpayable",
64
+ "type": "constructor"
65
+ },
66
+ {
67
+ "anonymous": false,
68
+ "inputs": [
69
+ {
70
+ "indexed": false,
71
+ "internalType": "string",
72
+ "name": "roomId",
73
+ "type": "string"
74
+ },
75
+ {
76
+ "indexed": false,
77
+ "internalType": "address",
78
+ "name": "sessionId",
79
+ "type": "address"
80
+ },
81
+ {
82
+ "indexed": false,
83
+ "internalType": "string[]",
84
+ "name": "dataChannels",
85
+ "type": "string[]"
86
+ }
87
+ ],
88
+ "name": "DataChannelsUpdated",
89
+ "type": "event"
90
+ },
91
+ {
92
+ "anonymous": false,
93
+ "inputs": [
94
+ {
95
+ "indexed": false,
96
+ "internalType": "string",
97
+ "name": "roomId",
98
+ "type": "string"
99
+ },
100
+ {
101
+ "indexed": false,
102
+ "internalType": "address",
103
+ "name": "user",
104
+ "type": "address"
105
+ }
106
+ ],
107
+ "name": "JoinedRoom",
108
+ "type": "event"
109
+ },
110
+ {
111
+ "inputs": [
112
+ {
113
+ "internalType": "string",
114
+ "name": "roomId",
115
+ "type": "string"
116
+ }
117
+ ],
118
+ "name": "joinRoom",
119
+ "outputs": [],
120
+ "stateMutability": "nonpayable",
121
+ "type": "function"
122
+ },
123
+ {
124
+ "inputs": [
125
+ {
126
+ "internalType": "string",
127
+ "name": "roomId",
128
+ "type": "string"
129
+ }
130
+ ],
131
+ "name": "leaveRoom",
132
+ "outputs": [],
133
+ "stateMutability": "nonpayable",
134
+ "type": "function"
135
+ },
136
+ {
137
+ "anonymous": false,
138
+ "inputs": [
139
+ {
140
+ "indexed": false,
141
+ "internalType": "string",
142
+ "name": "roomId",
143
+ "type": "string"
144
+ },
145
+ {
146
+ "indexed": false,
147
+ "internalType": "address",
148
+ "name": "user",
149
+ "type": "address"
150
+ }
151
+ ],
152
+ "name": "LeftRoom",
153
+ "type": "event"
154
+ },
155
+ {
156
+ "anonymous": false,
157
+ "inputs": [
158
+ {
159
+ "indexed": false,
160
+ "internalType": "string",
161
+ "name": "roomId",
162
+ "type": "string"
163
+ },
164
+ {
165
+ "indexed": false,
166
+ "internalType": "string",
167
+ "name": "key",
168
+ "type": "string"
169
+ },
170
+ {
171
+ "indexed": false,
172
+ "internalType": "string",
173
+ "name": "value",
174
+ "type": "string"
175
+ }
176
+ ],
177
+ "name": "MetadataUpdated",
178
+ "type": "event"
179
+ },
180
+ {
181
+ "anonymous": false,
182
+ "inputs": [
183
+ {
184
+ "indexed": false,
185
+ "internalType": "string",
186
+ "name": "roomId",
187
+ "type": "string"
188
+ },
189
+ {
190
+ "indexed": false,
191
+ "internalType": "string",
192
+ "name": "name",
193
+ "type": "string"
194
+ },
195
+ {
196
+ "indexed": false,
197
+ "internalType": "address",
198
+ "name": "owner",
199
+ "type": "address"
200
+ }
201
+ ],
202
+ "name": "RoomCreated",
203
+ "type": "event"
204
+ },
205
+ {
206
+ "anonymous": false,
207
+ "inputs": [
208
+ {
209
+ "indexed": false,
210
+ "internalType": "string",
211
+ "name": "roomId",
212
+ "type": "string"
213
+ },
214
+ {
215
+ "indexed": false,
216
+ "internalType": "bool",
217
+ "name": "isActive",
218
+ "type": "bool"
219
+ }
220
+ ],
221
+ "name": "RoomStatusChanged",
222
+ "type": "event"
223
+ },
224
+ {
225
+ "inputs": [
226
+ {
227
+ "internalType": "string",
228
+ "name": "roomId",
229
+ "type": "string"
230
+ },
231
+ {
232
+ "internalType": "string",
233
+ "name": "sessionID",
234
+ "type": "string"
235
+ }
236
+ ],
237
+ "name": "saveSessionID",
238
+ "outputs": [],
239
+ "stateMutability": "nonpayable",
240
+ "type": "function"
241
+ },
242
+ {
243
+ "anonymous": false,
244
+ "inputs": [
245
+ {
246
+ "indexed": false,
247
+ "internalType": "string",
248
+ "name": "roomId",
249
+ "type": "string"
250
+ },
251
+ {
252
+ "indexed": true,
253
+ "internalType": "address",
254
+ "name": "user",
255
+ "type": "address"
256
+ },
257
+ {
258
+ "indexed": false,
259
+ "internalType": "string",
260
+ "name": "sessionID",
261
+ "type": "string"
262
+ }
263
+ ],
264
+ "name": "SessionIDUpdated",
265
+ "type": "event"
266
+ },
267
+ {
268
+ "anonymous": false,
269
+ "inputs": [
270
+ {
271
+ "indexed": false,
272
+ "internalType": "string",
273
+ "name": "roomId",
274
+ "type": "string"
275
+ },
276
+ {
277
+ "indexed": false,
278
+ "internalType": "address",
279
+ "name": "sessionId",
280
+ "type": "address"
281
+ },
282
+ {
283
+ "indexed": false,
284
+ "internalType": "string",
285
+ "name": "sdp",
286
+ "type": "string"
287
+ },
288
+ {
289
+ "indexed": false,
290
+ "internalType": "string",
291
+ "name": "sdpType",
292
+ "type": "string"
293
+ }
294
+ ],
295
+ "name": "SessionRenegotiated",
296
+ "type": "event"
297
+ },
298
+ {
299
+ "inputs": [
300
+ {
301
+ "internalType": "string",
302
+ "name": "roomId",
303
+ "type": "string"
304
+ },
305
+ {
306
+ "internalType": "bool",
307
+ "name": "isActive",
308
+ "type": "bool"
309
+ }
310
+ ],
311
+ "name": "setRoomStatus",
312
+ "outputs": [],
313
+ "stateMutability": "nonpayable",
314
+ "type": "function"
315
+ },
316
+ {
317
+ "inputs": [
318
+ {
319
+ "internalType": "address",
320
+ "name": "userAddress",
321
+ "type": "address"
322
+ },
323
+ {
324
+ "internalType": "bool",
325
+ "name": "isModerator",
326
+ "type": "bool"
327
+ },
328
+ {
329
+ "internalType": "string",
330
+ "name": "role",
331
+ "type": "string"
332
+ }
333
+ ],
334
+ "name": "setUserInfo",
335
+ "outputs": [],
336
+ "stateMutability": "nonpayable",
337
+ "type": "function"
338
+ },
339
+ {
340
+ "anonymous": false,
341
+ "inputs": [
342
+ {
343
+ "indexed": false,
344
+ "internalType": "string",
345
+ "name": "roomId",
346
+ "type": "string"
347
+ },
348
+ {
349
+ "indexed": false,
350
+ "internalType": "address",
351
+ "name": "participant",
352
+ "type": "address"
353
+ },
354
+ {
355
+ "indexed": false,
356
+ "internalType": "string",
357
+ "name": "trackName",
358
+ "type": "string"
359
+ }
360
+ ],
361
+ "name": "TrackPublished",
362
+ "type": "event"
363
+ },
364
+ {
365
+ "anonymous": false,
366
+ "inputs": [
367
+ {
368
+ "indexed": false,
369
+ "internalType": "string",
370
+ "name": "roomId",
371
+ "type": "string"
372
+ },
373
+ {
374
+ "indexed": false,
375
+ "internalType": "address",
376
+ "name": "sessionId",
377
+ "type": "address"
378
+ },
379
+ {
380
+ "indexed": false,
381
+ "internalType": "address",
382
+ "name": "remoteSession",
383
+ "type": "address"
384
+ },
385
+ {
386
+ "indexed": false,
387
+ "internalType": "string",
388
+ "name": "trackName",
389
+ "type": "string"
390
+ }
391
+ ],
392
+ "name": "TrackPulled",
393
+ "type": "event"
394
+ },
395
+ {
396
+ "anonymous": false,
397
+ "inputs": [
398
+ {
399
+ "indexed": false,
400
+ "internalType": "string",
401
+ "name": "roomId",
402
+ "type": "string"
403
+ },
404
+ {
405
+ "indexed": false,
406
+ "internalType": "address",
407
+ "name": "participant",
408
+ "type": "address"
409
+ },
410
+ {
411
+ "indexed": false,
412
+ "internalType": "string",
413
+ "name": "trackName",
414
+ "type": "string"
415
+ }
416
+ ],
417
+ "name": "TrackUnpublished",
418
+ "type": "event"
419
+ },
420
+ {
421
+ "inputs": [
422
+ {
423
+ "internalType": "string",
424
+ "name": "roomId",
425
+ "type": "string"
426
+ },
427
+ {
428
+ "internalType": "string",
429
+ "name": "key",
430
+ "type": "string"
431
+ },
432
+ {
433
+ "internalType": "string",
434
+ "name": "value",
435
+ "type": "string"
436
+ }
437
+ ],
438
+ "name": "updateRoomMetadata",
439
+ "outputs": [],
440
+ "stateMutability": "nonpayable",
441
+ "type": "function"
442
+ },
443
+ {
444
+ "anonymous": false,
445
+ "inputs": [
446
+ {
447
+ "indexed": true,
448
+ "internalType": "address",
449
+ "name": "userAddress",
450
+ "type": "address"
451
+ },
452
+ {
453
+ "indexed": false,
454
+ "internalType": "bool",
455
+ "name": "isModerator",
456
+ "type": "bool"
457
+ },
458
+ {
459
+ "indexed": false,
460
+ "internalType": "string",
461
+ "name": "role",
462
+ "type": "string"
463
+ }
464
+ ],
465
+ "name": "UserUpdated",
466
+ "type": "event"
467
+ },
468
+ {
469
+ "inputs": [
470
+ {
471
+ "internalType": "string",
472
+ "name": "roomId",
473
+ "type": "string"
474
+ },
475
+ {
476
+ "internalType": "address",
477
+ "name": "user",
478
+ "type": "address"
479
+ }
480
+ ],
481
+ "name": "checkUserInRoom",
482
+ "outputs": [
483
+ {
484
+ "internalType": "bool",
485
+ "name": "",
486
+ "type": "bool"
487
+ }
488
+ ],
489
+ "stateMutability": "view",
490
+ "type": "function"
491
+ },
492
+ {
493
+ "inputs": [],
494
+ "name": "getAllRooms",
495
+ "outputs": [
496
+ {
497
+ "internalType": "string[]",
498
+ "name": "",
499
+ "type": "string[]"
500
+ }
501
+ ],
502
+ "stateMutability": "view",
503
+ "type": "function"
504
+ },
505
+ {
506
+ "inputs": [],
507
+ "name": "getIceServers",
508
+ "outputs": [
509
+ {
510
+ "components": [
511
+ {
512
+ "internalType": "string",
513
+ "name": "urls",
514
+ "type": "string"
515
+ },
516
+ {
517
+ "internalType": "string",
518
+ "name": "username",
519
+ "type": "string"
520
+ },
521
+ {
522
+ "internalType": "string",
523
+ "name": "credential",
524
+ "type": "string"
525
+ }
526
+ ],
527
+ "internalType": "struct Meeting.ICEServer[]",
528
+ "name": "",
529
+ "type": "tuple[]"
530
+ }
531
+ ],
532
+ "stateMutability": "view",
533
+ "type": "function"
534
+ },
535
+ {
536
+ "inputs": [
537
+ {
538
+ "internalType": "string",
539
+ "name": "roomId",
540
+ "type": "string"
541
+ }
542
+ ],
543
+ "name": "getRoomDetails",
544
+ "outputs": [
545
+ {
546
+ "internalType": "string",
547
+ "name": "id",
548
+ "type": "string"
549
+ },
550
+ {
551
+ "internalType": "string",
552
+ "name": "name",
553
+ "type": "string"
554
+ },
555
+ {
556
+ "internalType": "string",
557
+ "name": "metadata",
558
+ "type": "string"
559
+ },
560
+ {
561
+ "internalType": "address",
562
+ "name": "roomOwner",
563
+ "type": "address"
564
+ },
565
+ {
566
+ "internalType": "uint256",
567
+ "name": "createdAt",
568
+ "type": "uint256"
569
+ },
570
+ {
571
+ "internalType": "bool",
572
+ "name": "isActive",
573
+ "type": "bool"
574
+ }
575
+ ],
576
+ "stateMutability": "view",
577
+ "type": "function"
578
+ },
579
+ {
580
+ "inputs": [
581
+ {
582
+ "internalType": "string",
583
+ "name": "roomId",
584
+ "type": "string"
585
+ },
586
+ {
587
+ "internalType": "string",
588
+ "name": "key",
589
+ "type": "string"
590
+ }
591
+ ],
592
+ "name": "getRoomMetadata",
593
+ "outputs": [
594
+ {
595
+ "internalType": "string",
596
+ "name": "",
597
+ "type": "string"
598
+ }
599
+ ],
600
+ "stateMutability": "view",
601
+ "type": "function"
602
+ },
603
+ {
604
+ "inputs": [
605
+ {
606
+ "internalType": "string",
607
+ "name": "roomId",
608
+ "type": "string"
609
+ }
610
+ ],
611
+ "name": "getRoomParticipants",
612
+ "outputs": [
613
+ {
614
+ "internalType": "address[]",
615
+ "name": "",
616
+ "type": "address[]"
617
+ }
618
+ ],
619
+ "stateMutability": "view",
620
+ "type": "function"
621
+ },
622
+ {
623
+ "inputs": [
624
+ {
625
+ "internalType": "string",
626
+ "name": "roomId",
627
+ "type": "string"
628
+ },
629
+ {
630
+ "internalType": "address",
631
+ "name": "user",
632
+ "type": "address"
633
+ }
634
+ ],
635
+ "name": "getSessionID",
636
+ "outputs": [
637
+ {
638
+ "internalType": "string",
639
+ "name": "",
640
+ "type": "string"
641
+ }
642
+ ],
643
+ "stateMutability": "view",
644
+ "type": "function"
645
+ },
646
+ {
647
+ "inputs": [
648
+ {
649
+ "internalType": "string",
650
+ "name": "roomId",
651
+ "type": "string"
652
+ },
653
+ {
654
+ "internalType": "address",
655
+ "name": "participantAddr",
656
+ "type": "address"
657
+ }
658
+ ],
659
+ "name": "getSessionTracks",
660
+ "outputs": [
661
+ {
662
+ "internalType": "string[]",
663
+ "name": "",
664
+ "type": "string[]"
665
+ }
666
+ ],
667
+ "stateMutability": "view",
668
+ "type": "function"
669
+ },
670
+ {
671
+ "inputs": [
672
+ {
673
+ "internalType": "address",
674
+ "name": "userAddress",
675
+ "type": "address"
676
+ }
677
+ ],
678
+ "name": "getUserInfo",
679
+ "outputs": [
680
+ {
681
+ "internalType": "address",
682
+ "name": "userId",
683
+ "type": "address"
684
+ },
685
+ {
686
+ "internalType": "bool",
687
+ "name": "isModerator",
688
+ "type": "bool"
689
+ },
690
+ {
691
+ "internalType": "string",
692
+ "name": "role",
693
+ "type": "string"
694
+ }
695
+ ],
696
+ "stateMutability": "view",
697
+ "type": "function"
698
+ },
699
+ {
700
+ "inputs": [
701
+ {
702
+ "internalType": "string",
703
+ "name": "roomId",
704
+ "type": "string"
705
+ }
706
+ ],
707
+ "name": "roomExists",
708
+ "outputs": [
709
+ {
710
+ "internalType": "bool",
711
+ "name": "",
712
+ "type": "bool"
713
+ }
714
+ ],
715
+ "stateMutability": "view",
716
+ "type": "function"
717
+ }
718
+ ]'
.env.example DELETED
@@ -1,15 +0,0 @@
1
- # Cloudflare Calls Configuration
2
- CLOUDFLARE_APP_ID=your_app_id
3
- CLOUDFLARE_APP_SECRET=your_app_secret
4
- CLOUDFLARE_TURN_ID=your_turn_id
5
- CLOUDFLARE_TURN_TOKEN=your_turn_token
6
- CLOUDFLARE_APPS_URL=https://rtc.live.cloudflare.com/v1/apps
7
-
8
- # Server Configuration
9
- PORT=50000
10
- GIN_MODE=debug
11
- JWT_SECRET=your_jwt_secret
12
-
13
- # Feature Flags
14
- AUTH_REQUIRED=false
15
- DEBUG=true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Meeting.sol CHANGED
@@ -26,72 +26,68 @@ contract Meeting {
26
  uint256 joinedAt;
27
  mapping(string => Track) tracks;
28
  string[] trackNames;
29
- string sessionID; // Đổi từ string sang bytes32 để tiết kiệm gas
30
  }
31
 
32
  struct Room {
 
33
  string name;
 
34
  address owner;
35
  uint256 createdAt;
36
  mapping(address => Participant) participants;
37
  address[] participantList;
 
 
 
 
 
 
38
  }
39
 
40
  mapping(string => Room) private rooms;
 
41
  string[] private roomIds;
 
 
42
 
 
43
  event RoomCreated(string roomId, string name, address owner);
44
  event JoinedRoom(string roomId, address user);
 
45
  event TrackPublished(string roomId, address participant, string trackName);
46
- event TrackUnpublished(
47
- string roomId,
48
- address participant,
49
- string trackName
50
- );
51
- event TrackPulled(
52
- string roomId,
53
- address sessionId,
54
- address remoteSession,
55
- string trackName
56
- );
57
- event SessionRenegotiated(
58
- string roomId,
59
- address sessionId,
60
- string sdp,
61
- string sdpType
62
- );
63
- event DataChannelsUpdated(
64
- string roomId,
65
- address sessionId,
66
- string[] dataChannels
67
- );
68
- event SessionIDUpdated(
69
- string roomId,
70
- address indexed user,
71
- string sessionID
72
- );
73
-
74
- mapping(address => User) private users;
75
- address private owner;
76
-
77
 
78
  constructor() {
79
- //contructor khởi tạo list ice server
80
  iceServers.push(ICEServer("stun:stun.cloudflare.com:3478", "", ""));
81
  owner = msg.sender;
82
  }
83
 
84
- event UserUpdated(
85
- address indexed userAddress,
86
- bool isModerator,
87
- string role
88
- );
89
-
90
  modifier onlyOwner() {
91
- require(msg.sender == owner, "Only owner can update user info");
92
  _;
93
  }
94
 
 
 
 
 
 
 
 
 
 
 
 
95
  function setUserInfo(
96
  address userAddress,
97
  bool isModerator,
@@ -106,19 +102,9 @@ contract Meeting {
106
  emit UserUpdated(userAddress, isModerator, role);
107
  }
108
 
109
- function getIceServers() public view returns (ICEServer[] memory) {
110
- return iceServers;
111
- }
112
-
113
- function getUserInfo(address userAddress)
114
- public
115
- view
116
- returns (
117
- address userId,
118
- bool isModerator,
119
- string memory role
120
- )
121
- {
122
  require(users[userAddress].userAddress != address(0), "User not found");
123
 
124
  return (
@@ -128,93 +114,89 @@ contract Meeting {
128
  );
129
  }
130
 
131
-
 
 
 
 
 
 
 
 
 
 
 
132
 
133
- function createRoom(string memory roomId, string memory name) public {
 
134
  require(bytes(rooms[roomId].name).length == 0, "Room already exists");
135
 
 
136
  rooms[roomId].name = name;
 
137
  rooms[roomId].owner = msg.sender;
138
  rooms[roomId].createdAt = block.timestamp;
 
139
 
140
  roomIds.push(roomId);
141
  emit RoomCreated(roomId, name, msg.sender);
142
  }
143
 
144
-
145
- function publishTrack(string memory roomId, string memory trackName)
146
- public
147
- {
148
- require(
149
- rooms[roomId].participants[msg.sender].user != address(0),
150
- "Not in room"
151
- );
152
-
153
- Participant storage participant = rooms[roomId].participants[
154
- msg.sender
155
- ];
156
- require(
157
- participant.tracks[trackName].owner == address(0),
158
- "Track already exists"
159
- );
160
-
161
- participant.tracks[trackName] = Track(trackName, msg.sender);
162
- participant.trackNames.push(trackName);
163
-
164
- emit TrackPublished(roomId, msg.sender, trackName);
165
  }
166
 
167
- function unpublishTrack(string memory roomId, string memory trackName)
168
- public
169
- {
170
- require(
171
- rooms[roomId].participants[msg.sender].user != address(0),
172
- "Not in room"
173
- );
174
-
175
- Participant storage participant = rooms[roomId].participants[
176
- msg.sender
177
- ];
178
- require(
179
- participant.tracks[trackName].owner == address(0),
180
- "Track already exists"
181
- );
182
-
183
- require(
184
- participant.tracks[trackName].owner == msg.sender,
185
- "Not track owner"
186
- );
187
-
188
- delete participant.tracks[trackName];
189
- emit TrackUnpublished(roomId, msg.sender, trackName);
190
  }
191
 
192
- function getRoomParticipants(string memory roomId)
193
- public
194
- view
195
- returns (address[] memory)
196
- {
197
- return rooms[roomId].participantList;
198
  }
199
 
200
- function getSessionTracks(string memory roomId, address participant)
201
- public
202
- view
203
- returns (string[] memory)
204
- {
205
- require(
206
- rooms[roomId].participants[participant].user != address(0),
207
- "Participant not found"
 
 
 
 
 
 
 
 
 
208
  );
209
- return rooms[roomId].participants[participant].trackNames;
210
  }
211
 
212
  function getAllRooms() public view returns (string[] memory) {
213
  return roomIds;
214
  }
215
- function joinRoom(string memory roomId) public {
216
- require(bytes(rooms[roomId].name).length > 0, "Room not found");
 
 
 
 
 
217
  require(rooms[roomId].participants[msg.sender].user == address(0), "Already joined");
 
218
 
219
  Participant storage participant = rooms[roomId].participants[msg.sender];
220
  participant.user = msg.sender;
@@ -225,27 +207,70 @@ contract Meeting {
225
  emit JoinedRoom(roomId, msg.sender);
226
  }
227
 
228
- function saveSessionID(string memory roomId, string memory sessionID) public {
229
- require(bytes(rooms[roomId].name).length > 0, "Room not found");
230
- require(rooms[roomId].participants[msg.sender].user != address(0), "User not in room");
231
-
232
- if (keccak256(bytes(rooms[roomId].participants[msg.sender].sessionID)) != keccak256(bytes(sessionID))) {
233
- rooms[roomId].participants[msg.sender].sessionID = sessionID;
234
- emit SessionIDUpdated(roomId, msg.sender, sessionID);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  }
236
- }
237
 
238
- function getSessionID(string memory roomId, address user) public view returns (string memory) {
239
- require(bytes(rooms[roomId].name).length > 0, "Room not found");
240
- require(rooms[roomId].participants[user].user != address(0), "User not in room");
 
 
241
 
242
- return rooms[roomId].participants[user].sessionID;
243
- }
244
- function checkUserInRoom(string memory roomId, address user)
245
- public
246
- view
247
- returns (bool)
248
- {
249
  return rooms[roomId].participants[user].user != address(0);
250
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  }
 
26
  uint256 joinedAt;
27
  mapping(string => Track) tracks;
28
  string[] trackNames;
29
+ string sessionID;
30
  }
31
 
32
  struct Room {
33
+ string roomId; // Added field
34
  string name;
35
+ string metadata; // Added field
36
  address owner;
37
  uint256 createdAt;
38
  mapping(address => Participant) participants;
39
  address[] participantList;
40
+ bool isActive;
41
+ }
42
+
43
+ struct RoomMetadata {
44
+ string key;
45
+ string value;
46
  }
47
 
48
  mapping(string => Room) private rooms;
49
+ mapping(string => mapping(string => string)) private roomMetadata;
50
  string[] private roomIds;
51
+ mapping(address => User) private users;
52
+ address private owner;
53
 
54
+ // Events
55
  event RoomCreated(string roomId, string name, address owner);
56
  event JoinedRoom(string roomId, address user);
57
+ event LeftRoom(string roomId, address user);
58
  event TrackPublished(string roomId, address participant, string trackName);
59
+ event TrackUnpublished(string roomId, address participant, string trackName);
60
+ event TrackPulled(string roomId, address sessionId, address remoteSession, string trackName);
61
+ event SessionRenegotiated(string roomId, address sessionId, string sdp, string sdpType);
62
+ event DataChannelsUpdated(string roomId, address sessionId, string[] dataChannels);
63
+ event SessionIDUpdated(string roomId, address indexed user, string sessionID);
64
+ event UserUpdated(address indexed userAddress, bool isModerator, string role);
65
+ event MetadataUpdated(string roomId, string key, string value);
66
+ event RoomStatusChanged(string roomId, bool isActive);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  constructor() {
69
+ // Khởi tạo ICE server mặc định
70
  iceServers.push(ICEServer("stun:stun.cloudflare.com:3478", "", ""));
71
  owner = msg.sender;
72
  }
73
 
74
+ // Modifiers
 
 
 
 
 
75
  modifier onlyOwner() {
76
+ require(msg.sender == owner, "Only owner can perform this action");
77
  _;
78
  }
79
 
80
+ modifier roomMustExist(string memory roomId) {
81
+ require(bytes(rooms[roomId].name).length > 0, "Room not found");
82
+ _;
83
+ }
84
+
85
+ modifier mustBeInRoom(string memory roomId) {
86
+ require(rooms[roomId].participants[msg.sender].user != address(0), "Not in room");
87
+ _;
88
+ }
89
+
90
+ // User management
91
  function setUserInfo(
92
  address userAddress,
93
  bool isModerator,
 
102
  emit UserUpdated(userAddress, isModerator, role);
103
  }
104
 
105
+ function getUserInfo(
106
+ address userAddress
107
+ ) public view returns (address userId, bool isModerator, string memory role) {
 
 
 
 
 
 
 
 
 
 
108
  require(users[userAddress].userAddress != address(0), "User not found");
109
 
110
  return (
 
114
  );
115
  }
116
 
117
+ // ICE servers
118
+ function getIceServers() public view returns (ICEServer[] memory) {
119
+ return iceServers;
120
+ }
121
+
122
+ function addIceServer(
123
+ string memory urls,
124
+ string memory username,
125
+ string memory credential
126
+ ) public onlyOwner {
127
+ iceServers.push(ICEServer(urls, username, credential));
128
+ }
129
 
130
+ // Room management
131
+ function createRoom(string memory roomId, string memory name, string memory metadata) public {
132
  require(bytes(rooms[roomId].name).length == 0, "Room already exists");
133
 
134
+ rooms[roomId].roomId = roomId;
135
  rooms[roomId].name = name;
136
+ rooms[roomId].metadata = metadata;
137
  rooms[roomId].owner = msg.sender;
138
  rooms[roomId].createdAt = block.timestamp;
139
+ rooms[roomId].isActive = true;
140
 
141
  roomIds.push(roomId);
142
  emit RoomCreated(roomId, name, msg.sender);
143
  }
144
 
145
+ function setRoomStatus(string memory roomId, bool isActive) public roomMustExist(roomId) {
146
+ require(rooms[roomId].owner == msg.sender || users[msg.sender].isModerator, "Not authorized");
147
+
148
+ rooms[roomId].isActive = isActive;
149
+ emit RoomStatusChanged(roomId, isActive);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  }
151
 
152
+ function updateRoomMetadata(
153
+ string memory roomId,
154
+ string memory key,
155
+ string memory value
156
+ ) public roomMustExist(roomId) mustBeInRoom(roomId) {
157
+ roomMetadata[roomId][key] = value;
158
+ emit MetadataUpdated(roomId, key, value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
 
161
+ function getRoomMetadata(
162
+ string memory roomId,
163
+ string memory key
164
+ ) public view roomMustExist(roomId) returns (string memory) {
165
+ return roomMetadata[roomId][key];
 
166
  }
167
 
168
+ function getRoomDetails(
169
+ string memory roomId
170
+ ) public view roomMustExist(roomId) returns (
171
+ string memory id,
172
+ string memory name,
173
+ string memory metadata,
174
+ address roomOwner,
175
+ uint256 createdAt,
176
+ bool isActive
177
+ ) {
178
+ return (
179
+ rooms[roomId].roomId,
180
+ rooms[roomId].name,
181
+ rooms[roomId].metadata,
182
+ rooms[roomId].owner,
183
+ rooms[roomId].createdAt,
184
+ rooms[roomId].isActive
185
  );
 
186
  }
187
 
188
  function getAllRooms() public view returns (string[] memory) {
189
  return roomIds;
190
  }
191
+
192
+ function roomExists(string memory roomId) public view returns (bool) {
193
+ return bytes(rooms[roomId].name).length > 0;
194
+ }
195
+
196
+ // Participant management
197
+ function joinRoom(string memory roomId) public roomMustExist(roomId) {
198
  require(rooms[roomId].participants[msg.sender].user == address(0), "Already joined");
199
+ require(rooms[roomId].isActive, "Room is not active");
200
 
201
  Participant storage participant = rooms[roomId].participants[msg.sender];
202
  participant.user = msg.sender;
 
207
  emit JoinedRoom(roomId, msg.sender);
208
  }
209
 
210
+ function leaveRoom(string memory roomId) public roomMustExist(roomId) mustBeInRoom(roomId) {
211
+ // Remove from participant list
212
+ address[] storage participants = rooms[roomId].participantList;
213
+ for (uint i = 0; i < participants.length; i++) {
214
+ if (participants[i] == msg.sender) {
215
+ participants[i] = participants[participants.length - 1];
216
+ participants.pop();
217
+ break;
218
+ }
219
+ }
220
+
221
+ // Clear tracks
222
+ string[] memory trackNames = rooms[roomId].participants[msg.sender].trackNames;
223
+ for (uint i = 0; i < trackNames.length; i++) {
224
+ delete rooms[roomId].participants[msg.sender].tracks[trackNames[i]];
225
+ }
226
+
227
+ // Clear participant data
228
+ delete rooms[roomId].participants[msg.sender];
229
+
230
+ emit LeftRoom(roomId, msg.sender);
231
  }
 
232
 
233
+ function getRoomParticipants(
234
+ string memory roomId
235
+ ) public view roomMustExist(roomId) returns (address[] memory) {
236
+ return rooms[roomId].participantList;
237
+ }
238
 
239
+ function checkUserInRoom(
240
+ string memory roomId,
241
+ address user
242
+ ) public view roomMustExist(roomId) returns (bool) {
 
 
 
243
  return rooms[roomId].participants[user].user != address(0);
244
  }
245
+
246
+ // Session management
247
+ function saveSessionID(
248
+ string memory roomId,
249
+ string memory sessionID
250
+ ) public roomMustExist(roomId) mustBeInRoom(roomId) {
251
+ if (
252
+ keccak256(bytes(rooms[roomId].participants[msg.sender].sessionID)) !=
253
+ keccak256(bytes(sessionID))
254
+ ) {
255
+ rooms[roomId].participants[msg.sender].sessionID = sessionID;
256
+ emit SessionIDUpdated(roomId, msg.sender, sessionID);
257
+ }
258
+ }
259
+
260
+ function getSessionID(
261
+ string memory roomId,
262
+ address user
263
+ ) public view roomMustExist(roomId) returns (string memory) {
264
+ require(rooms[roomId].participants[user].user != address(0), "User not in room");
265
+ return rooms[roomId].participants[user].sessionID;
266
+ }
267
+
268
+ function getSessionTracks(
269
+ string memory roomId,
270
+ address participantAddr
271
+ ) public view roomMustExist(roomId) returns (string[] memory) {
272
+ require(rooms[roomId].participants[participantAddr].user != address(0), "Participant not found");
273
+ return rooms[roomId].participants[participantAddr].trackNames;
274
+ }
275
+
276
  }
go.mod CHANGED
@@ -1,44 +1,67 @@
1
  module dappmeeting
2
 
3
- go 1.21.0
4
 
5
  toolchain go1.23.5
6
 
7
  require (
8
- github.com/gin-contrib/cors v1.7.3
9
  github.com/gin-gonic/gin v1.10.0
10
  github.com/golang-jwt/jwt/v5 v5.0.0
11
- github.com/google/uuid v1.3.0
12
  github.com/gorilla/websocket v1.5.0
13
  github.com/joho/godotenv v1.5.1
14
  )
15
 
16
  require (
 
 
 
17
  github.com/bytedance/sonic v1.12.6 // indirect
18
  github.com/bytedance/sonic/loader v0.2.1 // indirect
19
  github.com/cloudwego/base64x v0.1.4 // indirect
20
  github.com/cloudwego/iasm v0.2.0 // indirect
 
 
 
 
 
 
 
 
21
  github.com/gabriel-vasile/mimetype v1.4.7 // indirect
22
  github.com/gin-contrib/sse v0.1.0 // indirect
 
23
  github.com/go-playground/locales v0.14.1 // indirect
24
  github.com/go-playground/universal-translator v0.18.1 // indirect
25
  github.com/go-playground/validator/v10 v10.23.0 // indirect
26
  github.com/goccy/go-json v0.10.4 // indirect
 
27
  github.com/json-iterator/go v1.1.12 // indirect
28
  github.com/klauspost/cpuid/v2 v2.2.9 // indirect
29
- github.com/kr/text v0.2.0 // indirect
30
  github.com/leodido/go-urn v1.4.0 // indirect
31
  github.com/mattn/go-isatty v0.0.20 // indirect
 
32
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
33
  github.com/modern-go/reflect2 v1.0.2 // indirect
34
  github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 
 
 
 
 
 
 
35
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
36
  github.com/ugorji/go/codec v1.2.12 // indirect
37
  golang.org/x/arch v0.12.0 // indirect
38
- golang.org/x/crypto v0.31.0 // indirect
39
- golang.org/x/net v0.33.0 // indirect
40
- golang.org/x/sys v0.28.0 // indirect
 
 
41
  golang.org/x/text v0.21.0 // indirect
42
  google.golang.org/protobuf v1.36.1 // indirect
43
  gopkg.in/yaml.v3 v3.0.1 // indirect
 
44
  )
 
1
  module dappmeeting
2
 
3
+ go 1.22.0
4
 
5
  toolchain go1.23.5
6
 
7
  require (
8
+ github.com/ethereum/go-ethereum v1.15.2
9
  github.com/gin-gonic/gin v1.10.0
10
  github.com/golang-jwt/jwt/v5 v5.0.0
11
+ github.com/google/uuid v1.3.1
12
  github.com/gorilla/websocket v1.5.0
13
  github.com/joho/godotenv v1.5.1
14
  )
15
 
16
  require (
17
+ github.com/Microsoft/go-winio v0.6.2 // indirect
18
+ github.com/StackExchange/wmi v1.2.1 // indirect
19
+ github.com/bits-and-blooms/bitset v1.17.0 // indirect
20
  github.com/bytedance/sonic v1.12.6 // indirect
21
  github.com/bytedance/sonic/loader v0.2.1 // indirect
22
  github.com/cloudwego/base64x v0.1.4 // indirect
23
  github.com/cloudwego/iasm v0.2.0 // indirect
24
+ github.com/consensys/bavard v0.1.22 // indirect
25
+ github.com/consensys/gnark-crypto v0.14.0 // indirect
26
+ github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect
27
+ github.com/crate-crypto/go-kzg-4844 v1.1.0 // indirect
28
+ github.com/deckarep/golang-set/v2 v2.6.0 // indirect
29
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
30
+ github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
31
+ github.com/ethereum/go-verkle v0.2.2 // indirect
32
  github.com/gabriel-vasile/mimetype v1.4.7 // indirect
33
  github.com/gin-contrib/sse v0.1.0 // indirect
34
+ github.com/go-ole/go-ole v1.3.0 // indirect
35
  github.com/go-playground/locales v0.14.1 // indirect
36
  github.com/go-playground/universal-translator v0.18.1 // indirect
37
  github.com/go-playground/validator/v10 v10.23.0 // indirect
38
  github.com/goccy/go-json v0.10.4 // indirect
39
+ github.com/holiman/uint256 v1.3.2 // indirect
40
  github.com/json-iterator/go v1.1.12 // indirect
41
  github.com/klauspost/cpuid/v2 v2.2.9 // indirect
 
42
  github.com/leodido/go-urn v1.4.0 // indirect
43
  github.com/mattn/go-isatty v0.0.20 // indirect
44
+ github.com/mmcloughlin/addchain v0.4.0 // indirect
45
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
46
  github.com/modern-go/reflect2 v1.0.2 // indirect
47
  github.com/pelletier/go-toml/v2 v2.2.3 // indirect
48
+ github.com/pion/dtls/v2 v2.2.12 // indirect
49
+ github.com/pion/transport/v2 v2.2.10 // indirect
50
+ github.com/pion/transport/v3 v3.0.2 // indirect
51
+ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
52
+ github.com/supranational/blst v0.3.14 // indirect
53
+ github.com/tklauser/go-sysconf v0.3.12 // indirect
54
+ github.com/tklauser/numcpus v0.6.1 // indirect
55
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
56
  github.com/ugorji/go/codec v1.2.12 // indirect
57
  golang.org/x/arch v0.12.0 // indirect
58
+ golang.org/x/crypto v0.32.0 // indirect
59
+ golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
60
+ golang.org/x/net v0.34.0 // indirect
61
+ golang.org/x/sync v0.10.0 // indirect
62
+ golang.org/x/sys v0.29.0 // indirect
63
  golang.org/x/text v0.21.0 // indirect
64
  google.golang.org/protobuf v1.36.1 // indirect
65
  gopkg.in/yaml.v3 v3.0.1 // indirect
66
+ rsc.io/tmplfunc v0.0.3 // indirect
67
  )
go.sum CHANGED
@@ -1,24 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
  github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
2
  github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
3
  github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
4
  github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
5
  github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 
 
6
  github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
7
  github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
8
  github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
9
  github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
10
- github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
13
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 
 
 
 
 
 
 
 
 
 
 
 
14
  github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
15
  github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
16
- github.com/gin-contrib/cors v1.7.3 h1:hV+a5xp8hwJoTw7OY+a70FsL8JkVVFTXw9EcfrYUdns=
17
- github.com/gin-contrib/cors v1.7.3/go.mod h1:M3bcKZhxzsvI+rlRSkkxHyljJt1ESd93COUvemZ79j4=
18
  github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
19
  github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
20
  github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
21
  github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
 
 
 
22
  github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
23
  github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
24
  github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -29,75 +79,229 @@ github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL
29
  github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
30
  github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
31
  github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 
 
 
 
 
 
32
  github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
33
  github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
34
- github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
35
- github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 
 
 
 
36
  github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
37
- github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
38
- github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 
 
 
39
  github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
40
  github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 
 
 
 
 
 
 
 
 
 
 
 
41
  github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
42
  github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
43
  github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
44
  github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 
 
45
  github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
46
  github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
47
  github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
48
  github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
49
- github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
50
- github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
51
  github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
52
  github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 
 
 
 
53
  github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
54
  github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 
 
55
  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
56
  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 
 
 
 
 
 
 
 
 
 
 
57
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
58
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
59
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
60
  github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
61
  github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 
 
62
  github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
63
  github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
65
  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
66
- github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
67
- github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
69
  github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
70
  github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 
71
  github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
72
  github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
73
  github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
74
  github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
75
  github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 
76
  github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
77
  github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 
 
 
 
 
 
 
 
78
  github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
79
  github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
80
  github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
81
  github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 
 
 
 
 
 
82
  golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
83
  golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
84
- golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
85
- golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
86
- golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
87
- golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
89
- golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
90
- golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
92
  golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
93
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
94
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 
 
 
 
 
95
  google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
96
  google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
97
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
98
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
99
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 
 
 
 
100
  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
101
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
102
  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
103
  nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
 
 
 
1
+ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
2
+ github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
3
+ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
4
+ github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
5
+ github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
6
+ github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
7
+ github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
8
+ github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
9
+ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
10
+ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
11
+ github.com/bits-and-blooms/bitset v1.17.0 h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI=
12
+ github.com/bits-and-blooms/bitset v1.17.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
13
  github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
14
  github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
15
  github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
16
  github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
17
  github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
18
+ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
19
+ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
20
  github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
21
  github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
22
  github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
23
  github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
24
+ github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
25
+ github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
26
+ github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4=
27
+ github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M=
28
+ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
29
+ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
30
+ github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA=
31
+ github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU=
32
+ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
33
+ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
34
+ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
35
+ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
36
+ github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A=
37
+ github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
38
+ github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E=
39
+ github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0=
40
+ github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
41
+ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
42
+ github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
43
+ github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM=
44
+ github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4=
45
+ github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks=
46
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
47
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
48
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
49
+ github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
50
+ github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
51
+ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
52
+ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
53
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
54
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
55
+ github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
56
+ github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
57
+ github.com/ethereum/go-ethereum v1.15.2 h1:CcU13w1IXOo6FvS60JGCTVcAJ5Ik6RkWoVIvziiHdTU=
58
+ github.com/ethereum/go-ethereum v1.15.2/go.mod h1:wGQINJKEVUunCeoaA9C9qKMQ9GEOsEIunzzqTUO2F6Y=
59
+ github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
60
+ github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
61
  github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
62
  github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
63
+ github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
64
+ github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
65
  github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
66
  github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
67
  github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
68
  github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
69
+ github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
70
+ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
71
+ github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
72
  github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
73
  github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
74
  github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 
79
  github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
80
  github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
81
  github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
82
+ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
83
+ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
84
+ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
85
+ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
86
+ github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
87
+ github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
88
  github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
89
  github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
90
+ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
91
+ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
92
+ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
93
+ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
94
+ github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
95
+ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
96
  github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
97
+ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
98
+ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
99
+ github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
100
+ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
101
+ github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
102
  github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
103
  github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
104
+ github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
105
+ github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
106
+ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4=
107
+ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
108
+ github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
109
+ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
110
+ github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
111
+ github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
112
+ github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
113
+ github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
114
+ github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
115
+ github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
116
  github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
117
  github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
118
  github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
119
  github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
120
+ github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
121
+ github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
122
  github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
123
  github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
124
  github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
125
  github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
126
+ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
127
+ github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
128
  github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
129
  github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
130
+ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
131
+ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
132
+ github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
133
+ github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
134
  github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
135
  github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
136
+ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
137
+ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
138
  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
139
  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
140
+ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
141
+ github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
142
+ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
143
+ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
144
+ github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
145
+ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
146
+ github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
147
+ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4=
148
+ github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
149
+ github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
150
+ github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
151
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
152
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
153
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
154
  github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
155
  github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
156
+ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
157
+ github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
158
  github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
159
  github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
160
+ github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk=
161
+ github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
162
+ github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
163
+ github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
164
+ github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0=
165
+ github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ=
166
+ github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
167
+ github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q=
168
+ github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E=
169
+ github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4=
170
+ github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0=
171
+ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
172
+ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
173
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
174
  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
175
+ github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
176
+ github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
177
+ github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y=
178
+ github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
179
+ github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
180
+ github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
181
+ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
182
+ github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
183
+ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
184
+ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
185
+ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
186
+ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
187
+ github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
188
+ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
189
+ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
190
+ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
191
+ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
192
+ github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
193
  github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
194
  github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
195
  github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
196
+ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
197
  github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
198
  github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
199
  github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
200
  github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
201
  github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
202
+ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
203
  github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
204
  github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
205
+ github.com/supranational/blst v0.3.14 h1:xNMoHRJOTwMn63ip6qoWJ2Ymgvj7E2b9jY2FAwY+qRo=
206
+ github.com/supranational/blst v0.3.14/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
207
+ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
208
+ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
209
+ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
210
+ github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
211
+ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
212
+ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
213
  github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
214
  github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
215
  github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
216
  github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
217
+ github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
218
+ github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
219
+ github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
220
+ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
221
+ github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
222
+ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
223
  golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
224
  golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
225
+ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
226
+ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
227
+ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
228
+ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
229
+ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
230
+ golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
231
+ golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
232
+ golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
233
+ golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
234
+ golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
235
+ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
236
+ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
237
+ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
238
+ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
239
+ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
240
+ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
241
+ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
242
+ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
243
+ golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
244
+ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
245
+ golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
246
+ golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
247
+ golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
248
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
249
+ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
250
+ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
251
+ golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
252
+ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
253
+ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
254
+ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
255
+ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
256
+ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
257
+ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
258
+ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
259
+ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
260
+ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
261
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
262
+ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
263
+ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
264
+ golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
265
+ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
266
+ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
267
+ golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
268
+ golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
269
+ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
270
+ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
271
+ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
272
+ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
273
+ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
274
+ golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
275
+ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
276
+ golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
277
+ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
278
+ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
279
+ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
280
+ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
281
+ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
282
+ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
283
+ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
284
  golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
285
  golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
286
+ golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
287
+ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
288
+ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
289
+ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
290
+ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
291
+ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
292
+ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
293
  google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
294
  google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
295
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
296
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
297
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
298
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
299
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
300
+ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
301
+ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
302
  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
303
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
304
  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
305
  nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
306
+ rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
307
+ rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA=
listenSM.html ADDED
@@ -0,0 +1,760 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Listen to Smart Contract Events</title>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/web3/4.0.2/web3.min.js"></script>
9
+ </head>
10
+
11
+ <body>
12
+ <h2>Smart Contract Event Listener</h2>
13
+ <button onclick="connectWallet()">Kết nối Metamask</button>
14
+ <div id="events"></div>
15
+
16
+ <script>
17
+ const contractAddress = "0xc8d9f01b9d1552D276a589db920620F328B7208E";
18
+ const contractABI = [
19
+ {
20
+ "inputs": [],
21
+ "stateMutability": "nonpayable",
22
+ "type": "constructor"
23
+ },
24
+ {
25
+ "anonymous": false,
26
+ "inputs": [
27
+ {
28
+ "indexed": false,
29
+ "internalType": "string",
30
+ "name": "roomId",
31
+ "type": "string"
32
+ },
33
+ {
34
+ "indexed": false,
35
+ "internalType": "address",
36
+ "name": "sessionId",
37
+ "type": "address"
38
+ },
39
+ {
40
+ "indexed": false,
41
+ "internalType": "string[]",
42
+ "name": "dataChannels",
43
+ "type": "string[]"
44
+ }
45
+ ],
46
+ "name": "DataChannelsUpdated",
47
+ "type": "event"
48
+ },
49
+ {
50
+ "anonymous": false,
51
+ "inputs": [
52
+ {
53
+ "indexed": false,
54
+ "internalType": "string",
55
+ "name": "roomId",
56
+ "type": "string"
57
+ },
58
+ {
59
+ "indexed": false,
60
+ "internalType": "address",
61
+ "name": "user",
62
+ "type": "address"
63
+ }
64
+ ],
65
+ "name": "JoinedRoom",
66
+ "type": "event"
67
+ },
68
+ {
69
+ "anonymous": false,
70
+ "inputs": [
71
+ {
72
+ "indexed": false,
73
+ "internalType": "string",
74
+ "name": "roomId",
75
+ "type": "string"
76
+ },
77
+ {
78
+ "indexed": false,
79
+ "internalType": "address",
80
+ "name": "user",
81
+ "type": "address"
82
+ }
83
+ ],
84
+ "name": "LeftRoom",
85
+ "type": "event"
86
+ },
87
+ {
88
+ "anonymous": false,
89
+ "inputs": [
90
+ {
91
+ "indexed": false,
92
+ "internalType": "string",
93
+ "name": "roomId",
94
+ "type": "string"
95
+ },
96
+ {
97
+ "indexed": false,
98
+ "internalType": "string",
99
+ "name": "key",
100
+ "type": "string"
101
+ },
102
+ {
103
+ "indexed": false,
104
+ "internalType": "string",
105
+ "name": "value",
106
+ "type": "string"
107
+ }
108
+ ],
109
+ "name": "MetadataUpdated",
110
+ "type": "event"
111
+ },
112
+ {
113
+ "anonymous": false,
114
+ "inputs": [
115
+ {
116
+ "indexed": false,
117
+ "internalType": "string",
118
+ "name": "roomId",
119
+ "type": "string"
120
+ },
121
+ {
122
+ "indexed": false,
123
+ "internalType": "string",
124
+ "name": "name",
125
+ "type": "string"
126
+ },
127
+ {
128
+ "indexed": false,
129
+ "internalType": "address",
130
+ "name": "owner",
131
+ "type": "address"
132
+ }
133
+ ],
134
+ "name": "RoomCreated",
135
+ "type": "event"
136
+ },
137
+ {
138
+ "anonymous": false,
139
+ "inputs": [
140
+ {
141
+ "indexed": false,
142
+ "internalType": "string",
143
+ "name": "roomId",
144
+ "type": "string"
145
+ },
146
+ {
147
+ "indexed": false,
148
+ "internalType": "bool",
149
+ "name": "isActive",
150
+ "type": "bool"
151
+ }
152
+ ],
153
+ "name": "RoomStatusChanged",
154
+ "type": "event"
155
+ },
156
+ {
157
+ "anonymous": false,
158
+ "inputs": [
159
+ {
160
+ "indexed": false,
161
+ "internalType": "string",
162
+ "name": "roomId",
163
+ "type": "string"
164
+ },
165
+ {
166
+ "indexed": true,
167
+ "internalType": "address",
168
+ "name": "user",
169
+ "type": "address"
170
+ },
171
+ {
172
+ "indexed": false,
173
+ "internalType": "string",
174
+ "name": "sessionID",
175
+ "type": "string"
176
+ }
177
+ ],
178
+ "name": "SessionIDUpdated",
179
+ "type": "event"
180
+ },
181
+ {
182
+ "anonymous": false,
183
+ "inputs": [
184
+ {
185
+ "indexed": false,
186
+ "internalType": "string",
187
+ "name": "roomId",
188
+ "type": "string"
189
+ },
190
+ {
191
+ "indexed": false,
192
+ "internalType": "address",
193
+ "name": "sessionId",
194
+ "type": "address"
195
+ },
196
+ {
197
+ "indexed": false,
198
+ "internalType": "string",
199
+ "name": "sdp",
200
+ "type": "string"
201
+ },
202
+ {
203
+ "indexed": false,
204
+ "internalType": "string",
205
+ "name": "sdpType",
206
+ "type": "string"
207
+ }
208
+ ],
209
+ "name": "SessionRenegotiated",
210
+ "type": "event"
211
+ },
212
+ {
213
+ "anonymous": false,
214
+ "inputs": [
215
+ {
216
+ "indexed": false,
217
+ "internalType": "string",
218
+ "name": "roomId",
219
+ "type": "string"
220
+ },
221
+ {
222
+ "indexed": false,
223
+ "internalType": "address",
224
+ "name": "participant",
225
+ "type": "address"
226
+ },
227
+ {
228
+ "indexed": false,
229
+ "internalType": "string",
230
+ "name": "trackName",
231
+ "type": "string"
232
+ }
233
+ ],
234
+ "name": "TrackPublished",
235
+ "type": "event"
236
+ },
237
+ {
238
+ "anonymous": false,
239
+ "inputs": [
240
+ {
241
+ "indexed": false,
242
+ "internalType": "string",
243
+ "name": "roomId",
244
+ "type": "string"
245
+ },
246
+ {
247
+ "indexed": false,
248
+ "internalType": "address",
249
+ "name": "sessionId",
250
+ "type": "address"
251
+ },
252
+ {
253
+ "indexed": false,
254
+ "internalType": "address",
255
+ "name": "remoteSession",
256
+ "type": "address"
257
+ },
258
+ {
259
+ "indexed": false,
260
+ "internalType": "string",
261
+ "name": "trackName",
262
+ "type": "string"
263
+ }
264
+ ],
265
+ "name": "TrackPulled",
266
+ "type": "event"
267
+ },
268
+ {
269
+ "anonymous": false,
270
+ "inputs": [
271
+ {
272
+ "indexed": false,
273
+ "internalType": "string",
274
+ "name": "roomId",
275
+ "type": "string"
276
+ },
277
+ {
278
+ "indexed": false,
279
+ "internalType": "address",
280
+ "name": "participant",
281
+ "type": "address"
282
+ },
283
+ {
284
+ "indexed": false,
285
+ "internalType": "string",
286
+ "name": "trackName",
287
+ "type": "string"
288
+ }
289
+ ],
290
+ "name": "TrackUnpublished",
291
+ "type": "event"
292
+ },
293
+ {
294
+ "anonymous": false,
295
+ "inputs": [
296
+ {
297
+ "indexed": true,
298
+ "internalType": "address",
299
+ "name": "userAddress",
300
+ "type": "address"
301
+ },
302
+ {
303
+ "indexed": false,
304
+ "internalType": "bool",
305
+ "name": "isModerator",
306
+ "type": "bool"
307
+ },
308
+ {
309
+ "indexed": false,
310
+ "internalType": "string",
311
+ "name": "role",
312
+ "type": "string"
313
+ }
314
+ ],
315
+ "name": "UserUpdated",
316
+ "type": "event"
317
+ },
318
+ {
319
+ "inputs": [
320
+ {
321
+ "internalType": "string",
322
+ "name": "urls",
323
+ "type": "string"
324
+ },
325
+ {
326
+ "internalType": "string",
327
+ "name": "username",
328
+ "type": "string"
329
+ },
330
+ {
331
+ "internalType": "string",
332
+ "name": "credential",
333
+ "type": "string"
334
+ }
335
+ ],
336
+ "name": "addIceServer",
337
+ "outputs": [],
338
+ "stateMutability": "nonpayable",
339
+ "type": "function"
340
+ },
341
+ {
342
+ "inputs": [
343
+ {
344
+ "internalType": "string",
345
+ "name": "roomId",
346
+ "type": "string"
347
+ },
348
+ {
349
+ "internalType": "address",
350
+ "name": "user",
351
+ "type": "address"
352
+ }
353
+ ],
354
+ "name": "checkUserInRoom",
355
+ "outputs": [
356
+ {
357
+ "internalType": "bool",
358
+ "name": "",
359
+ "type": "bool"
360
+ }
361
+ ],
362
+ "stateMutability": "view",
363
+ "type": "function"
364
+ },
365
+ {
366
+ "inputs": [
367
+ {
368
+ "internalType": "string",
369
+ "name": "roomId",
370
+ "type": "string"
371
+ },
372
+ {
373
+ "internalType": "string",
374
+ "name": "name",
375
+ "type": "string"
376
+ },
377
+ {
378
+ "internalType": "string",
379
+ "name": "metadata",
380
+ "type": "string"
381
+ }
382
+ ],
383
+ "name": "createRoom",
384
+ "outputs": [],
385
+ "stateMutability": "nonpayable",
386
+ "type": "function"
387
+ },
388
+ {
389
+ "inputs": [],
390
+ "name": "getAllRooms",
391
+ "outputs": [
392
+ {
393
+ "internalType": "string[]",
394
+ "name": "",
395
+ "type": "string[]"
396
+ }
397
+ ],
398
+ "stateMutability": "view",
399
+ "type": "function"
400
+ },
401
+ {
402
+ "inputs": [],
403
+ "name": "getIceServers",
404
+ "outputs": [
405
+ {
406
+ "components": [
407
+ {
408
+ "internalType": "string",
409
+ "name": "urls",
410
+ "type": "string"
411
+ },
412
+ {
413
+ "internalType": "string",
414
+ "name": "username",
415
+ "type": "string"
416
+ },
417
+ {
418
+ "internalType": "string",
419
+ "name": "credential",
420
+ "type": "string"
421
+ }
422
+ ],
423
+ "internalType": "struct Meeting.ICEServer[]",
424
+ "name": "",
425
+ "type": "tuple[]"
426
+ }
427
+ ],
428
+ "stateMutability": "view",
429
+ "type": "function"
430
+ },
431
+ {
432
+ "inputs": [
433
+ {
434
+ "internalType": "string",
435
+ "name": "roomId",
436
+ "type": "string"
437
+ }
438
+ ],
439
+ "name": "getRoomDetails",
440
+ "outputs": [
441
+ {
442
+ "internalType": "string",
443
+ "name": "id",
444
+ "type": "string"
445
+ },
446
+ {
447
+ "internalType": "string",
448
+ "name": "name",
449
+ "type": "string"
450
+ },
451
+ {
452
+ "internalType": "string",
453
+ "name": "metadata",
454
+ "type": "string"
455
+ },
456
+ {
457
+ "internalType": "address",
458
+ "name": "roomOwner",
459
+ "type": "address"
460
+ },
461
+ {
462
+ "internalType": "uint256",
463
+ "name": "createdAt",
464
+ "type": "uint256"
465
+ },
466
+ {
467
+ "internalType": "bool",
468
+ "name": "isActive",
469
+ "type": "bool"
470
+ }
471
+ ],
472
+ "stateMutability": "view",
473
+ "type": "function"
474
+ },
475
+ {
476
+ "inputs": [
477
+ {
478
+ "internalType": "string",
479
+ "name": "roomId",
480
+ "type": "string"
481
+ },
482
+ {
483
+ "internalType": "string",
484
+ "name": "key",
485
+ "type": "string"
486
+ }
487
+ ],
488
+ "name": "getRoomMetadata",
489
+ "outputs": [
490
+ {
491
+ "internalType": "string",
492
+ "name": "",
493
+ "type": "string"
494
+ }
495
+ ],
496
+ "stateMutability": "view",
497
+ "type": "function"
498
+ },
499
+ {
500
+ "inputs": [
501
+ {
502
+ "internalType": "string",
503
+ "name": "roomId",
504
+ "type": "string"
505
+ }
506
+ ],
507
+ "name": "getRoomParticipants",
508
+ "outputs": [
509
+ {
510
+ "internalType": "address[]",
511
+ "name": "",
512
+ "type": "address[]"
513
+ }
514
+ ],
515
+ "stateMutability": "view",
516
+ "type": "function"
517
+ },
518
+ {
519
+ "inputs": [
520
+ {
521
+ "internalType": "string",
522
+ "name": "roomId",
523
+ "type": "string"
524
+ },
525
+ {
526
+ "internalType": "address",
527
+ "name": "user",
528
+ "type": "address"
529
+ }
530
+ ],
531
+ "name": "getSessionID",
532
+ "outputs": [
533
+ {
534
+ "internalType": "string",
535
+ "name": "",
536
+ "type": "string"
537
+ }
538
+ ],
539
+ "stateMutability": "view",
540
+ "type": "function"
541
+ },
542
+ {
543
+ "inputs": [
544
+ {
545
+ "internalType": "string",
546
+ "name": "roomId",
547
+ "type": "string"
548
+ },
549
+ {
550
+ "internalType": "address",
551
+ "name": "participantAddr",
552
+ "type": "address"
553
+ }
554
+ ],
555
+ "name": "getSessionTracks",
556
+ "outputs": [
557
+ {
558
+ "internalType": "string[]",
559
+ "name": "",
560
+ "type": "string[]"
561
+ }
562
+ ],
563
+ "stateMutability": "view",
564
+ "type": "function"
565
+ },
566
+ {
567
+ "inputs": [
568
+ {
569
+ "internalType": "address",
570
+ "name": "userAddress",
571
+ "type": "address"
572
+ }
573
+ ],
574
+ "name": "getUserInfo",
575
+ "outputs": [
576
+ {
577
+ "internalType": "address",
578
+ "name": "userId",
579
+ "type": "address"
580
+ },
581
+ {
582
+ "internalType": "bool",
583
+ "name": "isModerator",
584
+ "type": "bool"
585
+ },
586
+ {
587
+ "internalType": "string",
588
+ "name": "role",
589
+ "type": "string"
590
+ }
591
+ ],
592
+ "stateMutability": "view",
593
+ "type": "function"
594
+ },
595
+ {
596
+ "inputs": [
597
+ {
598
+ "internalType": "string",
599
+ "name": "roomId",
600
+ "type": "string"
601
+ }
602
+ ],
603
+ "name": "joinRoom",
604
+ "outputs": [],
605
+ "stateMutability": "nonpayable",
606
+ "type": "function"
607
+ },
608
+ {
609
+ "inputs": [
610
+ {
611
+ "internalType": "string",
612
+ "name": "roomId",
613
+ "type": "string"
614
+ }
615
+ ],
616
+ "name": "leaveRoom",
617
+ "outputs": [],
618
+ "stateMutability": "nonpayable",
619
+ "type": "function"
620
+ },
621
+ {
622
+ "inputs": [
623
+ {
624
+ "internalType": "string",
625
+ "name": "roomId",
626
+ "type": "string"
627
+ }
628
+ ],
629
+ "name": "roomExists",
630
+ "outputs": [
631
+ {
632
+ "internalType": "bool",
633
+ "name": "",
634
+ "type": "bool"
635
+ }
636
+ ],
637
+ "stateMutability": "view",
638
+ "type": "function"
639
+ },
640
+ {
641
+ "inputs": [
642
+ {
643
+ "internalType": "string",
644
+ "name": "roomId",
645
+ "type": "string"
646
+ },
647
+ {
648
+ "internalType": "string",
649
+ "name": "sessionID",
650
+ "type": "string"
651
+ }
652
+ ],
653
+ "name": "saveSessionID",
654
+ "outputs": [],
655
+ "stateMutability": "nonpayable",
656
+ "type": "function"
657
+ },
658
+ {
659
+ "inputs": [
660
+ {
661
+ "internalType": "string",
662
+ "name": "roomId",
663
+ "type": "string"
664
+ },
665
+ {
666
+ "internalType": "bool",
667
+ "name": "isActive",
668
+ "type": "bool"
669
+ }
670
+ ],
671
+ "name": "setRoomStatus",
672
+ "outputs": [],
673
+ "stateMutability": "nonpayable",
674
+ "type": "function"
675
+ },
676
+ {
677
+ "inputs": [
678
+ {
679
+ "internalType": "address",
680
+ "name": "userAddress",
681
+ "type": "address"
682
+ },
683
+ {
684
+ "internalType": "bool",
685
+ "name": "isModerator",
686
+ "type": "bool"
687
+ },
688
+ {
689
+ "internalType": "string",
690
+ "name": "role",
691
+ "type": "string"
692
+ }
693
+ ],
694
+ "name": "setUserInfo",
695
+ "outputs": [],
696
+ "stateMutability": "nonpayable",
697
+ "type": "function"
698
+ },
699
+ {
700
+ "inputs": [
701
+ {
702
+ "internalType": "string",
703
+ "name": "roomId",
704
+ "type": "string"
705
+ },
706
+ {
707
+ "internalType": "string",
708
+ "name": "key",
709
+ "type": "string"
710
+ },
711
+ {
712
+ "internalType": "string",
713
+ "name": "value",
714
+ "type": "string"
715
+ }
716
+ ],
717
+ "name": "updateRoomMetadata",
718
+ "outputs": [],
719
+ "stateMutability": "nonpayable",
720
+ "type": "function"
721
+ }
722
+ ];
723
+
724
+ let web3;
725
+ let contract;
726
+ const wsWeb3 = new Web3(new Web3.providers.WebsocketProvider('wss://bsc-testnet-rpc.publicnode.com'));
727
+ const wsContract = new wsWeb3.eth.Contract(contractABI, contractAddress);
728
+
729
+ async function connectWallet() {
730
+ if (window.ethereum) {
731
+ web3 = new Web3(window.ethereum);
732
+ await window.ethereum.request({ method: "eth_requestAccounts" });
733
+ const accounts = await web3.eth.getAccounts();
734
+ console.log("Connected account:", accounts[0]);
735
+ listenToEvents();
736
+ } else {
737
+ alert("Vui lòng cài đặt MetaMask!");
738
+ }
739
+ }
740
+
741
+ function listenToEvents() {
742
+ wsContract.events.RoomCreated()
743
+ .on("data", event => {
744
+ console.log("📥 Room created:", event.returnValues);
745
+ const eventData = `
746
+ <p><strong>Room ID:</strong> ${event.returnValues.roomId}</p>
747
+ <p><strong>Tên phòng:</strong> ${event.returnValues.name}</p>
748
+ <p><strong>Chủ phòng:</strong> ${event.returnValues.owner}</p>
749
+ <hr>
750
+ `;
751
+ document.getElementById("events").innerHTML += eventData;
752
+ })
753
+ .on("error", error => {
754
+ console.error("❌ WebSocket Error:", error);
755
+ });
756
+ }
757
+ </script>
758
+ </body>
759
+
760
+ </html>
main.go CHANGED
@@ -2,6 +2,8 @@ package main
2
 
3
  import (
4
  "bytes"
 
 
5
  "crypto/hmac"
6
  "crypto/sha256"
7
  "encoding/base64"
@@ -9,12 +11,19 @@ import (
9
  "fmt"
10
  "io"
11
  "log"
 
12
  "net/http"
13
  "os"
14
  "strconv"
 
15
  "sync"
16
  "time"
17
 
 
 
 
 
 
18
  "github.com/gin-gonic/gin"
19
  "github.com/golang-jwt/jwt/v5"
20
  "github.com/google/uuid"
@@ -34,6 +43,10 @@ var (
34
  cloudflareCallsBaseURL string
35
  cloudflareBasePath string
36
  debug bool
 
 
 
 
37
  )
38
 
39
  func initConfig() {
@@ -51,6 +64,10 @@ func initConfig() {
51
  cloudflareCallsBaseURL = getEnv("CLOUDFLARE_APPS_URL", "https://rtc.live.cloudflare.com/v1/apps")
52
  cloudflareBasePath = fmt.Sprintf("%s/%s", cloudflareCallsBaseURL, cloudflareAppID)
53
  debug = getEnvBool("DEBUG", false)
 
 
 
 
54
 
55
  if cloudflareAppID == "" || cloudflareAppSecret == "" {
56
  log.Fatal("CLOUDFLARE_APP_ID and CLOUDFLARE_APP_SECRET must be set")
@@ -63,6 +80,10 @@ func initConfig() {
63
  log.Println("JWT_SECRET:", secretKey)
64
  log.Println("CLOUDFLARE_APPS_URL:", cloudflareCallsBaseURL)
65
  log.Println("DEBUG:", debug)
 
 
 
 
66
  }
67
 
68
  // Helper function to get environment variables with default values
@@ -617,6 +638,15 @@ func createRoom(c *gin.Context) {
617
  rooms.m[roomId] = room
618
  rooms.Unlock()
619
 
 
 
 
 
 
 
 
 
 
620
  // Trả về format giống Express
621
  c.JSON(http.StatusOK, gin.H{
622
  "roomId": room.RoomId,
@@ -627,6 +657,66 @@ func createRoom(c *gin.Context) {
627
  })
628
  }
629
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
  func inspectRooms(c *gin.Context) {
631
  if os.Getenv("NODE_ENV") != "development" {
632
  c.JSON(http.StatusForbidden, gin.H{"error": "This endpoint is only available in development mode."})
 
2
 
3
  import (
4
  "bytes"
5
+ "context"
6
+ "crypto/ecdsa"
7
  "crypto/hmac"
8
  "crypto/sha256"
9
  "encoding/base64"
 
11
  "fmt"
12
  "io"
13
  "log"
14
+ "math/big"
15
  "net/http"
16
  "os"
17
  "strconv"
18
+ "strings"
19
  "sync"
20
  "time"
21
 
22
+ "github.com/ethereum/go-ethereum/accounts/abi"
23
+ "github.com/ethereum/go-ethereum/common"
24
+ "github.com/ethereum/go-ethereum/core/types"
25
+ "github.com/ethereum/go-ethereum/crypto"
26
+ "github.com/ethereum/go-ethereum/ethclient"
27
  "github.com/gin-gonic/gin"
28
  "github.com/golang-jwt/jwt/v5"
29
  "github.com/google/uuid"
 
43
  cloudflareCallsBaseURL string
44
  cloudflareBasePath string
45
  debug bool
46
+ RPC_URL string
47
+ CONTRACT_ADDRESS string
48
+ ABI_JSON string
49
+ PRIVATE_KEY string
50
  )
51
 
52
  func initConfig() {
 
64
  cloudflareCallsBaseURL = getEnv("CLOUDFLARE_APPS_URL", "https://rtc.live.cloudflare.com/v1/apps")
65
  cloudflareBasePath = fmt.Sprintf("%s/%s", cloudflareCallsBaseURL, cloudflareAppID)
66
  debug = getEnvBool("DEBUG", false)
67
+ RPC_URL = getEnv("RPC_URL", "https://data-seed-prebsc-1-s1.binance.org:8545/")
68
+ CONTRACT_ADDRESS = getEnv("CONTRACT_ADDRESS", "")
69
+ ABI_JSON = getEnv("ABI_JSON", "")
70
+ PRIVATE_KEY = getEnv("PRIVATE_KEY", "")
71
 
72
  if cloudflareAppID == "" || cloudflareAppSecret == "" {
73
  log.Fatal("CLOUDFLARE_APP_ID and CLOUDFLARE_APP_SECRET must be set")
 
80
  log.Println("JWT_SECRET:", secretKey)
81
  log.Println("CLOUDFLARE_APPS_URL:", cloudflareCallsBaseURL)
82
  log.Println("DEBUG:", debug)
83
+ log.Println("RPC_URL:", RPC_URL)
84
+ log.Println("CONTRACT_ADDRESS:", CONTRACT_ADDRESS)
85
+ log.Println("ABI_JSON:", ABI_JSON)
86
+ log.Println("PRIVATE_KEY:", PRIVATE_KEY)
87
  }
88
 
89
  // Helper function to get environment variables with default values
 
638
  rooms.m[roomId] = room
639
  rooms.Unlock()
640
 
641
+ // Update data on the smart contract
642
+ err := updateRoomOnContract(roomId, req.Name, req.Metadata)
643
+ if err != nil {
644
+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update smart contract", "details": err.Error()})
645
+ return
646
+ }
647
+
648
+ log.Printf("Room metadata: %s", room.Metadata)
649
+
650
  // Trả về format giống Express
651
  c.JSON(http.StatusOK, gin.H{
652
  "roomId": room.RoomId,
 
657
  })
658
  }
659
 
660
+ func updateRoomOnContract(roomId string, name string, metadata map[string]interface{}) error {
661
+ client, err := ethclient.Dial(RPC_URL)
662
+ if err != nil {
663
+ return fmt.Errorf("failed to connect to blockchain: %v", err)
664
+ }
665
+ defer client.Close()
666
+
667
+ contractAddress := common.HexToAddress(CONTRACT_ADDRESS)
668
+ parsedABI, err := abi.JSON(strings.NewReader(ABI_JSON))
669
+ if err != nil {
670
+ return fmt.Errorf("failed to parse ABI: %v", err)
671
+ }
672
+
673
+ privateKey, err := crypto.HexToECDSA(PRIVATE_KEY)
674
+ if err != nil {
675
+ return fmt.Errorf("failed to parse private key: %v", err)
676
+ }
677
+ publicKey := privateKey.Public()
678
+ publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
679
+ if !ok {
680
+ return fmt.Errorf("error converting public key")
681
+ }
682
+ fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
683
+
684
+ nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
685
+ if err != nil {
686
+ return fmt.Errorf("failed to get nonce: %v", err)
687
+ }
688
+ gasLimit := uint64(300000)
689
+ gasPrice, err := client.SuggestGasPrice(context.Background())
690
+ if err != nil {
691
+ return fmt.Errorf("failed to get gas price: %v", err)
692
+ }
693
+
694
+ metadataJSON, err := json.Marshal(metadata)
695
+ if err != nil {
696
+ return fmt.Errorf("failed to marshal metadata: %v", err)
697
+ }
698
+
699
+ data, err := parsedABI.Pack("createRoom", roomId, name, string(metadataJSON))
700
+ if err != nil {
701
+ return fmt.Errorf("failed to pack transaction data: %v", err)
702
+ }
703
+
704
+ tx := types.NewTransaction(nonce, contractAddress, big.NewInt(0), gasLimit, gasPrice, data)
705
+ chainID := big.NewInt(97) // BSC Testnet chain ID
706
+ signedTx, err := types.SignTx(tx, types.NewLondonSigner(chainID), privateKey)
707
+ if err != nil {
708
+ return fmt.Errorf("failed to sign transaction: %v", err)
709
+ }
710
+
711
+ err = client.SendTransaction(context.Background(), signedTx)
712
+ if err != nil {
713
+ return fmt.Errorf("failed to send transaction: %v", err)
714
+ }
715
+
716
+ log.Printf("Transaction sent! Hash: %s", signedTx.Hash().Hex())
717
+ return nil
718
+ }
719
+
720
  func inspectRooms(c *gin.Context) {
721
  if os.Getenv("NODE_ENV") != "development" {
722
  c.JSON(http.StatusForbidden, gin.H{"error": "This endpoint is only available in development mode."})
public/index.html CHANGED
@@ -261,7 +261,8 @@
261
  import web3Auth from './js/auth.js';
262
 
263
  // Lấy current URL và cấu hình endpoints
264
- const currentUrl = 'https://manhteky123-dappmeetingv3.hf.space';
 
265
  const isLocalhost = currentUrl.includes('localhost') || currentUrl.includes('127.0.0.1');
266
 
267
  // Cấu hình endpoints dựa trên môi trường
 
261
  import web3Auth from './js/auth.js';
262
 
263
  // Lấy current URL và cấu hình endpoints
264
+ // const currentUrl = 'https://manhteky123-dappmeetingv3.hf.space';
265
+ const currentUrl = window.location.origin;
266
  const isLocalhost = currentUrl.includes('localhost') || currentUrl.includes('127.0.0.1');
267
 
268
  // Cấu hình endpoints dựa trên môi trường
public/join.html CHANGED
@@ -199,7 +199,8 @@
199
  import web3Auth from './js/auth.js';
200
 
201
  // Lấy current URL và cấu hình endpoints
202
- const currentUrl = 'https://manhteky123-dappmeetingv3.hf.space';
 
203
  const isLocalhost = currentUrl.includes('localhost') || currentUrl.includes('127.0.0.1');
204
 
205
  // Cấu hình endpoints dựa trên môi trường
 
199
  import web3Auth from './js/auth.js';
200
 
201
  // Lấy current URL và cấu hình endpoints
202
+ // const currentUrl = 'https://manhteky123-dappmeetingv3.hf.space';
203
+ const currentUrl = window.location.origin;
204
  const isLocalhost = currentUrl.includes('localhost') || currentUrl.includes('127.0.0.1');
205
 
206
  // Cấu hình endpoints dựa trên môi trường
public/js/room.js CHANGED
@@ -2,7 +2,8 @@ import CloudflareCalls from './CloudflareCalls.js';
2
  import web3Auth from './auth.js';
3
 
4
  // Lấy current URL và cấu hình endpoints
5
- const currentUrl = 'https://manhteky123-dappmeetingv3.hf.space';
 
6
  const isLocalhost = currentUrl.includes('localhost') || currentUrl.includes('127.0.0.1');
7
 
8
  // Cấu hình endpoints dựa trên môi trường
 
2
  import web3Auth from './auth.js';
3
 
4
  // Lấy current URL và cấu hình endpoints
5
+ // const currentUrl = 'https://manhteky123-dappmeetingv3.hf.space';
6
+ const currentUrl = window.location.origin;
7
  const isLocalhost = currentUrl.includes('localhost') || currentUrl.includes('127.0.0.1');
8
 
9
  // Cấu hình endpoints dựa trên môi trường
temp/test.go DELETED
@@ -1,1135 +0,0 @@
1
- package main
2
-
3
- import (
4
- "bytes"
5
- "context"
6
- "crypto/ecdsa"
7
- "encoding/json"
8
- "fmt"
9
- "io"
10
- "log"
11
- "math/big"
12
- "net/http"
13
- "strings"
14
-
15
- "github.com/ethereum/go-ethereum"
16
- "github.com/ethereum/go-ethereum/accounts/abi"
17
- "github.com/ethereum/go-ethereum/common"
18
- "github.com/ethereum/go-ethereum/core/types"
19
- "github.com/ethereum/go-ethereum/crypto"
20
- "github.com/ethereum/go-ethereum/ethclient"
21
- "github.com/gin-gonic/gin"
22
- "github.com/gorilla/websocket"
23
- "github.com/pion/webrtc/v3"
24
- )
25
-
26
- type OfferRequest struct {
27
- SessionDescription webrtc.SessionDescription `json:"sessionDescription"`
28
- }
29
-
30
- type OfferResponse struct {
31
- SessionID string `json:"sessionId"`
32
- SessionDescription webrtc.SessionDescription `json:"sessionDescription"`
33
- }
34
- type RoomCreatedEvent struct {
35
- RoomId string
36
- Name string
37
- Owner common.Address
38
- }
39
- type SessionDescription struct {
40
- SDP string `json:"sdp"`
41
- Type string `json:"type"`
42
- }
43
- type CreateSessionResponse struct {
44
- SessionDescription SessionDescription `json:"sessionDescription"`
45
- SessionId string `json:"sessionId"`
46
- }
47
- type User struct {
48
- ID string `json:"id"` // sessionID
49
- UserName string `json:"user_name"`
50
- Track0 string `json:"track_0"`
51
- Track1 string `json:"track_1"`
52
- }
53
-
54
- // UserShare lưu thông tin chia sẻ màn hình của 1 user
55
- type UserShare struct {
56
- ID string `json:"id"` // session id, cũng coi là user id
57
- Track0 string `json:"track_0"` // tên track 0
58
- Track1 string `json:"track_1"` // tên track 1
59
- }
60
- type UserChat struct {
61
- ID string `json:"id"`
62
- ChannelName string `json:"dataChannelName"`
63
- AssociatedUserID string `json:"userid"`
64
- }
65
-
66
- const cloudflareAPIBase = "https://rtc.live.cloudflare.com/v1"
67
- const appId = "7596d5732a9475dc94248813563462b2"
68
- const appSecret = "2eeee3673ef4383567e825dbbb75b5792b5b2363db4efc044c876858104d7f30"
69
- const (
70
- RPC_URL = "wss://bsc-testnet.publicnode.com" // WebSocket RPC URL của BSC Testnet
71
- CONTRACT_ADDRESS = "0x28ecAa17F7c81069aD0aE6aA76c706ED460dA299"
72
- PRIVATE_KEY = "4709120673cf1834f40194aeb21f1719e488dd61d4f7c96f92e160ffc3182c92"
73
- ABI_JSON = `[
74
- {
75
- "inputs": [
76
- {
77
- "internalType": "string",
78
- "name": "roomId",
79
- "type": "string"
80
- },
81
- {
82
- "internalType": "string",
83
- "name": "name",
84
- "type": "string"
85
- }
86
- ],
87
- "name": "createRoom",
88
- "outputs": [],
89
- "stateMutability": "nonpayable",
90
- "type": "function"
91
- },
92
- {
93
- "inputs": [],
94
- "stateMutability": "nonpayable",
95
- "type": "constructor"
96
- },
97
- {
98
- "anonymous": false,
99
- "inputs": [
100
- {
101
- "indexed": false,
102
- "internalType": "string",
103
- "name": "roomId",
104
- "type": "string"
105
- },
106
- {
107
- "indexed": false,
108
- "internalType": "address",
109
- "name": "sessionId",
110
- "type": "address"
111
- },
112
- {
113
- "indexed": false,
114
- "internalType": "string[]",
115
- "name": "dataChannels",
116
- "type": "string[]"
117
- }
118
- ],
119
- "name": "DataChannelsUpdated",
120
- "type": "event"
121
- },
122
- {
123
- "anonymous": false,
124
- "inputs": [
125
- {
126
- "indexed": false,
127
- "internalType": "string",
128
- "name": "roomId",
129
- "type": "string"
130
- },
131
- {
132
- "indexed": false,
133
- "internalType": "address",
134
- "name": "user",
135
- "type": "address"
136
- }
137
- ],
138
- "name": "JoinedRoom",
139
- "type": "event"
140
- },
141
- {
142
- "inputs": [
143
- {
144
- "internalType": "string",
145
- "name": "roomId",
146
- "type": "string"
147
- }
148
- ],
149
- "name": "joinRoom",
150
- "outputs": [],
151
- "stateMutability": "nonpayable",
152
- "type": "function"
153
- },
154
- {
155
- "inputs": [
156
- {
157
- "internalType": "string",
158
- "name": "roomId",
159
- "type": "string"
160
- },
161
- {
162
- "internalType": "string",
163
- "name": "trackName",
164
- "type": "string"
165
- }
166
- ],
167
- "name": "publishTrack",
168
- "outputs": [],
169
- "stateMutability": "nonpayable",
170
- "type": "function"
171
- },
172
- {
173
- "anonymous": false,
174
- "inputs": [
175
- {
176
- "indexed": false,
177
- "internalType": "string",
178
- "name": "roomId",
179
- "type": "string"
180
- },
181
- {
182
- "indexed": false,
183
- "internalType": "string",
184
- "name": "name",
185
- "type": "string"
186
- },
187
- {
188
- "indexed": false,
189
- "internalType": "address",
190
- "name": "owner",
191
- "type": "address"
192
- }
193
- ],
194
- "name": "RoomCreated",
195
- "type": "event"
196
- },
197
- {
198
- "inputs": [
199
- {
200
- "internalType": "string",
201
- "name": "roomId",
202
- "type": "string"
203
- },
204
- {
205
- "internalType": "string",
206
- "name": "sessionID",
207
- "type": "string"
208
- }
209
- ],
210
- "name": "saveSessionID",
211
- "outputs": [],
212
- "stateMutability": "nonpayable",
213
- "type": "function"
214
- },
215
- {
216
- "anonymous": false,
217
- "inputs": [
218
- {
219
- "indexed": false,
220
- "internalType": "string",
221
- "name": "roomId",
222
- "type": "string"
223
- },
224
- {
225
- "indexed": true,
226
- "internalType": "address",
227
- "name": "user",
228
- "type": "address"
229
- },
230
- {
231
- "indexed": false,
232
- "internalType": "string",
233
- "name": "sessionID",
234
- "type": "string"
235
- }
236
- ],
237
- "name": "SessionIDUpdated",
238
- "type": "event"
239
- },
240
- {
241
- "anonymous": false,
242
- "inputs": [
243
- {
244
- "indexed": false,
245
- "internalType": "string",
246
- "name": "roomId",
247
- "type": "string"
248
- },
249
- {
250
- "indexed": false,
251
- "internalType": "address",
252
- "name": "sessionId",
253
- "type": "address"
254
- },
255
- {
256
- "indexed": false,
257
- "internalType": "string",
258
- "name": "sdp",
259
- "type": "string"
260
- },
261
- {
262
- "indexed": false,
263
- "internalType": "string",
264
- "name": "sdpType",
265
- "type": "string"
266
- }
267
- ],
268
- "name": "SessionRenegotiated",
269
- "type": "event"
270
- },
271
- {
272
- "inputs": [
273
- {
274
- "internalType": "address",
275
- "name": "userAddress",
276
- "type": "address"
277
- },
278
- {
279
- "internalType": "bool",
280
- "name": "isModerator",
281
- "type": "bool"
282
- },
283
- {
284
- "internalType": "string",
285
- "name": "role",
286
- "type": "string"
287
- }
288
- ],
289
- "name": "setUserInfo",
290
- "outputs": [],
291
- "stateMutability": "nonpayable",
292
- "type": "function"
293
- },
294
- {
295
- "anonymous": false,
296
- "inputs": [
297
- {
298
- "indexed": false,
299
- "internalType": "string",
300
- "name": "roomId",
301
- "type": "string"
302
- },
303
- {
304
- "indexed": false,
305
- "internalType": "address",
306
- "name": "participant",
307
- "type": "address"
308
- },
309
- {
310
- "indexed": false,
311
- "internalType": "string",
312
- "name": "trackName",
313
- "type": "string"
314
- }
315
- ],
316
- "name": "TrackPublished",
317
- "type": "event"
318
- },
319
- {
320
- "anonymous": false,
321
- "inputs": [
322
- {
323
- "indexed": false,
324
- "internalType": "string",
325
- "name": "roomId",
326
- "type": "string"
327
- },
328
- {
329
- "indexed": false,
330
- "internalType": "address",
331
- "name": "sessionId",
332
- "type": "address"
333
- },
334
- {
335
- "indexed": false,
336
- "internalType": "address",
337
- "name": "remoteSession",
338
- "type": "address"
339
- },
340
- {
341
- "indexed": false,
342
- "internalType": "string",
343
- "name": "trackName",
344
- "type": "string"
345
- }
346
- ],
347
- "name": "TrackPulled",
348
- "type": "event"
349
- },
350
- {
351
- "anonymous": false,
352
- "inputs": [
353
- {
354
- "indexed": false,
355
- "internalType": "string",
356
- "name": "roomId",
357
- "type": "string"
358
- },
359
- {
360
- "indexed": false,
361
- "internalType": "address",
362
- "name": "participant",
363
- "type": "address"
364
- },
365
- {
366
- "indexed": false,
367
- "internalType": "string",
368
- "name": "trackName",
369
- "type": "string"
370
- }
371
- ],
372
- "name": "TrackUnpublished",
373
- "type": "event"
374
- },
375
- {
376
- "inputs": [
377
- {
378
- "internalType": "string",
379
- "name": "roomId",
380
- "type": "string"
381
- },
382
- {
383
- "internalType": "string",
384
- "name": "trackName",
385
- "type": "string"
386
- }
387
- ],
388
- "name": "unpublishTrack",
389
- "outputs": [],
390
- "stateMutability": "nonpayable",
391
- "type": "function"
392
- },
393
- {
394
- "anonymous": false,
395
- "inputs": [
396
- {
397
- "indexed": true,
398
- "internalType": "address",
399
- "name": "userAddress",
400
- "type": "address"
401
- },
402
- {
403
- "indexed": false,
404
- "internalType": "bool",
405
- "name": "isModerator",
406
- "type": "bool"
407
- },
408
- {
409
- "indexed": false,
410
- "internalType": "string",
411
- "name": "role",
412
- "type": "string"
413
- }
414
- ],
415
- "name": "UserUpdated",
416
- "type": "event"
417
- },
418
- {
419
- "inputs": [
420
- {
421
- "internalType": "string",
422
- "name": "roomId",
423
- "type": "string"
424
- },
425
- {
426
- "internalType": "address",
427
- "name": "user",
428
- "type": "address"
429
- }
430
- ],
431
- "name": "checkUserInRoom",
432
- "outputs": [
433
- {
434
- "internalType": "bool",
435
- "name": "",
436
- "type": "bool"
437
- }
438
- ],
439
- "stateMutability": "view",
440
- "type": "function"
441
- },
442
- {
443
- "inputs": [],
444
- "name": "getAllRooms",
445
- "outputs": [
446
- {
447
- "internalType": "string[]",
448
- "name": "",
449
- "type": "string[]"
450
- }
451
- ],
452
- "stateMutability": "view",
453
- "type": "function"
454
- },
455
- {
456
- "inputs": [],
457
- "name": "getIceServers",
458
- "outputs": [
459
- {
460
- "components": [
461
- {
462
- "internalType": "string",
463
- "name": "urls",
464
- "type": "string"
465
- },
466
- {
467
- "internalType": "string",
468
- "name": "username",
469
- "type": "string"
470
- },
471
- {
472
- "internalType": "string",
473
- "name": "credential",
474
- "type": "string"
475
- }
476
- ],
477
- "internalType": "struct Meeting.ICEServer[]",
478
- "name": "",
479
- "type": "tuple[]"
480
- }
481
- ],
482
- "stateMutability": "view",
483
- "type": "function"
484
- },
485
- {
486
- "inputs": [
487
- {
488
- "internalType": "string",
489
- "name": "roomId",
490
- "type": "string"
491
- }
492
- ],
493
- "name": "getRoomParticipants",
494
- "outputs": [
495
- {
496
- "internalType": "address[]",
497
- "name": "",
498
- "type": "address[]"
499
- }
500
- ],
501
- "stateMutability": "view",
502
- "type": "function"
503
- },
504
- {
505
- "inputs": [
506
- {
507
- "internalType": "string",
508
- "name": "roomId",
509
- "type": "string"
510
- },
511
- {
512
- "internalType": "address",
513
- "name": "user",
514
- "type": "address"
515
- }
516
- ],
517
- "name": "getSessionID",
518
- "outputs": [
519
- {
520
- "internalType": "string",
521
- "name": "",
522
- "type": "string"
523
- }
524
- ],
525
- "stateMutability": "view",
526
- "type": "function"
527
- },
528
- {
529
- "inputs": [
530
- {
531
- "internalType": "string",
532
- "name": "roomId",
533
- "type": "string"
534
- },
535
- {
536
- "internalType": "address",
537
- "name": "participant",
538
- "type": "address"
539
- }
540
- ],
541
- "name": "getSessionTracks",
542
- "outputs": [
543
- {
544
- "internalType": "string[]",
545
- "name": "",
546
- "type": "string[]"
547
- }
548
- ],
549
- "stateMutability": "view",
550
- "type": "function"
551
- },
552
- {
553
- "inputs": [
554
- {
555
- "internalType": "address",
556
- "name": "userAddress",
557
- "type": "address"
558
- }
559
- ],
560
- "name": "getUserInfo",
561
- "outputs": [
562
- {
563
- "internalType": "address",
564
- "name": "userId",
565
- "type": "address"
566
- },
567
- {
568
- "internalType": "bool",
569
- "name": "isModerator",
570
- "type": "bool"
571
- },
572
- {
573
- "internalType": "string",
574
- "name": "role",
575
- "type": "string"
576
- }
577
- ],
578
- "stateMutability": "view",
579
- "type": "function"
580
- }
581
- ]`
582
- )
583
-
584
- var userChats = make(map[string]UserChat)
585
- var roomShares = make(map[string]map[string]UserShare)
586
- var roomChats = make(map[string][]UserChat)
587
-
588
- // In-memory storage for simplicity (replace with a database in production)
589
- var users = make(map[string]User) // Maps user ID to user
590
- var userShares = make(map[string]UserShare)
591
-
592
- var rooms = make(map[string][]User) // Maps room ID to users
593
- var clients = make(map[string]*websocket.Conn)
594
- var upgrader = websocket.Upgrader{
595
- CheckOrigin: func(r *http.Request) bool {
596
- return true // Cho phép mọi nguồn gốc (có thể thay đổi để tăng cường bảo mật)
597
- },
598
- }
599
-
600
- // Hàm gửi yêu cầu đến Cloudflare API
601
- func countUsersInRoom(roomID string) int {
602
- // Kiểm tra xem room có tồn tại trong rooms không
603
- usersInRoom, exists := rooms[roomID]
604
- if !exists {
605
- // Nếu room không tồn tại, trả về 0
606
- return 0
607
- }
608
-
609
- // Trả về số người trong room
610
- return len(usersInRoom)
611
- }
612
- func sendRequest(url string, method string, body interface{}) ([]byte, error) {
613
- // Chuyển body thành JSON
614
- jsonBody, err := json.Marshal(body)
615
- if err != nil {
616
- return nil, err
617
- }
618
-
619
- // Tạo request
620
- req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonBody))
621
- if err != nil {
622
- return nil, err
623
- }
624
-
625
- // Thêm header cho yêu cầu
626
- req.Header.Set("Content-Type", "application/json")
627
- req.Header.Set("Authorization", "Bearer "+appSecret)
628
-
629
- // Gửi request
630
- client := &http.Client{}
631
- resp, err := client.Do(req)
632
- if err != nil {
633
- return nil, err
634
- }
635
- defer resp.Body.Close()
636
-
637
- // Đọc dữ liệu phản hồi
638
- respBody, err := io.ReadAll(resp.Body)
639
- if err != nil {
640
- return nil, err
641
- }
642
-
643
- return respBody, nil
644
- }
645
- func createSession(c *gin.Context) {
646
- var offerSDP struct {
647
- SDP string `json:"sdp"`
648
- }
649
- if err := c.ShouldBindJSON(&offerSDP); err != nil {
650
- log.Println("Invalid request body:", err)
651
- c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
652
- return
653
- }
654
-
655
- peerConnection, err := webrtc.NewPeerConnection(webrtc.Configuration{
656
- ICEServers: []webrtc.ICEServer{
657
- {
658
- URLs: []string{"stun:stun.cloudflare.com:3478"},
659
- },
660
- },
661
- })
662
- if err != nil {
663
- log.Println("Error creating PeerConnection:", err)
664
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create peer connection"})
665
- return
666
- }
667
-
668
- peerConnection.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo, webrtc.RTPTransceiverInit{
669
- Direction: webrtc.RTPTransceiverDirectionRecvonly,
670
- })
671
-
672
- localOffer, err := peerConnection.CreateOffer(nil)
673
- if err != nil {
674
- log.Println("Error creating offer:", err)
675
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create offer"})
676
- return
677
- }
678
-
679
- err = peerConnection.SetLocalDescription(localOffer)
680
- if err != nil {
681
- log.Println("Error setting local description:", err)
682
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to set local description"})
683
- return
684
- }
685
-
686
- url := fmt.Sprintf("%s/apps/%s/sessions/new", cloudflareAPIBase, appId)
687
- body := OfferRequest{SessionDescription: localOffer}
688
-
689
- // **Fix: Call `sendRequest` with correct arguments**
690
- answerBytes, err := sendRequest(url, "POST", body)
691
- if err != nil {
692
- log.Println("Error creating session on Cloudflare:", err)
693
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error creating session: %v", err)})
694
- return
695
- }
696
-
697
- // **Fix: Unmarshal response**
698
- var answer OfferResponse
699
- err = json.Unmarshal(answerBytes, &answer)
700
- if err != nil {
701
- log.Println("Failed to parse session response:", err)
702
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid response from server"})
703
- return
704
- }
705
-
706
- // **Fix: Access `SessionDescription` properly**
707
- err = peerConnection.SetRemoteDescription(answer.SessionDescription)
708
- if err != nil {
709
- log.Println("Error setting remote description:", err)
710
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to set remote description"})
711
- return
712
- }
713
-
714
- // **Fix: Access `SessionID` properly**
715
- sessionID := answer.SessionID
716
- if sessionID == "" {
717
- log.Println("Session ID is empty, something went wrong!")
718
- c.JSON(http.StatusInternalServerError, gin.H{"error": "Session ID not received"})
719
- return
720
- }
721
-
722
- log.Printf("Received Session ID: %s", sessionID)
723
-
724
- // **Save session ID to blockchain**
725
- roomID := "some-room-id" // Get roomID appropriately
726
- saveSuccess := false
727
-
728
- err = saveSessionID(roomID, sessionID)
729
- if err != nil {
730
- log.Printf("Failed to save session ID to blockchain: %v", err)
731
- } else {
732
- saveSuccess = true
733
- log.Println("Session ID successfully saved to blockchain")
734
- }
735
-
736
- // **Return response**
737
- c.JSON(http.StatusOK, gin.H{
738
- "sessionID": sessionID,
739
- "saveSuccess": saveSuccess,
740
- })
741
- }
742
- func saveSessionID(roomId string, sessionID string) error {
743
- client, err := ethclient.Dial(RPC_URL)
744
- if err != nil {
745
- return fmt.Errorf("failed to connect to blockchain: %v", err)
746
- }
747
- defer client.Close()
748
-
749
- contractAddress := common.HexToAddress(CONTRACT_ADDRESS)
750
- parsedABI, err := abi.JSON(strings.NewReader(ABI_JSON))
751
- if err != nil {
752
- return fmt.Errorf("failed to parse ABI: %v", err)
753
- }
754
-
755
- // Chuyển đổi PRIVATE_KEY từ hex sang ecdsa.PrivateKey
756
- privateKey, err := crypto.HexToECDSA(PRIVATE_KEY)
757
- if err != nil {
758
- return fmt.Errorf("failed to parse private key: %v", err)
759
- }
760
- publicKey := privateKey.Public()
761
- publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
762
- if !ok {
763
- return fmt.Errorf("error converting public key")
764
- }
765
- fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
766
-
767
- nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
768
- if err != nil {
769
- return fmt.Errorf("failed to get nonce: %v", err)
770
- }
771
- gasLimit := uint64(300000)
772
- gasPrice, err := client.SuggestGasPrice(context.Background())
773
- if err != nil {
774
- return fmt.Errorf("failed to get gas price: %v", err)
775
- }
776
-
777
- // Không cần convert sessionID sang bytes32 vì smart contract đã dùng string
778
- data, err := parsedABI.Pack("saveSessionID", roomId, sessionID)
779
- if err != nil {
780
- return fmt.Errorf("failed to pack transaction data: %v", err)
781
- }
782
-
783
- tx := types.NewTransaction(nonce, contractAddress, big.NewInt(0), gasLimit, gasPrice, data)
784
- chainID := big.NewInt(97) // BSC Testnet chain ID
785
- signedTx, err := types.SignTx(tx, types.NewLondonSigner(chainID), privateKey)
786
- if err != nil {
787
- return fmt.Errorf("failed to sign transaction: %v", err)
788
- }
789
-
790
- err = client.SendTransaction(context.Background(), signedTx)
791
- if err != nil {
792
- return fmt.Errorf("failed to send transaction: %v", err)
793
- }
794
-
795
- log.Printf("Transaction sent! Hash: %s", signedTx.Hash().Hex())
796
- return nil
797
- }
798
-
799
- // CORS middleware để thêm header CORS vào các phản hồi
800
- func handleCORS(c *gin.Context) {
801
- // Thêm các header CORS cho phép truy cập từ bất kỳ nguồn nào
802
- c.Header("Access-Control-Allow-Origin", "*")
803
- c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
804
- c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
805
-
806
- // Nếu là preflight request (OPTIONS), chỉ cần trả về thành công
807
- if c.Request.Method == http.MethodOptions {
808
- c.JSON(http.StatusOK, gin.H{})
809
- c.Abort()
810
- return
811
- }
812
- c.Next()
813
- }
814
-
815
- func addTrack(c *gin.Context) {
816
- handleCORS(c)
817
-
818
- // Lấy sessionId từ query
819
- sessionId := c.DefaultQuery("sessionId", "")
820
- if sessionId == "" {
821
- c.JSON(http.StatusBadRequest, gin.H{"error": "sessionId is required"})
822
- return
823
- }
824
-
825
- // Định nghĩa kiểu dữ liệu cho request body
826
- var trackInfo struct {
827
- SessionDescription struct {
828
- Type string `json:"type"`
829
- SDP string `json:"sdp"`
830
- } `json:"sessionDescription,omitempty"`
831
- Tracks []struct {
832
- Location string `json:"location"`
833
- SessionId string `json:"sessionId,omitempty"`
834
- Mid string `json:"mid"`
835
- TrackName string `json:"trackName"`
836
- } `json:"tracks"`
837
- }
838
-
839
- // Xử lý ràng buộc JSON
840
- if err := c.ShouldBindJSON(&trackInfo); err != nil {
841
- c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
842
- return
843
- }
844
- fmt.Println("Received TrackInfo:", trackInfo)
845
-
846
- // Xây dựng danh sách các track cho API Cloudflare
847
- var tracks []map[string]interface{}
848
- for _, track := range trackInfo.Tracks {
849
- trackData := map[string]interface{}{
850
- "location": track.Location,
851
- "mid": track.Mid,
852
- "trackName": track.TrackName,
853
- }
854
- tracks = append(tracks, trackData)
855
- }
856
- fmt.Println("Prepared Tracks for Cloudflare:", tracks)
857
-
858
- // Tạo yêu cầu gửi lên API Cloudflare
859
- body := map[string]interface{}{
860
- "sessionDescription": map[string]interface{}{
861
- "type": trackInfo.SessionDescription.Type,
862
- "sdp": trackInfo.SessionDescription.SDP,
863
- },
864
- "tracks": tracks,
865
- }
866
-
867
- url := fmt.Sprintf("%s/apps/%s/sessions/%s/tracks/new", cloudflareAPIBase, appId, sessionId)
868
- respBody, err := sendRequest(url, "POST", body)
869
- if err != nil {
870
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error adding track: %v", err)})
871
- return
872
- }
873
- //fmt.Println("Cloudflare API Response:", string(respBody))
874
-
875
- // Gửi kết quả trả về client
876
- c.Data(http.StatusOK, "application/json", respBody)
877
- }
878
-
879
- func getTrack(c *gin.Context) {
880
- handleCORS(c)
881
-
882
- // Lấy sessionId từ query
883
- sessionId := c.DefaultQuery("sessionId", "")
884
- if sessionId == "" {
885
- c.JSON(http.StatusBadRequest, gin.H{"error": "sessionId is required"})
886
- return
887
- }
888
- var requestData struct {
889
- SessionID string `json:"session_id"`
890
- Type string `json:"type"`
891
- }
892
- if err := c.ShouldBindJSON(&requestData); err != nil {
893
- c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
894
- return
895
- }
896
- peerSessionID := requestData.SessionID
897
- reqType := requestData.Type
898
- var trackObjects []map[string]string
899
-
900
- if reqType == "normal" {
901
- // Xử lý kiểu normal: truy xuất từ map users
902
- user, exists := users[peerSessionID]
903
- if !exists {
904
- c.JSON(http.StatusNotFound, gin.H{
905
- "error": fmt.Sprintf("User not found: %s", peerSessionID),
906
- })
907
- return
908
- }
909
-
910
- trackObjects = []map[string]string{
911
- {
912
- "location": "remote",
913
- "sessionId": user.ID,
914
- "trackName": user.Track0,
915
- },
916
- {
917
- "location": "remote",
918
- "sessionId": user.ID,
919
- "trackName": user.Track1,
920
- },
921
- }
922
- } else if reqType == "screen" {
923
- // Xử lý kiểu screen: truy xuất từ map userShares
924
- userShare, exists := userShares[peerSessionID]
925
- if !exists {
926
- c.JSON(http.StatusNotFound, gin.H{
927
- "error": fmt.Sprintf("UserShare not found: %s", peerSessionID),
928
- })
929
- return
930
- }
931
-
932
- trackObjects = []map[string]string{
933
- {
934
- "location": "remote",
935
- "sessionId": userShare.ID,
936
- "trackName": userShare.Track0,
937
- },
938
- {
939
- "location": "remote",
940
- "sessionId": userShare.ID,
941
- "trackName": userShare.Track1,
942
- },
943
- }
944
- } else {
945
- c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid type provided; expected 'normal' or 'screen'"})
946
- return
947
- }
948
- body := map[string]interface{}{
949
- "tracks": trackObjects,
950
- }
951
- url := fmt.Sprintf("%s/apps/%s/sessions/%s/tracks/new", cloudflareAPIBase, appId, sessionId)
952
- respBody, err := sendRequest(url, "POST", body)
953
- if err != nil {
954
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error adding track: %v", err)})
955
- return
956
- }
957
- //fmt.Println("Cloudflare API Response:", string(respBody))
958
-
959
- // Gửi kết quả trả về client
960
- c.Data(http.StatusOK, "application/json", respBody)
961
-
962
- }
963
-
964
- // -----------------------------
965
- func renegotiateSession(c *gin.Context) {
966
- // Xử lý CORS
967
- handleCORS(c)
968
-
969
- sessionId := c.DefaultQuery("sessionId", "")
970
-
971
- var answerSDP struct {
972
- SDP string `json:"sdp"`
973
- }
974
- if err := c.ShouldBindJSON(&answerSDP); err != nil {
975
- c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
976
- return
977
- }
978
-
979
- // Tạo body gửi lên Cloudflare API
980
- body := map[string]interface{}{
981
- "sessionDescription": map[string]interface{}{
982
- "type": "answer",
983
- "sdp": answerSDP.SDP,
984
- },
985
- }
986
-
987
- // Gửi yêu cầu đàm phán lại session
988
- url := fmt.Sprintf("%s/apps/%s/sessions/%s/renegotiate", cloudflareAPIBase, appId, sessionId)
989
- respBody, err := sendRequest(url, "PUT", body)
990
- if err != nil {
991
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error renegotiating session: %v", err)})
992
- return
993
- }
994
-
995
- // Gửi kết quả trả về từ Cloudflare về client
996
- c.Data(http.StatusOK, "application/json", respBody)
997
- }
998
-
999
- // ----------------------------
1000
- func getSessionId(c *gin.Context) {
1001
- handleCORS(c)
1002
- sessionId := c.DefaultQuery("sessionId", "")
1003
- url := fmt.Sprintf("%s/apps/%s/sessions/%s", cloudflareAPIBase, appId, sessionId)
1004
- const body = ""
1005
- respBody, err := sendRequest(url, "GET", body)
1006
- if err != nil {
1007
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error renegotiating session: %v", err)})
1008
- return
1009
- }
1010
-
1011
- // Gửi kết quả trả về từ Cloudflare về client
1012
- c.Data(http.StatusOK, "application/json", respBody)
1013
- }
1014
-
1015
- func leaveRoom(c *gin.Context) {
1016
- handleCORS(c)
1017
-
1018
- // Retrieve user ID and room ID
1019
- userID := c.Query("user_id")
1020
- roomID := c.Query("room_id")
1021
-
1022
- if userID == "" || roomID == "" {
1023
- c.JSON(http.StatusBadRequest, gin.H{"error": "user_id and room_id are required"})
1024
- return
1025
- }
1026
-
1027
- // Remove user from room
1028
- usersInRoom, exists := rooms[roomID]
1029
- if !exists {
1030
- c.JSON(http.StatusNotFound, gin.H{"error": "Room not found"})
1031
- return
1032
- }
1033
-
1034
- for i, user := range usersInRoom {
1035
- if user.ID == userID {
1036
- rooms[roomID] = append(usersInRoom[:i], usersInRoom[i+1:]...)
1037
- break
1038
- }
1039
- }
1040
- if rc, exists := roomChats[roomID]; exists {
1041
- // Lọc bỏ các UserChat có AssociatedUserID trùng với userID
1042
- newRC := []UserChat{}
1043
- for _, chat := range rc {
1044
- if chat.AssociatedUserID != userID {
1045
- newRC = append(newRC, chat)
1046
- }
1047
- }
1048
- roomChats[roomID] = newRC
1049
- }
1050
-
1051
- // Notify remaining users in the room
1052
- for _, u := range rooms[roomID] {
1053
- if conn, ok := clients[u.ID]; ok {
1054
- notification := gin.H{
1055
- "type": "a-peer-left",
1056
- "message": "A peer has been left",
1057
- "userId": userID,
1058
- }
1059
- if err := conn.WriteJSON(notification); err != nil {
1060
- fmt.Println("Failed to notify user:", u.ID, err)
1061
- }
1062
-
1063
- }
1064
- for _, u := range rooms[roomID] {
1065
- if conn, ok := clients[u.ID]; ok {
1066
- notification := gin.H{
1067
- "type": "count_partis",
1068
- "message": "Number of member of the room",
1069
- "count": countUsersInRoom(roomID),
1070
- }
1071
- if err := conn.WriteJSON(notification); err != nil {
1072
- fmt.Println("Failed to notify user:", u.ID, err)
1073
- }
1074
- }
1075
- }
1076
- }
1077
-
1078
- c.JSON(http.StatusOK, gin.H{"message": "User left the room successfully"})
1079
- }
1080
- func main() {
1081
- r := gin.Default()
1082
- r.Use(handleCORS)
1083
- fmt.Println("Cloudflare API Base:", cloudflareAPIBase)
1084
- fmt.Println("App ID:", appId)
1085
-
1086
- // Tạo Phòng và lắng nghe smrtract
1087
- client, err := ethclient.Dial(RPC_URL)
1088
- if err != nil {
1089
- log.Fatalf("Không thể kết nối đến BSC Testnet: %v", err)
1090
- }
1091
- fmt.Println("Đã kết nối đến BSC Testnet!")
1092
-
1093
- contractAddress := common.HexToAddress(CONTRACT_ADDRESS)
1094
- query := ethereum.FilterQuery{
1095
- Addresses: []common.Address{contractAddress},
1096
- }
1097
-
1098
- contractAbi, err := abi.JSON(strings.NewReader(ABI_JSON))
1099
- if err != nil {
1100
- log.Fatalf("Không thể phân tích ABI: %v", err)
1101
- }
1102
-
1103
- logs := make(chan types.Log)
1104
- sub, err := client.SubscribeFilterLogs(context.Background(), query, logs)
1105
- fmt.Println("Đã kết nối đến BSC Testnet!", sub)
1106
- if err != nil {
1107
- log.Fatalf("Không thể đăng ký lắng nghe sự kiện: %v", err)
1108
- }
1109
- fmt.Println("Đang lắng nghe sự kiện RoomCreated...")
1110
-
1111
- go func() {
1112
- for eventLog := range logs {
1113
- event := new(RoomCreatedEvent)
1114
- if err := contractAbi.UnpackIntoInterface(event, "RoomCreated", eventLog.Data); err != nil {
1115
- log.Printf("Lỗi giải mã sự kiện: %v", err)
1116
- continue
1117
- }
1118
- fmt.Printf("Sự kiện RoomCreated: RoomId=%s, Name=%s, Owner=%s\n", event.RoomId, event.Name, event.Owner.Hex())
1119
- }
1120
- }()
1121
- // sub.Unsubscribe()
1122
-
1123
- r.POST("/sessions/new", createSession)
1124
- r.POST("/sessions/tracks/new", addTrack)
1125
- r.POST("/sessions/tracks/getNew", getTrack)
1126
- r.PUT("/sessions/renegotiate", renegotiateSession)
1127
- r.GET("/sessions/sessionId", getSessionId)
1128
- r.GET("/sessions/TestCloseTrack", leaveRoom)
1129
- // Route kiểm tra server
1130
- r.GET("/", func(c *gin.Context) {
1131
- fmt.Println("Đã kết nối đến server:")
1132
- c.JSON(200, gin.H{"message": "Server is running!"})
1133
- })
1134
- r.Run(":8080")
1135
- }