良い感じに
This commit is contained in:
parent
1e4a86da8e
commit
1744316656
|
@ -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;
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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;
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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: '投稿します。'
|
||||||
},
|
},
|
||||||
|
|
|
@ -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))
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue