1 module soup.WebsocketConnection; 2 3 private import gio.IOStream; 4 private import glib.Bytes; 5 private import glib.ConstructionException; 6 private import glib.ErrorG; 7 private import glib.ListG; 8 private import glib.Str; 9 private import gobject.ObjectG; 10 private import gobject.Signals; 11 private import soup.URI; 12 private import soup.WebsocketExtension; 13 private import soup.c.functions; 14 public import soup.c.types; 15 private import std.algorithm; 16 17 18 /** 19 * A class representing a WebSocket connection. 20 * 21 * Since: 2.50 22 */ 23 public class WebsocketConnection : ObjectG 24 { 25 /** the main Gtk struct */ 26 protected SoupWebsocketConnection* soupWebsocketConnection; 27 28 /** Get the main Gtk struct */ 29 public SoupWebsocketConnection* getWebsocketConnectionStruct(bool transferOwnership = false) 30 { 31 if (transferOwnership) 32 ownedRef = false; 33 return soupWebsocketConnection; 34 } 35 36 /** the main Gtk struct as a void* */ 37 protected override void* getStruct() 38 { 39 return cast(void*)soupWebsocketConnection; 40 } 41 42 /** 43 * Sets our main struct and passes it to the parent class. 44 */ 45 public this (SoupWebsocketConnection* soupWebsocketConnection, bool ownedRef = false) 46 { 47 this.soupWebsocketConnection = soupWebsocketConnection; 48 super(cast(GObject*)soupWebsocketConnection, ownedRef); 49 } 50 51 52 /** */ 53 public static GType getType() 54 { 55 return soup_websocket_connection_get_type(); 56 } 57 58 /** 59 * Creates a #SoupWebsocketConnection on @stream. This should be 60 * called after completing the handshake to begin using the WebSocket 61 * protocol. 62 * 63 * Params: 64 * stream = a #GIOStream connected to the WebSocket server 65 * uri = the URI of the connection 66 * type = the type of connection (client/side) 67 * origin = the Origin of the client 68 * protocol = the subprotocol in use 69 * 70 * Returns: a new #SoupWebsocketConnection 71 * 72 * Since: 2.50 73 * 74 * Throws: ConstructionException GTK+ fails to create the object. 75 */ 76 public this(IOStream stream, URI uri, SoupWebsocketConnectionType type, string origin, string protocol) 77 { 78 auto __p = soup_websocket_connection_new((stream is null) ? null : stream.getIOStreamStruct(), (uri is null) ? null : uri.getURIStruct(), type, Str.toStringz(origin), Str.toStringz(protocol)); 79 80 if(__p is null) 81 { 82 throw new ConstructionException("null returned by new"); 83 } 84 85 this(cast(SoupWebsocketConnection*) __p, true); 86 } 87 88 /** 89 * Creates a #SoupWebsocketConnection on @stream with the given active @extensions. 90 * This should be called after completing the handshake to begin using the WebSocket 91 * protocol. 92 * 93 * Params: 94 * stream = a #GIOStream connected to the WebSocket server 95 * uri = the URI of the connection 96 * type = the type of connection (client/side) 97 * origin = the Origin of the client 98 * protocol = the subprotocol in use 99 * extensions = a #GList of #SoupWebsocketExtension objects 100 * 101 * Returns: a new #SoupWebsocketConnection 102 * 103 * Since: 2.68 104 * 105 * Throws: ConstructionException GTK+ fails to create the object. 106 */ 107 public this(IOStream stream, URI uri, SoupWebsocketConnectionType type, string origin, string protocol, ListG extensions) 108 { 109 auto __p = soup_websocket_connection_new_with_extensions((stream is null) ? null : stream.getIOStreamStruct(), (uri is null) ? null : uri.getURIStruct(), type, Str.toStringz(origin), Str.toStringz(protocol), (extensions is null) ? null : extensions.getListGStruct()); 110 111 if(__p is null) 112 { 113 throw new ConstructionException("null returned by new_with_extensions"); 114 } 115 116 this(cast(SoupWebsocketConnection*) __p, true); 117 } 118 119 /** 120 * Close the connection in an orderly fashion. 121 * 122 * Note that until the #SoupWebsocketConnection::closed signal fires, the connection 123 * is not yet completely closed. The close message is not even sent until the 124 * main loop runs. 125 * 126 * The @code and @data are sent to the peer along with the close request. 127 * If @code is %SOUP_WEBSOCKET_CLOSE_NO_STATUS a close message with no body 128 * (without code and data) is sent. 129 * Note that the @data must be UTF-8 valid. 130 * 131 * Params: 132 * code = close code 133 * data = close data 134 * 135 * Since: 2.50 136 */ 137 public void close(ushort code, string data) 138 { 139 soup_websocket_connection_close(soupWebsocketConnection, code, Str.toStringz(data)); 140 } 141 142 /** 143 * Get the close code received from the WebSocket peer. 144 * 145 * This only becomes valid once the WebSocket is in the 146 * %SOUP_WEBSOCKET_STATE_CLOSED state. The value will often be in the 147 * #SoupWebsocketCloseCode enumeration, but may also be an application 148 * defined close code. 149 * 150 * Returns: the close code or zero. 151 * 152 * Since: 2.50 153 */ 154 public ushort getCloseCode() 155 { 156 return soup_websocket_connection_get_close_code(soupWebsocketConnection); 157 } 158 159 /** 160 * Get the close data received from the WebSocket peer. 161 * 162 * This only becomes valid once the WebSocket is in the 163 * %SOUP_WEBSOCKET_STATE_CLOSED state. The data may be freed once 164 * the main loop is run, so copy it if you need to keep it around. 165 * 166 * Returns: the close data or %NULL 167 * 168 * Since: 2.50 169 */ 170 public string getCloseData() 171 { 172 return Str.toString(soup_websocket_connection_get_close_data(soupWebsocketConnection)); 173 } 174 175 /** 176 * Get the connection type (client/server) of the connection. 177 * 178 * Returns: the connection type 179 * 180 * Since: 2.50 181 */ 182 public SoupWebsocketConnectionType getConnectionType() 183 { 184 return soup_websocket_connection_get_connection_type(soupWebsocketConnection); 185 } 186 187 /** 188 * Get the extensions chosen via negotiation with the peer. 189 * 190 * Returns: a #GList of #SoupWebsocketExtension objects 191 * 192 * Since: 2.68 193 */ 194 public ListG getExtensions() 195 { 196 auto __p = soup_websocket_connection_get_extensions(soupWebsocketConnection); 197 198 if(__p is null) 199 { 200 return null; 201 } 202 203 return new ListG(cast(GList*) __p); 204 } 205 206 /** 207 * Get the I/O stream the WebSocket is communicating over. 208 * 209 * Returns: the WebSocket's I/O stream. 210 * 211 * Since: 2.50 212 */ 213 public IOStream getIoStream() 214 { 215 auto __p = soup_websocket_connection_get_io_stream(soupWebsocketConnection); 216 217 if(__p is null) 218 { 219 return null; 220 } 221 222 return ObjectG.getDObject!(IOStream)(cast(GIOStream*) __p); 223 } 224 225 /** 226 * Gets the keepalive interval in seconds or 0 if disabled. 227 * 228 * Returns: the keepalive interval. 229 * 230 * Since: 2.58 231 */ 232 public uint getKeepaliveInterval() 233 { 234 return soup_websocket_connection_get_keepalive_interval(soupWebsocketConnection); 235 } 236 237 /** 238 * Gets the maximum payload size allowed for incoming packets. 239 * 240 * Returns: the maximum payload size. 241 * 242 * Since: 2.56 243 */ 244 public ulong getMaxIncomingPayloadSize() 245 { 246 return soup_websocket_connection_get_max_incoming_payload_size(soupWebsocketConnection); 247 } 248 249 /** 250 * Get the origin of the WebSocket. 251 * 252 * Returns: the origin, or %NULL 253 * 254 * Since: 2.50 255 */ 256 public string getOrigin() 257 { 258 return Str.toString(soup_websocket_connection_get_origin(soupWebsocketConnection)); 259 } 260 261 /** 262 * Get the protocol chosen via negotiation with the peer. 263 * 264 * Returns: the chosen protocol, or %NULL 265 * 266 * Since: 2.50 267 */ 268 public string getProtocol() 269 { 270 return Str.toString(soup_websocket_connection_get_protocol(soupWebsocketConnection)); 271 } 272 273 /** 274 * Get the current state of the WebSocket. 275 * 276 * Returns: the state 277 * 278 * Since: 2.50 279 */ 280 public SoupWebsocketState getState() 281 { 282 return soup_websocket_connection_get_state(soupWebsocketConnection); 283 } 284 285 /** 286 * Get the URI of the WebSocket. 287 * 288 * For servers this represents the address of the WebSocket, and 289 * for clients it is the address connected to. 290 * 291 * Returns: the URI 292 * 293 * Since: 2.50 294 */ 295 public URI getUri() 296 { 297 auto __p = soup_websocket_connection_get_uri(soupWebsocketConnection); 298 299 if(__p is null) 300 { 301 return null; 302 } 303 304 return ObjectG.getDObject!(URI)(cast(SoupURI*) __p); 305 } 306 307 /** 308 * Send a binary message to the peer. If @length is 0, @data may be %NULL. 309 * 310 * The message is queued to be sent and will be sent when the main loop 311 * is run. 312 * 313 * Params: 314 * data = the message contents 315 * 316 * Since: 2.50 317 */ 318 public void sendBinary(ubyte[] data) 319 { 320 soup_websocket_connection_send_binary(soupWebsocketConnection, data.ptr, cast(size_t)data.length); 321 } 322 323 /** 324 * Send a message of the given @type to the peer. Note that this method, 325 * allows to send text messages containing %NULL characters. 326 * 327 * The message is queued to be sent and will be sent when the main loop 328 * is run. 329 * 330 * Params: 331 * type = the type of message contents 332 * message = the message data as #GBytes 333 * 334 * Since: 2.68 335 */ 336 public void sendMessage(SoupWebsocketDataType type, Bytes message) 337 { 338 soup_websocket_connection_send_message(soupWebsocketConnection, type, (message is null) ? null : message.getBytesStruct()); 339 } 340 341 /** 342 * Send a %NULL-terminated text (UTF-8) message to the peer. If you need 343 * to send text messages containing %NULL characters use 344 * soup_websocket_connection_send_message() instead. 345 * 346 * The message is queued to be sent and will be sent when the main loop 347 * is run. 348 * 349 * Params: 350 * text = the message contents 351 * 352 * Since: 2.50 353 */ 354 public void sendText(string text) 355 { 356 soup_websocket_connection_send_text(soupWebsocketConnection, Str.toStringz(text)); 357 } 358 359 /** 360 * Sets the interval in seconds on when to send a ping message which will serve 361 * as a keepalive message. If set to 0 the keepalive message is disabled. 362 * 363 * Params: 364 * interval = the interval to send a ping message or 0 to disable it 365 * 366 * Since: 2.58 367 */ 368 public void setKeepaliveInterval(uint interval) 369 { 370 soup_websocket_connection_set_keepalive_interval(soupWebsocketConnection, interval); 371 } 372 373 /** 374 * Sets the maximum payload size allowed for incoming packets. It 375 * does not limit the outgoing packet size. 376 * 377 * Params: 378 * maxIncomingPayloadSize = the maximum payload size 379 * 380 * Since: 2.56 381 */ 382 public void setMaxIncomingPayloadSize(ulong maxIncomingPayloadSize) 383 { 384 soup_websocket_connection_set_max_incoming_payload_size(soupWebsocketConnection, maxIncomingPayloadSize); 385 } 386 387 /** 388 * Emitted when the connection has completely closed, either 389 * due to an orderly close from the peer, one initiated via 390 * soup_websocket_connection_close() or a fatal error 391 * condition that caused a close. 392 * 393 * This signal will be emitted once. 394 * 395 * Since: 2.50 396 */ 397 gulong addOnClosed(void delegate(WebsocketConnection) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 398 { 399 return Signals.connect(this, "closed", dlg, connectFlags ^ ConnectFlags.SWAPPED); 400 } 401 402 /** 403 * This signal will be emitted during an orderly close. 404 * 405 * Since: 2.50 406 */ 407 gulong addOnClosing(void delegate(WebsocketConnection) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 408 { 409 return Signals.connect(this, "closing", dlg, connectFlags ^ ConnectFlags.SWAPPED); 410 } 411 412 /** 413 * Emitted when an error occurred on the WebSocket. This may 414 * be fired multiple times. Fatal errors will be followed by 415 * the #SoupWebsocketConnection::closed signal being emitted. 416 * 417 * Params: 418 * error = the error that occured 419 * 420 * Since: 2.50 421 */ 422 gulong addOnError(void delegate(ErrorG, WebsocketConnection) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 423 { 424 return Signals.connect(this, "error", dlg, connectFlags ^ ConnectFlags.SWAPPED); 425 } 426 427 /** 428 * Emitted when we receive a message from the peer. 429 * 430 * As a convenience, the @message data will always be 431 * NUL-terminated, but the NUL byte will not be included in 432 * the length count. 433 * 434 * Params: 435 * type = the type of message contents 436 * message = the message data 437 * 438 * Since: 2.50 439 */ 440 gulong addOnMessage(void delegate(int, Bytes, WebsocketConnection) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 441 { 442 return Signals.connect(this, "message", dlg, connectFlags ^ ConnectFlags.SWAPPED); 443 } 444 445 /** 446 * Emitted when we receive a Pong frame (solicited or 447 * unsolicited) from the peer. 448 * 449 * As a convenience, the @message data will always be 450 * NUL-terminated, but the NUL byte will not be included in 451 * the length count. 452 * 453 * Params: 454 * message = the application data (if any) 455 * 456 * Since: 2.60 457 */ 458 gulong addOnPong(void delegate(Bytes, WebsocketConnection) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 459 { 460 return Signals.connect(this, "pong", dlg, connectFlags ^ ConnectFlags.SWAPPED); 461 } 462 }