Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
286da28cd6 | |||
a4ee93a355 | |||
ab56cb1788 | |||
32435e4d8e | |||
900cdf9d9a | |||
e79019266f | |||
deee7361f0 | |||
bdcf09c618 | |||
7b5d6dcd9b | |||
0595d87759 | |||
fab0a0d6e2 | |||
3eb6b36866 | |||
50327158e2 | |||
a99756ef85 |
@ -21,7 +21,7 @@ const langs = {
|
||||
|
||||
Object.values(langs).forEach(locale => {
|
||||
// Extend native language (Japanese)
|
||||
Object.assign(locale, native);
|
||||
locale = Object.assign({}, native, locale);
|
||||
});
|
||||
|
||||
module.exports = langs;
|
||||
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"author": "syuilo <i@syuilo.com>",
|
||||
"version": "5.3.0",
|
||||
"clientVersion": "1.0.7588",
|
||||
"version": "5.5.0",
|
||||
"clientVersion": "1.0.7602",
|
||||
"codename": "nighthike",
|
||||
"main": "./built/index.js",
|
||||
"private": true,
|
||||
|
@ -105,7 +105,8 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
isMyTurn(): boolean {
|
||||
if (this.turnUser == null) return null;
|
||||
if (!this.iAmPlayer) return false;
|
||||
if (this.turnUser == null) return false;
|
||||
return this.turnUser.id == this.$store.state.i.id;
|
||||
},
|
||||
cellsStyle(): any {
|
||||
|
@ -67,7 +67,9 @@ export default Vue.extend({
|
||||
components: {
|
||||
XGameroom
|
||||
},
|
||||
|
||||
props: ['initGame'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
game: null,
|
||||
@ -82,54 +84,63 @@ export default Vue.extend({
|
||||
pingClock: null
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
game(g) {
|
||||
this.$emit('gamed', g);
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.initGame) {
|
||||
this.game = this.initGame;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.connection = (this as any).os.streams.reversiStream.getConnection();
|
||||
this.connectionId = (this as any).os.streams.reversiStream.use();
|
||||
if (this.$store.getters.isSignedIn) {
|
||||
this.connection = (this as any).os.streams.reversiStream.getConnection();
|
||||
this.connectionId = (this as any).os.streams.reversiStream.use();
|
||||
|
||||
this.connection.on('matched', this.onMatched);
|
||||
this.connection.on('invited', this.onInvited);
|
||||
this.connection.on('matched', this.onMatched);
|
||||
this.connection.on('invited', this.onInvited);
|
||||
|
||||
(this as any).api('games/reversi/games', {
|
||||
my: true
|
||||
}).then(games => {
|
||||
this.myGames = games;
|
||||
});
|
||||
(this as any).api('games/reversi/games', {
|
||||
my: true
|
||||
}).then(games => {
|
||||
this.myGames = games;
|
||||
});
|
||||
|
||||
(this as any).api('games/reversi/invitations').then(invitations => {
|
||||
this.invitations = this.invitations.concat(invitations);
|
||||
});
|
||||
|
||||
this.pingClock = setInterval(() => {
|
||||
if (this.matching) {
|
||||
this.connection.send({
|
||||
type: 'ping',
|
||||
id: this.matching.id
|
||||
});
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
(this as any).api('games/reversi/games').then(games => {
|
||||
this.games = games;
|
||||
this.gamesFetching = false;
|
||||
});
|
||||
|
||||
(this as any).api('games/reversi/invitations').then(invitations => {
|
||||
this.invitations = this.invitations.concat(invitations);
|
||||
});
|
||||
|
||||
this.pingClock = setInterval(() => {
|
||||
if (this.matching) {
|
||||
this.connection.send({
|
||||
type: 'ping',
|
||||
id: this.matching.id
|
||||
});
|
||||
}
|
||||
}, 3000);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.connection.off('matched', this.onMatched);
|
||||
this.connection.off('invited', this.onInvited);
|
||||
(this as any).os.streams.reversiStream.dispose(this.connectionId);
|
||||
if (this.connection) {
|
||||
this.connection.off('matched', this.onMatched);
|
||||
this.connection.off('invited', this.onInvited);
|
||||
(this as any).os.streams.reversiStream.dispose(this.connectionId);
|
||||
|
||||
clearInterval(this.pingClock);
|
||||
clearInterval(this.pingClock);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
go(game) {
|
||||
(this as any).api('games/reversi/games/show', {
|
||||
@ -139,6 +150,7 @@ export default Vue.extend({
|
||||
this.game = game;
|
||||
});
|
||||
},
|
||||
|
||||
match() {
|
||||
(this as any).apis.input({
|
||||
title: 'ユーザー名を入力してください'
|
||||
@ -158,10 +170,12 @@ export default Vue.extend({
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this.matching = null;
|
||||
(this as any).api('games/reversi/match/cancel');
|
||||
},
|
||||
|
||||
accept(invitation) {
|
||||
(this as any).api('games/reversi/match', {
|
||||
userId: invitation.parent.id
|
||||
@ -172,10 +186,12 @@ export default Vue.extend({
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onMatched(game) {
|
||||
this.matching = null;
|
||||
this.game = game;
|
||||
},
|
||||
|
||||
onInvited(invite) {
|
||||
this.invitations.unshift(invite);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ const nativeDbConn = async (): Promise<mongodb.Db> => {
|
||||
if (mdb) return mdb;
|
||||
|
||||
const db = await ((): Promise<mongodb.Db> => new Promise((resolve, reject) => {
|
||||
mongodb.MongoClient.connect(uri, (e: Error, client: any) => {
|
||||
mongodb.MongoClient.connect(uri, { useNewUrlParser: true }, (e: Error, client: any) => {
|
||||
if (e) return reject(e);
|
||||
resolve(client.db(config.mongodb.db));
|
||||
});
|
||||
|
@ -71,6 +71,9 @@ APIの詳しい使用法は「Misskey APIの利用」セクションをご覧く
|
||||
|
||||
## Misskey APIの利用
|
||||
APIはすべてリクエストのパラメータ・レスポンスともにJSON形式です。また、すべてのエンドポイントはPOSTメソッドのみ受け付けます。
|
||||
|
||||
ストリーミングAPIも提供しています。
|
||||
|
||||
APIリファレンスもご確認ください。
|
||||
|
||||
### レートリミット
|
||||
|
183
src/docs/stream.ja.md
Normal file
183
src/docs/stream.ja.md
Normal file
@ -0,0 +1,183 @@
|
||||
# ストリーミングAPI
|
||||
|
||||
ストリーミングAPIを使うと、リアルタイムで様々な情報(例えばタイムラインに新しい投稿が流れてきた、メッセージが届いた、フォローされた、など)を受け取ったり、HTTPリクエストを発生させることなくAPIにアクセスしたりすることができます。
|
||||
|
||||
ストリーミングAPIは複数の種類がありますが、ここではメインとなる「ホームストリーム」について説明します。
|
||||
|
||||
## ストリームに接続する
|
||||
|
||||
以下のURLに**websocket**接続します。
|
||||
```
|
||||
%URL%
|
||||
```
|
||||
|
||||
接続する際は、`i`というパラメータ名で認証情報を含めます。例:
|
||||
```
|
||||
%URL%/?i=xxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
認証情報は、自分のAPIキーや、アプリケーションからストリームに接続する際はユーザーのアクセストークンのことを指します。
|
||||
|
||||
<div class="ui info">
|
||||
<p><i class="fas fa-info-circle"></i> 認証情報の取得については、<a href="./api">こちらのドキュメント</a>をご確認ください。</p>
|
||||
</div>
|
||||
|
||||
|
||||
## ストリームを経由してAPIリクエストする
|
||||
|
||||
ストリームを経由してAPIリクエストすると、HTTPリクエストを発生させずにAPIを利用できます。そのため、コードを簡潔にできたり、パフォーマンスの向上を見込めるかもしれません。
|
||||
|
||||
ストリームを経由してAPIリクエストするには、次のようなメッセージをストリームに送信します:
|
||||
```json
|
||||
{
|
||||
type: 'api',
|
||||
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-res:xxxxxxxxxxxxxxxx',
|
||||
body: {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`xxxxxxxxxxxxxxxx`の部分には、リクエストの際に設定された`id`が含まれています。これにより、どのリクエストに対するレスポンスなのか判別することができます。
|
||||
|
||||
`body`には、レスポンスが含まれています。
|
||||
|
||||
## 投稿のキャプチャ
|
||||
|
||||
Misskeyは投稿のキャプチャと呼ばれる仕組みを提供しています。これは、指定した投稿のイベントをストリームで受け取る機能です。
|
||||
|
||||
例えばタイムラインを取得してユーザーに表示したとします。ここで誰かがそのタイムラインに含まれるどれかの投稿に対してリアクションしたとします。
|
||||
|
||||
しかし、クライアントからするとある投稿にリアクションが付いたことなどは知る由がないため、リアルタイムでリアクションをタイムライン上の投稿に反映して表示するといったことができません。
|
||||
|
||||
この問題を解決するために、Misskeyは投稿のキャプチャ機構を用意しています。投稿をキャプチャすると、その投稿に関するイベントを受け取ることができるため、リアルタイムでリアクションを反映させたりすることが可能になります。
|
||||
|
||||
### 投稿をキャプチャする
|
||||
|
||||
投稿をキャプチャするには、ストリームに次のようなメッセージを送信します:
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'capture',
|
||||
id: 'xxxxxxxxxxxxxxxx'
|
||||
}
|
||||
```
|
||||
|
||||
`id`には、キャプチャしたい投稿の`id`を設定します。
|
||||
|
||||
このメッセージを送信すると、Misskeyにキャプチャを要請したことになり、以後、その投稿に関するイベントが流れてくるようになります。
|
||||
|
||||
例えば投稿にリアクションが付いたとすると、次のようなメッセージが流れてきます:
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'note-updated',
|
||||
body: {
|
||||
note: {
|
||||
...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`body`内の`note`には、その投稿の最新の情報が含まれています。
|
||||
|
||||
---
|
||||
|
||||
このように、投稿の情報が更新されると、`note-updated`イベントが流れてくるようになります。`note-updated`イベントが発生するのは、以下の場合です:
|
||||
|
||||
- 投稿にリアクションが付いた
|
||||
- 投稿に添付されたアンケートに投票がされた
|
||||
- 投稿が削除された
|
||||
|
||||
### 投稿のキャプチャを解除する
|
||||
|
||||
その投稿がもう画面に表示されなくなったりして、その投稿に関するイベントをもう受け取る必要がなくなったときは、キャプチャの解除を申請してください。
|
||||
|
||||
次のメッセージを送信します:
|
||||
|
||||
```json
|
||||
{
|
||||
type: 'decapture',
|
||||
id: 'xxxxxxxxxxxxxxxx'
|
||||
}
|
||||
```
|
||||
|
||||
`id`には、キャプチャを解除したい投稿の`id`を設定します。
|
||||
|
||||
このメッセージを送信すると、以後、その投稿に関するイベントは流れてこないようになります。
|
||||
|
||||
## 流れてくるイベント一覧
|
||||
|
||||
流れてくるすべてのメッセージはJSON形式で、必ず`type`というプロパティが含まれています。これにより、メッセージの種類(イベント)を判別することができます。
|
||||
|
||||
### `note`
|
||||
|
||||
タイムラインに新しい投稿が流れてきたときに発生するイベントです。
|
||||
|
||||
`body`プロパティの中に、投稿情報が含まれています。
|
||||
|
||||
### `renote`
|
||||
|
||||
自分の投稿がRenoteされた時に発生するイベントです。自分自身の投稿をRenoteしたときは発生しません。
|
||||
|
||||
`body`プロパティの中に、Renoteされた投稿情報が含まれています。
|
||||
|
||||
### `mention`
|
||||
|
||||
誰かからメンションされたときに発生するイベントです。
|
||||
|
||||
`body`プロパティの中に、投稿情報が含まれています。
|
||||
|
||||
### `read_all_notifications`
|
||||
|
||||
自分宛ての通知がすべて既読になったことを表すイベントです。このイベントを利用して、「通知があることを示すアイコン」のようなものをオフにしたりする等のケースが想定されます。
|
||||
|
||||
### `meUpdated`
|
||||
|
||||
自分の情報が更新されたことを表すイベントです。
|
||||
|
||||
`body`プロパティの中に、最新の自分のアカウントの情報が含まれています。
|
||||
|
||||
### `follow`
|
||||
|
||||
自分が誰かをフォローしたときに発生するイベントです。
|
||||
|
||||
`body`プロパティの中に、フォローしたユーザーの情報が含まれています。
|
||||
|
||||
### `unfollow`
|
||||
|
||||
自分が誰かのフォローを解除したときに発生するイベントです。
|
||||
|
||||
`body`プロパティの中に、フォロー解除したユーザーの情報が含まれています。
|
||||
|
||||
### `followed`
|
||||
|
||||
自分が誰かにフォローされたときに発生するイベントです。
|
||||
|
||||
`body`プロパティの中に、フォローしてきたユーザーの情報が含まれています。
|
||||
|
@ -36,6 +36,10 @@ main
|
||||
margin 1em 0
|
||||
line-height 1.6em
|
||||
|
||||
hr
|
||||
border none
|
||||
border-bottom solid 2px #eee
|
||||
|
||||
footer
|
||||
margin 32px 0 0 0
|
||||
border-top solid 2px #eee
|
||||
|
@ -3,7 +3,6 @@ import ReversiGame, { pack } from '../../../../../models/games/reversi/game';
|
||||
import { ILocalUser } from '../../../../../models/user';
|
||||
|
||||
export const meta = {
|
||||
requireCredential: true
|
||||
};
|
||||
|
||||
export default (params: any, user: ILocalUser) => new Promise(async (res, rej) => {
|
||||
|
@ -22,7 +22,8 @@ export default async function(user: IUser, note: INote) {
|
||||
text: null,
|
||||
tags: [],
|
||||
mediaIds: [],
|
||||
poll: null
|
||||
poll: null,
|
||||
geo: null
|
||||
}
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user