-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebsocket.go
More file actions
119 lines (98 loc) · 3.39 KB
/
websocket.go
File metadata and controls
119 lines (98 loc) · 3.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"github.com/gorilla/websocket"
)
func RunWebSocketExample() {
fmt.Println("Connecting to tx-indexer WebSocket...")
// Build WebSocket URL - replace localhost:8546 with your indexer's address
u := url.URL{Scheme: "ws", Host: "localhost:8546", Path: "/graphql/query"}
// Establish WebSocket connection with GraphQL-WS protocol
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("WebSocket connection failed:", err)
}
defer conn.Close() // Clean up connection when function exits
fmt.Println("Connected! Initializing GraphQL-WS connection...")
// Step 1: Send connection_init message
// GraphQL-WS protocol requires this handshake before subscriptions
initMsg := map[string]interface{}{
"type": "connection_init",
}
initBytes, _ := json.Marshal(initMsg)
conn.WriteMessage(websocket.TextMessage, initBytes)
// Step 2: Wait for connection_ack from server
// Server must acknowledge our connection before we can subscribe
_, ackMessage, err := conn.ReadMessage()
if err != nil {
log.Fatal("Failed to receive connection ack:", err)
}
var ackResponse map[string]interface{}
json.Unmarshal(ackMessage, &ackResponse)
// Verify server sent the correct acknowledgment
if ackResponse["type"] != "connection_ack" {
log.Fatalf("Expected connection_ack, got: %+v", ackResponse)
}
fmt.Println("Connection acknowledged! Setting up subscription...")
// Step 3: Send subscription message
// This give the query to the server
subscription := map[string]interface{}{
"id": "1", // Unique ID for this subscription
"type": "start", // GraphQL-WS message type for subscriptions
"payload": map[string]interface{}{
"query": `subscription { ... }`, // Your GraphQL subscription here
},
}
subscriptionBytes, _ := json.Marshal(subscription)
conn.WriteMessage(websocket.TextMessage, subscriptionBytes)
fmt.Println("Listening for new send transactions...")
// Step 4: Listen for incoming messages in an infinite loop
for {
// Read next message from WebSocket
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
continue
}
// Parse JSON message from server
var response map[string]interface{}
err = json.Unmarshal(message, &response)
if err != nil {
log.Printf("JSON parse error: %v\n", err)
continue
}
// Handle different message types from GraphQL-WS protocol
switch response["type"] {
case "data":
// New transaction data received!
// Extract payload and process transaction data
data := response["payload"]
dataBytes, _ := json.Marshal(data)
parsedData, err := parseTransactions(dataBytes)
if err != nil {
log.Printf("Error parsing transactions: %v", err)
continue
}
displayTransactions(parsedData) // Show formatted transaction details
case "error":
// GraphQL query/subscription error
fmt.Printf("GraphQL error: %+v\n", response["payload"])
case "complete":
// Subscription finished
fmt.Println("Subscription completed")
case "connection_error":
// WebSocket connection issue
fmt.Printf("Connection error: %+v\n", response["payload"])
case "ka":
// Keep-alive message from server - ignore silently
// Server sends these periodically to prevent connection timeouts
continue
default:
// Unknown message type
fmt.Printf("Unknown message type: %s\n", response["type"])
}
}
}