JavaScript 接入
适用于 Electron 应用和其他 Node.js 桌面程序
准备工作
- 获取
dm_api.dll和dm_api.js文件 - 将 DLL 文件放置在程序运行目录
- 将
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')参数:
| 参数 | 类型 | 描述 |
|---|---|---|
publicKeyPEM | string | PEM 格式的 RSA 公钥 |
dllPath | string | DLL 文件路径,默认为 dm_api.dll |
restartAppIfNecessary
检查程序是否由 Launcher 启动,如果不是则通过 Launcher 重启。
restartAppIfNecessary(): boolean返回值:
true: 已启动 Launcher,当前进程应退出false: 程序由 Launcher 启动,无需重启
connect
连接到 Launcher。
connect(pipe: string, timeout?: number): boolean参数:
| 参数 | 类型 | 描述 |
|---|---|---|
pipe | string | Pipe 名称,格式: \\.\pipe\<name> |
timeout | number | 超时时间(毫秒),默认 5000 |
返回值: 连接是否成功
close
关闭与 Launcher 的连接。
close(): voidverify
验证许可证。自动生成 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);注意事项
- Node.js SDK 内置了 RSA 签名验证功能
- 需要安装
ffi-napi和ref-napi依赖 - Electron 打包时需要将 DLL 文件包含在资源中
- 所有 API 调用都是同步的
- 在 Electron 中只能在主进程调用 SDK