良い感じに

This commit is contained in:
syuilo 2018-07-16 03:43:36 +09:00
parent 1e4a86da8e
commit 1744316656
8 changed files with 76 additions and 50 deletions

View file

@ -1,12 +1,12 @@
import * as Koa from 'koa'; import * as Koa from 'koa';
import Endpoint from './endpoint'; import { IEndpoint } from './endpoints';
import authenticate from './authenticate'; import authenticate from './authenticate';
import call from './call'; import call from './call';
import { IUser } from '../../models/user'; import { IUser } from '../../models/user';
import { IApp } from '../../models/app'; import { IApp } from '../../models/app';
export default async (endpoint: Endpoint, ctx: Koa.Context) => { export default async (endpoint: IEndpoint, ctx: Koa.Context) => {
const body = ctx.is('multipart/form-data') ? (ctx.req as any).body : ctx.request.body; const body = ctx.is('multipart/form-data') ? (ctx.req as any).body : ctx.request.body;
const reply = (x?: any, y?: any) => { const reply = (x?: any, y?: any) => {
@ -37,7 +37,7 @@ export default async (endpoint: Endpoint, ctx: Koa.Context) => {
// API invoking // API invoking
try { try {
res = await call(endpoint, user, app, body, (ctx.req as any).file); res = await call(endpoint.name, user, app, body, (ctx.req as any).file);
} catch (e) { } catch (e) {
reply(400, e); reply(400, e);
return; return;

View file

@ -1,35 +1,12 @@
import * as path from 'path';
import * as glob from 'glob';
import Endpoint from './endpoint';
import limitter from './limitter'; import limitter from './limitter';
import { IUser } from '../../models/user'; import { IUser } from '../../models/user';
import { IApp } from '../../models/app'; import { IApp } from '../../models/app';
import endpoints from './endpoints';
const files = glob.sync('**/*.js', { export default (endpoint: string, user: IUser, app: IApp, data: any, file?: any) => new Promise<any>(async (ok, rej) => {
cwd: path.resolve(__dirname + '/endpoints/')
});
const endpoints: Array<{
exec: any,
meta: Endpoint
}> = files.map(f => {
const ep = require('./endpoints/' + f);
ep.meta = ep.meta || {};
ep.meta.name = f.replace('.js', '');
return {
exec: ep.default,
meta: ep.meta
};
});
export default (endpoint: string | Endpoint, user: IUser, app: IApp, data: any, file?: any) => new Promise<any>(async (ok, rej) => {
const isSecure = user != null && app == null; const isSecure = user != null && app == null;
const epName = typeof endpoint === 'string' ? endpoint : endpoint.name; const ep = endpoints.find(e => e.name === endpoint);
const ep = endpoints.find(e => e.meta.name === epName);
if (ep.meta.secure && !isSecure) { if (ep.meta.secure && !isSecure) {
return rej('ACCESS_DENIED'); return rej('ACCESS_DENIED');
@ -51,7 +28,7 @@ export default (endpoint: string | Endpoint, user: IUser, app: IApp, data: any,
if (ep.meta.requireCredential && ep.meta.limit) { if (ep.meta.requireCredential && ep.meta.limit) {
try { try {
await limitter(ep.meta, user); // Rate limit await limitter(ep, user); // Rate limit
} catch (e) { } catch (e) {
// drop request if limit exceeded // drop request if limit exceeded
return rej('RATE_LIMIT_EXCEEDED'); return rej('RATE_LIMIT_EXCEEDED');

View file

@ -1,9 +1,7 @@
export default interface IEndpoint { import * as path from 'path';
/** import * as glob from 'glob';
*
*/
name: string;
export interface IEndpointMeta {
/** /**
* *
* false * false
@ -58,3 +56,25 @@ export default interface IEndpoint {
*/ */
kind?: string; kind?: string;
} }
export interface IEndpoint {
name: string;
exec: any;
meta: IEndpointMeta;
}
const files = glob.sync('**/*.js', {
cwd: path.resolve(__dirname + '/endpoints/')
});
const endpoints: IEndpoint[] = files.map(f => {
const ep = require('./endpoints/' + f);
return {
name: f.replace('.js', ''),
exec: ep.default,
meta: ep.meta || {}
};
});
export default endpoints;

View file

@ -1,8 +1,36 @@
import * as fs from 'fs'; import * as fs from 'fs';
const ms = require('ms');
import $ from 'cafy'; import ID from '../../../../../misc/cafy-id'; import $ from 'cafy'; import ID from '../../../../../misc/cafy-id';
import { validateFileName, pack } from '../../../../../models/drive-file'; import { validateFileName, pack } from '../../../../../models/drive-file';
import create from '../../../../../services/drive/add-file'; import create from '../../../../../services/drive/add-file';
import { ILocalUser } from '../../../../../models/user'; import { ILocalUser } from '../../../../../models/user';
import getParams from '../../../get-params';
export const meta = {
desc: {
ja: 'ドライブにファイルをアップロードします。'
},
requireCredential: true,
limit: {
duration: ms('1hour'),
max: 100
},
withFile: true,
kind: 'drive-write',
params: {
folderId: $.type(ID).optional.nullable.note({
default: null,
desc: {
ja: 'フォルダID'
}
})
}
};
/** /**
* Create a file * Create a file
@ -27,17 +55,19 @@ export default async (file: any, params: any, user: ILocalUser): Promise<any> =>
name = null; name = null;
} }
// Get 'folderId' parameter
const [folderId = null, folderIdErr] = $.type(ID).optional.nullable.get(params.folderId);
if (folderIdErr) throw 'invalid folderId param';
function cleanup() { function cleanup() {
fs.unlink(file.path, () => {}); fs.unlink(file.path, () => {});
} }
const [ps, psErr] = getParams(meta, params);
if (psErr) {
cleanup();
throw psErr;
}
try { try {
// Create file // Create file
const driveFile = await create(user, file.path, name, null, folderId); const driveFile = await create(user, file.path, name, null, ps.folderId);
cleanup(); cleanup();

View file

@ -8,8 +8,6 @@ import { IApp } from '../../../../models/app';
import getParams from '../../get-params'; import getParams from '../../get-params';
export const meta = { export const meta = {
name: 'notes/create',
desc: { desc: {
ja: '投稿します。' ja: '投稿します。'
}, },

View file

@ -35,7 +35,7 @@ const router = new Router();
/** /**
* Register endpoint handlers * Register endpoint handlers
*/ */
endpoints.forEach(endpoint => endpoint.withFile endpoints.forEach(endpoint => endpoint.meta.withFile
? router.post(`/${endpoint.name}`, upload.single('file'), handler.bind(null, endpoint)) ? router.post(`/${endpoint.name}`, upload.single('file'), handler.bind(null, endpoint))
: router.post(`/${endpoint.name}`, handler.bind(null, endpoint)) : router.post(`/${endpoint.name}`, handler.bind(null, endpoint))
); );

View file

@ -1,14 +1,14 @@
import * as Limiter from 'ratelimiter'; import * as Limiter from 'ratelimiter';
import * as debug from 'debug'; import * as debug from 'debug';
import limiterDB from '../../db/redis'; import limiterDB from '../../db/redis';
import Endpoint from './endpoint'; import { IEndpoint } from './endpoints';
import getAcct from '../../misc/acct/render'; import getAcct from '../../misc/acct/render';
import { IUser } from '../../models/user'; import { IUser } from '../../models/user';
const log = debug('misskey:limitter'); const log = debug('misskey:limitter');
export default (endpoint: Endpoint, user: IUser) => new Promise((ok, reject) => { export default (endpoint: IEndpoint, user: IUser) => new Promise((ok, reject) => {
const limitation = endpoint.limit; const limitation = endpoint.meta.limit;
const key = limitation.hasOwnProperty('key') const key = limitation.hasOwnProperty('key')
? limitation.key ? limitation.key

View file

@ -168,14 +168,15 @@ router.get('/assets/*', async ctx => {
router.get('/*/api/endpoints/*', async ctx => { router.get('/*/api/endpoints/*', async ctx => {
const lang = ctx.params[0]; const lang = ctx.params[0];
const ep = require('../../../built/server/api/endpoints/' + ctx.params[1]).meta; const name = ctx.params[1];
const ep = require('../../../built/server/api/endpoints/' + name).meta || {};
const vars = { const vars = {
title: ep.name, title: name,
endpoint: ep.name, endpoint: name,
url: { url: {
host: config.api_url, host: config.api_url,
path: ep.name path: name
}, },
desc: ep.desc, desc: ep.desc,
// @ts-ignore // @ts-ignore