Utils.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. "use strict";
  2. // Licensed to the .NET Foundation under one or more agreements.
  3. // The .NET Foundation licenses this file to you under the MIT license.
  4. Object.defineProperty(exports, "__esModule", { value: true });
  5. exports.getGlobalThis = exports.getErrorString = exports.constructUserAgent = exports.getUserAgentHeader = exports.ConsoleLogger = exports.SubjectSubscription = exports.createLogger = exports.sendMessage = exports.isArrayBuffer = exports.formatArrayBuffer = exports.getDataDetail = exports.Platform = exports.Arg = exports.VERSION = void 0;
  6. const ILogger_1 = require("./ILogger");
  7. const Loggers_1 = require("./Loggers");
  8. // Version token that will be replaced by the prepack command
  9. /** The version of the SignalR client. */
  10. exports.VERSION = "7.0.14";
  11. /** @private */
  12. class Arg {
  13. static isRequired(val, name) {
  14. if (val === null || val === undefined) {
  15. throw new Error(`The '${name}' argument is required.`);
  16. }
  17. }
  18. static isNotEmpty(val, name) {
  19. if (!val || val.match(/^\s*$/)) {
  20. throw new Error(`The '${name}' argument should not be empty.`);
  21. }
  22. }
  23. static isIn(val, values, name) {
  24. // TypeScript enums have keys for **both** the name and the value of each enum member on the type itself.
  25. if (!(val in values)) {
  26. throw new Error(`Unknown ${name} value: ${val}.`);
  27. }
  28. }
  29. }
  30. exports.Arg = Arg;
  31. /** @private */
  32. class Platform {
  33. // react-native has a window but no document so we should check both
  34. static get isBrowser() {
  35. return typeof window === "object" && typeof window.document === "object";
  36. }
  37. // WebWorkers don't have a window object so the isBrowser check would fail
  38. static get isWebWorker() {
  39. return typeof self === "object" && "importScripts" in self;
  40. }
  41. // react-native has a window but no document
  42. static get isReactNative() {
  43. return typeof window === "object" && typeof window.document === "undefined";
  44. }
  45. // Node apps shouldn't have a window object, but WebWorkers don't either
  46. // so we need to check for both WebWorker and window
  47. static get isNode() {
  48. return !this.isBrowser && !this.isWebWorker && !this.isReactNative;
  49. }
  50. }
  51. exports.Platform = Platform;
  52. /** @private */
  53. function getDataDetail(data, includeContent) {
  54. let detail = "";
  55. if (isArrayBuffer(data)) {
  56. detail = `Binary data of length ${data.byteLength}`;
  57. if (includeContent) {
  58. detail += `. Content: '${formatArrayBuffer(data)}'`;
  59. }
  60. }
  61. else if (typeof data === "string") {
  62. detail = `String data of length ${data.length}`;
  63. if (includeContent) {
  64. detail += `. Content: '${data}'`;
  65. }
  66. }
  67. return detail;
  68. }
  69. exports.getDataDetail = getDataDetail;
  70. /** @private */
  71. function formatArrayBuffer(data) {
  72. const view = new Uint8Array(data);
  73. // Uint8Array.map only supports returning another Uint8Array?
  74. let str = "";
  75. view.forEach((num) => {
  76. const pad = num < 16 ? "0" : "";
  77. str += `0x${pad}${num.toString(16)} `;
  78. });
  79. // Trim of trailing space.
  80. return str.substr(0, str.length - 1);
  81. }
  82. exports.formatArrayBuffer = formatArrayBuffer;
  83. // Also in signalr-protocol-msgpack/Utils.ts
  84. /** @private */
  85. function isArrayBuffer(val) {
  86. return val && typeof ArrayBuffer !== "undefined" &&
  87. (val instanceof ArrayBuffer ||
  88. // Sometimes we get an ArrayBuffer that doesn't satisfy instanceof
  89. (val.constructor && val.constructor.name === "ArrayBuffer"));
  90. }
  91. exports.isArrayBuffer = isArrayBuffer;
  92. /** @private */
  93. async function sendMessage(logger, transportName, httpClient, url, content, options) {
  94. const headers = {};
  95. const [name, value] = getUserAgentHeader();
  96. headers[name] = value;
  97. logger.log(ILogger_1.LogLevel.Trace, `(${transportName} transport) sending data. ${getDataDetail(content, options.logMessageContent)}.`);
  98. const responseType = isArrayBuffer(content) ? "arraybuffer" : "text";
  99. const response = await httpClient.post(url, {
  100. content,
  101. headers: { ...headers, ...options.headers },
  102. responseType,
  103. timeout: options.timeout,
  104. withCredentials: options.withCredentials,
  105. });
  106. logger.log(ILogger_1.LogLevel.Trace, `(${transportName} transport) request complete. Response status: ${response.statusCode}.`);
  107. }
  108. exports.sendMessage = sendMessage;
  109. /** @private */
  110. function createLogger(logger) {
  111. if (logger === undefined) {
  112. return new ConsoleLogger(ILogger_1.LogLevel.Information);
  113. }
  114. if (logger === null) {
  115. return Loggers_1.NullLogger.instance;
  116. }
  117. if (logger.log !== undefined) {
  118. return logger;
  119. }
  120. return new ConsoleLogger(logger);
  121. }
  122. exports.createLogger = createLogger;
  123. /** @private */
  124. class SubjectSubscription {
  125. constructor(subject, observer) {
  126. this._subject = subject;
  127. this._observer = observer;
  128. }
  129. dispose() {
  130. const index = this._subject.observers.indexOf(this._observer);
  131. if (index > -1) {
  132. this._subject.observers.splice(index, 1);
  133. }
  134. if (this._subject.observers.length === 0 && this._subject.cancelCallback) {
  135. this._subject.cancelCallback().catch((_) => { });
  136. }
  137. }
  138. }
  139. exports.SubjectSubscription = SubjectSubscription;
  140. /** @private */
  141. class ConsoleLogger {
  142. constructor(minimumLogLevel) {
  143. this._minLevel = minimumLogLevel;
  144. this.out = console;
  145. }
  146. log(logLevel, message) {
  147. if (logLevel >= this._minLevel) {
  148. const msg = `[${new Date().toISOString()}] ${ILogger_1.LogLevel[logLevel]}: ${message}`;
  149. switch (logLevel) {
  150. case ILogger_1.LogLevel.Critical:
  151. case ILogger_1.LogLevel.Error:
  152. this.out.error(msg);
  153. break;
  154. case ILogger_1.LogLevel.Warning:
  155. this.out.warn(msg);
  156. break;
  157. case ILogger_1.LogLevel.Information:
  158. this.out.info(msg);
  159. break;
  160. default:
  161. // console.debug only goes to attached debuggers in Node, so we use console.log for Trace and Debug
  162. this.out.log(msg);
  163. break;
  164. }
  165. }
  166. }
  167. }
  168. exports.ConsoleLogger = ConsoleLogger;
  169. /** @private */
  170. function getUserAgentHeader() {
  171. let userAgentHeaderName = "X-SignalR-User-Agent";
  172. if (Platform.isNode) {
  173. userAgentHeaderName = "User-Agent";
  174. }
  175. return [userAgentHeaderName, constructUserAgent(exports.VERSION, getOsName(), getRuntime(), getRuntimeVersion())];
  176. }
  177. exports.getUserAgentHeader = getUserAgentHeader;
  178. /** @private */
  179. function constructUserAgent(version, os, runtime, runtimeVersion) {
  180. // Microsoft SignalR/[Version] ([Detailed Version]; [Operating System]; [Runtime]; [Runtime Version])
  181. let userAgent = "Microsoft SignalR/";
  182. const majorAndMinor = version.split(".");
  183. userAgent += `${majorAndMinor[0]}.${majorAndMinor[1]}`;
  184. userAgent += ` (${version}; `;
  185. if (os && os !== "") {
  186. userAgent += `${os}; `;
  187. }
  188. else {
  189. userAgent += "Unknown OS; ";
  190. }
  191. userAgent += `${runtime}`;
  192. if (runtimeVersion) {
  193. userAgent += `; ${runtimeVersion}`;
  194. }
  195. else {
  196. userAgent += "; Unknown Runtime Version";
  197. }
  198. userAgent += ")";
  199. return userAgent;
  200. }
  201. exports.constructUserAgent = constructUserAgent;
  202. // eslint-disable-next-line spaced-comment
  203. /*#__PURE__*/ function getOsName() {
  204. if (Platform.isNode) {
  205. switch (process.platform) {
  206. case "win32":
  207. return "Windows NT";
  208. case "darwin":
  209. return "macOS";
  210. case "linux":
  211. return "Linux";
  212. default:
  213. return process.platform;
  214. }
  215. }
  216. else {
  217. return "";
  218. }
  219. }
  220. // eslint-disable-next-line spaced-comment
  221. /*#__PURE__*/ function getRuntimeVersion() {
  222. if (Platform.isNode) {
  223. return process.versions.node;
  224. }
  225. return undefined;
  226. }
  227. function getRuntime() {
  228. if (Platform.isNode) {
  229. return "NodeJS";
  230. }
  231. else {
  232. return "Browser";
  233. }
  234. }
  235. /** @private */
  236. function getErrorString(e) {
  237. if (e.stack) {
  238. return e.stack;
  239. }
  240. else if (e.message) {
  241. return e.message;
  242. }
  243. return `${e}`;
  244. }
  245. exports.getErrorString = getErrorString;
  246. /** @private */
  247. function getGlobalThis() {
  248. // globalThis is semi-new and not available in Node until v12
  249. if (typeof globalThis !== "undefined") {
  250. return globalThis;
  251. }
  252. if (typeof self !== "undefined") {
  253. return self;
  254. }
  255. if (typeof window !== "undefined") {
  256. return window;
  257. }
  258. if (typeof global !== "undefined") {
  259. return global;
  260. }
  261. throw new Error("could not find global");
  262. }
  263. exports.getGlobalThis = getGlobalThis;
  264. //# sourceMappingURL=Utils.js.map