Source: client/typed-message.js

  1. /*
  2. * Copyright 2023, TeamDev. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Redistribution and use in source and/or binary forms, with or without
  11. * modification, must retain the above copyright notice and the following
  12. * disclaimer.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  15. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  16. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  17. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  18. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  19. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  20. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. "use strict";
  27. import {Message} from 'google-protobuf';
  28. import base64 from 'base64-js';
  29. import {
  30. BoolValue,
  31. DoubleValue,
  32. FloatValue,
  33. Int32Value,
  34. Int64Value,
  35. StringValue,
  36. UInt32Value,
  37. UInt64Value,
  38. } from '../proto/google/protobuf/wrappers_pb';
  39. import {convertDateToTimestamp} from './time-utils';
  40. import KnownTypes from './known-types';
  41. /**
  42. * Checks if the object extends {@link Message}.
  43. *
  44. * <p>The implementation doesn't use `instanceof` check and check on prototypes
  45. * since they may fail if different versions of the file are used at the same time
  46. * (e.g. bundled and the original one).
  47. *
  48. * @param object the object to check
  49. */
  50. export function isProtobufMessage(object) {
  51. return typeof object.constructor.typeUrl === 'function';
  52. }
  53. /**
  54. * A URL of a Protobuf type.
  55. *
  56. * Consists of the two parts separated with a slash. The first part is
  57. * the type URL prefix (for example, `type.googleapis.com`).
  58. * The second part is a fully-qualified Protobuf type name.
  59. *
  60. * @template <T>
  61. */
  62. export class TypeUrl {
  63. /**
  64. * Creates a new instance of TypeUrl from the given string value.
  65. *
  66. * The value should be a valid type URL of format:
  67. * (typeUrlPrefix)/(typeName)
  68. *
  69. * @param {!string} value the type URL value
  70. */
  71. constructor(value) {
  72. const urlParts = value.split('/');
  73. this._value = value;
  74. this._prefix = urlParts[0];
  75. this._name = urlParts[1];
  76. }
  77. /**
  78. * @return {string} part of the type URL before `/` specifying a namespace
  79. */
  80. prefix() {
  81. return this._prefix;
  82. }
  83. /**
  84. * @return {string} part of the type URL after `/` specifying the type name
  85. */
  86. name() {
  87. return this._name;
  88. }
  89. /**
  90. * @return {!string} full type URL value formatted as `<prefix>/<name>` string
  91. */
  92. value() {
  93. return this._value;
  94. }
  95. }
  96. /**
  97. * A type of the Protobuf message represented by its JavaScript class and type URL.
  98. *
  99. * @template <T>
  100. */
  101. export class Type {
  102. /**
  103. * @param {!Class<T>} cls a class of the `Message` type is for
  104. * @param {!TypeUrl<T>} typeUrl a type URL of the `Message` type is for
  105. */
  106. constructor(cls, typeUrl) {
  107. this._cls = cls;
  108. this._typeUrl = typeUrl;
  109. }
  110. /**
  111. * @return {!TypeUrl<T>} a type URL of a defined type
  112. */
  113. url() {
  114. return this._typeUrl;
  115. }
  116. /**
  117. * @return {!Class<T>} a JS class of a defined type
  118. */
  119. class() {
  120. return this._cls;
  121. }
  122. /**
  123. * A static factory for creating Type instances from `Message` class and type URL.
  124. *
  125. * @param {!Class<T>} cls a class of the `Message` type is for
  126. * @param {!string|TypeUrl<T>} typeUrl a type URL of the `Message` type is for
  127. *
  128. * @return {Type<T>} new Type instance
  129. */
  130. static of(cls, typeUrl) {
  131. if (!(typeUrl instanceof TypeUrl)) {
  132. typeUrl = new TypeUrl(typeUrl);
  133. }
  134. return new Type(cls, typeUrl);
  135. }
  136. /**
  137. * Creates a new `Type` for the passed `Message` class.
  138. *
  139. * @param cls {!Class<T>} cls a class of the `Message`
  140. */
  141. static forClass(cls) {
  142. const typeUrl = KnownTypes.typeUrlFor(cls);
  143. return this.of(cls, typeUrl);
  144. }
  145. /**
  146. * Creates a new `Type` for the passed `Message`.
  147. *
  148. * @param {!Message} message a Protobuf message
  149. */
  150. static forMessage(message) {
  151. return this.forClass(message.constructor);
  152. }
  153. }
  154. // PRIMITIVE WRAPPERS
  155. Type.STRING = Type.forClass(StringValue);
  156. Type.INT32 = Type.forClass(Int32Value);
  157. Type.UINT32 = Type.forClass(UInt32Value);
  158. Type.INT64 = Type.forClass(Int64Value);
  159. Type.UINT64 = Type.forClass(UInt64Value);
  160. Type.BOOL = Type.forClass(BoolValue);
  161. Type.DOUBLE = Type.forClass(DoubleValue);
  162. Type.FLOAT = Type.forClass(FloatValue);
  163. /**
  164. * A Protobuf message with a {@link TypeUrl}.
  165. *
  166. * The type URL specifies the type of the associated message.
  167. *
  168. * @template <T>
  169. */
  170. export class TypedMessage {
  171. /**
  172. * Creates a new instance of TypedMessage from the given Protobuf message and
  173. * type URL.
  174. *
  175. * @param {!Message} message a Protobuf message
  176. * @param {!Type<T>} type a Protobuf type of the message
  177. */
  178. constructor(message, type) {
  179. this.message = message;
  180. this.type = type;
  181. }
  182. /**
  183. * Creates a new instance of TypedMessage from the given Protobuf message.
  184. *
  185. * @param {!Message} message a Protobuf message
  186. * @returns {!TypedMessage} the created typed message
  187. */
  188. static of(message) {
  189. const type = Type.forMessage(message);
  190. return new TypedMessage(message, type);
  191. }
  192. /**
  193. * Converts this message into a Base64-encoded byte string.
  194. *
  195. * @return the string representing this message
  196. */
  197. toBase64() {
  198. const bytes = this.message.serializeBinary();
  199. return base64.fromByteArray(bytes);
  200. }
  201. /**
  202. * Creates a new `TypedMessage` wrapping a string.
  203. *
  204. * @param {!String} value a string value for `TypedMessage`
  205. * @return {TypedMessage<StringValue>} a new `TypedMessage` instance with provided value
  206. */
  207. static string(value) {
  208. const message = new StringValue([value.toString()]);
  209. return TypedMessage.of(message);
  210. }
  211. /**
  212. * Creates a new `TypedMessage` with a 32-bit integer value.
  213. *
  214. * The number gets floored if the provided value contains a floating point.
  215. *
  216. * @param {!number|Number} value a number value for `TypedMessage`
  217. * @return {TypedMessage<Int32Value>} a new `TypedMessage` instance with provided value
  218. */
  219. static int32(value) {
  220. const message = new Int32Value([Math.floor(value.valueOf())]);
  221. return TypedMessage.of(message);
  222. }
  223. /**
  224. * Creates a new `TypedMessage` with an unsigned 32-bit integer value.
  225. *
  226. * The number gets floored if the provided value contains a floating point.
  227. *
  228. * @param {!number|Number} value a number value for `TypedMessage`
  229. * @return {TypedMessage<UInt32Value>} a new `TypedMessage` instance with provided value
  230. */
  231. static uint32(value) {
  232. const message = new UInt32Value([Math.floor(value.valueOf())]);
  233. return TypedMessage.of(message);
  234. }
  235. /**
  236. * Creates a new `TypedMessage` with a 64-bit integer value.
  237. *
  238. * The number gets floored if the provided value contains a floating point.
  239. *
  240. * @param {!number|Number} value a number value for `TypedMessage`
  241. * @return {TypedMessage<Int64Value>} a new `TypedMessage` instance with provided value
  242. */
  243. static int64(value) {
  244. const message = new Int64Value([Math.floor(value.valueOf())]);
  245. return TypedMessage.of(message);
  246. }
  247. /**
  248. * Creates a new `TypedMessage` with an unsigned 64-bit integer value.
  249. *
  250. * The number gets floored if the provided value contains a floating point.
  251. *
  252. * @param {!number|Number} value a number value for `TypedMessage`
  253. * @return {TypedMessage<UInt64Value>} a new `TypedMessage` instance with provided value
  254. */
  255. static uint64(value) {
  256. const message = new UInt64Value([Math.floor(value.valueOf())]);
  257. return TypedMessage.of(message);
  258. }
  259. /**
  260. * Creates a new `TypedMessage` with a float value.
  261. *
  262. * @param {!number|Number} value a number value for `TypedMessage`
  263. * @return {TypedMessage<FloatValue>} a new `TypedMessage` instance with provided value
  264. */
  265. static float(value) {
  266. const message = new FloatValue([value.valueOf()]);
  267. return TypedMessage.of(message);
  268. }
  269. /**
  270. * Creates a new `TypedMessage` with a double value.
  271. *
  272. * @param {!number|Number} value a number value for `TypedMessage`
  273. * @return {TypedMessage<DoubleValue>} a new `TypedMessage` instance with provided value
  274. */
  275. static double(value) {
  276. const message = new DoubleValue([value.valueOf()]);
  277. return TypedMessage.of(message);
  278. }
  279. /**
  280. * Creates a new `TypedMessage` with a boolean value.
  281. *
  282. * @param {!boolean|Boolean} value `true` or `false` value for the `TypedMessage`
  283. * @return {TypedMessage<BoolValue>} a new `TypedMessage` instance with provided value
  284. */
  285. static bool(value) {
  286. const message = new BoolValue([value]);
  287. return TypedMessage.of(message);
  288. }
  289. /**
  290. * Creates a new `TypedMessage` with a timestamp value composed from the given JavaScript date.
  291. *
  292. * @param {!Date} date a JavaScript `Date` value
  293. * @return {TypedMessage<Timestamp>} a new `TypedMessage` instance with provided value
  294. */
  295. static timestamp(date) {
  296. const message = convertDateToTimestamp(date);
  297. return TypedMessage.of(message);
  298. }
  299. }