Distromate Docs

JavaScript 接入

适用于 Electron 应用和其他 Node.js 桌面程序

准备工作

  1. 获取 dm_api.dlldm_api.js 文件
  2. 将 DLL 文件放置在程序运行目录
  3. dm_api.js 添加到项目中

依赖

安装 FFI 相关依赖:

npm install ffi-napi ref-napi

导入模块

const { DmApi } = require('./dm_api');

快速开始

const { DmApi } = require('./dm_api');

const publicKey = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
`;

// 创建 API 实例
const api = new DmApi(publicKey, 'dm_api.dll');

// 1. 检查是否由 Launcher 启动
if (api.restartAppIfNecessary()) {
    // Launcher 已启动,退出当前进程
    process.exit(0);
}

// 2. 连接到 Launcher
if (!api.connect('\\\\.\\pipe\\distromate_pipe', 5000)) {
    console.error('Connection failed');
    process.exit(1);
}

// 3. 验证许可证
const data = api.verify();
if (data) {
    console.log('License verified!');
    console.log('License:', data.license_key);
    console.log('Expires:', data.expires_at);
} else {
    console.error('Verification failed');
    api.close();
    process.exit(1);
}

// 4. 通知初始化完成
if (!api.initiated()) {
    console.error('Failed to notify initiated');
}

// 应用主逻辑...
console.log('Application running...');

// 程序退出时关闭连接
process.on('exit', () => {
    api.close();
});

API 参考

DmApi 类

构造函数

new DmApi(publicKeyPEM, dllPath = 'dm_api.dll')

参数:

参数类型描述
publicKeyPEMstringPEM 格式的 RSA 公钥
dllPathstringDLL 文件路径,默认为 dm_api.dll

restartAppIfNecessary

检查程序是否由 Launcher 启动,如果不是则通过 Launcher 重启。

restartAppIfNecessary(): boolean

返回值:

  • true: 已启动 Launcher,当前进程应退出
  • false: 程序由 Launcher 启动,无需重启

connect

连接到 Launcher。

connect(pipe: string, timeout?: number): boolean

参数:

参数类型描述
pipestringPipe 名称,格式: \\.\pipe\<name>
timeoutnumber超时时间(毫秒),默认 5000

返回值: 连接是否成功

close

关闭与 Launcher 的连接。

close(): void

verify

验证许可证。自动生成 nonce 并验证响应签名。

verify(): object | null

返回值:

  • 成功: 包含许可证数据的对象
  • 失败: null

activate

激活许可证。自动生成 nonce 并验证响应签名。

activate(): object | null

返回值:verify

initiated

通知 Launcher 程序初始化完成。

initiated(): boolean

返回值: 操作是否成功

Electron 集成

主进程 (main.js)

const { app, BrowserWindow } = require('electron');
const { DmApi } = require('./dm_api');
const path = require('path');

const publicKey = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
`;

let mainWindow;
let api;

async function verifyLicense() {
    // DLL 路径(打包后在 resources 目录)
    const dllPath = app.isPackaged
        ? path.join(process.resourcesPath, 'dm_api.dll')
        : path.join(__dirname, 'dm_api.dll');

    api = new DmApi(publicKey, dllPath);

    // 检查启动方式
    if (api.restartAppIfNecessary()) {
        app.quit();
        return false;
    }

    // 连接
    if (!api.connect('\\\\.\\pipe\\distromate_pipe')) {
        console.error('Failed to connect to launcher');
        return false;
    }

    // 验证
    const data = api.verify();
    if (!data) {
        console.error('License verification failed');
        api.close();
        return false;
    }

    console.log('License verified:', data);

    // 通知完成
    api.initiated();

    return true;
}

app.whenReady().then(async () => {
    // 先验证许可证
    if (!await verifyLicense()) {
        app.quit();
        return;
    }

    // 创建窗口
    mainWindow = new BrowserWindow({
        width: 1200,
        height: 800,
        webPreferences: {
            nodeIntegration: true
        }
    });

    mainWindow.loadFile('index.html');
});

app.on('window-all-closed', () => {
    if (api) {
        api.close();
    }
    app.quit();
});

package.json 配置

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "build": "electron-builder"
  },
  "dependencies": {
    "ffi-napi": "^4.0.3",
    "ref-napi": "^3.0.3"
  },
  "devDependencies": {
    "electron": "^28.0.0",
    "electron-builder": "^24.0.0"
  },
  "build": {
    "extraResources": [
      {
        "from": "dm_api.dll",
        "to": "dm_api.dll"
      }
    ]
  }
}

完整示例

const { DmApi } = require('./dm_api');

const publicKey = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----
`;

function main() {
    const api = new DmApi(publicKey);

    // 检查启动方式
    if (api.restartAppIfNecessary()) {
        console.log('Restarting via launcher...');
        process.exit(0);
    }

    // 连接
    if (!api.connect('\\\\.\\pipe\\distromate_pipe')) {
        console.error('Connection failed');
        process.exit(1);
    }

    console.log('Connected to launcher');

    // 验证
    const data = api.verify();
    if (!data) {
        console.error('Verification failed');
        api.close();
        process.exit(1);
    }

    // 打印许可证信息
    console.log('License verified!');
    printLicenseInfo(data);

    // 通知完成
    if (!api.initiated()) {
        console.warn('Warning: failed to notify initiated');
    }

    // 应用主逻辑...
    console.log('Application running...');

    // 清理
    process.on('SIGINT', () => {
        console.log('Shutting down...');
        api.close();
        process.exit(0);
    });
}

function printLicenseInfo(data) {
    if (data.user_name) {
        console.log('User:', data.user_name);
    }

    if (data.product_id) {
        console.log('Product:', data.product_id);
    }

    if (data.expires_at) {
        console.log('Expires:', data.expires_at);
    }

    if (data.features && Array.isArray(data.features)) {
        console.log('Features:');
        data.features.forEach(feature => {
            console.log(`  - ${feature}`);
        });
    }
}

main();

错误处理

const { DmApi } = require('./dm_api');

function initLicense(publicKey) {
    try {
        const api = new DmApi(publicKey);

        if (api.restartAppIfNecessary()) {
            return { success: false, reason: 'restart' };
        }

        if (!api.connect('\\\\.\\pipe\\distromate_pipe')) {
            return { success: false, reason: 'connection_failed' };
        }

        const data = api.verify();
        if (!data) {
            api.close();
            return { success: false, reason: 'verification_failed' };
        }

        api.initiated();

        return { success: true, data, api };

    } catch (error) {
        return { success: false, reason: 'error', error: error.message };
    }
}

// 使用
const result = initLicense(publicKey);

if (!result.success) {
    switch (result.reason) {
        case 'restart':
            process.exit(0);
            break;
        case 'connection_failed':
            console.error('Cannot connect to launcher');
            break;
        case 'verification_failed':
            console.error('License verification failed');
            break;
        case 'error':
            console.error('Error:', result.error);
            break;
    }
    process.exit(1);
}

console.log('License data:', result.data);

注意事项

  1. Node.js SDK 内置了 RSA 签名验证功能
  2. 需要安装 ffi-napiref-napi 依赖
  3. Electron 打包时需要将 DLL 文件包含在资源中
  4. 所有 API 调用都是同步的
  5. 在 Electron 中只能在主进程调用 SDK

On this page