From 6575a6de5bbcab9a88448e4366feb77f1845a580 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 22 Dec 2017 07:26:23 +0900 Subject: wip --- src/api/stream/home.ts | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'src/api/stream') diff --git a/src/api/stream/home.ts b/src/api/stream/home.ts index 7c8f3bfec8..7dcdb5ed73 100644 --- a/src/api/stream/home.ts +++ b/src/api/stream/home.ts @@ -3,19 +3,48 @@ import * as redis from 'redis'; import * as debug from 'debug'; import User from '../models/user'; +import Mute from '../models/mute'; import serializePost from '../serializers/post'; import readNotification from '../common/read-notification'; const log = debug('misskey'); -export default function homeStream(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { +export default async function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any) { // Subscribe Home stream channel subscriber.subscribe(`misskey:user-stream:${user._id}`); + const mute = await Mute.find({ + muter_id: user._id, + deleted_at: { $exists: false } + }); + const mutedUserIds = mute.map(m => m.mutee_id.toString()); + subscriber.on('message', async (channel, data) => { switch (channel.split(':')[1]) { case 'user-stream': - connection.send(data); + try { + const x = JSON.parse(data); + + if (x.type == 'post') { + if (mutedUserIds.indexOf(x.body.user_id) != -1) { + return; + } + if (x.body.reply != null && mutedUserIds.indexOf(x.body.reply.user_id) != -1) { + return; + } + if (x.body.repost != null && mutedUserIds.indexOf(x.body.repost.user_id) != -1) { + return; + } + } else if (x.type == 'notification') { + if (mutedUserIds.indexOf(x.body.user_id) != -1) { + return; + } + } + + connection.send(data); + } catch (e) { + connection.send(data); + } break; case 'post-stream': const postId = channel.split(':')[2]; -- cgit v1.2.3-freya From bcd65d290d25219631bb47570478378a698d0fa0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 4 Feb 2018 14:52:33 +0900 Subject: wip --- src/api/endpoints/aggregation/posts/reactions.ts | 11 +++++++---- src/api/endpoints/aggregation/users.ts | 13 ++++++++----- src/api/endpoints/app/create.ts | 3 +-- src/api/endpoints/channels/show.ts | 2 +- src/api/endpoints/drive/files/create.ts | 2 +- src/api/endpoints/drive/files/update.ts | 3 +-- src/api/endpoints/drive/files/upload_from_url.ts | 2 +- src/api/endpoints/drive/folders/create.ts | 3 +-- src/api/endpoints/drive/folders/update.ts | 3 +-- src/api/endpoints/following/create.ts | 7 +++---- src/api/endpoints/following/delete.ts | 5 ++--- src/api/endpoints/i/update.ts | 3 +-- src/api/endpoints/posts/reactions/create.ts | 9 ++++----- src/api/endpoints/users/posts.ts | 4 ++-- src/api/endpoints/users/search.ts | 2 +- src/api/models/app.ts | 1 + src/api/models/drive-file.ts | 1 + src/api/models/post-reaction.ts | 3 +++ src/api/models/post.ts | 4 +++- src/api/models/user.ts | 1 + src/api/private/signup.ts | 3 +-- src/api/service/twitter.ts | 2 +- src/api/stream/home.ts | 4 ++-- 23 files changed, 48 insertions(+), 43 deletions(-) (limited to 'src/api/stream') diff --git a/src/api/endpoints/aggregation/posts/reactions.ts b/src/api/endpoints/aggregation/posts/reactions.ts index 2cd4588ae1..790b523be9 100644 --- a/src/api/endpoints/aggregation/posts/reactions.ts +++ b/src/api/endpoints/aggregation/posts/reactions.ts @@ -35,10 +35,13 @@ module.exports = (params) => new Promise(async (res, rej) => { { deleted_at: { $gt: startTime } } ] }, { - _id: false, - post_id: false - }, { - sort: { created_at: -1 } + sort: { + _id: -1 + }, + fields: { + _id: false, + post_id: false + } }); const graph = []; diff --git a/src/api/endpoints/aggregation/users.ts b/src/api/endpoints/aggregation/users.ts index 9eb2d035ec..e38ce92ff9 100644 --- a/src/api/endpoints/aggregation/users.ts +++ b/src/api/endpoints/aggregation/users.ts @@ -17,11 +17,14 @@ module.exports = params => new Promise(async (res, rej) => { const users = await User .find({}, { - _id: false, - created_at: true, - deleted_at: true - }, { - sort: { created_at: -1 } + sort: { + _id: -1 + }, + fields: { + _id: false, + created_at: true, + deleted_at: true + } }); const graph = []; diff --git a/src/api/endpoints/app/create.ts b/src/api/endpoints/app/create.ts index 71633f7def..0f688792a7 100644 --- a/src/api/endpoints/app/create.ts +++ b/src/api/endpoints/app/create.ts @@ -3,8 +3,7 @@ */ import rndstr from 'rndstr'; import $ from 'cafy'; -import App from '../../models/app'; -import { isValidNameId }, { pack } from '../../models/app'; +import App, { isValidNameId, pack } from '../../models/app'; /** * @swagger diff --git a/src/api/endpoints/channels/show.ts b/src/api/endpoints/channels/show.ts index 3238616fa5..332da64675 100644 --- a/src/api/endpoints/channels/show.ts +++ b/src/api/endpoints/channels/show.ts @@ -2,7 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import { default as Channel, IChannel }, { pack } from '../../models/channel'; +import Channel, { IChannel, pack } from '../../models/channel'; /** * Show a channel diff --git a/src/api/endpoints/drive/files/create.ts b/src/api/endpoints/drive/files/create.ts index 7b424f3f5a..96bcace886 100644 --- a/src/api/endpoints/drive/files/create.ts +++ b/src/api/endpoints/drive/files/create.ts @@ -2,7 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import { validateFileName }, { pack } from '../../../models/drive-file'; +import { validateFileName, pack } from '../../../models/drive-file'; import create from '../../../common/add-file-to-drive'; /** diff --git a/src/api/endpoints/drive/files/update.ts b/src/api/endpoints/drive/files/update.ts index ff65a48f71..83da462113 100644 --- a/src/api/endpoints/drive/files/update.ts +++ b/src/api/endpoints/drive/files/update.ts @@ -3,8 +3,7 @@ */ import $ from 'cafy'; import DriveFolder from '../../../models/drive-folder'; -import DriveFile from '../../../models/drive-file'; -import { validateFileName }, { pack } from '../../../models/drive-file'; +import DriveFile, { validateFileName, pack } from '../../../models/drive-file'; import { publishDriveStream } from '../../../event'; /** diff --git a/src/api/endpoints/drive/files/upload_from_url.ts b/src/api/endpoints/drive/files/upload_from_url.ts index 009f06aaaf..68428747ef 100644 --- a/src/api/endpoints/drive/files/upload_from_url.ts +++ b/src/api/endpoints/drive/files/upload_from_url.ts @@ -3,7 +3,7 @@ */ import * as URL from 'url'; import $ from 'cafy'; -import { validateFileName }, { pack } from '../../../models/drive-file'; +import { validateFileName, pack } from '../../../models/drive-file'; import create from '../../../common/add-file-to-drive'; import * as debug from 'debug'; import * as tmp from 'tmp'; diff --git a/src/api/endpoints/drive/folders/create.ts b/src/api/endpoints/drive/folders/create.ts index 6543b11274..03f396ddc9 100644 --- a/src/api/endpoints/drive/folders/create.ts +++ b/src/api/endpoints/drive/folders/create.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFolder from '../../../models/drive-folder'; -import { isValidFolderName }, { pack } from '../../../models/drive-folder'; +import DriveFolder, { isValidFolderName, pack } from '../../../models/drive-folder'; import { publishDriveStream } from '../../../event'; /** diff --git a/src/api/endpoints/drive/folders/update.ts b/src/api/endpoints/drive/folders/update.ts index 2adcadcb08..d3df8bdae5 100644 --- a/src/api/endpoints/drive/folders/update.ts +++ b/src/api/endpoints/drive/folders/update.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import DriveFolder from '../../../models/drive-folder'; -import { isValidFolderName }, { pack } from '../../../models/drive-folder'; +import DriveFolder, { isValidFolderName, pack } from '../../../models/drive-folder'; import { publishDriveStream } from '../../../event'; /** diff --git a/src/api/endpoints/following/create.ts b/src/api/endpoints/following/create.ts index b4a2217b16..8e1aa34713 100644 --- a/src/api/endpoints/following/create.ts +++ b/src/api/endpoints/following/create.ts @@ -2,11 +2,10 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; +import User, { pack as packUser } from '../../models/user'; import Following from '../../models/following'; import notify from '../../common/notify'; import event from '../../event'; -import serializeUser from '../../serializers/user'; /** * Follow a user @@ -77,8 +76,8 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Publish follow event - event(follower._id, 'follow', await serializeUser(followee, follower)); - event(followee._id, 'followed', await serializeUser(follower, followee)); + event(follower._id, 'follow', await packUser(followee, follower)); + event(followee._id, 'followed', await packUser(follower, followee)); // Notify notify(followee._id, follower._id, 'follow'); diff --git a/src/api/endpoints/following/delete.ts b/src/api/endpoints/following/delete.ts index aa1639ef6c..b68cec09dd 100644 --- a/src/api/endpoints/following/delete.ts +++ b/src/api/endpoints/following/delete.ts @@ -2,10 +2,9 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; +import User, { pack as packUser } from '../../models/user'; import Following from '../../models/following'; import event from '../../event'; -import serializeUser from '../../serializers/user'; /** * Unfollow a user @@ -78,5 +77,5 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // Publish follow event - event(follower._id, 'unfollow', await serializeUser(followee, follower)); + event(follower._id, 'unfollow', await packUser(followee, follower)); }); diff --git a/src/api/endpoints/i/update.ts b/src/api/endpoints/i/update.ts index cd4b1a13f5..7bbbf95900 100644 --- a/src/api/endpoints/i/update.ts +++ b/src/api/endpoints/i/update.ts @@ -2,8 +2,7 @@ * Module dependencies */ import $ from 'cafy'; -import User from '../../models/user'; -import { isValidName, isValidDescription, isValidLocation, isValidBirthday }, { pack } from '../../models/user'; +import User, { isValidName, isValidDescription, isValidLocation, isValidBirthday, pack } from '../../models/user'; import event from '../../event'; import config from '../../../conf'; diff --git a/src/api/endpoints/posts/reactions/create.ts b/src/api/endpoints/posts/reactions/create.ts index d537463dfe..0b0e0e294d 100644 --- a/src/api/endpoints/posts/reactions/create.ts +++ b/src/api/endpoints/posts/reactions/create.ts @@ -3,13 +3,12 @@ */ import $ from 'cafy'; import Reaction from '../../../models/post-reaction'; -import Post from '../../../models/post'; +import Post, { pack as packPost } from '../../../models/post'; +import { pack as packUser } from '../../../models/user'; import Watching from '../../../models/post-watching'; import notify from '../../../common/notify'; import watch from '../../../common/watch-post'; import { publishPostStream, pushSw } from '../../../event'; -import serializePost from '../../../serializers/post'; -import serializeUser from '../../../serializers/user'; /** * React to a post @@ -90,8 +89,8 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); pushSw(post.user_id, 'reaction', { - user: await serializeUser(user, post.user_id), - post: await serializePost(post, post.user_id), + user: await packUser(user, post.user_id), + post: await packPost(post, post.user_id), reaction: reaction }); diff --git a/src/api/endpoints/users/posts.ts b/src/api/endpoints/users/posts.ts index 285e5bc46c..0c8bceee3d 100644 --- a/src/api/endpoints/users/posts.ts +++ b/src/api/endpoints/users/posts.ts @@ -2,8 +2,8 @@ * Module dependencies */ import $ from 'cafy'; -import Post from '../../models/post'; -import User, { pack } from '../../models/user'; +import Post, { pack } from '../../models/post'; +import User from '../../models/user'; /** * Get posts of a user diff --git a/src/api/endpoints/users/search.ts b/src/api/endpoints/users/search.ts index 1142db9e9b..39e2ff9890 100644 --- a/src/api/endpoints/users/search.ts +++ b/src/api/endpoints/users/search.ts @@ -51,7 +51,7 @@ async function byNative(res, rej, me, query, offset, max) { // Serialize res(await Promise.all(users.map(async user => - await serialize(user, me, { detail: true })))); + await pack(user, me, { detail: true })))); } // Search by Elasticsearch diff --git a/src/api/models/app.ts b/src/api/models/app.ts index fe9d49ff67..34e9867db7 100644 --- a/src/api/models/app.ts +++ b/src/api/models/app.ts @@ -14,6 +14,7 @@ export type IApp = { _id: mongo.ObjectID; created_at: Date; user_id: mongo.ObjectID; + secret: string; }; export function isValidNameId(nameId: string): boolean { diff --git a/src/api/models/drive-file.ts b/src/api/models/drive-file.ts index 9b9df1dac6..2a46d8dc4d 100644 --- a/src/api/models/drive-file.ts +++ b/src/api/models/drive-file.ts @@ -23,6 +23,7 @@ export type IDriveFile = { uploadDate: Date; md5: string; filename: string; + contentType: string; metadata: { properties: any; user_id: mongodb.ObjectID; diff --git a/src/api/models/post-reaction.ts b/src/api/models/post-reaction.ts index 568bfc89a2..639a70e006 100644 --- a/src/api/models/post-reaction.ts +++ b/src/api/models/post-reaction.ts @@ -9,6 +9,9 @@ export default PostReaction; export interface IPostReaction { _id: mongo.ObjectID; + created_at: Date; + deleted_at: Date; + reaction: string; } /** diff --git a/src/api/models/post.ts b/src/api/models/post.ts index ecc5e1a5e4..0bbacebf66 100644 --- a/src/api/models/post.ts +++ b/src/api/models/post.ts @@ -25,10 +25,12 @@ export type IPost = { media_ids: mongo.ObjectID[]; reply_id: mongo.ObjectID; repost_id: mongo.ObjectID; - poll: {}; // todo + poll: any; // todo text: string; user_id: mongo.ObjectID; app_id: mongo.ObjectID; + category: string; + is_category_verified: boolean; }; /** diff --git a/src/api/models/user.ts b/src/api/models/user.ts index 48a45ac2f7..e92f244dd0 100644 --- a/src/api/models/user.ts +++ b/src/api/models/user.ts @@ -42,6 +42,7 @@ export function isValidBirthday(birthday: string): boolean { export type IUser = { _id: mongo.ObjectID; created_at: Date; + deleted_at: Date; email: string; followers_count: number; following_count: number; diff --git a/src/api/private/signup.ts b/src/api/private/signup.ts index 392f3b1fc7..8efdb6db47 100644 --- a/src/api/private/signup.ts +++ b/src/api/private/signup.ts @@ -2,8 +2,7 @@ import * as uuid from 'uuid'; import * as express from 'express'; import * as bcrypt from 'bcryptjs'; import recaptcha = require('recaptcha-promise'); -import { default as User, IUser } from '../models/user'; -import { validateUsername, validatePassword }, { pack } from '../models/user'; +import User, { IUser, validateUsername, validatePassword, pack } from '../models/user'; import generateUserToken from '../common/generate-native-user-token'; import config from '../../conf'; diff --git a/src/api/service/twitter.ts b/src/api/service/twitter.ts index 7d4964eba6..adcd5ac49b 100644 --- a/src/api/service/twitter.ts +++ b/src/api/service/twitter.ts @@ -163,7 +163,7 @@ module.exports = (app: express.Application) => { res.send(`Twitter: @${result.screenName} を、Misskey: @${user.username} に接続しました!`); // Publish i updated event - event(user._id, 'i_updated', await serialize(user, user, { + event(user._id, 'i_updated', await pack(user, user, { detail: true, includeSecrets: true })); diff --git a/src/api/stream/home.ts b/src/api/stream/home.ts index 7dcdb5ed73..10078337c3 100644 --- a/src/api/stream/home.ts +++ b/src/api/stream/home.ts @@ -4,7 +4,7 @@ import * as debug from 'debug'; import User from '../models/user'; import Mute from '../models/mute'; -import serializePost from '../serializers/post'; +import { pack as packPost } from '../models/post'; import readNotification from '../common/read-notification'; const log = debug('misskey'); @@ -49,7 +49,7 @@ export default async function(request: websocket.request, connection: websocket. case 'post-stream': const postId = channel.split(':')[2]; log(`RECEIVED: ${postId} ${data} by @${user.username}`); - const post = await serializePost(postId, user, { + const post = await packPost(postId, user, { detail: true }); connection.send(JSON.stringify({ -- cgit v1.2.3-freya From bec7ed723be235b94daf1d5e5aa7f595bf7d9815 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 3 Mar 2018 14:42:25 +0900 Subject: :v: --- src/api/stream/home.ts | 4 +++ src/web/app/common/mios.ts | 55 ++++++++++++++++++++++++++++++++++++--- src/web/app/common/scripts/api.ts | 47 --------------------------------- 3 files changed, 56 insertions(+), 50 deletions(-) delete mode 100644 src/web/app/common/scripts/api.ts (limited to 'src/api/stream') diff --git a/src/api/stream/home.ts b/src/api/stream/home.ts index 10078337c3..cc3fb885e4 100644 --- a/src/api/stream/home.ts +++ b/src/api/stream/home.ts @@ -66,6 +66,10 @@ export default async function(request: websocket.request, connection: websocket. const msg = JSON.parse(data.utf8Data); switch (msg.type) { + case 'api': + // TODO + break; + case 'alive': // Update lastUsedAt User.update({ _id: user._id }, { diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts index 3701a24c30..bc83ec0bbb 100644 --- a/src/web/app/common/mios.ts +++ b/src/web/app/common/mios.ts @@ -2,7 +2,6 @@ import Vue from 'vue'; import { EventEmitter } from 'eventemitter3'; import { host, apiUrl, swPublickey, version, lang } from '../config'; -import api from './scripts/api'; import Progress from './scripts/loading'; import HomeStreamManager from './scripts/streaming/home-stream-manager'; import DriveStreamManager from './scripts/streaming/drive-stream-manager'; @@ -12,6 +11,11 @@ import MessagingIndexStreamManager from './scripts/streaming/messaging-index-str import Err from '../common/views/components/connect-failed.vue'; +//#region api requests +let spinner = null; +let pending = 0; +//#endregion + export type API = { chooseDriveFile: (opts: { title?: string; @@ -365,8 +369,53 @@ export default class MiOS extends EventEmitter { * @param endpoint エンドポイント名 * @param data パラメータ */ - public api(endpoint: string, data?: { [x: string]: any }) { - return api(this.i, endpoint, data); + public api(endpoint: string, data: { [x: string]: any } = {}): Promise<{ [x: string]: any }> { + if (++pending === 1) { + spinner = document.createElement('div'); + spinner.setAttribute('id', 'wait'); + document.body.appendChild(spinner); + } + + // Append a credential + if (this.isSignedIn) (data as any).i = this.i.token; + + // TODO + //const viaStream = localStorage.getItem('enableExperimental') == 'true'; + + return new Promise((resolve, reject) => { + /*if (viaStream) { + const stream = this.stream.borrow(); + const id = Math.random().toString(); + stream.once(`api-res:${id}`, res => { + resolve(res); + }); + stream.send({ + type: 'api', + id, + endpoint, + data + }); + } else {*/ + // Send request + fetch(endpoint.indexOf('://') > -1 ? endpoint : `${apiUrl}/${endpoint}`, { + method: 'POST', + body: JSON.stringify(data), + credentials: endpoint === 'signin' ? 'include' : 'omit', + cache: 'no-cache' + }).then(res => { + if (--pending === 0) spinner.parentNode.removeChild(spinner); + if (res.status === 200) { + res.json().then(resolve); + } else if (res.status === 204) { + resolve(); + } else { + res.json().then(err => { + reject(err.error); + }, reject); + } + }).catch(reject); + /*}*/ + }); } /** diff --git a/src/web/app/common/scripts/api.ts b/src/web/app/common/scripts/api.ts deleted file mode 100644 index bba838f56b..0000000000 --- a/src/web/app/common/scripts/api.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * API Request - */ - -declare const _API_URL_: string; - -let spinner = null; -let pending = 0; - -/** - * Send a request to API - * @param {string|Object} i Credential - * @param {string} endpoint Endpoint - * @param {any} [data={}] Data - * @return {Promise} Response - */ -export default (i, endpoint, data = {}): Promise<{ [x: string]: any }> => { - if (++pending === 1) { - spinner = document.createElement('div'); - spinner.setAttribute('id', 'wait'); - document.body.appendChild(spinner); - } - - // Append the credential - if (i != null) (data as any).i = typeof i === 'object' ? i.token : i; - - return new Promise((resolve, reject) => { - // Send request - fetch(endpoint.indexOf('://') > -1 ? endpoint : `${_API_URL_}/${endpoint}`, { - method: 'POST', - body: JSON.stringify(data), - credentials: endpoint === 'signin' ? 'include' : 'omit', - cache: 'no-cache' - }).then(res => { - if (--pending === 0) spinner.parentNode.removeChild(spinner); - if (res.status === 200) { - res.json().then(resolve); - } else if (res.status === 204) { - resolve(); - } else { - res.json().then(err => { - reject(err.error); - }, reject); - } - }).catch(reject); - }); -}; -- cgit v1.2.3-freya From 6c495268aec2d2fa02ac16dbc119fb9c4e34cdae Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 7 Mar 2018 11:40:40 +0900 Subject: wip --- src/api/endpoints/othello/match.ts | 80 ++++++++++++++++++++++ src/api/endpoints/othello/sessions/create.ts | 18 ----- src/api/endpoints/othello/sessions/in.ts | 34 --------- src/api/event.ts | 6 ++ src/api/models/othello-matching.ts | 11 +++ src/api/models/othello-session.ts | 29 -------- src/api/stream/messaging.ts | 2 +- src/api/stream/othello-game.ts | 12 ++++ src/api/stream/othello-matching.ts | 12 ++++ src/api/stream/requests.ts | 2 +- src/api/stream/server.ts | 2 +- src/api/streaming.ts | 4 ++ src/web/app/common/views/components/messaging.vue | 2 +- .../app/common/views/components/othello.game.vue | 29 ++++++++ src/web/app/common/views/components/othello.vue | 80 +++++++++++++++++++--- 15 files changed, 229 insertions(+), 94 deletions(-) create mode 100644 src/api/endpoints/othello/match.ts delete mode 100644 src/api/endpoints/othello/sessions/create.ts delete mode 100644 src/api/endpoints/othello/sessions/in.ts create mode 100644 src/api/models/othello-matching.ts delete mode 100644 src/api/models/othello-session.ts create mode 100644 src/api/stream/othello-game.ts create mode 100644 src/api/stream/othello-matching.ts create mode 100644 src/web/app/common/views/components/othello.game.vue (limited to 'src/api/stream') diff --git a/src/api/endpoints/othello/match.ts b/src/api/endpoints/othello/match.ts new file mode 100644 index 0000000000..2dc22d11f9 --- /dev/null +++ b/src/api/endpoints/othello/match.ts @@ -0,0 +1,80 @@ +import $ from 'cafy'; +import Matching from '../../models/othello-matchig'; +import Game, { pack } from '../../models/othello-game'; +import User from '../../models/user'; +import { publishOthelloStream } from '../../event'; + +module.exports = (params, user) => new Promise(async (res, rej) => { + // Get 'user_id' parameter + const [childId, childIdErr] = $(params.user_id).id().$; + if (childIdErr) return rej('invalid user_id param'); + + // Myself + if (childId.equals(user._id)) { + return rej('invalid user_id param'); + } + + // Find session + const exist = await Matching.findOne({ + parent_id: childId, + child_id: user._id + }); + + if (exist) { + // Destroy session + Matching.remove({ + _id: exist._id + }); + + const parentIsBlack = Math.random() > 0.5; + + // Start game + const game = await Game.insert({ + created_at: new Date(), + black_user_id: parentIsBlack ? exist.parent_id : user._id, + white_user_id: parentIsBlack ? user._id : exist.parent_id, + logs: [] + }); + + const packedGame = await pack(game); + + // Reponse + res(packedGame); + + publishOthelloStream(exist.parent_id, 'matched', { + game + }); + } else { + // Fetch child + const child = await User.findOne({ + _id: childId + }, { + fields: { + _id: true + } + }); + + if (child === null) { + return rej('user not found'); + } + + // 以前のセッションはすべて削除しておく + await Matching.remove({ + parent_id: user._id + }); + + // セッションを作成 + await Matching.insert({ + parent_id: user._id, + child_id: child._id + }); + + // Reponse + res(204); + + // 招待 + publishOthelloStream(child._id, 'invited', { + user_id: user._id + }); + } +}); diff --git a/src/api/endpoints/othello/sessions/create.ts b/src/api/endpoints/othello/sessions/create.ts deleted file mode 100644 index 09c3cff62b..0000000000 --- a/src/api/endpoints/othello/sessions/create.ts +++ /dev/null @@ -1,18 +0,0 @@ -import rndstr from 'rndstr'; -import Session, { pack } from '../../../models/othello-session'; - -module.exports = (params, user) => new Promise(async (res, rej) => { - // 以前のセッションはすべて削除しておく - await Session.remove({ - user_id: user._id - }); - - // セッションを作成 - const session = await Session.insert({ - user_id: user._id, - code: rndstr('a-z0-9', 3) - }); - - // Reponse - res(await pack(session)); -}); diff --git a/src/api/endpoints/othello/sessions/in.ts b/src/api/endpoints/othello/sessions/in.ts deleted file mode 100644 index d4b95bc4f9..0000000000 --- a/src/api/endpoints/othello/sessions/in.ts +++ /dev/null @@ -1,34 +0,0 @@ -import $ from 'cafy'; -import Session from '../../../models/othello-session'; -import Game, { pack } from '../../../models/othello-game'; - -module.exports = (params, user) => new Promise(async (res, rej) => { - // Get 'code' parameter - const [code, codeErr] = $(params.code).string().$; - if (codeErr) return rej('invalid code param'); - - // Fetch session - const session = await Session.findOne({ code }); - - if (session == null) { - return rej('session not found'); - } - - // Destroy session - Session.remove({ - _id: session._id - }); - - const parentIsBlack = Math.random() > 0.5; - - // Start game - const game = await Game.insert({ - created_at: new Date(), - black_user_id: parentIsBlack ? session.user_id : user._id, - white_user_id: parentIsBlack ? user._id : session.user_id, - logs: [] - }); - - // Reponse - res(await pack(game)); -}); diff --git a/src/api/event.ts b/src/api/event.ts index 4a2e4e453d..e68082f0a9 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -38,6 +38,10 @@ class MisskeyEvent { this.publish(`messaging-index-stream:${userId}`, type, typeof value === 'undefined' ? null : value); } + public publishOthelloStream(userId: ID, type: string, value?: any): void { + this.publish(`othello-stream:${userId}`, type, typeof value === 'undefined' ? null : value); + } + public publishChannelStream(channelId: ID, type: string, value?: any): void { this.publish(`channel-stream:${channelId}`, type, typeof value === 'undefined' ? null : value); } @@ -65,4 +69,6 @@ export const publishMessagingStream = ev.publishMessagingStream.bind(ev); export const publishMessagingIndexStream = ev.publishMessagingIndexStream.bind(ev); +export const publishOthelloStream = ev.publishOthelloStream.bind(ev); + export const publishChannelStream = ev.publishChannelStream.bind(ev); diff --git a/src/api/models/othello-matching.ts b/src/api/models/othello-matching.ts new file mode 100644 index 0000000000..bd7aeef3cf --- /dev/null +++ b/src/api/models/othello-matching.ts @@ -0,0 +1,11 @@ +import * as mongo from 'mongodb'; +import db from '../../db/mongodb'; + +const Matching = db.get('othello_matchings'); +export default Matching; + +export interface IMatching { + _id: mongo.ObjectID; + parent_id: mongo.ObjectID; + child_id: mongo.ObjectID; +} diff --git a/src/api/models/othello-session.ts b/src/api/models/othello-session.ts deleted file mode 100644 index 0aa1d01e54..0000000000 --- a/src/api/models/othello-session.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as mongo from 'mongodb'; -import deepcopy = require('deepcopy'); -import db from '../../db/mongodb'; - -const Session = db.get('othello_sessions'); -export default Session; - -export interface ISession { - _id: mongo.ObjectID; - code: string; - user_id: mongo.ObjectID; -} - -/** - * Pack an othello session for API response - * - * @param {any} session - * @return {Promise} - */ -export const pack = ( - session: any -) => new Promise(async (resolve, reject) => { - - const _session = deepcopy(session); - - delete _session._id; - - resolve(_session); -}); diff --git a/src/api/stream/messaging.ts b/src/api/stream/messaging.ts index 3f505cfafa..a4a12426a3 100644 --- a/src/api/stream/messaging.ts +++ b/src/api/stream/messaging.ts @@ -2,7 +2,7 @@ import * as websocket from 'websocket'; import * as redis from 'redis'; import read from '../common/read-messaging-message'; -export default function messagingStream(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { const otherparty = request.resourceURL.query.otherparty; // Subscribe messaging stream diff --git a/src/api/stream/othello-game.ts b/src/api/stream/othello-game.ts new file mode 100644 index 0000000000..ab91ef6422 --- /dev/null +++ b/src/api/stream/othello-game.ts @@ -0,0 +1,12 @@ +import * as websocket from 'websocket'; +import * as redis from 'redis'; + +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient): void { + const game = request.resourceURL.query.game; + + // Subscribe game stream + subscriber.subscribe(`misskey:othello-game-stream:${game}`); + subscriber.on('message', (_, data) => { + connection.send(data); + }); +} diff --git a/src/api/stream/othello-matching.ts b/src/api/stream/othello-matching.ts new file mode 100644 index 0000000000..f30ce6eb0a --- /dev/null +++ b/src/api/stream/othello-matching.ts @@ -0,0 +1,12 @@ +import * as websocket from 'websocket'; +import * as redis from 'redis'; + +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { + const otherparty = request.resourceURL.query.otherparty; + + // Subscribe matching stream + subscriber.subscribe(`misskey:othello-matching:${user._id}-${otherparty}`); + subscriber.on('message', (_, data) => { + connection.send(data); + }); +} diff --git a/src/api/stream/requests.ts b/src/api/stream/requests.ts index 2c36e58b6e..d7bb5e6c5c 100644 --- a/src/api/stream/requests.ts +++ b/src/api/stream/requests.ts @@ -3,7 +3,7 @@ import Xev from 'xev'; const ev = new Xev(); -export default function homeStream(request: websocket.request, connection: websocket.connection): void { +export default function(request: websocket.request, connection: websocket.connection): void { const onRequest = request => { connection.send(JSON.stringify({ type: 'request', diff --git a/src/api/stream/server.ts b/src/api/stream/server.ts index 0db6643d40..4ca2ad1b10 100644 --- a/src/api/stream/server.ts +++ b/src/api/stream/server.ts @@ -3,7 +3,7 @@ import Xev from 'xev'; const ev = new Xev(); -export default function homeStream(request: websocket.request, connection: websocket.connection): void { +export default function(request: websocket.request, connection: websocket.connection): void { const onStats = stats => { connection.send(JSON.stringify({ type: 'stats', diff --git a/src/api/streaming.ts b/src/api/streaming.ts index c06d64c245..66c2e0cec0 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -10,6 +10,8 @@ import homeStream from './stream/home'; import driveStream from './stream/drive'; import messagingStream from './stream/messaging'; import messagingIndexStream from './stream/messaging-index'; +import othelloGameStream from './stream/othello-game'; +import othelloMatchingStream from './stream/othello-matching'; import serverStream from './stream/server'; import requestsStream from './stream/requests'; import channelStream from './stream/channel'; @@ -62,6 +64,8 @@ module.exports = (server: http.Server) => { request.resourceURL.pathname === '/drive' ? driveStream : request.resourceURL.pathname === '/messaging' ? messagingStream : request.resourceURL.pathname === '/messaging-index' ? messagingIndexStream : + request.resourceURL.pathname === '/othello-game' ? othelloGameStream : + request.resourceURL.pathname === '/othello-matching' ? othelloMatchingStream : null; if (channel !== null) { diff --git a/src/web/app/common/views/components/messaging.vue b/src/web/app/common/views/components/messaging.vue index a94a996685..2ec488c247 100644 --- a/src/web/app/common/views/components/messaging.vue +++ b/src/web/app/common/views/components/messaging.vue @@ -89,7 +89,7 @@ export default Vue.extend({ beforeDestroy() { this.connection.off('message', this.onMessage); this.connection.off('read', this.onRead); - (this as any).os.stream.dispose(this.connectionId); + (this as any).streams.messagingIndexStream.dispose(this.connectionId); }, methods: { isMe(message) { diff --git a/src/web/app/common/views/components/othello.game.vue b/src/web/app/common/views/components/othello.game.vue new file mode 100644 index 0000000000..3d3ffb2c07 --- /dev/null +++ b/src/web/app/common/views/components/othello.game.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/web/app/common/views/components/othello.vue b/src/web/app/common/views/components/othello.vue index 136046db24..f5abcfb103 100644 --- a/src/web/app/common/views/components/othello.vue +++ b/src/web/app/common/views/components/othello.vue @@ -1,16 +1,19 @@ @@ -36,11 +37,13 @@ import Vue from 'vue'; import { chUrl } from '../../../config'; import MkMessagingWindow from './messaging-window.vue'; +import MkGameWindow from './game-window.vue'; export default Vue.extend({ data() { return { hasUnreadMessagingMessages: false, + hasGameInvitations: false, connection: null, connectionId: null, chUrl @@ -80,6 +83,10 @@ export default Vue.extend({ messaging() { (this as any).os.new(MkMessagingWindow); + }, + + game() { + (this as any).os.new(MkGameWindow); } } }); diff --git a/src/web/app/desktop/views/widgets/channel.channel.vue b/src/web/app/desktop/views/widgets/channel.channel.vue index 70dac316cf..02cdf6de13 100644 --- a/src/web/app/desktop/views/widgets/channel.channel.vue +++ b/src/web/app/desktop/views/widgets/channel.channel.vue @@ -11,7 +11,7 @@ diff --git a/src/web/app/common/views/components/othello.room.vue b/src/web/app/common/views/components/othello.room.vue new file mode 100644 index 0000000000..b41d97ec61 --- /dev/null +++ b/src/web/app/common/views/components/othello.room.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/src/web/app/common/views/components/othello.vue b/src/web/app/common/views/components/othello.vue index 326a8d80cc..31858fca19 100644 --- a/src/web/app/common/views/components/othello.vue +++ b/src/web/app/common/views/components/othello.vue @@ -1,7 +1,7 @@