buildReq.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. import APP from '@/services';
  2. import { getUserId } from '@/services/bus/account';
  3. import { getErrorInfoByCode } from '@/services/bus/error';
  4. import { funCode } from '@/services/funcode/index';
  5. import ProtobufCtr from '@/services/socket/protobuf/index';
  6. import { Callback } from '@/utils/websocket';
  7. import { Package50 } from '@/utils/websocket/package';
  8. import { v4 as uuidv4 } from 'uuid';
  9. import * as type from './interface';
  10. import { CommonSearchParam, ParseRsp, SoleSearchParam } from './interface';
  11. import { IMessageHead } from './proto.d';
  12. import { getProtoHeadParam, HeadEnum } from './protoHeader';
  13. /**
  14. * 构建proto50 报文
  15. * 具体某个proto查询参数 SoleSearchParam
  16. * 通用查询查询参数 CommonSearchParam
  17. * @param param SoleSearchParam | CommonSearchParam
  18. */
  19. export function buildProtoReq50(param: SoleSearchParam | CommonSearchParam): Package50 {
  20. if (Reflect.has(param, 'funCodeName')) {
  21. return buildSoleProtoReq50(param as SoleSearchParam);
  22. } else {
  23. return buildCommonProtoReq50(param as CommonSearchParam);
  24. }
  25. }
  26. /**
  27. * 解析proto50 报文
  28. */
  29. export function parseProtoRsp50(rspPackage: any, funCodeName?: string): ParseRsp {
  30. if (funCodeName) {
  31. // 解析funCodeName 相对应的报文
  32. return parseSoleProtoRsp(rspPackage, funCodeName);
  33. } else {
  34. // 解析通用查询报文
  35. return parseCommonProtoRsp(rspPackage);
  36. }
  37. }
  38. /**
  39. * 生成 Package50 报文
  40. * @param funCodeName
  41. * @param req
  42. */
  43. function setPackage50(funCodeName: string, req: any): Package50 {
  44. const buffer = new Uint8Array(req.toArrayBuffer());
  45. const reqPackage = new Package50([funCode[funCodeName], buffer], undefined);
  46. return reqPackage;
  47. }
  48. /**
  49. * 获取proto实例
  50. * @param protobufName
  51. */
  52. function getProtoInstence(protobufName: string) {
  53. return ProtobufCtr.generateProtoInstence(protobufName);
  54. }
  55. /**
  56. * 构建单独的proto
  57. * @param protobufName
  58. * @param reqParams
  59. */
  60. function buildSoleProtoReq(protobufName: string, reqParams: type.ReqParams) {
  61. // 登录报文
  62. const Req = getProtoInstence(protobufName);
  63. // 此处处理 一:为了 不需要单独写 构建报文函数,二:是 处理 报文中例如 id 和 ID 各种大写混乱的情况
  64. const ReqKeys = Object.keys(Req);
  65. const ReqKeysMap = new Map();
  66. ReqKeys.forEach((e) => {
  67. ReqKeysMap.set(e.toLowerCase(), e);
  68. });
  69. // 此处需要待优化,proto嵌套的时候存在问题
  70. const paramKeys = Object.keys(reqParams);
  71. for (let i = 0; i < paramKeys.length; i++) {
  72. const item = paramKeys[i];
  73. const lowerKey = item.toLowerCase();
  74. if (ReqKeysMap.has(lowerKey)) {
  75. Req[ReqKeysMap.get(lowerKey)] = reqParams[item];
  76. } else {
  77. console.error(`$报文包中不存在 ${item} 属性}`);
  78. }
  79. }
  80. console.log('Req', Req)
  81. return Req;
  82. }
  83. /**
  84. * 构建消息头部
  85. * @param funCodeName funCodeName
  86. * @param params IMessageHead
  87. */
  88. function buildMsgHead(funCodeName: string, params: IMessageHead) {
  89. const code = funCode[funCodeName];
  90. if (!code) console.error('没有找到对应的funCode值,请配置');
  91. const messageHead = getProtoInstence('MessageHead');
  92. const head = {
  93. FunCode: code,
  94. UUID: uuidv4(),
  95. UserID: getUserId(),
  96. };
  97. Object.assign(messageHead, head, params);
  98. return messageHead;
  99. }
  100. /**
  101. * 构建单独的proto请求 Package50 报文
  102. * @param params SoleSearchParam
  103. */
  104. function buildSoleProtoReq50(params: SoleSearchParam): Package50 {
  105. const { protobufName, funCodeName, reqParams, Header } = params;
  106. // // // 消息头
  107. // const messageHead = buildMsgHead(funCodeName, headParam);
  108. // proto头部参数,站在用户角度,参数数据可以通用获取,但站在管理端的角度,则需要不能通用获取,而是需用选中对应数据中传入进来
  109. // 登录报文
  110. const header = typeof Header == 'object' ? buildMsgHead(funCodeName, Header) : getProtoHeadParam(funCodeName, Header);
  111. const Req = buildSoleProtoReq(protobufName, reqParams);
  112. Req.Header = header
  113. return setPackage50(funCodeName, Req);
  114. }
  115. /**
  116. * 构建通用查询 Package50 报文
  117. * @param param CommonSearchParam
  118. */
  119. function buildCommonProtoReq50(param: CommonSearchParam): Package50 {
  120. const { senNames, statement, params } = param;
  121. let queryReq = null;
  122. let funCodeName = '';
  123. // 加密信息
  124. if (senNames && senNames.length > 0) {
  125. queryReq = getProtoInstence('QueryCommonSenReq');
  126. queryReq.setSenNames(senNames);
  127. funCodeName = 'QueryCommonSenReq';
  128. } else {
  129. queryReq = getProtoInstence('QueryCommonReq');
  130. funCodeName = 'QueryCommonReq';
  131. }
  132. // 消息头
  133. const messageHead = getProtoHeadParam(funCodeName, 0);
  134. queryReq.setStatement(statement);
  135. // 构建查询参数
  136. const paramValues = [];
  137. for (const key in params) {
  138. const value = params[key];
  139. const Req = getProtoInstence('ParamValue');
  140. const hasId = (id: string): boolean => key.toLowerCase() === id;
  141. // 如果有accountid则需加到head中
  142. if (hasId('accountid') || hasId('buyaccountid') || hasId('sellaccountid')) {
  143. messageHead.AccountID = value;
  144. }
  145. Req.setKey(key);
  146. Req.setValue(value);
  147. paramValues.push(Req);
  148. }
  149. queryReq.setParamValues(paramValues);
  150. queryReq.setHeader(messageHead);
  151. return setPackage50(funCodeName, queryReq);
  152. }
  153. function isErrer(rspPackage: any, funCodeName: string): void {
  154. if (APP.Socket.trade.connState !== 2) {
  155. console.error(`交易服务未连接!`);
  156. }
  157. // 判断回复FunCode是否正确
  158. if (rspPackage.funCode !== funCode[funCodeName]) {
  159. console.error(`服务返回【${funCodeName}: ${funCode[funCodeName]}】解析包错误!`);
  160. }
  161. // 判断是否有数据体
  162. if (!rspPackage.content) {
  163. console.error(`服务未返回数据体!`);
  164. }
  165. }
  166. /**
  167. * 解析 funCodeName 对应的报文
  168. * @param rspPackage
  169. * @param funCodeName
  170. */
  171. function parseSoleProtoRsp(rspPackage: any, funCodeName: string): ParseRsp {
  172. isErrer(rspPackage, funCodeName);
  173. const reqPackage = ProtobufCtr.generateProtoContent(funCodeName, rspPackage.content);
  174. const { RetCode, Status, RetDesc } = reqPackage;
  175. // console.warn(`解析${funCodeName}对应的报文错误:RetCode: ${RetCode}: RetDesc${RetDesc}`)
  176. if (RetCode !== null) {
  177. if (RetCode === 0) {
  178. return { isSuccess: true, result: reqPackage };
  179. } if (RetCode === -1) { // 管理端错误消息
  180. return { isSuccess: false, result: RetDesc };
  181. } else {
  182. const errMsg = getErrorInfoByCode(String(RetCode));
  183. const result = errMsg ? errMsg : `未知错误:${RetCode}`;
  184. return { isSuccess: false, result };
  185. }
  186. } else {
  187. // 银行 业务 以 Status 作为判断依据
  188. console.log(`Status:${Status}`);
  189. if (Status === 0) {
  190. return { isSuccess: true, result: getErrorInfoByCode(Status) };
  191. } else {
  192. return { isSuccess: false, result: getErrorInfoByCode(Status) };
  193. }
  194. }
  195. }
  196. /**
  197. * 解析通用查询报文
  198. * @param rspParam
  199. */
  200. function parseCommonProtoRsp(rspParam: any): ParseRsp {
  201. //是否加密
  202. const funCodeName = rspParam.isSen ? 'QueryCommonSenRsp' : 'QueryCommonRsp';
  203. const { isSuccess, result } = parseSoleProtoRsp(rspParam, funCodeName);
  204. if (isSuccess) {
  205. // 组装数据
  206. const { FieldInfos, RowValues } = result.Rsps[0];
  207. // 此处只是简单处理
  208. const arr = RowValues.map((item: any) => {
  209. const result: any = {};
  210. FieldInfos.forEach((el: any, i: number) => {
  211. const { FieldName, FieldType } = el;
  212. const dateType = ['date', 'time', 'datetime', 'timestamp'];
  213. let value = item.RowValues[i];
  214. if (dateType.includes(lower(FieldType))) {
  215. // 解决safari时间问题
  216. value = value.replace(/-/g, '/').replace('.0', '');
  217. }
  218. result[lower(FieldName)] = value;
  219. });
  220. return result;
  221. });
  222. return { isSuccess: true, result: arr };
  223. } else {
  224. return { isSuccess, result };
  225. }
  226. }
  227. /**
  228. * 解析通知
  229. * @param rspPackage 回应包
  230. * @param funCodeName funcode 名
  231. */
  232. export const noticeParseRsp = (rspPackage: any, funCodeName: string) => {
  233. isErrer(rspPackage, funCodeName);
  234. const reqPackage = ProtobufCtr.generateProtoContent(funCodeName, rspPackage.content);
  235. const { RetCode } = reqPackage;
  236. let errMsg = getErrorInfoByCode(String(RetCode));
  237. if (errMsg === '') {
  238. errMsg = `未知错误:${RetCode}`;
  239. }
  240. return errMsg;
  241. };
  242. function lower(value: string): string {
  243. return value.toLowerCase();
  244. }
  245. // 枚举 proto hader
  246. export function protoMiddleware<T>(param: T, reqName: string, rspName: string, headerEnum: HeadEnum): Promise<any>
  247. // 自定义 protp header
  248. export function protoMiddleware<T>(param: T, reqName: string, rspName: string, headerEnum: IMessageHead): Promise<any>
  249. /**
  250. * @param param proto除去head 剩下参数
  251. * @param headerEnum 自定义的proto参数枚举值,减小重复抒写 默认0
  252. * @param reqFuncodeName proto 发送请求定义的头名字,特别需要注意,自已的funCodeName要与这个一致
  253. * @param rspFuncodeName proto 响应请求定义的头名字
  254. * @returns
  255. */
  256. export function protoMiddleware<T>(param: T, reqName: string, rspName: string, headerEnumOrParam: HeadEnum | IMessageHead = 0): Promise<any> {
  257. return new Promise((resolve, reject) => {
  258. const params = {
  259. protobufName: reqName,
  260. funCodeName: reqName,
  261. reqParams: param,
  262. Header: headerEnumOrParam,
  263. };
  264. const package50 = buildProtoReq50(params);
  265. const code = rspName ? funCode[rspName] : undefined
  266. APP.sendTradingServer(package50, code, {
  267. onSuccess: (res) => {
  268. const { isSuccess, result } = parseProtoRsp50(res, rspName);
  269. if (isSuccess) {
  270. resolve(result);
  271. } else {
  272. reject(result);
  273. }
  274. },
  275. onFail: (err) => {
  276. console.log(`proto:${reqName}错误消息:${err}`)
  277. reject(err.message)
  278. },
  279. } as Callback);
  280. });
  281. }