This commit is contained in:
syuilo 2020-03-07 01:04:36 +09:00
parent c7c537c8b8
commit 1947835c51
16 changed files with 167 additions and 64 deletions

View file

@ -1,6 +1,6 @@
const dateTimeIntervals = { const dateTimeIntervals = {
'days': 86400000, 'day': 86400000,
'hours': 3600000, 'hour': 3600000,
}; };
export function DateUTC(time: number[]): Date { export function DateUTC(time: number[]): Date {

View file

@ -25,11 +25,16 @@ export const meta = {
'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。' 'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。'
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
}, },
res: convertLog(activeUsersChart.schema), res: convertLog(activeUsersChart.schema),
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await activeUsersChart.getChart(ps.span as any, ps.limit!); return await activeUsersChart.getChart(ps.span as any, ps.limit!, ps.offset!);
}); });

View file

@ -25,11 +25,16 @@ export const meta = {
'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。' 'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。'
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
}, },
res: convertLog(driveChart.schema), res: convertLog(driveChart.schema),
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await driveChart.getChart(ps.span as any, ps.limit!); return await driveChart.getChart(ps.span as any, ps.limit!, ps.offset!);
}); });

View file

@ -25,11 +25,16 @@ export const meta = {
'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。' 'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。'
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
}, },
res: convertLog(federationChart.schema), res: convertLog(federationChart.schema),
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await federationChart.getChart(ps.span as any, ps.limit!); return await federationChart.getChart(ps.span as any, ps.limit!, ps.offset!);
}); });

View file

@ -26,6 +26,11 @@ export const meta = {
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
tag: { tag: {
validator: $.str, validator: $.str,
desc: { desc: {
@ -38,5 +43,5 @@ export const meta = {
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await hashtagChart.getChart(ps.span as any, ps.limit!, ps.tag); return await hashtagChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.tag);
}); });

View file

@ -26,6 +26,11 @@ export const meta = {
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
host: { host: {
validator: $.str, validator: $.str,
desc: { desc: {
@ -39,5 +44,5 @@ export const meta = {
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await instanceChart.getChart(ps.span as any, ps.limit!, ps.host); return await instanceChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.host);
}); });

View file

@ -25,11 +25,16 @@ export const meta = {
'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。' 'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。'
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
}, },
res: convertLog(networkChart.schema), res: convertLog(networkChart.schema),
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await networkChart.getChart(ps.span as any, ps.limit!); return await networkChart.getChart(ps.span as any, ps.limit!, ps.offset!);
}); });

View file

@ -25,11 +25,16 @@ export const meta = {
'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。' 'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。'
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
}, },
res: convertLog(notesChart.schema), res: convertLog(notesChart.schema),
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await notesChart.getChart(ps.span as any, ps.limit!); return await notesChart.getChart(ps.span as any, ps.limit!, ps.offset!);
}); });

View file

@ -27,6 +27,11 @@ export const meta = {
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
userId: { userId: {
validator: $.type(ID), validator: $.type(ID),
desc: { desc: {
@ -40,5 +45,5 @@ export const meta = {
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await perUserDriveChart.getChart(ps.span as any, ps.limit!, ps.userId); return await perUserDriveChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId);
}); });

View file

@ -27,6 +27,11 @@ export const meta = {
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
userId: { userId: {
validator: $.type(ID), validator: $.type(ID),
desc: { desc: {
@ -40,5 +45,5 @@ export const meta = {
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await perUserFollowingChart.getChart(ps.span as any, ps.limit!, ps.userId); return await perUserFollowingChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId);
}); });

View file

@ -27,6 +27,11 @@ export const meta = {
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
userId: { userId: {
validator: $.type(ID), validator: $.type(ID),
desc: { desc: {
@ -40,5 +45,5 @@ export const meta = {
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await perUserNotesChart.getChart(ps.span as any, ps.limit!, ps.userId); return await perUserNotesChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId);
}); });

View file

@ -27,6 +27,11 @@ export const meta = {
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
userId: { userId: {
validator: $.type(ID), validator: $.type(ID),
desc: { desc: {
@ -40,5 +45,5 @@ export const meta = {
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await perUserReactionsChart.getChart(ps.span as any, ps.limit!, ps.userId); return await perUserReactionsChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId);
}); });

View file

@ -25,11 +25,16 @@ export const meta = {
'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。' 'ja-JP': '最大数。例えば 30 を指定したとすると、スパンが"day"の場合は30日分のデータが、スパンが"hour"の場合は30時間分のデータが返ります。'
} }
}, },
offset: {
validator: $.optional.num,
default: 0,
},
}, },
res: convertLog(usersChart.schema), res: convertLog(usersChart.schema),
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {
return await usersChart.getChart(ps.span as any, ps.limit!); return await usersChart.getChart(ps.span as any, ps.limit!, ps.offset!);
}); });

View file

@ -60,9 +60,9 @@ export default define(meta, async () => {
Notes.count({ where: { userHost: null }, cache: 3600000 }), Notes.count({ where: { userHost: null }, cache: 3600000 }),
Users.count({ cache: 3600000 }), Users.count({ cache: 3600000 }),
Users.count({ where: { host: null }, cache: 3600000 }), Users.count({ where: { host: null }, cache: 3600000 }),
federationChart.getChart('hour', 1).then(chart => chart.instance.total[0]), federationChart.getChart('hour', 1, 0).then(chart => chart.instance.total[0]),
driveChart.getChart('hour', 1).then(chart => chart.local.totalSize[0]), driveChart.getChart('hour', 1, 0).then(chart => chart.local.totalSize[0]),
driveChart.getChart('hour', 1).then(chart => chart.remote.totalSize[0]), driveChart.getChart('hour', 1, 0).then(chart => chart.remote.totalSize[0]),
]); ]);
return { return {

View file

@ -8,7 +8,7 @@ import * as nestedProperty from 'nested-property';
import autobind from 'autobind-decorator'; import autobind from 'autobind-decorator';
import Logger from '../logger'; import Logger from '../logger';
import { Schema } from '../../misc/schema'; import { Schema } from '../../misc/schema';
import { EntitySchema, getRepository, Repository, LessThan, MoreThanOrEqual } from 'typeorm'; import { EntitySchema, getRepository, Repository, LessThan, MoreThanOrEqual, Between } from 'typeorm';
import { DateUTC, isTimeSame, isTimeBefore, subtractTimespan } from '../../prelude/time'; import { DateUTC, isTimeSame, isTimeBefore, subtractTimespan } from '../../prelude/time';
import { getChartInsertLock } from '../../misc/app-lock'; import { getChartInsertLock } from '../../misc/app-lock';
@ -133,6 +133,21 @@ export default abstract class Chart<T extends Record<string, any>> {
return Math.floor(x.getTime() / 1000); return Math.floor(x.getTime() / 1000);
} }
@autobind
private static dateToYMDH(date: Date): [number, number, number, number] {
const y = date.getUTCFullYear();
const m = date.getUTCMonth();
const d = date.getUTCDate();
const h = date.getUTCHours();
return [y, m, d, h];
}
@autobind
private static getCurrentDate(): [number, number, number, number] {
return Chart.dateToYMDH(new Date());
}
@autobind @autobind
public static schemaToEntity(name: string, schema: Schema): EntitySchema { public static schemaToEntity(name: string, schema: Schema): EntitySchema {
return new EntitySchema({ return new EntitySchema({
@ -211,18 +226,6 @@ export default abstract class Chart<T extends Record<string, any>> {
return log as T; return log as T;
} }
@autobind
private getCurrentDate(): [number, number, number, number] {
const now = new Date();
const y = now.getUTCFullYear();
const m = now.getUTCMonth();
const d = now.getUTCDate();
const h = now.getUTCHours();
return [y, m, d, h];
}
@autobind @autobind
private getLatestLog(span: Span, group: string | null = null): Promise<Log | null> { private getLatestLog(span: Span, group: string | null = null): Promise<Log | null> {
return this.repository.findOne({ return this.repository.findOne({
@ -237,7 +240,7 @@ export default abstract class Chart<T extends Record<string, any>> {
@autobind @autobind
private async getCurrentLog(span: Span, group: string | null = null): Promise<Log> { private async getCurrentLog(span: Span, group: string | null = null): Promise<Log> {
const [y, m, d, h] = this.getCurrentDate(); const [y, m, d, h] = Chart.getCurrentDate();
const current = const current =
span == 'day' ? DateUTC([y, m, d]) : span == 'day' ? DateUTC([y, m, d]) :
@ -378,12 +381,23 @@ export default abstract class Chart<T extends Record<string, any>> {
} }
@autobind @autobind
public async getChart(span: Span, range: number, group: string | null = null): Promise<ArrayValue<T>> { public async getChart(span: Span, range: number, offset: number, group: string | null = null): Promise<ArrayValue<T>> {
const [y, m, d, h] = this.getCurrentDate(); let [y, m, d, h] = Chart.getCurrentDate();
let lt: Date = null as never;
if (offset > 0) {
[y, m, d, h] = Chart.dateToYMDH(subtractTimespan(DateUTC([y, m, d, h]), offset, span));
lt =
span === 'day' ? DateUTC([y, m, d]) :
span === 'hour' ? DateUTC([y, m, d, h]) :
null as never;
}
const gt = const gt =
span === 'day' ? subtractTimespan(DateUTC([y, m, d]), range - 1, 'days') : span === 'day' ? subtractTimespan(DateUTC([y, m, d]), range - 1, 'day') :
span === 'hour' ? subtractTimespan(DateUTC([y, m, d, h]), range - 1, 'hours') : span === 'hour' ? subtractTimespan(DateUTC([y, m, d, h]), range - 1, 'hour') :
null as never; null as never;
// ログ取得 // ログ取得
@ -391,7 +405,9 @@ export default abstract class Chart<T extends Record<string, any>> {
where: { where: {
group: group, group: group,
span: span, span: span,
date: MoreThanOrEqual(Chart.dateToTimestamp(gt)) date: offset === 0
? MoreThanOrEqual(Chart.dateToTimestamp(gt))
: Between(Chart.dateToTimestamp(gt), Chart.dateToTimestamp(lt))
}, },
order: { order: {
date: -1 date: -1
@ -439,8 +455,8 @@ export default abstract class Chart<T extends Record<string, any>> {
// 整形 // 整形
for (let i = (range - 1); i >= 0; i--) { for (let i = (range - 1); i >= 0; i--) {
const current = const current =
span == 'day' ? subtractTimespan(DateUTC([y, m, d]), i, 'days') : span == 'day' ? subtractTimespan(DateUTC([y, m, d]), i, 'day') :
span == 'hour' ? subtractTimespan(DateUTC([y, m, d, h]), i, 'hours') : span == 'hour' ? subtractTimespan(DateUTC([y, m, d, h]), i, 'hour') :
null as never; null as never;
const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current)); const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current));

View file

@ -86,8 +86,8 @@ describe('Chart', () => {
it('Can updates', async(async () => { it('Can updates', async(async () => {
await testChart.increment(); await testChart.increment();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -109,8 +109,8 @@ describe('Chart', () => {
it('Can updates (dec)', async(async () => { it('Can updates (dec)', async(async () => {
await testChart.decrement(); await testChart.decrement();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -130,8 +130,8 @@ describe('Chart', () => {
})); }));
it('Empty chart', async(async () => { it('Empty chart', async(async () => {
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -155,8 +155,8 @@ describe('Chart', () => {
await testChart.increment(); await testChart.increment();
await testChart.increment(); await testChart.increment();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -182,8 +182,8 @@ describe('Chart', () => {
await testChart.increment(); await testChart.increment();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -209,8 +209,8 @@ describe('Chart', () => {
await testChart.increment(); await testChart.increment();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -235,8 +235,8 @@ describe('Chart', () => {
clock.tick('05:00:00'); clock.tick('05:00:00');
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -262,8 +262,8 @@ describe('Chart', () => {
clock.tick('05:00:00'); clock.tick('05:00:00');
await testChart.increment(); await testChart.increment();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -282,14 +282,41 @@ describe('Chart', () => {
}); });
})); }));
it('Can specify offset', async(async () => {
await testChart.increment();
clock.tick('01:00:00');
await testChart.increment();
const chartHours = await testChart.getChart('hour', 3, 1);
const chartDays = await testChart.getChart('day', 3, 1);
assert.deepStrictEqual(chartHours, {
foo: {
dec: [0, 0, 0],
inc: [1, 0, 0],
total: [1, 0, 0]
},
});
assert.deepStrictEqual(chartDays, {
foo: {
dec: [0, 0, 0],
inc: [0, 0, 0],
total: [0, 0, 0]
},
});
}));
describe('Grouped', () => { describe('Grouped', () => {
it('Can updates', async(async () => { it('Can updates', async(async () => {
await testGroupedChart.increment('alice'); await testGroupedChart.increment('alice');
const aliceChartHours = await testGroupedChart.getChart('hour', 3, 'alice'); const aliceChartHours = await testGroupedChart.getChart('hour', 3, 0, 'alice');
const aliceChartDays = await testGroupedChart.getChart('day', 3, 'alice'); const aliceChartDays = await testGroupedChart.getChart('day', 3, 0, 'alice');
const bobChartHours = await testGroupedChart.getChart('hour', 3, 'bob'); const bobChartHours = await testGroupedChart.getChart('hour', 3, 0, 'bob');
const bobChartDays = await testGroupedChart.getChart('day', 3, 'bob'); const bobChartDays = await testGroupedChart.getChart('day', 3, 0, 'bob');
assert.deepStrictEqual(aliceChartHours, { assert.deepStrictEqual(aliceChartHours, {
foo: { foo: {
@ -331,8 +358,8 @@ describe('Chart', () => {
await testUniqueChart.uniqueIncrement('alice'); await testUniqueChart.uniqueIncrement('alice');
await testUniqueChart.uniqueIncrement('bob'); await testUniqueChart.uniqueIncrement('bob');
const chartHours = await testUniqueChart.getChart('hour', 3); const chartHours = await testUniqueChart.getChart('hour', 3, 0);
const chartDays = await testUniqueChart.getChart('day', 3); const chartDays = await testUniqueChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: [2, 0, 0], foo: [2, 0, 0],
@ -350,8 +377,8 @@ describe('Chart', () => {
await testChart.resync(); await testChart.resync();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {
@ -379,8 +406,8 @@ describe('Chart', () => {
await testChart.resync(); await testChart.resync();
const chartHours = await testChart.getChart('hour', 3); const chartHours = await testChart.getChart('hour', 3, 0);
const chartDays = await testChart.getChart('day', 3); const chartDays = await testChart.getChart('day', 3, 0);
assert.deepStrictEqual(chartHours, { assert.deepStrictEqual(chartHours, {
foo: { foo: {