# 스트리밍 API

스트리밍 API를 사용하면, 실시간으로 다양한 정보(예를 들어 타임라인에 새로운 노트가 올라왔다거나, 메시지가 도착했다거나 팔로우 되었다거나 등)를 받거나, 다양한 작업을 할 수 있습니다.

## 스트림에 접속하기

스트리밍 API를 이용하려면, 먼저 Misskey 서버에 **websocket** 접속이 필요합니다.

아래 URL에, `i` 라고 하는 매개변수명으로 인증 정보를 포함해서, websocket에 접속해주세요. 예:
```
%WS_URL%/streaming?i=xxxxxxxxxxxxxxx
```

인증 정보는 자신의 API 키나 애플리케이션에서 스트림에 접속할 때, 사용자의 접속 토큰을 뜻합니다.

<div class="ui info">
    <p><i class="fas fa-info-circle"></i> 인증 정보 발급에 대해서는, <a href="./api">해당 문서</a>를 참고해 주세요.</p>
</div>

---

인증 정보는 생략할 수 있지만, 이렇게 하면 게스트로 작동하기 때문에, 수신할 수 있는 정보나 조작이 한정됩니다. 예:

```
%WS_URL%/streaming
```

---

스트림에 접속하면, 뒤에서 서술하는 API 조작 및 노트 구독을 할 수 있습니다. 그러나 아직 이 단계에서는, 타임라인에 새로운 노트를 확인하는 등의 행동을 할 수 없습니다. 이것을 하기 위해서는, 스트림 상에서 후술하는 **채널**에 접속할 필요가 있습니다.

**스트림에서 주고 받는 정보는 모두 JSON 입니다.**

## 채널
Misskey의 스트리밍 API에는 채널이라는 개념이 있습니다. 이것은 송수신하는 정보를 분리하기 위한 구조입니다. Misskey의 스트림 연결만으로는, 아직 실시간으로 타임라인의 노트를 수신할 수 없습니다. 스트림 상에서 채널에 접속함으로써, 다양한 정보를 받거나 보낼 수 있게 됩니다.

### 채널에 접속하기
채널에 접속하려면, 다음 데이터를 JSON으로 스트림에 전송합니다:

```json
{
    type: 'connect',
    body: {
        channel: 'xxxxxxxx',
        id: 'foobar',
        params: {
            ...
        }
    }
}
```

여기서,
* `channel`에는 접속하고자 하는 채널명을 입력합니다. 채널의 종류에 대해서는 후술하겠습니다.
* `id`에는 해당 채널과 주고받기 위한 임의의 ID를 입력합니다. 스트림에서는 다양한 메시지가 나오기 때문에, 그 메시지가 어떤 채널에서 나오는 것인지 식별할 수 있어야 합니다. ID는 UUID나 난수 같은 것이면 됩니다.
* `params`는 채널에 접속할 때의 매개변수입니다. 채널에 따라서 접속 시 필요한 매개변수는 다릅니다. 매개변수가 필요없는 채널에 접속할 때는, 이 속성은 생략할 수 있습니다.

<div class="ui info">
    <p><i class="fas fa-info-circle"></i> ID는 채널별로 설정하는 것이 아니라, 「채널에 접속하는 스트림마다」 설정해야 합니다. 왜냐하면, 같은 채널에 다른 매개변수로 다중 접속하는 경우도 존재하기 때문입니다.</p>
</div>

### 채널에서 메시지 수신하기
예를 들어, 타임라인 채널이라면. 새로운 노트가 올라왔을 때 메시지를 보냅니다. 메시지를 받음으로써, 타임라인에 새로운 노트가 올라온 것을 실시간으로 알 수 있습니다.

채널에서 메시지를 보내면, 다음 데이터가 JSON에서 스트림으로 전달됩니다:
```json
{
    type: 'channel',
    body: {
        id: 'foobar',
        type: 'something',
        body: {
            some: 'thing'
        }
    }
}
```

여기서,
* `id`에는 앞서 말한 채널에 접속할 때 설정한 ID를 입력합니다. 이제 이 메시지가 어느 채널에서 온 것인지 알 수 있습니다.
* `type`에는 메시지의 종류를 입력합니다. 채널에 따라 어떤 종류의 메시지가 나오는지가 달라집니다.
* `body`에는 메시지 내용을 입력합니다. 채널에 따라, 어떤 내용의 메시지가 나오는지가 달라집니다.

### 채널에 메시지 보내기
채널에 따라서는, 메시지를 받을 뿐만 아니라, 반대로 메시지를 발송해서 특정한 동작을 실행할 수도 있습니다.

채널에 메시지를 보내려면, 다음 데이터를 JSON으로 스트림에 보냅니다:
```json
{
    type: 'channel',
    body: {
        id: 'foobar',
        type: 'something',
        body: {
            some: 'thing'
        }
    }
}
```

여기서,
* `id`에는 앞서 말한 채널에 접속할 때 설정한 ID를 입력합니다. 이제 이 메시지가 어느 채널로 갈 것인지 알 수 있습니다.
* `type`에는 메시지 종류를 입력합니다. 채널에 따라 어떤 종류의 메시지를 수신할지는 다릅니다.
* `body`에는 메시지 내용을 입력합니다. 채널에 따라, 어떤 내용의 메시지를 수신할지가 달라집니다.

### 채널 접속 끊기
채널 접속을 끊으려면, 다음 데이터를 JSON으로 스트림에 전송합니다:

```json
{
    type: 'disconnect',
    body: {
        id: 'foobar'
    }
}
```

여기서,
* `id`에는 앞서 말한 채널에 접속할 때 설정한 ID를 입력합니다.

## 스트림을 경유하여 API 요청하기

스트림을 통해 API를 요청하면, HTTP 요청을 발생시키지 않고 API를 이용할 수 있습니다. 이렇게 하면, 코드를 간결하게 만들거나, 성능을 향상시킬 수 있을지도 모릅니다.

스트림을 통해 API를 요청하려면, 다음 데이터를 JSON으로 스트림에 전송합니다:
```json
{
    type: 'api',
    body: {
        id: 'xxxxxxxxxxxxxxxx',
        endpoint: 'notes/create',
        data: {
            text: 'yee haw!'
        }
    }
}
```

여기서,
* `id`에는 API의 응답을 식별할 수 있는 API 요청별 핵심 ID를 입력해야 합니다. UUID나 간단한 난수 같은 것으로 설정해도 됩니다.
* `endpoint`에는 내가 요청하려는 API의 엔드포인트를 입력합니다.
* `data`에는 엔드포인트의 매개변수를 입력합니다.

<div class="ui info">
    <p><i class="fas fa-info-circle"></i> API의 엔드포인트 및 매개변수는 API 레퍼런스를 확인하시기 바랍니다.</p>
</div>

### 응답 수신

API로 요청하면, 응답이 스트림에서 다음 형식으로 전달됩니다.

```json
{
    type: 'api:xxxxxxxxxxxxxxxx',
    body: {
        ...
    }
}
```

여기서,
* `xxxxxxxxxxxxxxxx` 부분에는, 요청 시 설정된 `id`가 포함되어 있습니다. 이를 통해, 어떤 요청에 대한 응답인지 판별할 수 있습니다.
* `body`에는 응답이 포함되어 있습니다.

## 노트 캡처

Misskey는 게시한 노트를 캡처할 수 있는 시스템을 제공하고 있습니다. 이것은 지정한 노트의 이벤트를 스트림으로 받을 수 있는 기능입니다.

예를 들어, 타임라인을 불러와 유저에게 표시했습니다. 여기서 누군가가 그 타임라인에 포함된 어떤 노트에 대해서 리액션을 했다고 가정합니다.

그러나, 클라이언트가 보기에 어떤 글에 리액션이 붙었는지 등은 알 수가 없기 때문에, 실시간으로 리액션을 타임라인 상의 노트에 반영해서 표시하는 것은 불가능합니다.

이 문제를 해결하기 위해, Misskey는 게시 캡처 도구를 제공하고 있습니다. 노트를 캡처하면, 해당 노트에 대한 이벤트를 받을 수 있기 때문에, 실시간으로 리액션을 반영할 수 있습니다.

### 노트 게시 캡처

노트를 캡처하려면, 스트림에 다음 메시지를 발송합니다:

```json
{
    type: 'subNote',
    body: {
        id: 'xxxxxxxxxxxxxxxx'
    }
}
```

여기서,
* `id`에 캡처하려는 노트의 `id`를 입력합니다.

이 메시지를 발송하면, Misskey에 캡처를 요청하게 되고, 이후, 해당 노트에 대한 이벤트를 불러오게 됩니다.

예를 들면, 노트에 리액션이 붙었을 때 다음과 같은 메시지를 받습니다:

```json
{
    type: 'noteUpdated',
    body: {
        id: 'xxxxxxxxxxxxxxxx',
        type: 'reacted',
        body: {
            reaction: 'like',
            userId: 'yyyyyyyyyyyyyyyy'
        }
    }
}
```

여기서,
* `body`내에 `id`에는 이벤트를 발생시킨 노트의 ID가 포함됩니다.
* `body`내에 `type`에는 이벤트 종류가 포함됩니다.
* `body`내에 `body`에는 이벤트의 상세 내용이 포함됩니다.

#### 이벤트의 종류

##### `reacted`
해당 노트에 리액션이 올라갔을 때 발생합니다.

* `reaction`에 리액션 종류가 포함됩니다.
* `userId`에 리액션을 한 유저의 ID가 포함됩니다.

예:
```json
{
    type: 'noteUpdated',
    body: {
        id: 'xxxxxxxxxxxxxxxx',
        type: 'reacted',
        body: {
            reaction: 'like',
            userId: 'yyyyyyyyyyyyyyyy'
        }
    }
}
```

##### `deleted`
해당 노트가 삭제되었을 때 발생합니다.

* `deletedAt`에 삭제한 날짜가 포함됩니다.

예:
```json
{
    type: 'noteUpdated',
    body: {
        id: 'xxxxxxxxxxxxxxxx',
        type: 'deleted',
        body: {
            deletedAt: '2018-10-22T02:17:09.703Z'
        }
    }
}
```

##### `pollVoted`
해당 노트에 첨부된 투표에 투표했을 때 발생합니다.

* `choice`에 선택 항목의 ID가 포함됩니다.
* `userId`에 투표한 유저의 ID가 포함됩니다.

예:
```json
{
    type: 'noteUpdated',
    body: {
        id: 'xxxxxxxxxxxxxxxx',
        type: 'pollVoted',
        body: {
            choice: 2,
            userId: 'yyyyyyyyyyyyyyyy'
        }
    }
}
```

### 노트 캡처 해제

노트가 더 이상 화면에 표시되지 않는 등의 이유로, 해당 노트에 대한 이벤트를 받을 필요가 없을 때는, 캡처 해제를 진행해 주세요.

아래 메시지를 보냅니다:

```json
{
    type: 'unsubNote',
    body: {
        id: 'xxxxxxxxxxxxxxxx'
    }
}
```

여기서,
* `id`에 캡처를 해제하고자 하는 노트의 `id`를 입력합니다.

이 메시지를 보내면, 더 이상 해당 노트에 대한 이벤트는 발생하지 않습니다.

# 채널 목록
## `main`
계정에 대한 기본적인 정보를 표시됩니다. 이 채널에 대응하는 매개변수는 없습니다.

### 발생하는 이벤트 목록

#### `renote`
내 노트가 Renote 되었을 때 발생하는 이벤트입니다. 내가 올린 노트를 Renote 했을 때는 발생하지 않습니다.

#### `mention`
다른 사람이 나를 멘션 했을 때 발생하는 이벤트입니다.

#### `readAllNotifications`
나에게 온 알림을 모두 읽었음을 나타내는 이벤트입니다. 이 이벤트를 이용해, 「알림이 있음을 나타내는 아이콘」과 같은 것을 끄는 등의 활용이 가능합니다.

#### `meUpdated`
내 정보가 업데이트 되었음을 나타내는 이벤트입니다.

#### `follow`
내가 누군가를 팔로우 했을 때 발생하는 이벤트입니다.

#### `unfollow`
내가 누군가를 언팔로우 했을 때 발생하는 이벤트입니다.

#### `followed`
다른 사람이 나를 팔로우 했을 때 발생하는 이벤트입니다.

## `homeTimeline`
홈 타임라인에 게시된 정보가 표시됩니다. 이 채널에 대응하는 매개변수는 없습니다.

### 발생하는 이벤트 목록

#### `note`
타임라인에 새로운 노트가 올라왔을 때 발생하는 이벤트입니다.

## `localTimeline`
로컬 타임라인에 게시된 정보가 표시됩니다. 이 채널에 대응하는 매개변수는 없습니다.

### 발생하는 이벤트 목록

#### `note`
로컬 타임라인에 새로운 노트가 올라왔을 때 발생하는 이벤트입니다.

## `hybridTimeline`
소셜 타임라인에 게시된 정보가 표시됩니다. 이 채널에 대응하는 매개변수는 없습니다.

### 발생하는 이벤트 목록

#### `note`
소셜 타임라인에 새로운 노트가 올라왔을 때 발생하는 이벤트입니다.

## `globalTimeline`
글로벌 타임라인에 게시된 정보가 표시됩니다. 이 채널에 대응하는 매개변수는 없습니다.

### 발생하는 이벤트 목록

#### `note`
글로벌 타임라인에 새로운 노트가 올라왔을 때 발생하는 이벤트입니다.
