PromisedWebSockets.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import { w3cwebsocket } from "websocket";
  2. import { Mutex } from "async-mutex";
  3. const mutex = new Mutex();
  4. const closeError = new Error("WebSocket was closed");
  5. export class PromisedWebSockets {
  6. private closed: boolean;
  7. private stream: Buffer;
  8. private canRead?: boolean | Promise<boolean>;
  9. private resolveRead: ((value?: any) => void) | undefined;
  10. private client: w3cwebsocket | undefined;
  11. private website?: string;
  12. constructor() {
  13. this.client = undefined;
  14. this.stream = Buffer.alloc(0);
  15. this.closed = true;
  16. }
  17. async readExactly(number: number) {
  18. let readData = Buffer.alloc(0);
  19. while (true) {
  20. const thisTime = await this.read(number);
  21. readData = Buffer.concat([readData, thisTime]);
  22. number = number - thisTime.length;
  23. if (!number) {
  24. return readData;
  25. }
  26. }
  27. }
  28. async read(number: number) {
  29. if (this.closed) {
  30. throw closeError;
  31. }
  32. await this.canRead;
  33. if (this.closed) {
  34. throw closeError;
  35. }
  36. const toReturn = this.stream.slice(0, number);
  37. this.stream = this.stream.slice(number);
  38. if (this.stream.length === 0) {
  39. this.canRead = new Promise((resolve) => {
  40. this.resolveRead = resolve;
  41. });
  42. }
  43. return toReturn;
  44. }
  45. async readAll() {
  46. if (this.closed || !(await this.canRead)) {
  47. throw closeError;
  48. }
  49. const toReturn = this.stream;
  50. this.stream = Buffer.alloc(0);
  51. this.canRead = new Promise((resolve) => {
  52. this.resolveRead = resolve;
  53. });
  54. return toReturn;
  55. }
  56. getWebSocketLink(ip: string, port: number) {
  57. if (port === 443) {
  58. return `wss://${ip}:${port}/apiws`;
  59. } else {
  60. return `ws://${ip}:${port}/apiws`;
  61. }
  62. }
  63. async connect(port: number, ip: string) {
  64. this.stream = Buffer.alloc(0);
  65. this.canRead = new Promise((resolve) => {
  66. this.resolveRead = resolve;
  67. });
  68. this.closed = false;
  69. this.website = this.getWebSocketLink(ip, port);
  70. this.client = new w3cwebsocket(this.website, "binary");
  71. return new Promise((resolve, reject) => {
  72. if (this.client) {
  73. this.client.onopen = () => {
  74. this.receive();
  75. resolve(this);
  76. };
  77. this.client.onerror = (error: any) => {
  78. reject(error);
  79. };
  80. this.client.onclose = () => {
  81. if (this.resolveRead) {
  82. this.resolveRead(false);
  83. }
  84. this.closed = true;
  85. };
  86. //CONTEST
  87. if (typeof window !== "undefined") {
  88. window.addEventListener("offline", async () => {
  89. await this.close();
  90. if (this.resolveRead) {
  91. this.resolveRead(false);
  92. }
  93. });
  94. }
  95. }
  96. });
  97. }
  98. write(data: Buffer) {
  99. if (this.closed) {
  100. throw closeError;
  101. }
  102. if (this.client) {
  103. this.client.send(data);
  104. }
  105. }
  106. async close() {
  107. if (this.client) {
  108. await this.client.close();
  109. }
  110. this.closed = true;
  111. }
  112. async receive() {
  113. if (this.client) {
  114. this.client.onmessage = async (message: any) => {
  115. const release = await mutex.acquire();
  116. try {
  117. let data;
  118. //CONTEST BROWSER
  119. data = Buffer.from(
  120. await new Response(message.data).arrayBuffer()
  121. );
  122. this.stream = Buffer.concat([this.stream, data]);
  123. if (this.resolveRead) {
  124. this.resolveRead(true);
  125. }
  126. } finally {
  127. release();
  128. }
  129. };
  130. }
  131. }
  132. }