No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

localFunction.js 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. "use strict";
  2. var _ = require("lodash");
  3. var request = require("request");
  4. var { encodeFirestoreValue } = require("./firestore/encodeFirestoreValue");
  5. var utils = require("./utils");
  6. var LocalFunction = function (trigger, urls, controller) {
  7. const isCallable = _.get(trigger, ["labels", "deployment-callable"], "false");
  8. this.id = trigger.id;
  9. this.name = trigger.name;
  10. this.eventTrigger = trigger.eventTrigger;
  11. this.httpsTrigger = trigger.httpsTrigger;
  12. this.controller = controller;
  13. this.url = _.get(urls, this.id);
  14. if (this.httpsTrigger) {
  15. if (isCallable == "true") {
  16. this.call = this._constructCallableFunc.bind(this);
  17. }
  18. else {
  19. this.call = request.defaults({
  20. callback: this._requestCallBack,
  21. baseUrl: this.url,
  22. uri: "",
  23. });
  24. }
  25. }
  26. else {
  27. this.call = this._call.bind(this);
  28. }
  29. };
  30. LocalFunction.prototype._isDatabaseFunc = function (eventTrigger) {
  31. return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Database";
  32. };
  33. LocalFunction.prototype._isFirestoreFunc = function (eventTrigger) {
  34. return utils.getFunctionsEventProvider(eventTrigger.eventType) === "Firestore";
  35. };
  36. LocalFunction.prototype._substituteParams = function (resource, params) {
  37. var wildcardRegex = new RegExp("{[^/{}]*}", "g");
  38. return resource.replace(wildcardRegex, function (wildcard) {
  39. var wildcardNoBraces = wildcard.slice(1, -1);
  40. var sub = _.get(params, wildcardNoBraces);
  41. return sub || wildcardNoBraces + utils.randomInt(1, 9);
  42. });
  43. };
  44. LocalFunction.prototype._constructCallableFunc = function (data, opts) {
  45. opts = opts || {};
  46. var headers = {};
  47. if (opts.instanceIdToken) {
  48. headers["Firebase-Instance-ID-Token"] = opts.instanceIdToken;
  49. }
  50. return request.post({
  51. callback: this._requestCallBack,
  52. baseUrl: this.url,
  53. uri: "",
  54. body: { data: data },
  55. json: true,
  56. headers: headers,
  57. });
  58. };
  59. LocalFunction.prototype._constructAuth = function (auth, authType) {
  60. if (_.get(auth, "admin") || _.get(auth, "variable")) {
  61. return auth;
  62. }
  63. if (typeof authType !== "undefined") {
  64. switch (authType) {
  65. case "USER":
  66. return {
  67. variable: {
  68. uid: _.get(auth, "uid", ""),
  69. token: _.get(auth, "token", {}),
  70. },
  71. };
  72. case "ADMIN":
  73. if (_.get(auth, "uid") || _.get(auth, "token")) {
  74. throw new Error("authType and auth are incompatible.");
  75. }
  76. return { admin: true };
  77. case "UNAUTHENTICATED":
  78. if (_.get(auth, "uid") || _.get(auth, "token")) {
  79. throw new Error("authType and auth are incompatible.");
  80. }
  81. return { admin: false };
  82. default:
  83. throw new Error("Unrecognized authType, valid values are: " + "ADMIN, USER, and UNAUTHENTICATED");
  84. }
  85. }
  86. if (auth) {
  87. return {
  88. variable: {
  89. uid: auth.uid,
  90. token: auth.token || {},
  91. },
  92. };
  93. }
  94. return { admin: true };
  95. };
  96. LocalFunction.prototype._makeFirestoreValue = function (input) {
  97. if (typeof input === "undefined" || _.isEmpty(input)) {
  98. return {};
  99. }
  100. if (typeof input !== "object") {
  101. throw new Error("Firestore data must be key-value pairs.");
  102. }
  103. var currentTime = new Date().toISOString();
  104. return {
  105. fields: encodeFirestoreValue(input),
  106. createTime: currentTime,
  107. updateTime: currentTime,
  108. };
  109. };
  110. LocalFunction.prototype._requestCallBack = function (err, response, body) {
  111. if (err) {
  112. return console.warn("\nERROR SENDING REQUEST: " + err);
  113. }
  114. var status = response ? response.statusCode + ", " : "";
  115. var bodyString = body;
  116. if (typeof body === "string") {
  117. try {
  118. bodyString = JSON.stringify(JSON.parse(bodyString), null, 2);
  119. }
  120. catch (e) {
  121. }
  122. }
  123. else {
  124. bodyString = JSON.stringify(body, null, 2);
  125. }
  126. return console.log("\nRESPONSE RECEIVED FROM FUNCTION: " + status + bodyString);
  127. };
  128. LocalFunction.prototype._call = function (data, opts) {
  129. opts = opts || {};
  130. var operationType;
  131. var dataPayload;
  132. if (this.httpsTrigger) {
  133. this.controller.call(this.name, data || {});
  134. }
  135. else if (this.eventTrigger) {
  136. if (this._isDatabaseFunc(this.eventTrigger)) {
  137. operationType = utils.last(this.eventTrigger.eventType.split("."));
  138. switch (operationType) {
  139. case "create":
  140. dataPayload = {
  141. data: null,
  142. delta: data,
  143. };
  144. break;
  145. case "delete":
  146. dataPayload = {
  147. data: data,
  148. delta: null,
  149. };
  150. break;
  151. default:
  152. dataPayload = {
  153. data: data.before,
  154. delta: data.after,
  155. };
  156. }
  157. opts.resource = this._substituteParams(this.eventTrigger.resource, opts.params);
  158. opts.auth = this._constructAuth(opts.auth, opts.authType);
  159. this.controller.call(this.name, dataPayload, opts);
  160. }
  161. else if (this._isFirestoreFunc(this.eventTrigger)) {
  162. operationType = utils.last(this.eventTrigger.eventType.split("."));
  163. switch (operationType) {
  164. case "create":
  165. dataPayload = {
  166. value: this._makeFirestoreValue(data),
  167. oldValue: {},
  168. };
  169. break;
  170. case "delete":
  171. dataPayload = {
  172. value: {},
  173. oldValue: this._makeFirestoreValue(data),
  174. };
  175. break;
  176. default:
  177. dataPayload = {
  178. value: this._makeFirestoreValue(data.after),
  179. oldValue: this._makeFirestoreValue(data.before),
  180. };
  181. }
  182. opts.resource = this._substituteParams(this.eventTrigger.resource, opts.params);
  183. this.controller.call(this.name, dataPayload, opts);
  184. }
  185. else {
  186. this.controller.call(this.name, data || {}, opts);
  187. }
  188. }
  189. return "Successfully invoked function.";
  190. };
  191. module.exports = LocalFunction;