> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# 实时流

> 通过 Server-Sent Events（SSE）流订阅应用的实时事件。

`api.ApplicationRealtime(appID)` 打开一个 [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events) 流并返回 `*rest.RealtimeStream`。使用 `stream.Next()` 迭代它，直到 `io.EOF`。

```go theme={null}
client := rest.NewClient(os.Getenv("SQUARECLOUD_API_KEY"))
defer client.Close()

api := rest.New(client)
```

## 消费流

```go theme={null}
stream, err := api.ApplicationRealtime("abc123def456abc123def456")
if err != nil {
	panic(err)
}
defer stream.Close()

for {
	event, err := stream.Next()
	if err == io.EOF {
		break // stream ended (e.g. 10-minute TTL reached)
	}
	if err != nil {
		panic(err)
	}

	fmt.Println(event.Name, string(event.Data))
}
```

始终 `defer stream.Close()` —— 未关闭的流会一直占用你账户的一个连接槽位。

## 事件形态

流会发出两类帧：

* **系统事件** —— 连接生命周期消息：`REALTIME_CONNECTING`、`REALTIME_TIMEOUT`、`REALTIME_DISCONNECTED`、`REALTIME_RECONNECT` 和 `REALTIME_ERROR`。
* **`message` 事件** —— 应用载荷。`Data` 对 SDK 来说是不透明的，通常是 JSON —— 需要你自己反序列化：

```go theme={null}
if event.Name == "message" {
	var payload map[string]any
	if err := json.Unmarshal(event.Data, &payload); err == nil {
		fmt.Println(payload)
	}
}
```

## 连接限制

<Warning>
  单个账户最多可同时保持 **5 个连接**，每个连接最长持续 **10 分钟**（其 TTL）。达到 TTL 时流以 `io.EOF` 结束 —— 在循环中重连以保持订阅。
</Warning>

```go theme={null}
for {
	stream, err := api.ApplicationRealtime("abc123def456abc123def456")
	if err != nil {
		panic(err)
	}

	for {
		event, err := stream.Next()
		if err != nil {
			break // io.EOF on TTL — reconnect
		}
		fmt.Println(event.Name, string(event.Data))
	}

	stream.Close()
}
```

## 取消

使用 `rest.WithContext` 附加一个 `context.Context`，以便从外部停止流：

```go theme={null}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

stream, err := api.ApplicationRealtime("abc123def456abc123def456", rest.WithContext(ctx))
if err != nil {
	panic(err)
}
defer stream.Close()

// cancel() from another goroutine ends the stream
```
