make-client.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. "use strict";
  2. /*
  3. * Copyright 2019 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. Object.defineProperty(exports, "__esModule", { value: true });
  19. exports.loadPackageDefinition = exports.makeClientConstructor = void 0;
  20. const client_1 = require("./client");
  21. /**
  22. * Map with short names for each of the requester maker functions. Used in
  23. * makeClientConstructor
  24. * @private
  25. */
  26. const requesterFuncs = {
  27. unary: client_1.Client.prototype.makeUnaryRequest,
  28. server_stream: client_1.Client.prototype.makeServerStreamRequest,
  29. client_stream: client_1.Client.prototype.makeClientStreamRequest,
  30. bidi: client_1.Client.prototype.makeBidiStreamRequest,
  31. };
  32. /**
  33. * Returns true, if given key is included in the blacklisted
  34. * keys.
  35. * @param key key for check, string.
  36. */
  37. function isPrototypePolluted(key) {
  38. return ['__proto__', 'prototype', 'constructor'].includes(key);
  39. }
  40. /**
  41. * Creates a constructor for a client with the given methods, as specified in
  42. * the methods argument. The resulting class will have an instance method for
  43. * each method in the service, which is a partial application of one of the
  44. * [Client]{@link grpc.Client} request methods, depending on `requestSerialize`
  45. * and `responseSerialize`, with the `method`, `serialize`, and `deserialize`
  46. * arguments predefined.
  47. * @param methods An object mapping method names to
  48. * method attributes
  49. * @param serviceName The fully qualified name of the service
  50. * @param classOptions An options object.
  51. * @return New client constructor, which is a subclass of
  52. * {@link grpc.Client}, and has the same arguments as that constructor.
  53. */
  54. function makeClientConstructor(methods, serviceName, classOptions) {
  55. if (!classOptions) {
  56. classOptions = {};
  57. }
  58. class ServiceClientImpl extends client_1.Client {
  59. }
  60. Object.keys(methods).forEach((name) => {
  61. if (isPrototypePolluted(name)) {
  62. return;
  63. }
  64. const attrs = methods[name];
  65. let methodType;
  66. // TODO(murgatroid99): Verify that we don't need this anymore
  67. if (typeof name === 'string' && name.charAt(0) === '$') {
  68. throw new Error('Method names cannot start with $');
  69. }
  70. if (attrs.requestStream) {
  71. if (attrs.responseStream) {
  72. methodType = 'bidi';
  73. }
  74. else {
  75. methodType = 'client_stream';
  76. }
  77. }
  78. else {
  79. if (attrs.responseStream) {
  80. methodType = 'server_stream';
  81. }
  82. else {
  83. methodType = 'unary';
  84. }
  85. }
  86. const serialize = attrs.requestSerialize;
  87. const deserialize = attrs.responseDeserialize;
  88. const methodFunc = partial(requesterFuncs[methodType], attrs.path, serialize, deserialize);
  89. ServiceClientImpl.prototype[name] = methodFunc;
  90. // Associate all provided attributes with the method
  91. Object.assign(ServiceClientImpl.prototype[name], attrs);
  92. if (attrs.originalName && !isPrototypePolluted(attrs.originalName)) {
  93. ServiceClientImpl.prototype[attrs.originalName] =
  94. ServiceClientImpl.prototype[name];
  95. }
  96. });
  97. ServiceClientImpl.service = methods;
  98. ServiceClientImpl.serviceName = serviceName;
  99. return ServiceClientImpl;
  100. }
  101. exports.makeClientConstructor = makeClientConstructor;
  102. function partial(fn, path, serialize, deserialize) {
  103. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  104. return function (...args) {
  105. return fn.call(this, path, serialize, deserialize, ...args);
  106. };
  107. }
  108. function isProtobufTypeDefinition(obj) {
  109. return 'format' in obj;
  110. }
  111. /**
  112. * Load a gRPC package definition as a gRPC object hierarchy.
  113. * @param packageDef The package definition object.
  114. * @return The resulting gRPC object.
  115. */
  116. function loadPackageDefinition(packageDef) {
  117. const result = {};
  118. for (const serviceFqn in packageDef) {
  119. if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) {
  120. const service = packageDef[serviceFqn];
  121. const nameComponents = serviceFqn.split('.');
  122. if (nameComponents.some((comp) => isPrototypePolluted(comp))) {
  123. continue;
  124. }
  125. const serviceName = nameComponents[nameComponents.length - 1];
  126. let current = result;
  127. for (const packageName of nameComponents.slice(0, -1)) {
  128. if (!current[packageName]) {
  129. current[packageName] = {};
  130. }
  131. current = current[packageName];
  132. }
  133. if (isProtobufTypeDefinition(service)) {
  134. current[serviceName] = service;
  135. }
  136. else {
  137. current[serviceName] = makeClientConstructor(service, serviceName, {});
  138. }
  139. }
  140. }
  141. return result;
  142. }
  143. exports.loadPackageDefinition = loadPackageDefinition;
  144. //# sourceMappingURL=make-client.js.map