gen_proxy.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /**
  2. * Tencent is pleased to support the open source community by making Tars available.
  3. *
  4. * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  7. * in compliance with the License. You may obtain a copy of the License at
  8. *
  9. * https://opensource.org/licenses/BSD-3-Clause
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed
  12. * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  13. * CONDITIONS OF ANY KIND, either express or implied. See the License for the
  14. * specific language governing permissions and limitations under the License.
  15. */
  16. #include "code_generator.h"
  17. #define INVOKE_RETURN(protocol, prefix, params) \
  18. str << TAB << "return this._worker." << TC_Common::lower(protocol) << "_invoke(\"" << oPtr->getId() << "\", "; \
  19. str << "__" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$" << prefix << "E"; \
  20. str << "(" << sParams << params << "), arguments[arguments.length - 1], "; \
  21. str << "__" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$IF" << ").then("; \
  22. str << "__" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$" << prefix << "D, "; \
  23. str << "__" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$ER);" << endl;
  24. #define PROTOCOL_PARAMS (sParams.empty() ? "" : ", ") << "version"
  25. struct SortOperation
  26. {
  27. bool operator()(const OperationPtr &o1, const OperationPtr &o2)
  28. {
  29. return o1->getId() < o2->getId();
  30. }
  31. };
  32. string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr, const OperationPtr &oPtr)
  33. {
  34. ostringstream str;
  35. vector<ParamDeclPtr> & vParamDecl = oPtr->getAllParamDeclPtr();
  36. bool bHasParamOut = false;
  37. string sParams = "";
  38. for (size_t i = 0; i < vParamDecl.size(); i++)
  39. {
  40. if (vParamDecl[i]->isOut())
  41. {
  42. continue;
  43. }
  44. sParams += (sParams.empty()?"":", ") + vParamDecl[i]->getTypeIdPtr()->getId();
  45. }
  46. // generate function metadata (SharedFunctionInfo)
  47. str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$IF = {" << endl;
  48. INC_TAB;
  49. str << TAB << "\"name\" : \"" << oPtr->getId() << "\"," << endl;
  50. str << TAB << "\"return\" : \"" << getClassName(oPtr->getReturnPtr()->getTypePtr()) << "\"," << endl;
  51. str << TAB << "\"arguments\" : [";
  52. for (size_t i = 0; i < vParamDecl.size(); i++)
  53. {
  54. str << (i > 0 ? ", {" : "{") << endl;
  55. INC_TAB;
  56. str << TAB << "\"name\" : \"" << vParamDecl[i]->getTypeIdPtr()->getId() << "\"," << endl;
  57. str << TAB << "\"class\" : \"" << getClassName(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << "\"," << endl;
  58. if (vParamDecl[i]->isOut())
  59. {
  60. bHasParamOut = true;
  61. str << TAB << "\"direction\" : \"out\"" << endl;
  62. }
  63. else
  64. {
  65. str << TAB << "\"direction\" : \"in\"" << endl;
  66. }
  67. DEL_TAB;
  68. str << TAB << "}";
  69. }
  70. str << "]" << endl;
  71. DEL_TAB;
  72. str << TAB << "};" << endl << endl;
  73. // generate IDL Encoder ($IE)
  74. str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$IE = function (" << sParams << ") {" << endl;
  75. INC_TAB;
  76. str << TAB << "var os = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "OutputStream();" << endl;
  77. for (size_t i = 0; i < vParamDecl.size(); i++)
  78. {
  79. if (vParamDecl[i]->isOut()) continue;
  80. str << TAB << "os." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "write") << "("
  81. << (i + 1) << ", " << vParamDecl[i]->getTypeIdPtr()->getId()
  82. << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << ");" << endl;
  83. // push the symbol into dependent list
  84. getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
  85. }
  86. str << TAB << "return os.getBinBuffer();" << endl;
  87. DEL_TAB;
  88. str << TAB << "};" << endl << endl;
  89. // generate IDL Decoder ($ID)
  90. str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$ID = function (data) {" << endl;
  91. INC_TAB;
  92. str << TAB << "try {" << endl;
  93. INC_TAB;
  94. if (oPtr->getReturnPtr()->getTypePtr() || bHasParamOut)
  95. {
  96. str << TAB << "var is = new " << IDL_NAMESPACE_STR << "Stream." << IDL_TYPE << "InputStream(data.response.sBuffer);" << endl;
  97. }
  98. str << TAB << "return {" << endl;
  99. INC_TAB;
  100. str << TAB << "\"request\" : data.request," << endl;
  101. str << TAB << "\"response\" : {" << endl;
  102. INC_TAB;
  103. str << TAB << "\"costtime\" : data.request.costtime";
  104. if (oPtr->getReturnPtr()->getTypePtr())
  105. {
  106. str << "," << endl;
  107. str << TAB << "\"return\""
  108. << " : is." << toFunctionName(oPtr->getReturnPtr(), "read") << "(0, true, ";
  109. if (isSimple(oPtr->getReturnPtr()->getTypePtr()))
  110. {
  111. str << getDefault(oPtr->getReturnPtr(), oPtr->getReturnPtr()->def(), nPtr->getId())
  112. << representArgument(oPtr->getReturnPtr()->getTypePtr());
  113. }
  114. else
  115. {
  116. str << getDataType(oPtr->getReturnPtr()->getTypePtr());
  117. }
  118. str << ")";
  119. }
  120. if (bHasParamOut)
  121. {
  122. str << "," << endl;
  123. str << TAB << "\"arguments\" : {" << endl;
  124. INC_TAB;
  125. for (size_t i = 0; i < vParamDecl.size(); i++)
  126. {
  127. if (!vParamDecl[i]->isOut()) continue;
  128. str << TAB << "\"" << vParamDecl[i]->getTypeIdPtr()->getId() << "\""
  129. << " : is." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "read") << "(" << (i + 1) << ", true, ";
  130. if (isSimple(vParamDecl[i]->getTypeIdPtr()->getTypePtr()))
  131. {
  132. str << getDefault(vParamDecl[i]->getTypeIdPtr(), vParamDecl[i]->getTypeIdPtr()->def(), nPtr->getId())
  133. << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
  134. }
  135. else
  136. {
  137. str << getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
  138. }
  139. str << ")";
  140. if (i == vParamDecl.size() - 1)
  141. {
  142. str << endl;
  143. }
  144. else
  145. {
  146. str << "," << endl;
  147. }
  148. }
  149. DEL_TAB;
  150. str << TAB << "}";
  151. }
  152. str << endl;
  153. DEL_TAB;
  154. str << TAB << "}" << endl;
  155. DEL_TAB;
  156. str << TAB << "};" << endl;
  157. DEL_TAB;
  158. str << TAB << "} catch (e) {" << endl;
  159. INC_TAB;
  160. str << TAB << "throw _makeError(data, e.message, " << IDL_NAMESPACE_STR << "Error.CLIENT.DECODE_ERROR);" << endl;
  161. DEL_TAB;
  162. str << TAB << "}" << endl;
  163. DEL_TAB;
  164. str << TAB << "};" << endl << endl;
  165. // generate Protocol Encoder ($PE)
  166. str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$PE = function ("
  167. << sParams << (sParams.empty() ? "" : ", ") << "__$PROTOCOL$VERSION) {" << endl;
  168. INC_TAB;
  169. str << TAB << "var " << PROTOCOL_VAR << " = new " << IDL_NAMESPACE_STR << "Stream.UniAttribute();" << endl;
  170. str << TAB << PROTOCOL_VAR << "." << PROTOCOL_VAR << "Version = __$PROTOCOL$VERSION;" << endl;
  171. for (size_t i = 0; i < vParamDecl.size(); i++)
  172. {
  173. if (vParamDecl[i]->isOut()) continue;
  174. str << TAB << PROTOCOL_VAR << "." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "write") << "(\""
  175. << vParamDecl[i]->getTypeIdPtr()->getId() << "\", " << vParamDecl[i]->getTypeIdPtr()->getId()
  176. << representArgument(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) << ");" << endl;
  177. // push the symbol into dependent list
  178. getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
  179. }
  180. str << TAB << "return " << PROTOCOL_VAR << ";" << endl;
  181. DEL_TAB;
  182. str << TAB << "};" << endl << endl;
  183. // generate Protocol Decoder ($PD)
  184. str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$PD = function (data) {" << endl;
  185. INC_TAB;
  186. str << TAB << "try {" << endl;
  187. INC_TAB;
  188. if (oPtr->getReturnPtr()->getTypePtr() || bHasParamOut) {
  189. str << TAB << "var " << PROTOCOL_VAR << " = data.response." << PROTOCOL_VAR << ";" << endl;
  190. }
  191. str << TAB << "return {" << endl;
  192. INC_TAB;
  193. str << TAB << "\"request\" : data.request," << endl;
  194. str << TAB << "\"response\" : {" << endl;
  195. INC_TAB;
  196. str << TAB << "\"costtime\" : data.request.costtime";
  197. if (oPtr->getReturnPtr()->getTypePtr())
  198. {
  199. str << "," << endl;
  200. str << TAB << "\"return\" : " << PROTOCOL_VAR << "." << toFunctionName(oPtr->getReturnPtr(), "read") << "(\"\"";
  201. if (!isSimple(oPtr->getReturnPtr()->getTypePtr()) && !isBinBuffer(oPtr->getReturnPtr()->getTypePtr()))
  202. {
  203. str << ", " << getDataType(oPtr->getReturnPtr()->getTypePtr());
  204. }
  205. str << ", " << getDefault(oPtr->getReturnPtr(), "", nPtr->getId(), true)
  206. << representArgument(oPtr->getReturnPtr()->getTypePtr());
  207. str << ")";
  208. }
  209. if (bHasParamOut)
  210. {
  211. str << "," << endl;
  212. str << TAB << "\"arguments\" : {" << endl;
  213. INC_TAB;
  214. for (size_t i = 0; i < vParamDecl.size(); i++)
  215. {
  216. if (!vParamDecl[i]->isOut()) continue;
  217. str << TAB << "\"" << vParamDecl[i]->getTypeIdPtr()->getId() << "\" : "
  218. << PROTOCOL_VAR << "." << toFunctionName(vParamDecl[i]->getTypeIdPtr(), "read")
  219. << "(\"" << vParamDecl[i]->getTypeIdPtr()->getId() << "\"";
  220. if (!isSimple(vParamDecl[i]->getTypeIdPtr()->getTypePtr()) && !isBinBuffer(vParamDecl[i]->getTypeIdPtr()->getTypePtr()))
  221. {
  222. str << ", " << getDataType(vParamDecl[i]->getTypeIdPtr()->getTypePtr());
  223. }
  224. str << ")";
  225. if (i == vParamDecl.size() - 1)
  226. {
  227. str << endl;
  228. }
  229. else
  230. {
  231. str << "," << endl;
  232. }
  233. }
  234. DEL_TAB;
  235. str << TAB << "}";
  236. }
  237. str << endl;
  238. DEL_TAB;
  239. str << TAB << "}" << endl;
  240. DEL_TAB;
  241. str << TAB << "};" << endl;
  242. DEL_TAB;
  243. str << TAB << "} catch (e) {" << endl;
  244. INC_TAB;
  245. str << TAB << "throw _makeError(data, e.message, " << IDL_NAMESPACE_STR << "Error.CLIENT.DECODE_ERROR);" << endl;
  246. DEL_TAB;
  247. str << TAB << "}" << endl;
  248. DEL_TAB;
  249. str << TAB << "};" << endl << endl;
  250. // generate error handler ($ER)
  251. str << TAB << "var __" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$ER = function (data) {" << endl;
  252. INC_TAB;
  253. str << TAB << "throw _makeError(data, \"Call " << pPtr->getId() << "::" << oPtr->getId() << " failed\");" << endl;
  254. DEL_TAB;
  255. str << TAB << "};" << endl << endl;
  256. // generate function body
  257. str << TAB << nPtr->getId() << "." << pPtr->getId() << "Proxy.prototype." << oPtr->getId() << " = function ("
  258. << sParams << ") {" << endl;
  259. INC_TAB;
  260. str << TAB << "var version = this._worker.version;" << endl;
  261. str << TAB << "if (version === " << PROTOCOL_SIMPLE << " || version === " << PROTOCOL_COMPLEX << ") {" << endl;
  262. INC_TAB;
  263. INVOKE_RETURN(PROTOCOL_VAR, "P", PROTOCOL_PARAMS);
  264. DEL_TAB;
  265. str << TAB << "} else {" << endl;
  266. INC_TAB;
  267. INVOKE_RETURN(IDL_NAMESPACE_STR, "I", "");
  268. DEL_TAB;
  269. str << TAB << "}" << endl;
  270. DEL_TAB;
  271. str << TAB << "};" << endl;
  272. // add the function into the prototype of the proxy class
  273. str << TAB << nPtr->getId() << "." << pPtr->getId() << "Proxy." << oPtr->getId() << " = "
  274. << "__" << nPtr->getId() << "_" << pPtr->getId() << "$" << oPtr->getId() << "$IF;" << endl;
  275. return str.str();
  276. }
  277. string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, const InterfacePtr &pPtr)
  278. {
  279. ostringstream str;
  280. vector<OperationPtr> & vOperation = pPtr->getAllOperationPtr();
  281. sort(vOperation.begin(), vOperation.end(), SortOperation());
  282. for (size_t i = 0; i < vOperation.size(); i++)
  283. {
  284. str << generateJSProxy(nPtr, pPtr, vOperation[i]) << endl;
  285. }
  286. return str.str();
  287. }
  288. string CodeGenerator::generateJSProxy(const NamespacePtr &nPtr, bool &bNeedRpc, bool &bNeedStream)
  289. {
  290. ostringstream str;
  291. vector<InterfacePtr> & is = nPtr->getAllInterfacePtr();
  292. for (size_t i = 0; i < is.size(); i++)
  293. {
  294. str << generateJSProxy(nPtr, is[i]) << endl;
  295. }
  296. if (is.size() != 0)
  297. {
  298. bNeedRpc = true;
  299. bNeedStream = true;
  300. }
  301. return str.str();
  302. }
  303. bool CodeGenerator::generateJSProxy(const ContextPtr &cPtr)
  304. {
  305. vector<NamespacePtr> namespaces = cPtr->getNamespaces();
  306. ostringstream istr;
  307. set<string> setNamespace;
  308. for(size_t i = 0; i < namespaces.size(); i++)
  309. {
  310. if (setNamespace.count(namespaces[i]->getId()) == 0)
  311. {
  312. istr << TAB << "var " << namespaces[i]->getId() << " = " << namespaces[i]->getId() << " || {};" << endl;
  313. istr << TAB << "module.exports." << namespaces[i]->getId() << " = " << namespaces[i]->getId() << ";" << endl << endl;
  314. setNamespace.insert(namespaces[i]->getId());
  315. }
  316. }
  317. set<string> setInterface;
  318. for(size_t i = 0; i < namespaces.size(); i++)
  319. {
  320. vector<InterfacePtr> & is = namespaces[i]->getAllInterfacePtr();
  321. for (size_t ii = 0; ii < is.size(); ii++)
  322. {
  323. if (setInterface.count(namespaces[i]->getId() + "::" + is[ii]->getId()) != 0)
  324. {
  325. continue;
  326. }
  327. setInterface.insert(namespaces[i]->getId() + "::" + is[ii]->getId());
  328. istr << TAB << namespaces[i]->getId() << "." << is[ii]->getId() << "Proxy = function () {" << endl;
  329. INC_TAB;
  330. istr << TAB << "this._name = undefined;" << endl;
  331. istr << TAB << "this._worker = undefined;" << endl;
  332. DEL_TAB;
  333. istr << TAB << "};" << endl << endl;
  334. istr << TAB << namespaces[i]->getId() << "." << is[ii]->getId() << "Proxy.prototype.setTimeout = function (iTimeout) {" << endl;
  335. INC_TAB;
  336. istr << TAB << "this._worker.timeout = iTimeout;" << endl;
  337. DEL_TAB;
  338. istr << TAB << "};" << endl << endl;
  339. istr << TAB << namespaces[i]->getId() << "." << is[ii]->getId() << "Proxy.prototype.getTimeout = function () {" << endl;
  340. INC_TAB;
  341. istr << TAB << "return this._worker.timeout;" << endl;
  342. DEL_TAB;
  343. istr << TAB << "};" << endl << endl;
  344. istr << TAB << namespaces[i]->getId() << "." << is[ii]->getId() << "Proxy.prototype.setVersion = function (iVersion) {" << endl;
  345. INC_TAB;
  346. istr << TAB << "this._worker.version = iVersion;" << endl;
  347. DEL_TAB;
  348. istr << TAB << "};" << endl << endl;
  349. istr << TAB << namespaces[i]->getId() << "." << is[ii]->getId() << "Proxy.prototype.getVersion = function () {" << endl;
  350. INC_TAB;
  351. istr << TAB << "return this._worker.version;" << endl;
  352. DEL_TAB;
  353. istr << TAB << "};" << endl;
  354. }
  355. }
  356. // generate proxy classes with encoders and decoders
  357. ostringstream estr;
  358. bool bNeedAssert = false;
  359. bool bNeedStream = false;
  360. bool bQuickFunc = false;
  361. for(size_t i = 0; i < namespaces.size(); i++)
  362. {
  363. estr << generateJS(namespaces[i], bNeedStream, bNeedAssert, bQuickFunc);
  364. }
  365. bool bNeedRpc = false;
  366. for(size_t i = 0; i < namespaces.size(); i++)
  367. {
  368. estr << generateJSProxy(namespaces[i], bNeedRpc, bNeedStream);
  369. }
  370. if (estr.str().empty())
  371. {
  372. return false;
  373. }
  374. // generate module imports
  375. ostringstream ostr;
  376. for (map<string, ImportFile>::iterator it = _mapFiles.begin(); it != _mapFiles.end(); it++)
  377. {
  378. if (it->second.sModule.empty()) continue;
  379. if (estr.str().find(it->second.sModule + ".") == string::npos) continue;
  380. ostr << "var " << it->second.sModule << " = require(\"" << it->second.sFile << "\");" << endl;
  381. }
  382. // concat generated code
  383. ostringstream sstr;
  384. sstr << printHeaderRemark("Client");
  385. sstr << DISABLE_ESLINT << endl;
  386. sstr << endl;
  387. sstr << "\"use strict\";" << endl << endl;
  388. if (bNeedAssert)
  389. {
  390. sstr << "var assert = require(\"assert\");" << endl;
  391. }
  392. if (bNeedStream)
  393. {
  394. sstr << "var " << IDL_NAMESPACE_STR << "Stream = require(\"" << _sStreamPath << "\");" << endl;
  395. }
  396. if (bNeedRpc)
  397. {
  398. sstr << "var " << IDL_NAMESPACE_STR << "Error = require(\"" << _sRpcPath << "\").error;" << endl;
  399. }
  400. sstr << ostr.str() << endl;
  401. // generate helper functions
  402. if (bQuickFunc)
  403. {
  404. sstr << "var _hasOwnProperty = Object.prototype.hasOwnProperty;" << endl;
  405. }
  406. if (bNeedRpc)
  407. {
  408. sstr << TAB << "var _makeError = function (data, message, type) {" << endl;
  409. INC_TAB;
  410. sstr << TAB << "var error = new Error(message || \"\");" << endl;
  411. sstr << TAB << "error.request = data.request;" << endl;
  412. sstr << TAB << "error.response = {" << endl;
  413. INC_TAB;
  414. sstr << TAB << "\"costtime\" : data.request.costtime" << endl;
  415. DEL_TAB;
  416. sstr << TAB << "};" << endl;
  417. sstr << TAB << "if (type === " << IDL_NAMESPACE_STR << "Error.CLIENT.DECODE_ERROR) {" << endl;
  418. INC_TAB;
  419. sstr << TAB << "error.name = \"DECODE_ERROR\";" << endl;
  420. sstr << TAB << "error.response.error = {" << endl;
  421. INC_TAB;
  422. sstr << TAB << "\"code\" : type," << endl;
  423. sstr << TAB << "\"message\" : message" << endl;
  424. DEL_TAB;
  425. sstr << TAB << "};" << endl;
  426. DEL_TAB;
  427. sstr << TAB << "} else {" << endl;
  428. INC_TAB;
  429. sstr << TAB << "error.name = \"RPC_ERROR\";" << endl;
  430. sstr << TAB << "error.response.error = data.error;" << endl;
  431. DEL_TAB;
  432. sstr << TAB << "}" << endl;
  433. sstr << TAB << "return error;" << endl;
  434. DEL_TAB;
  435. sstr << TAB << "};" << endl;
  436. }
  437. if (bQuickFunc || bNeedRpc)
  438. {
  439. sstr << endl;
  440. }
  441. sstr << istr.str() << endl;
  442. sstr << estr.str() << endl;
  443. string sFileName = TC_File::excludeFileExt(_sToPath + TC_File::extractFileName(cPtr->getFileName())) + "Proxy.js";
  444. TC_File::makeDirRecursive(_sToPath);
  445. makeUTF8File(sFileName, sstr.str());
  446. return true;
  447. }
  448. #undef INVOKE_RETURN
  449. #undef PROTOCOL_PARAMS