buildReq.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. import APP from '@/services';
  2. import { getErrorInfoByCode } from '@/services/bus/error';
  3. import { getUserId } from '@/services/bus/user';
  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.log('protobuf回调===================================================================================', reqPackage)
  176. if (RetCode !== null) {
  177. if (RetCode === 0) {
  178. return { isSuccess: true, result: reqPackage };
  179. }
  180. if (RetCode === -1) { // 管理端错误消息
  181. return { isSuccess: false, result: RetDesc };
  182. }
  183. if (RetDesc) {
  184. return { isSuccess: false, result: Buffer.from(RetDesc, 'base64').toString() };
  185. }
  186. const errMsg = getErrorInfoByCode(String(RetCode));
  187. const result = errMsg ? errMsg : `未知错误:${RetCode}`;
  188. return { isSuccess: false, result };
  189. } else {
  190. // 银行 业务 以 Status 作为判断依据
  191. console.log(`Status:${Status}`);
  192. if (Status === 0) {
  193. return { isSuccess: true, result: getErrorInfoByCode(Status) };
  194. }
  195. return { isSuccess: false, result: getErrorInfoByCode(Status) };
  196. }
  197. }
  198. /**
  199. * 解析通用查询报文
  200. * @param rspParam
  201. */
  202. function parseCommonProtoRsp(rspParam: any): ParseRsp {
  203. //是否加密
  204. const funCodeName = rspParam.isSen ? 'QueryCommonSenRsp' : 'QueryCommonRsp';
  205. const { isSuccess, result } = parseSoleProtoRsp(rspParam, funCodeName);
  206. if (isSuccess) {
  207. // 组装数据
  208. const { FieldInfos, RowValues } = result.Rsps[0];
  209. // 此处只是简单处理
  210. const arr = RowValues.map((item: any) => {
  211. const result: any = {};
  212. FieldInfos.forEach((el: any, i: number) => {
  213. const { FieldName, FieldType } = el;
  214. const dateType = ['date', 'time', 'datetime', 'timestamp'];
  215. let value = item.RowValues[i];
  216. if (dateType.includes(lower(FieldType))) {
  217. // 解决safari时间问题
  218. value = value.replace(/-/g, '/').replace('.0', '');
  219. }
  220. result[lower(FieldName)] = value;
  221. });
  222. return result;
  223. });
  224. return { isSuccess: true, result: arr };
  225. } else {
  226. return { isSuccess, result };
  227. }
  228. }
  229. /**
  230. * 解析通知
  231. * @param rspPackage 回应包
  232. * @param funCodeName funcode 名
  233. */
  234. export const noticeParseRsp = (rspPackage: any, funCodeName: string) => {
  235. isErrer(rspPackage, funCodeName);
  236. const reqPackage = ProtobufCtr.generateProtoContent(funCodeName, rspPackage.content);
  237. console.log('接收到推送通知', reqPackage)
  238. if (reqPackage.RetCode) {
  239. let errMsg = getErrorInfoByCode(String(reqPackage.RetCode));
  240. if (errMsg === '') {
  241. errMsg = `未知错误:${reqPackage.RetCode}`;
  242. }
  243. return errMsg;
  244. }
  245. };
  246. function lower(value: string): string {
  247. return value.toLowerCase();
  248. }
  249. // 枚举 proto hader
  250. export function protoMiddleware<T>(param: T, reqName: string, rspName: string, headerEnum: HeadEnum): Promise<any>
  251. // 自定义 protp header
  252. export function protoMiddleware<T>(param: T, reqName: string, rspName: string, headerEnum: IMessageHead): Promise<any>
  253. /**
  254. * 此方法站在 用户角度
  255. * @param param proto除去head 剩下参数
  256. * @param headerEnumOrParam 自定义的proto参数枚举值,减小重复抒写 默认0,当枚举情况不满足,可以重新写一个 header 传入
  257. * @param reqFuncodeName proto 发送请求定义的头名字,特别需要注意,自已的funCodeName要与这个一致
  258. * @param rspFuncodeName proto 响应请求定义的头名字
  259. * @returns
  260. */
  261. export function protoMiddleware<T>(param: T, reqName: string, rspName: string, headerEnumOrParam: HeadEnum | IMessageHead = 0): Promise<any> {
  262. return new Promise((resolve, reject) => {
  263. const params = {
  264. protobufName: reqName,
  265. funCodeName: reqName,
  266. reqParams: param,
  267. Header: headerEnumOrParam,
  268. };
  269. const package50 = buildProtoReq50(params);
  270. const code = rspName ? funCode[rspName] : undefined
  271. APP.sendTradingServer(package50, code, {
  272. onSuccess: (res) => {
  273. const { isSuccess, result } = parseProtoRsp50(res, rspName);
  274. if (isSuccess) {
  275. resolve(result);
  276. } else {
  277. reject(result);
  278. }
  279. },
  280. onFail: (err) => {
  281. //console.log(`proto:${reqName}错误消息:${err}`)
  282. reject(err.message)
  283. },
  284. } as Callback);
  285. });
  286. }