Browse Source

fix: 修复基础api
test: 基础api的测试用例

kindring 10 months ago
parent
commit
858f85188b
5 changed files with 1445 additions and 601 deletions
  1. 485 565
      package-lock.json
  2. 3 0
      package.json
  3. 35 28
      src/apis/baseApi.ts
  4. 120 0
      src/test/baseApi.test.ts
  5. 802 8
      yarn.lock

File diff suppressed because it is too large
+ 485 - 565
package-lock.json


+ 3 - 0
package.json

@@ -12,6 +12,7 @@
   "devDependencies": {
     "@types/better-sqlite3": "^7.6.10",
     "@types/express": "^4.17.21",
+    "@types/jest": "^29.5.12",
     "@vitejs/plugin-vue": "^4.2.3",
     "autoprefixer": "^10.4.19",
     "better-sqlite3": "^10.0.0",
@@ -20,10 +21,12 @@
     "electron-rebuild": "^3.2.9",
     "express": "^4.19.2",
     "fs-extra": "^11.2.0",
+    "jest": "^29.7.0",
     "knex": "^3.1.0",
     "log4js": "^6.9.1",
     "postcss": "^8.4.38",
     "tailwindcss": "^3.4.3",
+    "ts-jest": "^29.1.4",
     "typescript": "^5.0.2",
     "vite": "^4.4.5",
     "vite-plugin-optimizer": "^1.4.2",

+ 35 - 28
src/apis/baseApi.ts

@@ -3,8 +3,6 @@
  */
 import {ApiType, ErrorCode, NotifyData, RequestData, ResponseData} from "@/types/apiTypes.ts";
 import {randomId} from "@/util/random.ts";
-import {ipcRenderer} from "electron";
-import {actionMap} from "@/tools/IpcCmd.ts";
 
 interface CallItem {
     callId: string;
@@ -39,7 +37,7 @@ export type ListenerFunction = (channel: string, listener: (event: any, ...args:
 
 
 
-class ApiController {
+export class ApiController {
     sign = ''
     calls: Calls = {}
     notifyMap: NotifyMap = {}
@@ -48,8 +46,8 @@ class ApiController {
     // 最近的过期检测id
     lastCheckId: string = ""
     checkTimer: NodeJS.Timeout | null = null
-    // 下一次检测的间隔时间
-    checkInterval = 100
+    // 下一次检测的间隔时间, 毫秒
+    checkInterval = 10
     isInit: boolean = false
     // init 前尝试发送的数据
     sendTasks: RequestData[] = []
@@ -107,7 +105,7 @@ class ApiController {
         }
         return this.buildNotifyId(action)
     }
-    private apiControllerHandler(_:any, data: ResponseData | NotifyData)
+    private apiControllerHandler = (_:any, data: ResponseData | NotifyData) =>
     {
         switch(data.type){
             case ApiType.res:
@@ -123,7 +121,7 @@ class ApiController {
                 break;
         }
     }
-    private callResponseHandle(call: CallItem, responseData: ResponseData){
+    private callResponseHandle = (call: CallItem, responseData: ResponseData) => {
         if( this.lastCheckId === call.callId){
             // 取消检测当前函数的定时器, 防止多次触发
             if(this.checkTimer){
@@ -132,7 +130,6 @@ class ApiController {
             this.checkTimer = null
             this.lastCheckId = "";
             this.lastCheckTime = 0;
-
         }
         // 执行回调
         call.resolve(responseData)
@@ -162,6 +159,7 @@ class ApiController {
         }
 
         let timeWait = callItem.endTime - nowTimeStamp - this.checkInterval
+        console.log(`[I] startTimeoutCheck: ${callId} timeWait: ${timeWait}`)
         // 在已经有一个超时检查的情况下, 判断新的超时时间是否小于当前正在执行的超时时间. 用于将计时器更新为最新的
         if(this.lastCheckId && callId !== this.lastCheckId){
             if(callItem.endTime < this.lastCheckTime){
@@ -182,12 +180,16 @@ class ApiController {
         }
         this.lastCheckTime = callItem.endTime
         this.lastCheckId = callId
-        if(timeWait > 0){
-            
+        // 防止负数导致疯狂执行
+        if(timeWait > 0 || timeWait + this.checkInterval > 5){
+            if(timeWait < 0){
+                timeWait = Math.abs(timeWait)
+            }
             this.checkTimer = setTimeout(() => {
                 this.checkTimeout()
             }, timeWait)
         }
+        // 如果超时时间小于等于0, 立即判断是否已经超时
         if(timeWait <= 0){
             // 立即执行
             this.checkTimeout()
@@ -196,20 +198,21 @@ class ApiController {
     // 超时检查
     private checkTimeout() {
         let callItem = this.calls[this.lastCheckId]
-        if(!callItem || callItem.endTime != -1){
+        if(!callItem || callItem.endTime === -1){
             // 尝试获取calls中获取到期时间最小的一个请求
             this.logFn(`[W] checkTimeout: ${this.lastCheckId} not supported check timeoutDate: ${callItem?.endTime}`)
             return this.findNextTimeoutCall()
         }
         let nowTimeStamp = Date.now()
-        if (callItem.endTime > nowTimeStamp){
-            this.callTimeoutHandle(callItem)
+        if (callItem.endTime < nowTimeStamp){
+            return this.callTimeoutHandle(callItem)
         }
         // 暂未超时,
         this.startTimeoutCheck(this.lastCheckId)
     }
     private callTimeoutHandle(callItem: CallItem)
     {
+        this.logFn(`[E] ${callItem.callId} timeout endTime:${callItem.endTime}`)
         // 移除超时检查
         this.lastCheckTime = 0;
         this.lastCheckId = "";
@@ -269,7 +272,7 @@ class ApiController {
      * @param params
      * @param timeout
      */
-    sendQuery(action: string, params: any, timeout: number = 5000) {
+    sendQuery(action: string, params: any, timeout: number = 5000): [callId: string, Promise<ResponseData>] {
         let callId = this.buildCallId()
         let requestData: RequestData = {
             type: ApiType.req,
@@ -291,29 +294,32 @@ class ApiController {
         // 获取当前的时间戳
         let timeStamp = Date.now()
         // 加上通信超时时间
-        let endTime = timeStamp +  + 200
+        let endTime = timeStamp + timeout + 200
+
+        let promise: Promise<ResponseData> = new Promise((resolve, reject) => {
+            this.calls[callId] = {
+                action: action,
+                callId: callId,
+                resolve: resolve,
+                reject: reject,
+                endTime: endTime,
+                isInit: !this.isInit,
+            }
+        })
         // 如果是-1, 则表示不设置超时时间, 永久等待检测
         if(timeout === -1){
             endTime = -1
         }else{
             if(this.isInit){
+                console.log(`[I] start timeout check: ${callId} now: ${timeStamp} endTime: ${endTime} wait: ${timeout}`)
                 this.startTimeoutCheck(callId)
             }else{
                 this.logFn(`!!!Try calling the send function before initializing`)
             }
         }
-        return new Promise((resolve, reject) => {
-            this.calls[callId] = {
-                action: action,
-                callId: callId,
-                resolve: resolve,
-                reject: reject,
-                endTime: endTime,
-                isInit: !this.isInit,
-            }
-        })
+        return [callId, promise]
     }
-    registerNotify(action: string, isOnce: boolean = false, callback: (params: any) => void): string {
+    registerNotify(action: string, isOnce: boolean = false, callback: (params: NotifyData) => void): string {
         if (!this.notifyMap[action]) {
             // 初始化 notify 对象
             this.notifyMap[action] = {
@@ -331,7 +337,6 @@ class ApiController {
     // 取消方法
     cancelQuery(callId: string) {
         if(this.calls[callId]){
-
             this.callResponseHandle(this.calls[callId], {
                 type: ApiType.res,
                 action: this.calls[callId].action,
@@ -344,7 +349,7 @@ class ApiController {
         }
     }
     destroy() {
-        ipcRenderer.removeListener(actionMap.apiControllerHandler.code, this.apiControllerHandler)
+
     }
 }
 
@@ -354,5 +359,7 @@ let api: ApiController | null = null
 if(!api){
     api = new ApiController()
 }
+
+
 export default api as ApiController
 

+ 120 - 0
src/test/baseApi.test.ts

@@ -0,0 +1,120 @@
+import { ApiController } from '@/apis/baseApi.ts';
+import {ApiType, ErrorCode, NotifyData, RequestData, ResponseData} from "@/types/apiTypes.ts";
+
+let listenFn: (event:any , data: ResponseData | NotifyData) => void = () => {}
+function sendFn(action: string, params: RequestData){
+    // 随机延迟
+    // console.log(`sendFn`)
+    // 延迟4秒
+    setTimeout(() => {
+        listenFn(action, {
+            type: ApiType.res,
+            code: ErrorCode.success,
+            callId: params.callId,
+            msg: 'success',
+            action: action,
+            data: params.data
+        })
+    }, 4000)
+}
+
+
+describe('ApiController', () => {
+    const sendActionKey = 'testSendKey';
+    const listenerActionKey = 'testListenerKey';
+    let apiController: ApiController;
+
+    beforeEach(() => {
+        apiController = new ApiController();
+        // 初始化发送以及监听函数
+        apiController.init('testSign', sendFn, (_action: string, callback: (event:any , data: ResponseData | NotifyData) => void) => {
+            // console.log(`callback init listen ${action}`)
+            listenFn = callback
+        }, sendActionKey, listenerActionKey);
+        apiController.setLogFn(console.log);
+    });
+
+    afterEach(() => {
+        apiController.destroy();
+    });
+
+    it('should send a query and receive a response', async () => {
+        const params = { key: 'value' };
+        const timeout = 5000;
+
+        const [_callId, responsePromise] = apiController.sendQuery(sendActionKey, params, timeout);
+        const response = await responsePromise;
+        console.log(response)
+        expect(response).toBeDefined();
+        expect(response.type).toBe(ApiType.res);
+        expect(response.action).toBe(sendActionKey);
+        expect(response.data).toEqual(params);
+        expect(response.code).toBe(ErrorCode.success)
+        expect(response.msg).toBe('success')
+    });
+
+    it('should register a notify handler and receive a notification', (done) => {
+        const action = 'testNotifyAction';
+        const params = { key: 'value' };
+
+        const notifyCallback = (data: NotifyData) => {
+            expect(data).toBeDefined();
+            expect(data.type).toBe(ApiType.notify);
+            expect(data.action).toBe(action);
+            expect(data.data).toEqual(params);
+            expect(data.code).toBe(ErrorCode.success);
+            expect(data.msg).toBe('is notify')
+            done();
+        };
+
+       apiController.registerNotify(action, false, notifyCallback);
+
+       listenFn(action, {
+           type: ApiType.notify,
+           action: action,
+           code: ErrorCode.success,
+           msg: 'is notify',
+           data: params
+       })
+
+    }, 10000);
+
+    it('should cancel a query ', async () => {
+        const params = { key: 'value' };
+        const timeout = 5000;
+
+        const [callId, responsePromise] = apiController.sendQuery(sendActionKey, params, timeout);
+
+        expect(apiController.calls[callId]).toBeDefined();
+
+        apiController.cancelQuery(callId);
+        expect(apiController.calls[callId]).toBeUndefined();
+
+        const response = await responsePromise;
+
+
+
+
+        expect(response.type).toBe(ApiType.res)
+        expect(response.action).toBe(sendActionKey)
+        expect(response.code).toBe(ErrorCode.cancel)
+    });
+
+    it('should change the sign', () => {
+        const newSign = 'newSign';
+
+        apiController.changeSign(newSign);
+
+        expect(apiController.sign).toBe(newSign);
+    });
+
+    it('should set a log function', () => {
+        const logFn = jest.fn();
+
+        apiController.setLogFn(logFn);
+
+        expect(apiController.logFn).toBe(logFn);
+    });
+
+
+});

File diff suppressed because it is too large
+ 802 - 8
yarn.lock


Some files were not shown because too many files changed in this diff