Croupier JavaScript SDKCroupier JavaScript SDK
指南
API 参考
  • C++
  • Go
  • Java
  • Python
Croupier 主项目
GitHub
指南
API 参考
  • C++
  • Go
  • Java
  • Python
Croupier 主项目
GitHub
  • Croupier JavaScript SDK
  • 指南

    • 入门指南
  • API

    • API 参考

API 参考

本文档提供 Croupier JS/TS SDK 的完整 API 参考。

包结构

import {
  // 核心类
  BasicClient,
  createClient,

  // 类型定义
  CroupierClient,
  FunctionDescriptor,
  FunctionHandler,
  FileTransferConfig,
  FileUploadRequest,
} from 'croupier-sdk';

核心类型

FunctionHandler

函数处理器类型定义。

type FunctionHandler = (
  context: string,
  payload: string
) => Promise<string> | string;

参数:

  • context: 调用上下文(JSON 字符串)
  • payload: 函数参数(JSON 字符串)

返回值:

  • Promise<string> | string: 函数执行结果(JSON 字符串),支持同步或异步

使用示例:

const handler: FunctionHandler = async (context, payload) => {
  const ctx = JSON.parse(context);
  const data = JSON.parse(payload);
  const playerId = data.player_id;

  // 业务逻辑
  await banPlayer(playerId);

  return JSON.stringify({ status: 'success' });
};

FunctionDescriptor

函数描述符接口。

interface FunctionDescriptor {
  // 必填字段
  id: string;                              // 函数 ID,格式: [namespace.]entity.operation
  version: string;                         // 语义化版本号

  // 可选字段
  name?: string;                           // 显示名称
  description?: string;                    // 描述
  input_schema?: Record<string, any>;      // 输入 JSON Schema
  output_schema?: Record<string, any>;     // 输出 JSON Schema
}

使用示例:

const descriptor: FunctionDescriptor = {
  id: 'player.ban',
  version: '1.0.0',
  name: '封禁玩家',
  description: '封禁指定玩家账号',
  input_schema: {
    type: 'object',
    required: ['player_id'],
    properties: {
      player_id: { type: 'string' },
      reason: { type: 'string' },
    },
  },
};

FileTransferConfig

客户端配置接口(兼作 ClientConfig 使用)。

interface FileTransferConfig {
  // 连接配置
  agentAddr?: string;                      // Agent gRPC 地址,默认 "127.0.0.1:19090"
  controlAddr?: string;                    // 控制服务地址
  localListen?: string;                    // 本地服务器监听地址,默认 "127.0.0.1:0"
  timeout?: number;                        // 连接超时(毫秒),默认 30000
  insecure?: boolean;                      // 是否跳过 TLS,默认 true

  // 服务标识
  serviceId?: string;                      // 服务标识符
  serviceVersion?: string;                 // 服务版本,默认 "1.0.0"

  // 心跳配置
  heartbeatIntervalSeconds?: number;       // 心跳间隔(秒),默认 60

  // 重试配置
  retryAttempts?: number;                  // 重试次数,默认 3

  // Provider 元数据
  providerLang?: string;                   // Provider 语言,默认 "node"
  providerSdk?: string;                    // SDK 标识,默认 "croupier-js-sdk"
}

使用示例:

const config: FileTransferConfig = {
  agentAddr: 'localhost:19090',
  insecure: true,
  serviceId: 'player-service',
  serviceVersion: '1.0.0',
  heartbeatIntervalSeconds: 30,
};

FileUploadRequest

文件上传请求接口。

interface FileUploadRequest {
  filePath: string;                        // 文件路径
  content: Buffer | string;                // 文件内容
  metadata?: Record<string, any>;          // 元数据
}

CroupierClient 接口

客户端接口定义。

interface CroupierClient {
  // 连接到 Agent
  connect(): Promise<void>;

  // 断开连接
  disconnect(): Promise<void>;

  // 注册函数
  registerFunction(
    descriptor: FunctionDescriptor,
    handler: FunctionHandler
  ): Promise<void>;

  // 上传文件
  uploadFile(request: FileUploadRequest): Promise<void>;
}

BasicClient 类

主客户端类,实现 CroupierClient 接口。

构造函数

constructor(config?: FileTransferConfig)

参数:

  • config: 客户端配置,可选,使用默认配置

公共方法

connect

连接到 Agent。

async connect(): Promise<void>

异常:

  • Error: 未注册任何函数时抛出
  • Error: 连接失败时抛出

disconnect

断开连接。

async disconnect(): Promise<void>

registerFunction

注册函数处理器。

async registerFunction(
  descriptor: FunctionDescriptor,
  handler: FunctionHandler
): Promise<void>

参数:

  • descriptor: 函数描述符
  • handler: 函数处理器

异常:

  • Error: 已连接时注册抛出
  • Error: 描述符缺少 id 或 version 时抛出

uploadFile

上传文件(未实现)。

async uploadFile(request: FileUploadRequest): Promise<void>

注意: 当前版本未实现,调用会抛出错误。


工厂函数

createClient

创建客户端实例的工厂函数。

function createClient(config?: FileTransferConfig): CroupierClient

使用示例:

const client = createClient({
  agentAddr: 'localhost:19090',
  insecure: true,
});

内部类型

JobEvent(来自 Proto 定义)

任务事件类型。

interface JobEvent {
  type: string;       // 事件类型: "started"|"progress"|"completed"|"error"|"cancelled"
  message: string;    // 事件消息
  progress: number;   // 进度 0-100
  payload: Uint8Array; // 结果负载
}

完整示例

Provider 示例

import { createClient, FunctionDescriptor, FunctionHandler } from 'croupier-sdk';

async function main() {
  // 创建客户端
  const client = createClient({
    agentAddr: 'localhost:19090',
    insecure: true,
    serviceId: 'player-service',
    serviceVersion: '1.0.0',
  });

  // 定义函数描述符
  const banDescriptor: FunctionDescriptor = {
    id: 'player.ban',
    version: '1.0.0',
    name: '封禁玩家',
    description: '封禁指定玩家账号',
    input_schema: {
      type: 'object',
      required: ['player_id'],
      properties: {
        player_id: { type: 'string' },
        reason: { type: 'string' },
      },
    },
  };

  // 定义处理器
  const banHandler: FunctionHandler = async (context, payload) => {
    const data = JSON.parse(payload);
    const playerId = data.player_id;
    const reason = data.reason || '未指定';

    console.log(`封禁玩家: ${playerId}, 原因: ${reason}`);

    // 业务逻辑
    await performBan(playerId, reason);

    return JSON.stringify({ status: 'success' });
  };

  // 注册函数
  await client.registerFunction(banDescriptor, banHandler);

  // 注册更多函数
  await client.registerFunction(
    { id: 'player.get', version: '1.0.0' },
    async (ctx, payload) => {
      const { player_id } = JSON.parse(payload);
      const player = await getPlayer(player_id);
      return JSON.stringify(player);
    }
  );

  // 连接到 Agent
  await client.connect();
  console.log('服务已启动');

  // 优雅退出
  process.on('SIGINT', async () => {
    console.log('正在关闭...');
    await client.disconnect();
    process.exit(0);
  });

  // 保持进程运行
  await new Promise(() => {});
}

async function performBan(playerId: string, reason: string) {
  // 实际业务逻辑
}

async function getPlayer(playerId: string) {
  // 实际业务逻辑
  return { id: playerId, name: 'Player' };
}

main().catch(console.error);

Express 集成示例

import express from 'express';
import { createClient, CroupierClient } from 'croupier-sdk';

const app = express();
let croupierClient: CroupierClient;

// 初始化 Croupier 客户端
async function initCroupier() {
  croupierClient = createClient({
    agentAddr: process.env.CROUPIER_AGENT_ADDR || 'localhost:19090',
    insecure: process.env.NODE_ENV !== 'production',
    serviceId: 'express-service',
    serviceVersion: '1.0.0',
  });

  // 注册 HTTP 触发的函数
  await croupierClient.registerFunction(
    { id: 'api.health', version: '1.0.0' },
    () => JSON.stringify({ status: 'healthy', timestamp: Date.now() })
  );

  await croupierClient.registerFunction(
    { id: 'user.create', version: '1.0.0' },
    async (ctx, payload) => {
      const user = JSON.parse(payload);
      // 创建用户逻辑
      return JSON.stringify({ id: 'new-user-id', ...user });
    }
  );

  await croupierClient.connect();
  console.log('Croupier 客户端已连接');
}

// Express 路由
app.get('/health', (req, res) => {
  res.json({ status: 'ok' });
});

// 启动服务器
const PORT = process.env.PORT || 3000;

initCroupier()
  .then(() => {
    app.listen(PORT, () => {
      console.log(`服务器运行在端口 ${PORT}`);
    });
  })
  .catch((err) => {
    console.error('初始化失败:', err);
    process.exit(1);
  });

// 优雅退出
process.on('SIGTERM', async () => {
  await croupierClient?.disconnect();
  process.exit(0);
});

NestJS 集成示例

// croupier.module.ts
import { Module, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { createClient, CroupierClient } from 'croupier-sdk';

@Module({
  providers: [
    {
      provide: 'CROUPIER_CLIENT',
      useFactory: () => {
        return createClient({
          agentAddr: process.env.CROUPIER_AGENT_ADDR || 'localhost:19090',
          insecure: process.env.NODE_ENV !== 'production',
        });
      },
    },
  ],
  exports: ['CROUPIER_CLIENT'],
})
export class CroupierModule implements OnModuleInit, OnModuleDestroy {
  constructor(
    @Inject('CROUPIER_CLIENT') private readonly client: CroupierClient
  ) {}

  async onModuleInit() {
    await this.client.registerFunction(
      { id: 'service.status', version: '1.0.0' },
      () => JSON.stringify({ status: 'running' })
    );
    await this.client.connect();
  }

  async onModuleDestroy() {
    await this.client.disconnect();
  }
}

// player.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { CroupierClient } from 'croupier-sdk';

@Injectable()
export class PlayerService {
  constructor(
    @Inject('CROUPIER_CLIENT') private readonly croupier: CroupierClient
  ) {}

  async registerHandlers() {
    await this.croupier.registerFunction(
      { id: 'player.get', version: '1.0.0' },
      async (ctx, payload) => {
        const { id } = JSON.parse(payload);
        const player = await this.findPlayer(id);
        return JSON.stringify(player);
      }
    );
  }

  private async findPlayer(id: string) {
    // 实际数据库查询
    return { id, name: 'Player' };
  }
}

同步处理器示例

import { createClient } from 'croupier-sdk';

const client = createClient({
  agentAddr: 'localhost:19090',
  insecure: true,
});

// 同步处理器(不使用 async)
await client.registerFunction(
  { id: 'math.add', version: '1.0.0' },
  (ctx, payload) => {
    const { a, b } = JSON.parse(payload);
    return JSON.stringify({ result: a + b });
  }
);

// 异步处理器
await client.registerFunction(
  { id: 'data.fetch', version: '1.0.0' },
  async (ctx, payload) => {
    const { url } = JSON.parse(payload);
    const response = await fetch(url);
    const data = await response.json();
    return JSON.stringify(data);
  }
);

await client.connect();

错误处理示例

import { createClient } from 'croupier-sdk';

const client = createClient({
  agentAddr: 'localhost:19090',
  insecure: true,
});

// 带错误处理的处理器
await client.registerFunction(
  { id: 'user.validate', version: '1.0.0' },
  async (ctx, payload) => {
    try {
      const { email, password } = JSON.parse(payload);

      if (!email) {
        return JSON.stringify({
          status: 'error',
          code: 'INVALID_PARAM',
          message: 'Email is required',
        });
      }

      if (password.length < 8) {
        return JSON.stringify({
          status: 'error',
          code: 'INVALID_PARAM',
          message: 'Password must be at least 8 characters',
        });
      }

      const user = await validateUser(email, password);
      return JSON.stringify({ status: 'success', data: user });

    } catch (error) {
      console.error('Validation error:', error);
      return JSON.stringify({
        status: 'error',
        code: 'INTERNAL_ERROR',
        message: error instanceof Error ? error.message : 'Unknown error',
      });
    }
  }
);

// 连接错误处理
try {
  await client.connect();
} catch (error) {
  console.error('连接失败:', error);
  // 重试逻辑或退出
  process.exit(1);
}

// 优雅退出
async function shutdown() {
  try {
    await client.disconnect();
    console.log('已断开连接');
  } catch (error) {
    console.error('断开连接失败:', error);
  }
  process.exit(0);
}

process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);

TypeScript 类型安全示例

import { createClient, FunctionDescriptor, FunctionHandler } from 'croupier-sdk';

// 定义请求和响应类型
interface BanRequest {
  player_id: string;
  reason?: string;
  duration_hours?: number;
}

interface BanResponse {
  status: 'success' | 'error';
  message?: string;
  banned_until?: string;
}

interface PlayerInfo {
  id: string;
  name: string;
  level: number;
  created_at: string;
}

// 类型安全的处理器工厂
function createTypedHandler<TReq, TRes>(
  handler: (ctx: Record<string, string>, req: TReq) => Promise<TRes> | TRes
): FunctionHandler {
  return async (context: string, payload: string) => {
    const ctx = JSON.parse(context) as Record<string, string>;
    const req = JSON.parse(payload) as TReq;
    const res = await handler(ctx, req);
    return JSON.stringify(res);
  };
}

// 使用类型安全的处理器
const client = createClient({ agentAddr: 'localhost:19090', insecure: true });

await client.registerFunction(
  { id: 'player.ban', version: '1.0.0' },
  createTypedHandler<BanRequest, BanResponse>(async (ctx, req) => {
    // req 具有完整的类型提示
    const { player_id, reason, duration_hours = 24 } = req;

    await banPlayer(player_id, reason, duration_hours);

    return {
      status: 'success',
      banned_until: new Date(Date.now() + duration_hours * 3600000).toISOString(),
    };
  })
);

await client.registerFunction(
  { id: 'player.get', version: '1.0.0' },
  createTypedHandler<{ player_id: string }, PlayerInfo>(async (ctx, req) => {
    const player = await getPlayer(req.player_id);
    return player;
  })
);

await client.connect();

// 辅助函数
async function banPlayer(id: string, reason?: string, hours?: number) {
  // 实现
}

async function getPlayer(id: string): Promise<PlayerInfo> {
  return {
    id,
    name: 'Player',
    level: 1,
    created_at: new Date().toISOString(),
  };
}

环境变量

环境变量说明默认值
CROUPIER_AGENT_ADDRAgent 地址127.0.0.1:19090
CROUPIER_INSECURE是否跳过 TLStrue
NODE_ENV环境模式-

错误处理

常见错误

错误消息原因解决方案
Register at least one function before connecting未注册函数就连接先调用 registerFunction
Cannot register new functions while connected连接后注册函数先调用 disconnect
Function descriptor must include id and version描述符不完整提供 id 和 version
Function not registered调用未注册的函数确保函数已注册

标准错误响应格式

interface ErrorResponse {
  status: 'error';
  code: string;
  message: string;
  details?: Record<string, any>;
}

标准错误码:

  • INVALID_PARAM: 参数错误
  • INVALID_JSON: JSON 格式错误
  • UNAUTHORIZED: 未授权
  • FORBIDDEN: 无权限
  • NOT_FOUND: 资源不存在
  • INTERNAL_ERROR: 内部错误

最佳实践

1. 函数 ID 命名

// ✅ 正确
'player.get'
'player.ban'
'game.player.ban'

// ❌ 错误
'PlayerGet'
'player-get'
'getPlayer'

2. 错误处理

// ✅ 总是返回标准格式的错误响应
const handler: FunctionHandler = async (ctx, payload) => {
  try {
    // 业务逻辑
    return JSON.stringify({ status: 'success', data: result });
  } catch (error) {
    return JSON.stringify({
      status: 'error',
      code: 'INTERNAL_ERROR',
      message: error.message,
    });
  }
};

3. 资源清理

// ✅ 使用优雅退出
const client = createClient(config);
await client.connect();

const shutdown = async () => {
  await client.disconnect();
  process.exit(0);
};

process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);

4. 配置管理

// ✅ 使用环境变量
const client = createClient({
  agentAddr: process.env.CROUPIER_AGENT_ADDR || 'localhost:19090',
  insecure: process.env.NODE_ENV !== 'production',
  serviceId: process.env.SERVICE_ID || 'my-service',
});
Edit this page
最近更新: 2026/3/19 03:59
Contributors: cuihairu