# 事件订阅

OCAP Client 提供了一个强大的实时事件订阅系统，允许您的应用程序实时监听链上活动。该功能基于 WebSocket 构建，提供与区块链节点的持久连接，无需通过持续轮询来检查更新。

通过订阅特定的事件主题，您可以收到各种链上事件的即时通知，例如新交易创建、资产转移或代币交换。这对于构建能够实时响应区块链状态变化的响应式和交互式应用程序至关重要。要更深入地了解触发这些事件的原因，您可能需要查看[交易生命周期](./core-concepts-transaction-lifecycle.md)。


## 工作原理

在底层，当您首次订阅事件时，OCAP Client 会自动与区块链节点的指定端点建立 WebSocket 连接。该连接会保持活动状态，允许节点在事件发生时立即将事件数据推送到您的客户端。

客户端会为您管理 WebSocket 连接的生命周期。它会处理初始连接、发送心跳消息以保持连接活跃，并在连接断开时尝试重新连接。这确保了事件流的稳定可靠，而您只需进行最少的配置。


## 订阅事件

要开始监听事件，您可以使用 `subscribe` 方法。您需要提供一个事件主题（用于标识事件的字符串）和一个回调函数，该函数会在收到事件时执行。

```javascript OCAP Client icon=logos:javascript
const client = new GraphQLClient('https://beta.abtnetwork.io/api/v2/gql');

const handleNewTransaction = (eventData) => {
  console.log('A new transaction was created on-chain:', eventData);
};

// 订阅 'tx.create' 主题
client.subscribe('tx.create', handleNewTransaction);
```

### 方法签名

**`subscribe(topic, callback)`**

<x-field-group>
  <x-field data-name="topic" data-type="string" data-required="true" data-desc="要订阅的事件主题名称。例如 'tx.create'。"></x-field>
  <x-field data-name="callback" data-type="Function" data-required="true" data-desc="收到事件时要执行的函数。事件数据作为第一个参数传入。"></x-field>
</x-field-group>

### 常见事件主题

事件主题通常遵循 `tx.<transaction_type>` 的模式。以下是一些常见示例：

| Topic             | Description                  |
| ----------------- | ---------------------------- |
| `tx.create`       | 任何新交易成功处理并添加到区块时触发。          |
| `tx.transfer_v2`  | 当 `transferV2` 交易发生时专门触发。    |
| `tx.exchange_v2`  | 当 `exchangeV2`（原子交换）交易完成时触发。 |
| `tx.create_asset` | 当新资产（NFT）创建时触发。              |


## 取消订阅事件

在不再需要订阅时进行清理是一种良好实践，尤其是在组件会挂载和卸载的单页应用程序中。这样可以防止内存泄漏和不必要的处理。您可以使用 `unsubscribe` 方法移除订阅。

```javascript OCAP Client icon=logos:javascript
// 要移除特定的监听器，请传入相同的回调函数引用
client.unsubscribe('tx.create', handleNewTransaction);

// 要移除特定主题的所有监听器
client.unsubscribe('tx.create');
```

### 方法签名

**`unsubscribe(topic, [callback])`**

<x-field-group>
  <x-field data-name="topic" data-type="string" data-required="true" data-desc="要取消订阅的事件主题名称。"></x-field>
  <x-field data-name="callback" data-type="Function" data-required="false" data-desc="可选。要移除的特定回调函数。如果省略，该主题的所有监听器都将被移除。"></x-field>
</x-field-group>


## 完整示例

以下是一个完整的示例，演示了订阅事件、触发事件，然后取消订阅的整个过程。

```javascript Event Subscription Lifecycle icon=logos:javascript
import GraphQLClient from '@ocap/client';
import { fromRandom } from '@ocap/wallet';

const main = async () => {
  const client = new GraphQLClient('https://beta.abtnetwork.io/api/v2/gql');
  const events = { txCreate: 0, txTransfer: 0 };

  // 1. 订阅事件
  client.subscribe('tx.create', () => (events.txCreate += 1));
  client.subscribe('tx.transfer_v2', () => (events.txTransfer += 1));

  console.log('Subscribed to tx.create and tx.transfer_v2 events...');

  // 等待一小段时间的辅助函数
  const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
  await sleep(100); // 稍等片刻，以便订阅注册成功

  // 2. 执行一个触发事件的操作
  // 注意：这需要一个有资金的钱包。您可以从 https://faucet.abtnetwork.io/ 获取测试代币
  const sender = fromRandom(); // 在实际应用中，加载一个有资金的钱包
  // 在本示例中，我们假设操作会成功。
  console.log('A transfer transaction would trigger the event handlers.');
  
  // 在实际场景中，成功转账后：
  // await client.transfer({ to: 'z1...', token: 1, wallet: sender });

  // 让我们模拟成功交易后事件计数器递增的情况
  events.txCreate = 1;
  events.txTransfer = 1;

  await sleep(100); // 等待事件处理

  // 3. 验证事件处理函数是否被调用
  console.log(`tx.create was called ${events.txCreate} time(s).`);
  console.log(`tx.transfer_v2 was called ${events.txTransfer} time(s).`);

  // 4. 取消订阅以进行清理
  client.unsubscribe('tx.create');
  client.unsubscribe('tx.transfer_v2');
  console.log('Unsubscribed from events.');
};

main().catch(console.error);
```


## 总结

事件订阅是使用 OCAP Client 构建动态 dApp 的核心功能。它们提供了一个简单而强大的 API，通过可靠的 WebSocket 连接实时响应链上事件。通过使用 `subscribe` 和 `unsubscribe` 方法，您可以高效地管理应用程序中的实时数据流。

有关如何构造和发送交易（这些交易会生成这些事件）的更多详细信息，请参阅[交易生命周期](./core-concepts-transaction-lifecycle.md)文档。要了解如何为您的用户代付交易费用（这在与事件监听器结合使用时非常有用），请阅读[燃料费支付](./core-concepts-gas-payment.md)。
