This commit is contained in:
syuilo
2018-03-07 11:40:40 +09:00
parent 06eabcbc63
commit 6c495268ae
15 changed files with 230 additions and 95 deletions

View File

@ -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
});
}
});

View File

@ -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));
});

View File

@ -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));
});

View File

@ -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);

View File

@ -0,0 +1,11 @@
import * as mongo from 'mongodb';
import db from '../../db/mongodb';
const Matching = db.get<IMatching>('othello_matchings');
export default Matching;
export interface IMatching {
_id: mongo.ObjectID;
parent_id: mongo.ObjectID;
child_id: mongo.ObjectID;
}

View File

@ -1,29 +0,0 @@
import * as mongo from 'mongodb';
import deepcopy = require('deepcopy');
import db from '../../db/mongodb';
const Session = db.get<ISession>('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<any>}
*/
export const pack = (
session: any
) => new Promise<any>(async (resolve, reject) => {
const _session = deepcopy(session);
delete _session._id;
resolve(_session);
});

View File

@ -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

View File

@ -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);
});
}

View File

@ -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);
});
}

View File

@ -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',

View File

@ -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',

View File

@ -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) {