yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
emscripten_websocket.cc
Go to the documentation of this file.
1#ifdef __EMSCRIPTEN__
2
4
5#include <cstring>
6
7namespace yaze {
8namespace net {
9
10EmscriptenWebSocket::EmscriptenWebSocket()
11 : socket_(0), socket_valid_(false) {
12 state_ = WebSocketState::kDisconnected;
13}
14
15EmscriptenWebSocket::~EmscriptenWebSocket() {
16 if (socket_valid_ && state_ != WebSocketState::kDisconnected) {
17 Close();
18 }
19}
20
21EM_BOOL EmscriptenWebSocket::OnOpenCallback(
22 int eventType,
23 const EmscriptenWebSocketOpenEvent* websocketEvent,
24 void* userData) {
25
26 EmscriptenWebSocket* self = static_cast<EmscriptenWebSocket*>(userData);
27
28 self->state_ = WebSocketState::kConnected;
29
30 if (self->open_callback_) {
31 self->open_callback_();
32 }
33
34 return EM_TRUE;
35}
36
37EM_BOOL EmscriptenWebSocket::OnCloseCallback(
38 int eventType,
39 const EmscriptenWebSocketCloseEvent* websocketEvent,
40 void* userData) {
41
42 EmscriptenWebSocket* self = static_cast<EmscriptenWebSocket*>(userData);
43
44 self->state_ = WebSocketState::kClosed;
45 self->socket_valid_ = false;
46
47 if (self->close_callback_) {
48 self->close_callback_(websocketEvent->code,
49 websocketEvent->reason ? websocketEvent->reason : "");
50 }
51
52 self->state_ = WebSocketState::kDisconnected;
53
54 return EM_TRUE;
55}
56
57EM_BOOL EmscriptenWebSocket::OnErrorCallback(
58 int eventType,
59 const EmscriptenWebSocketErrorEvent* websocketEvent,
60 void* userData) {
61
62 EmscriptenWebSocket* self = static_cast<EmscriptenWebSocket*>(userData);
63
64 self->state_ = WebSocketState::kError;
65
66 if (self->error_callback_) {
67 self->error_callback_("WebSocket error occurred");
68 }
69
70 return EM_TRUE;
71}
72
73EM_BOOL EmscriptenWebSocket::OnMessageCallback(
74 int eventType,
75 const EmscriptenWebSocketMessageEvent* websocketEvent,
76 void* userData) {
77
78 EmscriptenWebSocket* self = static_cast<EmscriptenWebSocket*>(userData);
79
80 if (websocketEvent->isText) {
81 // Text message
82 if (self->message_callback_) {
83 // Convert UTF-8 data to string
84 std::string message(reinterpret_cast<const char*>(websocketEvent->data),
85 websocketEvent->numBytes);
86 self->message_callback_(message);
87 }
88 } else {
89 // Binary message
90 if (self->binary_message_callback_) {
91 self->binary_message_callback_(websocketEvent->data,
92 websocketEvent->numBytes);
93 }
94 }
95
96 return EM_TRUE;
97}
98
99absl::Status EmscriptenWebSocket::Connect(const std::string& url) {
100 if (state_ != WebSocketState::kDisconnected) {
101 return absl::FailedPreconditionError(
102 "WebSocket already connected or connecting");
103 }
104
105 state_ = WebSocketState::kConnecting;
106 url_ = url;
107
108 // Create WebSocket attributes
109 EmscriptenWebSocketCreateAttributes attrs = {
110 url.c_str(),
111 nullptr, // protocols (NULL = default)
112 EM_TRUE // createOnMainThread
113 };
114
115 // Create the WebSocket
116 socket_ = emscripten_websocket_new(&attrs);
117
118 if (socket_ <= 0) {
119 state_ = WebSocketState::kError;
120 return absl::InternalError("Failed to create WebSocket");
121 }
122
123 socket_valid_ = true;
124
125 // Set callbacks
126 EMSCRIPTEN_RESULT result;
127
128 result = emscripten_websocket_set_onopen_callback(
129 socket_, this, OnOpenCallback);
130 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
131 state_ = WebSocketState::kError;
132 socket_valid_ = false;
133 return absl::InternalError("Failed to set onopen callback");
134 }
135
136 result = emscripten_websocket_set_onclose_callback(
137 socket_, this, OnCloseCallback);
138 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
139 state_ = WebSocketState::kError;
140 socket_valid_ = false;
141 return absl::InternalError("Failed to set onclose callback");
142 }
143
144 result = emscripten_websocket_set_onerror_callback(
145 socket_, this, OnErrorCallback);
146 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
147 state_ = WebSocketState::kError;
148 socket_valid_ = false;
149 return absl::InternalError("Failed to set onerror callback");
150 }
151
152 result = emscripten_websocket_set_onmessage_callback(
153 socket_, this, OnMessageCallback);
154 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
155 state_ = WebSocketState::kError;
156 socket_valid_ = false;
157 return absl::InternalError("Failed to set onmessage callback");
158 }
159
160 // Connection is asynchronous in the browser
161 // The OnOpenCallback will be called when connected
162
163 return absl::OkStatus();
164}
165
166absl::Status EmscriptenWebSocket::Send(const std::string& message) {
167 if (state_ != WebSocketState::kConnected || !socket_valid_) {
168 return absl::FailedPreconditionError("WebSocket not connected");
169 }
170
171 EMSCRIPTEN_RESULT result = emscripten_websocket_send_utf8_text(
172 socket_, message.c_str());
173
174 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
175 return absl::InternalError("Failed to send text message");
176 }
177
178 return absl::OkStatus();
179}
180
181absl::Status EmscriptenWebSocket::SendBinary(const uint8_t* data,
182 size_t length) {
183 if (state_ != WebSocketState::kConnected || !socket_valid_) {
184 return absl::FailedPreconditionError("WebSocket not connected");
185 }
186
187 EMSCRIPTEN_RESULT result = emscripten_websocket_send_binary(
188 socket_, const_cast<void*>(static_cast<const void*>(data)), length);
189
190 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
191 return absl::InternalError("Failed to send binary message");
192 }
193
194 return absl::OkStatus();
195}
196
197absl::Status EmscriptenWebSocket::Close(int code, const std::string& reason) {
198 if (state_ == WebSocketState::kDisconnected ||
199 state_ == WebSocketState::kClosed ||
200 !socket_valid_) {
201 return absl::OkStatus();
202 }
203
204 state_ = WebSocketState::kClosing;
205
206 EMSCRIPTEN_RESULT result = emscripten_websocket_close(
207 socket_, code, reason.c_str());
208
209 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
210 // Force state to closed even if close fails
211 state_ = WebSocketState::kClosed;
212 socket_valid_ = false;
213 return absl::InternalError("Failed to close WebSocket");
214 }
215
216 // OnCloseCallback will be called when the close completes
217
218 return absl::OkStatus();
219}
220
221} // namespace net
222} // namespace yaze
223
224#endif // __EMSCRIPTEN__