智能图书馆管理系统开发实战系列(五):前后端集成 - koffi调用与接口设计

前言

在前面的文章中,我们分别完成了前端React应用和后端C++ DLL的开发。本文将详细介绍如何通过koffi库实现JavaScript与C++的无缝集成,这是整个系统最关键的技术环节。我们将深入探讨数据类型转换、错误处理、性能优化等核心实践。

koffi技术方案概述

为什么选择koffi?

koffi是一个现代化的Node.js原生库调用方案,相比传统的node-ffi具有以下优势:

  1. 性能更优: 基于最新的V8 API,调用开销更小
  2. 类型安全: 更好的TypeScript支持和类型检查
  3. 内存管理: 自动的内存管理,减少内存泄漏风险
  4. 现代API: 支持Promise、async/await等现代异步模式
  5. 跨平台: 支持Windows、Linux、macOS等多平台

技术架构设计

我们的前后端集成采用三层架构:

Frontend (React/TypeScript)
    ↓ (IPC)
Electron Main Process (koffi)
    ↓ (FFI)
C++ DLL (Business Logic)

数据流向:

  1. React组件调用useBackendAPI Hook
  2. 通过Electron IPC发送请求到主进程
  3. 主进程使用koffi调用C++ DLL函数
  4. C++ DLL处理业务逻辑并返回JSON结果
  5. 结果通过相同路径返回到React组件

koffi集成实现

1. 主进程koffi配置

code/frontend/electron/main.ts 中配置koffi:

import {
   
    koffi } from 'koffi';
import path from 'path';

interface BackendLibrary {
   
   
  InitLibrary: (configJson: string) => boolean;
  ShutdownLibrary: () => void;
  AddBook: (bookJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
  DeleteBook: (bookId: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
  EditBook: (bookJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
  GetBookList: (queryJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
  BorrowBook: (requestJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
  ReturnBook: (requestJson: string, resultJson: koffi.Buffer, resultSize: number) => boolean;
  GetDashboardStats: (resultJson: koffi.Buffer, resultSize: number) => boolean;
}

class BackendManager {
   
   
  private static instance: BackendManager;
  private library: BackendLibrary | null = null;
  private initialized = false;

  public static getInstance(): BackendManager {
   
   
    if (!BackendManager.instance) {
   
   
      BackendManager.instance = new BackendManager();
    }
    return BackendManager.instance;
  }

  public initialize(): boolean {
   
   
    try {
   
   
      // 确定DLL路径
      const dllPath = this.getDllPath();
      
      // 加载DLL
      const lib = koffi.load(dllPath);

      // 定义函数接口
      this.library = {
   
   
        InitLibrary: lib.func('InitLibrary', 'bool', ['string']),
        ShutdownLibrary: lib.func('ShutdownLibrary', 'void', []),
        
        // 图书管理接口
        AddBook: lib.func('AddBook', 'bool', ['string', 'char *', 'int']),
        DeleteBook: lib.func('DeleteBook', 'bool', ['string', 'char *', 'int']),
        EditBook: lib.func('EditBook', 'bool', ['string', 'char *', 'int']),
        GetBookList: lib.func('GetBookList', 'bool', ['string', 'char *', 'int']),
        
        // 借阅管理接口
        BorrowBook: lib.func('BorrowBook', 'bool', ['string', 'char *', 'int']),
        ReturnBook: lib.func('ReturnBook', 'bool', ['string', 'char *', 'int']),
        
        // 仪表板接口
        GetDashboardStats: lib.func('GetDashboardStats', 'bool', ['char *', 'int'])
      };

      // 初始化C++库
      const config = {
   
   
        dbPath: path.join(app.getPath('userData'), 'library.db'),
        logPath: path.join(app.getPath('userData'), 'logs'),
        maxCacheSize: 1000,
        enableDebugLog: process.env.NODE_ENV === 'development'
      };

      const success = this.library.InitLibrary(JSON.stringify(config));
      if (success) {
   
   
        this.initialized = true;
        console.log('Backend library initialized successfully');
      }

      return success;
    } catch (error) {
   
   
      console.error('Failed to initialize backend library:', error);
      return false;
    }
  }

  private getDllPath(): string {
   
   
    const isDev = process.env.NODE_ENV === 'development';
    const basePath = isDev 
      ? path.join(__dirname, '../../dll')
      : path.join(process.resourcesPath, 'dll');
    
    const dllName = process.platform === 'win32' 
      ? 'libBackend.dll'
      : process.platform === 'darwin'
      ? 'libBackend.dylib'
      : 'libBackend.so';
      
    return path.join(basePath, dllName);
  }

  public async callFunction<T = any>(
    functionName: keyof BackendLibrary,
    params?: any
  ): Promise<{
   
    success: boolean; data?: T; error?: string }> {
   
   
    if (!this.initialized || !this.library) {
   
   
      throw new Error('Backend library not initialized');
    }

    return new Promise((resolve) => {
   
   
      try {
   
   
        const resultBuffer = Buffer.alloc(8192); // 8KB缓冲区
        let success = false;

        // 根据函数类型调用不同的接口
        switch (functionName) {
   
   
          case 'GetDashboardStats':
            success = this.library.GetDashboardStats(resultBuffer, resultBuffer.length);
            break;
            
          case 'AddBook':
          case 'EditBook':
            success = this.library[functionName](
              JSON.stringify(params),
              resultBuffer,
              resultBuffer.length
            );
            break;
            
          case 'DeleteBook':
            success = this.library.DeleteBook(
              params.id,
              resultBuffer,
              resultBuffer.length
            );
            break;
            
          case 'GetBookList':
            success = this.library.GetBookList(
              JSON.stringify(params || {
   
   }),
              resultBuffer,
              resultBuffer.length
            );
            break;
            
          case 'BorrowBook':
          case 'ReturnBook':
            success = this.library[functionName](
              JSON.stringify(params),
              resultBuffer,
              resultBuffer.length
            );
            break;
            
          default:
            resolve({
   
    success: false, error: 'Unknown function' });
            return;
        }

        if (success) {
   
   
          // 解析返回的JSON数据
          const resultStr = resultBuffer.toString('utf8').replace(/\0.*$/g, '');
          try {
   
   
            const result = JSON.parse(resultStr);
            resolve({
   
    success: true, data: result });
          } catch (parseError) {
   
   
            resolve({
   
    success: false, error: 'Failed to parse result JSON' });
          }
        } else {
   
   
          resolve({
   
    success: false, error: 'Backend function call failed' });
        }
      } catch (error) {
   
   
        resolve({
   
    
          success: false, 
          error: error instanceof Error ? error.message : 'Unknown error' 
        });
      }
    });
  }

  public shutdown(): void {
   
   
    if (this.initialized && this.library) {
   
   
      this.library.ShutdownLibrary();
      this.initialized = false;
      console.log('Backend library shutdown');
    }
  }
}

export {
   
    BackendManager };

2. IPC通信层

实际项目中的IPC处理器通过 DllBridge 类实现:

// electron/main.ts 中的主进程配置
import {
   
    app, BrowserWindow, ipcMain 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值