util.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Types aren’t accurate
  2. //@ts-ignore
  3. import BinaryPack from "peerjs-js-binarypack";
  4. import { Supports } from "./supports";
  5. export interface UtilSupportsObj {
  6. browser: boolean;
  7. webRTC: boolean;
  8. audioVideo: boolean;
  9. data: boolean;
  10. binaryBlob: boolean;
  11. reliable: boolean;
  12. }
  13. const DEFAULT_CONFIG = {
  14. iceServers: [
  15. { urls: "stun:stun.l.google.com:19302" },
  16. {
  17. urls: [
  18. "turn:eu-0.turn.peerjs.com:3478",
  19. "turn:us-0.turn.peerjs.com:3478",
  20. ],
  21. username: "peerjs",
  22. credential: "peerjsp",
  23. },
  24. ],
  25. sdpSemantics: "unified-plan",
  26. };
  27. class Util {
  28. noop(): void {}
  29. readonly CLOUD_HOST = "0.peerjs.com";
  30. readonly CLOUD_PORT = 443;
  31. // Browsers that need chunking:
  32. readonly chunkedBrowsers = { Chrome: 1, chrome: 1 };
  33. readonly chunkedMTU = 16300; // The original 60000 bytes setting does not work when sending data from Firefox to Chrome, which is "cut off" after 16384 bytes and delivered individually.
  34. // Returns browser-agnostic default config
  35. readonly defaultConfig = DEFAULT_CONFIG;
  36. readonly browser = Supports.getBrowser();
  37. readonly browserVersion = Supports.getVersion();
  38. // Lists which features are supported
  39. readonly supports = (function () {
  40. const supported: UtilSupportsObj = {
  41. browser: Supports.isBrowserSupported(),
  42. webRTC: Supports.isWebRTCSupported(),
  43. audioVideo: false,
  44. data: false,
  45. binaryBlob: false,
  46. reliable: false,
  47. };
  48. if (!supported.webRTC) return supported;
  49. let pc: RTCPeerConnection;
  50. try {
  51. pc = new RTCPeerConnection(DEFAULT_CONFIG);
  52. supported.audioVideo = true;
  53. let dc: RTCDataChannel;
  54. try {
  55. dc = pc.createDataChannel("_PEERJSTEST", { ordered: true });
  56. supported.data = true;
  57. supported.reliable = !!dc.ordered;
  58. // Binary test
  59. try {
  60. dc.binaryType = "blob";
  61. supported.binaryBlob = !Supports.isIOS;
  62. } catch (e) {}
  63. } catch (e) {
  64. } finally {
  65. if (dc) {
  66. dc.close();
  67. }
  68. }
  69. } catch (e) {
  70. } finally {
  71. if (pc) {
  72. pc.close();
  73. }
  74. }
  75. return supported;
  76. })();
  77. // Ensure alphanumeric ids
  78. validateId(id: string): boolean {
  79. // Allow empty ids
  80. return !id || /^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/.test(id);
  81. }
  82. pack = BinaryPack.pack;
  83. unpack = BinaryPack.unpack;
  84. // Binary stuff
  85. private _dataCount: number = 1;
  86. chunk(
  87. blob: Blob,
  88. ): { __peerData: number; n: number; total: number; data: Blob }[] {
  89. const chunks = [];
  90. const size = blob.size;
  91. const total = Math.ceil(size / util.chunkedMTU);
  92. let index = 0;
  93. let start = 0;
  94. while (start < size) {
  95. const end = Math.min(size, start + util.chunkedMTU);
  96. const b = blob.slice(start, end);
  97. const chunk = {
  98. __peerData: this._dataCount,
  99. n: index,
  100. data: b,
  101. total,
  102. };
  103. chunks.push(chunk);
  104. start = end;
  105. index++;
  106. }
  107. this._dataCount++;
  108. return chunks;
  109. }
  110. blobToArrayBuffer(
  111. blob: Blob,
  112. cb: (arg: ArrayBuffer | null) => void,
  113. ): FileReader {
  114. const fr = new FileReader();
  115. fr.onload = function (evt) {
  116. if (evt.target) {
  117. cb(evt.target.result as ArrayBuffer);
  118. }
  119. };
  120. fr.readAsArrayBuffer(blob);
  121. return fr;
  122. }
  123. binaryStringToArrayBuffer(binary: string): ArrayBuffer | SharedArrayBuffer {
  124. const byteArray = new Uint8Array(binary.length);
  125. for (let i = 0; i < binary.length; i++) {
  126. byteArray[i] = binary.charCodeAt(i) & 0xff;
  127. }
  128. return byteArray.buffer;
  129. }
  130. randomToken(): string {
  131. return Math.random().toString(36).slice(2);
  132. }
  133. isSecure(): boolean {
  134. return location.protocol === "https:";
  135. }
  136. }
  137. export const util = new Util();