Tanoda
WebSocket.cs
Go to the documentation of this file.
1/*
2 * unity-websocket-webgl
3 *
4 * @author Jiri Hybek <jiri@hybek.cz>
5 * @copyright 2018 Jiri Hybek <jiri@hybek.cz>
6 * @license Apache 2.0 - See LICENSE file distributed with this source code.
7 */
8
9using System;
10using System.Collections.Generic;
11using System.Text;
12using System.Runtime.InteropServices;
13using UnityEngine;
14using AOT;
15
17{
18
22 public delegate void WebSocketOpenEventHandler();
23
27 public delegate void WebSocketMessageEventHandler(byte[] data);
28
32 public delegate void WebSocketErrorEventHandler(string errorMsg);
33
37 public delegate void WebSocketCloseEventHandler(WebSocketCloseCode closeCode);
38
42 public enum WebSocketState
43 {
45 Open,
46 Closing,
47 Closed
48 }
49
54 {
55 /* Do NOT use NotSet - it's only purpose is to indicate that the close code cannot be parsed. */
56 NotSet = 0,
57 Normal = 1000,
58 Away = 1001,
59 ProtocolError = 1002,
60 UnsupportedData = 1003,
61 Undefined = 1004,
62 NoStatus = 1005,
63 Abnormal = 1006,
64 InvalidData = 1007,
65 PolicyViolation = 1008,
66 TooBig = 1009,
67 MandatoryExtension = 1010,
68 ServerError = 1011,
70 }
71
75 public interface IWebSocket
76 {
80 void Connect();
81
87 void Close(WebSocketCloseCode code = WebSocketCloseCode.Normal, string reason = null);
88
93 void Send(byte[] data);
94
100
105
110
115
120 }
121
125 public static class WebSocketHelpers
126 {
127
133 public static WebSocketCloseCode ParseCloseCodeEnum(int closeCode)
134 {
135
136 if (WebSocketCloseCode.IsDefined(typeof(WebSocketCloseCode), closeCode))
137 {
138 return (WebSocketCloseCode)closeCode;
139 }
140 else
141 {
142 return WebSocketCloseCode.Undefined;
143 }
144
145 }
146
147 /*
148 * Return error message based on int code
149 *
150
151 */
160 public static WebSocketException GetErrorMessageFromCode(int errorCode, Exception inner)
161 {
162
163 switch(errorCode)
164 {
165
166 case -1: return new WebSocketUnexpectedException("WebSocket instance not found.", inner);
167 case -2: return new WebSocketInvalidStateException("WebSocket is already connected or in connecting state.", inner);
168 case -3: return new WebSocketInvalidStateException("WebSocket is not connected.", inner);
169 case -4: return new WebSocketInvalidStateException("WebSocket is already closing.", inner);
170 case -5: return new WebSocketInvalidStateException("WebSocket is already closed.", inner);
171 case -6: return new WebSocketInvalidStateException("WebSocket is not in open state.", inner);
172 case -7: return new WebSocketInvalidArgumentException("Cannot close WebSocket. An invalid code was specified or reason is too long.", inner);
173 default: return new WebSocketUnexpectedException("Unknown error.", inner);
174
175 }
176
177 }
178
179 }
180
184 public class WebSocketException : Exception
185 {
186
188 {
189 }
190
191 public WebSocketException(string message)
192 : base(message)
193 {
194 }
195
196 public WebSocketException(string message, Exception inner)
197 : base(message, inner)
198 {
199 }
200
201 }
202
207 {
209 public WebSocketUnexpectedException(string message) : base(message){}
210 public WebSocketUnexpectedException(string message, Exception inner) : base(message, inner) {}
211 }
212
217 {
219 public WebSocketInvalidArgumentException(string message) : base(message) { }
220 public WebSocketInvalidArgumentException(string message, Exception inner) : base(message, inner) { }
221 }
222
227 {
229 public WebSocketInvalidStateException(string message) : base(message) { }
230 public WebSocketInvalidStateException(string message, Exception inner) : base(message, inner) { }
231 }
232
233#if UNITY_WEBGL && !UNITY_EDITOR
237 public class WebSocket: IWebSocket
238 {
239
240 /* WebSocket JSLIB functions */
241 [DllImport("__Internal")]
242 public static extern int WebSocketConnect(int instanceId);
243
244 [DllImport("__Internal")]
245 public static extern int WebSocketClose(int instanceId, int code, string reason);
246
247 [DllImport("__Internal")]
248 public static extern int WebSocketSend(int instanceId, byte[] dataPtr, int dataLength);
249
250 [DllImport("__Internal")]
251 public static extern int WebSocketGetState(int instanceId);
252
256 protected int instanceId;
257
262
267
272
277
282 public WebSocket(int instanceId)
283 {
284
285 this.instanceId = instanceId;
286
287 }
288
294 ~WebSocket()
295 {
296 WebSocketFactory.HandleInstanceDestroy(this.instanceId);
297 }
298
303 public int GetInstanceId()
304 {
305
306 return this.instanceId;
307
308 }
309
313 public void Connect()
314 {
315
316 int ret = WebSocketConnect(this.instanceId);
317
318 if (ret < 0)
319 throw WebSocketHelpers.GetErrorMessageFromCode(ret, null);
320
321 }
322
328 public void Close(WebSocketCloseCode code = WebSocketCloseCode.Normal, string reason = null)
329 {
330
331 int ret = WebSocketClose(this.instanceId, (int)code, reason);
332
333 if (ret < 0)
334 throw WebSocketHelpers.GetErrorMessageFromCode(ret, null);
335
336 }
337
342 public void Send(byte[] data)
343 {
344
345 int ret = WebSocketSend(this.instanceId, data, data.Length);
346
347 if (ret < 0)
348 throw WebSocketHelpers.GetErrorMessageFromCode(ret, null);
349
350 }
351
356 public void Send(string text)
357 {
358 var data = Encoding.UTF8.GetBytes(text);
359 int ret = WebSocketSend(this.instanceId, data, data.Length);
360
361 if (ret < 0)
362 throw WebSocketHelpers.GetErrorMessageFromCode(ret, null);
363
364 }
365
370 public WebSocketState GetState()
371 {
372
373 int state = WebSocketGetState(this.instanceId);
374
375 if (state < 0)
376 throw WebSocketHelpers.GetErrorMessageFromCode(state, null);
377
378 switch (state)
379 {
380 case 0:
381 return WebSocketState.Connecting;
382
383 case 1:
384 return WebSocketState.Open;
385
386 case 2:
387 return WebSocketState.Closing;
388
389 case 3:
390 return WebSocketState.Closed;
391
392 default:
393 return WebSocketState.Closed;
394 }
395
396 }
397
402 public void DelegateOnOpenEvent()
403 {
404 var onOnOpen = this.OnOpen;
405 if (onOnOpen != null) onOnOpen.Invoke();
406 }
407
413 public void DelegateOnMessageEvent(byte[] data)
414 {
415 var onOnMessage = this.OnMessage;
416 if (onOnMessage != null) onOnMessage.Invoke(data);
417 }
418
424 public void DelegateOnErrorEvent(string errorMsg)
425 {
426 var onOnError = this.OnError;
427 if (onOnError != null) onOnError.Invoke(errorMsg);
428 }
429
435 public void DelegateOnCloseEvent(int closeCode)
436 {
437 var onOnClose = this.OnClose;
438 if (onOnClose != null) onOnClose.Invoke(WebSocketHelpers.ParseCloseCodeEnum(closeCode));
439 }
440
441 }
442#else
443 public class WebSocket : IWebSocket
444 {
445
450
455
460
465
469 protected WebSocketSharp.WebSocket ws;
470
475 public WebSocket(string url)
476 {
477
478 try
479 {
480
481 // Create WebSocket instance
482 this.ws = new WebSocketSharp.WebSocket(url);
483
484 // Bind OnOpen event
485 this.ws.OnOpen += (sender, ev) =>
486 {
487 var onOnOpen = this.OnOpen;
488 if (onOnOpen != null) onOnOpen.Invoke();
489 };
490
491 // Bind OnMessage event
492 this.ws.OnMessage += (sender, ev) =>
493 {
494 if (ev.RawData != null)
495 {
496 var onOnMessage = this.OnMessage;
497 if (onOnMessage != null)
498 onOnMessage.Invoke(ev.RawData);
499 }
500 };
501
502 // Bind OnError event
503 this.ws.OnError += (sender, ev) =>
504 {
505 var onOnError = this.OnError;
506 if (onOnError != null) onOnError.Invoke(ev.Message);
507 };
508
509 // Bind OnClose event
510 this.ws.OnClose += (sender, ev) =>
511 {
512 var onOnClose = this.OnClose;
513 if (onOnClose != null)
514 onOnClose.Invoke(
515 WebSocketHelpers.ParseCloseCodeEnum((int) ev.Code)
516 );
517 };
518
519 }
520 catch (Exception e)
521 {
522
523 throw new WebSocketUnexpectedException("Failed to create WebSocket Client.", e);
524
525 }
526
527 }
528
532 public void Connect()
533 {
534
535 // Check state
536 if (this.ws.ReadyState == WebSocketSharp.WebSocketState.Open || this.ws.ReadyState == WebSocketSharp.WebSocketState.Closing)
537 throw new WebSocketInvalidStateException("WebSocket is already connected or is closing.");
538
539 try
540 {
541 this.ws.ConnectAsync();
542 }
543 catch (Exception e)
544 {
545 throw new WebSocketUnexpectedException("Failed to connect.", e);
546 }
547
548 }
549
555 public void Close(WebSocketCloseCode code = WebSocketCloseCode.Normal, string reason = null)
556 {
557
558 // Check state
559 if (this.ws.ReadyState == WebSocketSharp.WebSocketState.Closing)
560 throw new WebSocketInvalidStateException("WebSocket is already closing.");
561
562 if (this.ws.ReadyState == WebSocketSharp.WebSocketState.Closed)
563 throw new WebSocketInvalidStateException("WebSocket is already closed.");
564
565 try
566 {
567 this.ws.CloseAsync((ushort)code, reason);
568 }
569 catch (Exception e)
570 {
571 throw new WebSocketUnexpectedException("Failed to close the connection.", e);
572 }
573
574 }
575
580 public void Send(byte[] data)
581 {
582
583 // Check state
584 if (this.ws.ReadyState != WebSocketSharp.WebSocketState.Open)
585 throw new WebSocketInvalidStateException("WebSocket is not in open state.");
586
587 try
588 {
589 this.ws.Send(data);
590 }
591 catch (Exception e)
592 {
593 throw new WebSocketUnexpectedException("Failed to send message.", e);
594 }
595
596 }
597
602 public void Send(string data)
603 {
604
605 // Check state
606 if (this.ws.ReadyState != WebSocketSharp.WebSocketState.Open)
607 throw new WebSocketInvalidStateException("WebSocket is not in open state.");
608
609 try
610 {
611 this.ws.Send(data);
612 }
613 catch (Exception e)
614 {
615 throw new WebSocketUnexpectedException("Failed to send message.", e);
616 }
617
618 }
619
623 public bool Ping()
624 {
625
626 // Check state
627 if (this.ws.ReadyState != WebSocketSharp.WebSocketState.Open)
628 throw new WebSocketInvalidStateException("WebSocket is not in open state.");
629
630 try
631 {
632 return this.ws.Ping();
633 }
634 catch (Exception e)
635 {
636 throw new WebSocketUnexpectedException("Failed to ping.", e);
637 }
638 }
639
645 {
646
647 switch (this.ws.ReadyState)
648 {
649 case WebSocketSharp.WebSocketState.Connecting:
650 return WebSocketState.Connecting;
651
652 case WebSocketSharp.WebSocketState.Open:
653 return WebSocketState.Open;
654
655 case WebSocketSharp.WebSocketState.Closing:
656 return WebSocketState.Closing;
657
658 case WebSocketSharp.WebSocketState.Closed:
659 return WebSocketState.Closed;
660
661 default:
662 return WebSocketState.Closed;
663 }
664
665 }
666
667 }
668#endif
669
673 public static class WebSocketFactory
674 {
675
676#if UNITY_WEBGL && !UNITY_EDITOR
677 /* Map of websocket instances */
678 private static Dictionary<Int32, WebSocket> instances = new Dictionary<Int32, WebSocket>();
679
680 /* Delegates */
681 public delegate void OnOpenCallback(int instanceId);
682 public delegate void OnMessageCallback(int instanceId, System.IntPtr msgPtr, int msgSize);
683 public delegate void OnErrorCallback(int instanceId, System.IntPtr errorPtr);
684 public delegate void OnCloseCallback(int instanceId, int closeCode);
685
686 /* WebSocket JSLIB callback setters and other functions */
687 [DllImport("__Internal")]
688 public static extern int WebSocketAllocate(string url);
689
690 [DllImport("__Internal")]
691 public static extern void WebSocketFree(int instanceId);
692
693 [DllImport("__Internal")]
694 public static extern void WebSocketSetOnOpen(OnOpenCallback callback);
695
696 [DllImport("__Internal")]
697 public static extern void WebSocketSetOnMessage(OnMessageCallback callback);
698
699 [DllImport("__Internal")]
700 public static extern void WebSocketSetOnError(OnErrorCallback callback);
701
702 [DllImport("__Internal")]
703 public static extern void WebSocketSetOnClose(OnCloseCallback callback);
704
705 /* If callbacks was initialized and set */
706 private static bool isInitialized = false;
707
708 /*
709 * Initialize WebSocket callbacks to JSLIB
710 */
711 private static void Initialize()
712 {
713
714 WebSocketSetOnOpen(DelegateOnOpenEvent);
715 WebSocketSetOnMessage(DelegateOnMessageEvent);
716 WebSocketSetOnError(DelegateOnErrorEvent);
717 WebSocketSetOnClose(DelegateOnCloseEvent);
718
719 isInitialized = true;
720
721 }
722
728 public static void HandleInstanceDestroy(int instanceId)
729 {
730
731 instances.Remove(instanceId);
732 WebSocketFree(instanceId);
733
734 }
735
736 [MonoPInvokeCallback(typeof(OnOpenCallback))]
737 public static void DelegateOnOpenEvent(int instanceId)
738 {
739
740 WebSocket instanceRef;
741
742 if (instances.TryGetValue(instanceId, out instanceRef))
743 {
744 instanceRef.DelegateOnOpenEvent();
745 }
746
747 }
748
749 [MonoPInvokeCallback(typeof(OnMessageCallback))]
750 public static void DelegateOnMessageEvent(int instanceId, System.IntPtr msgPtr, int msgSize)
751 {
752
753 WebSocket instanceRef;
754
755 if (instances.TryGetValue(instanceId, out instanceRef))
756 {
757 byte[] msg = new byte[msgSize];
758 Marshal.Copy(msgPtr, msg, 0, msgSize);
759
760 instanceRef.DelegateOnMessageEvent(msg);
761 }
762
763 }
764
765 [MonoPInvokeCallback(typeof(OnErrorCallback))]
766 public static void DelegateOnErrorEvent(int instanceId, System.IntPtr errorPtr)
767 {
768
769 WebSocket instanceRef;
770
771 if (instances.TryGetValue(instanceId, out instanceRef))
772 {
773
774 string errorMsg = Marshal.PtrToStringAuto(errorPtr);
775 instanceRef.DelegateOnErrorEvent(errorMsg);
776
777 }
778
779 }
780
781 [MonoPInvokeCallback(typeof(OnCloseCallback))]
782 public static void DelegateOnCloseEvent(int instanceId, int closeCode)
783 {
784
785 WebSocket instanceRef;
786
787 if (instances.TryGetValue(instanceId, out instanceRef))
788 {
789 instanceRef.DelegateOnCloseEvent(closeCode);
790 }
791
792 }
793#endif
794
800 public static WebSocket CreateInstance(string url)
801 {
802#if UNITY_WEBGL && !UNITY_EDITOR
803 if (!isInitialized)
804 Initialize();
805
806 int instanceId = WebSocketAllocate(url);
807 WebSocket wrapper = new WebSocket(instanceId);
808 instances.Add(instanceId, wrapper);
809
810 return wrapper;
811#else
812 return new WebSocket(url);
813#endif
814 }
815
816 }
817
818}
Generic WebSocket exception class
Definition: WebSocket.cs:185
WebSocketException(string message)
Definition: WebSocket.cs:191
WebSocketException(string message, Exception inner)
Definition: WebSocket.cs:196
void Send(string data)
Send text data over the socket.
Definition: WebSocket.cs:602
WebSocket(string url)
WebSocket constructor.
Definition: WebSocket.cs:475
WebSocketSharp.WebSocket ws
The WebSocketSharp instance.
Definition: WebSocket.cs:469
void Send(byte[] data)
Send binary data over the socket.
Definition: WebSocket.cs:580
WebSocketMessageEventHandler OnMessage
Occurs when a message is received.
Definition: WebSocket.cs:454
WebSocketErrorEventHandler OnError
Occurs when an error was reported from WebSocket.
Definition: WebSocket.cs:459
WebSocketOpenEventHandler OnOpen
Occurs when the connection is opened.
Definition: WebSocket.cs:449
bool Ping()
Trys to ping the host.
Definition: WebSocket.cs:623
void Connect()
Open WebSocket connection
Definition: WebSocket.cs:532
void Close(WebSocketCloseCode code=WebSocketCloseCode.Normal, string reason=null)
Close WebSocket connection with optional status code and reason.
Definition: WebSocket.cs:555
WebSocketCloseEventHandler OnClose
Occurs when the socked was closed.
Definition: WebSocket.cs:464
WebSocketState GetState()
Return WebSocket connection state.
Definition: WebSocket.cs:644
Invalid argument exception raised when bad arguments are passed to a method.
Definition: WebSocket.cs:217
WebSocketInvalidArgumentException(string message, Exception inner)
Definition: WebSocket.cs:220
Invalid state exception raised when trying to invoke action which cannot be done due to different the...
Definition: WebSocket.cs:227
WebSocketInvalidStateException(string message, Exception inner)
Definition: WebSocket.cs:230
Web socket exception raised when an error was not expected, probably due to corrupted internal state.
Definition: WebSocket.cs:207
WebSocketUnexpectedException(string message, Exception inner)
Definition: WebSocket.cs:210
WebSocket class interface shared by both native and JSLIB implementation.
Definition: WebSocket.cs:76
WebSocketMessageEventHandler OnMessage
Occurs when a message is received.
Definition: WebSocket.cs:109
WebSocketCloseEventHandler OnClose
Occurs when the socked was closed.
Definition: WebSocket.cs:119
void Send(byte[] data)
Send binary data over the socket.
WebSocketOpenEventHandler OnOpen
Occurs when the connection is opened.
Definition: WebSocket.cs:104
WebSocketErrorEventHandler OnError
Occurs when an error was reported from WebSocket.
Definition: WebSocket.cs:114
void Connect()
Open WebSocket connection
void Close(WebSocketCloseCode code=WebSocketCloseCode.Normal, string reason=null)
Close WebSocket connection with optional status code and reason.
WebSocketState GetState()
Return WebSocket connection state.
delegate void WebSocketCloseEventHandler(WebSocketCloseCode closeCode)
Handler for WebSocket Close event.
WebSocketCloseCode
Web socket close codes.
Definition: WebSocket.cs:54
delegate void WebSocketErrorEventHandler(string errorMsg)
Handler for an error event received from WebSocket.
delegate void WebSocketOpenEventHandler()
Handler for WebSocket Open event.
WebSocketState
Enum representing WebSocket connection state
Definition: WebSocket.cs:43
delegate void WebSocketMessageEventHandler(byte[] data)
Handler for message received from WebSocket.