diff --git a/src/prelude/time.ts b/src/prelude/time.ts index 77a5fc1af..a65366d74 100644 --- a/src/prelude/time.ts +++ b/src/prelude/time.ts @@ -1,13 +1,11 @@ const dateTimeIntervals = { 'day': 86400000, 'hour': 3600000, + 'ms': 1, }; -export function DateUTC(time: number[]): Date { - const r = new Date(0); - r.setUTCFullYear(time[0], time[1], time[2]); - if (time[3]) r.setUTCHours(time[3], ...time.slice(4)); - return r; +export function dateUTC(time: number[]): Date { + return new Date(Date.UTC(...time)); } export function isTimeSame(a: Date, b: Date): boolean { @@ -22,10 +20,10 @@ export function isTimeAfter(a: Date, b: Date): boolean { return (a.getTime() - b.getTime()) > 0; } -export function addTimespan(x: Date, value: number, span: keyof typeof dateTimeIntervals): Date { +export function addTime(x: Date, value: number, span: keyof typeof dateTimeIntervals = 'ms'): Date { return new Date(x.getTime() + (value * dateTimeIntervals[span])); } -export function subtractTimespan(x: Date, value: number, span: keyof typeof dateTimeIntervals): Date { +export function subtractTime(x: Date, value: number, span: keyof typeof dateTimeIntervals = 'ms'): Date { return new Date(x.getTime() - (value * dateTimeIntervals[span])); } diff --git a/src/server/api/endpoints/charts/active-users.ts b/src/server/api/endpoints/charts/active-users.ts index 327dd4de3..df427ff4b 100644 --- a/src/server/api/endpoints/charts/active-users.ts +++ b/src/server/api/endpoints/charts/active-users.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, }, @@ -36,5 +36,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await activeUsersChart.getChart(ps.span as any, ps.limit!, ps.offset!); + return await activeUsersChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); }); diff --git a/src/server/api/endpoints/charts/drive.ts b/src/server/api/endpoints/charts/drive.ts index 752cb6f03..e1f279fa0 100644 --- a/src/server/api/endpoints/charts/drive.ts +++ b/src/server/api/endpoints/charts/drive.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, }, @@ -36,5 +36,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await driveChart.getChart(ps.span as any, ps.limit!, ps.offset!); + return await driveChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); }); diff --git a/src/server/api/endpoints/charts/federation.ts b/src/server/api/endpoints/charts/federation.ts index 1701f9bde..581e42f30 100644 --- a/src/server/api/endpoints/charts/federation.ts +++ b/src/server/api/endpoints/charts/federation.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, }, @@ -36,5 +36,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await federationChart.getChart(ps.span as any, ps.limit!, ps.offset!); + return await federationChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); }); diff --git a/src/server/api/endpoints/charts/hashtag.ts b/src/server/api/endpoints/charts/hashtag.ts index bb353e703..1aa5c86b3 100644 --- a/src/server/api/endpoints/charts/hashtag.ts +++ b/src/server/api/endpoints/charts/hashtag.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, tag: { @@ -43,5 +43,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await hashtagChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.tag); + return await hashtagChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.tag); }); diff --git a/src/server/api/endpoints/charts/instance.ts b/src/server/api/endpoints/charts/instance.ts index 3ccb2ba12..f0f85ed71 100644 --- a/src/server/api/endpoints/charts/instance.ts +++ b/src/server/api/endpoints/charts/instance.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, host: { @@ -44,5 +44,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await instanceChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.host); + return await instanceChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.host); }); diff --git a/src/server/api/endpoints/charts/network.ts b/src/server/api/endpoints/charts/network.ts index 20f5977ba..d1337681a 100644 --- a/src/server/api/endpoints/charts/network.ts +++ b/src/server/api/endpoints/charts/network.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, }, @@ -36,5 +36,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await networkChart.getChart(ps.span as any, ps.limit!, ps.offset!); + return await networkChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); }); diff --git a/src/server/api/endpoints/charts/notes.ts b/src/server/api/endpoints/charts/notes.ts index 5111e299e..74aa48b36 100644 --- a/src/server/api/endpoints/charts/notes.ts +++ b/src/server/api/endpoints/charts/notes.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, }, @@ -36,5 +36,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await notesChart.getChart(ps.span as any, ps.limit!, ps.offset!); + return await notesChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); }); diff --git a/src/server/api/endpoints/charts/user/drive.ts b/src/server/api/endpoints/charts/user/drive.ts index 576bc7be6..5aae5bd75 100644 --- a/src/server/api/endpoints/charts/user/drive.ts +++ b/src/server/api/endpoints/charts/user/drive.ts @@ -28,8 +28,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, userId: { @@ -45,5 +45,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await perUserDriveChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId); + return await perUserDriveChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/src/server/api/endpoints/charts/user/following.ts b/src/server/api/endpoints/charts/user/following.ts index dcdf15b41..9d772c39c 100644 --- a/src/server/api/endpoints/charts/user/following.ts +++ b/src/server/api/endpoints/charts/user/following.ts @@ -28,8 +28,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, userId: { @@ -45,5 +45,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await perUserFollowingChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId); + return await perUserFollowingChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/src/server/api/endpoints/charts/user/notes.ts b/src/server/api/endpoints/charts/user/notes.ts index 65c12d6be..8de7c0c3e 100644 --- a/src/server/api/endpoints/charts/user/notes.ts +++ b/src/server/api/endpoints/charts/user/notes.ts @@ -28,8 +28,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, userId: { @@ -45,5 +45,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await perUserNotesChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId); + return await perUserNotesChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/src/server/api/endpoints/charts/user/reactions.ts b/src/server/api/endpoints/charts/user/reactions.ts index c83a203b9..4c37305fc 100644 --- a/src/server/api/endpoints/charts/user/reactions.ts +++ b/src/server/api/endpoints/charts/user/reactions.ts @@ -28,8 +28,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, userId: { @@ -45,5 +45,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await perUserReactionsChart.getChart(ps.span as any, ps.limit!, ps.offset!, ps.userId); + return await perUserReactionsChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null, ps.userId); }); diff --git a/src/server/api/endpoints/charts/users.ts b/src/server/api/endpoints/charts/users.ts index 7f52184f1..18eec384a 100644 --- a/src/server/api/endpoints/charts/users.ts +++ b/src/server/api/endpoints/charts/users.ts @@ -27,8 +27,8 @@ export const meta = { }, offset: { - validator: $.optional.num, - default: 0, + validator: $.optional.nullable.num, + default: null, }, }, @@ -36,5 +36,5 @@ export const meta = { }; export default define(meta, async (ps) => { - return await usersChart.getChart(ps.span as any, ps.limit!, ps.offset!); + return await usersChart.getChart(ps.span as any, ps.limit!, ps.offset ? new Date(ps.offset) : null); }); diff --git a/src/server/api/endpoints/stats.ts b/src/server/api/endpoints/stats.ts index a6ee240a8..dab05c167 100644 --- a/src/server/api/endpoints/stats.ts +++ b/src/server/api/endpoints/stats.ts @@ -60,9 +60,9 @@ export default define(meta, async () => { Notes.count({ where: { userHost: null }, cache: 3600000 }), Users.count({ cache: 3600000 }), Users.count({ where: { host: null }, cache: 3600000 }), - federationChart.getChart('hour', 1, 0).then(chart => chart.instance.total[0]), - driveChart.getChart('hour', 1, 0).then(chart => chart.local.totalSize[0]), - driveChart.getChart('hour', 1, 0).then(chart => chart.remote.totalSize[0]), + federationChart.getChart('hour', 1, null).then(chart => chart.instance.total[0]), + driveChart.getChart('hour', 1, null).then(chart => chart.local.totalSize[0]), + driveChart.getChart('hour', 1, null).then(chart => chart.remote.totalSize[0]), ]); return { diff --git a/src/services/chart/core.ts b/src/services/chart/core.ts index ca24082e7..dc09923ae 100644 --- a/src/services/chart/core.ts +++ b/src/services/chart/core.ts @@ -8,8 +8,8 @@ import * as nestedProperty from 'nested-property'; import autobind from 'autobind-decorator'; import Logger from '../logger'; import { Schema } from '../../misc/schema'; -import { EntitySchema, getRepository, Repository, LessThan, MoreThanOrEqual, Between } from 'typeorm'; -import { DateUTC, isTimeSame, isTimeBefore, subtractTimespan } from '../../prelude/time'; +import { EntitySchema, getRepository, Repository, LessThan, Between } from 'typeorm'; +import { dateUTC, isTimeSame, isTimeBefore, subtractTime, addTime } from '../../prelude/time'; import { getChartInsertLock } from '../../misc/app-lock'; const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test'); @@ -134,18 +134,21 @@ export default abstract class Chart> { } @autobind - private static dateToYMDH(date: Date): [number, number, number, number] { + private static parseDate(date: Date): [number, number, number, number, number, number, number] { const y = date.getUTCFullYear(); const m = date.getUTCMonth(); const d = date.getUTCDate(); const h = date.getUTCHours(); + const _m = date.getUTCMinutes(); + const _s = date.getUTCSeconds(); + const _ms = date.getUTCMilliseconds(); - return [y, m, d, h]; + return [y, m, d, h, _m, _s, _ms]; } @autobind - private static getCurrentDate(): [number, number, number, number] { - return Chart.dateToYMDH(new Date()); + private static getCurrentDate() { + return Chart.parseDate(new Date()); } @autobind @@ -243,8 +246,8 @@ export default abstract class Chart> { const [y, m, d, h] = Chart.getCurrentDate(); const current = - span == 'day' ? DateUTC([y, m, d]) : - span == 'hour' ? DateUTC([y, m, d, h]) : + span == 'day' ? dateUTC([y, m, d, 0]) : + span == 'hour' ? dateUTC([y, m, d, h]) : null as never; // 現在(今日または今のHour)のログ @@ -381,23 +384,15 @@ export default abstract class Chart> { } @autobind - public async getChart(span: Span, amount: number, offset: number, group: string | null = null): Promise> { - let [y, m, d, h] = Chart.getCurrentDate(); + public async getChart(span: Span, amount: number, begin: Date | null, group: string | null = null): Promise> { + const [y, m, d, h, _m, _s, _ms] = begin ? Chart.parseDate(subtractTime(addTime(begin, 1, span), 1)) : Chart.getCurrentDate(); + const [y2, m2, d2, h2] = begin ? Chart.parseDate(addTime(begin, 1, span)) : [] as never; - 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 lt = dateUTC([y, m, d, h, _m, _s, _ms]); const gt = - span === 'day' ? subtractTimespan(DateUTC([y, m, d]), amount - 1, 'day') : - span === 'hour' ? subtractTimespan(DateUTC([y, m, d, h]), amount - 1, 'hour') : + span === 'day' ? subtractTime(begin ? dateUTC([y2, m2, d2, 0]) : dateUTC([y, m, d, 0]), amount - 1, 'day') : + span === 'hour' ? subtractTime(begin ? dateUTC([y2, m2, d2, h2]) : dateUTC([y, m, d, h]), amount - 1, 'hour') : null as never; // ログ取得 @@ -405,9 +400,7 @@ export default abstract class Chart> { where: { group: group, span: span, - date: offset === 0 - ? MoreThanOrEqual(Chart.dateToTimestamp(gt)) - : Between(Chart.dateToTimestamp(gt), Chart.dateToTimestamp(lt)) + date: Between(Chart.dateToTimestamp(gt), Chart.dateToTimestamp(lt)) }, order: { date: -1 @@ -455,8 +448,8 @@ export default abstract class Chart> { // 整形 for (let i = (amount - 1); i >= 0; i--) { const current = - span == 'day' ? subtractTimespan(DateUTC([y, m, d]), i, 'day') : - span == 'hour' ? subtractTimespan(DateUTC([y, m, d, h]), i, 'hour') : + span === 'day' ? subtractTime(dateUTC([y, m, d, 0]), i, 'day') : + span === 'hour' ? subtractTime(dateUTC([y, m, d, h]), i, 'hour') : null as never; const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current)); diff --git a/test/chart.ts b/test/chart.ts index 6a04569a9..5548d1869 100644 --- a/test/chart.ts +++ b/test/chart.ts @@ -86,8 +86,8 @@ describe('Chart', () => { it('Can updates', async(async () => { await testChart.increment(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -109,8 +109,8 @@ describe('Chart', () => { it('Can updates (dec)', async(async () => { await testChart.decrement(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -130,8 +130,8 @@ describe('Chart', () => { })); it('Empty chart', async(async () => { - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -155,8 +155,8 @@ describe('Chart', () => { await testChart.increment(); await testChart.increment(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -182,8 +182,8 @@ describe('Chart', () => { await testChart.increment(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -209,8 +209,8 @@ describe('Chart', () => { await testChart.increment(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -235,8 +235,8 @@ describe('Chart', () => { clock.tick('05:00:00'); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -262,8 +262,8 @@ describe('Chart', () => { clock.tick('05:00:00'); await testChart.increment(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -289,8 +289,8 @@ describe('Chart', () => { await testChart.increment(); - const chartHours = await testChart.getChart('hour', 3, 1); - const chartDays = await testChart.getChart('day', 3, 1); + const chartHours = await testChart.getChart('hour', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0))); + const chartDays = await testChart.getChart('day', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0))); assert.deepStrictEqual(chartHours, { foo: { @@ -303,8 +303,8 @@ describe('Chart', () => { assert.deepStrictEqual(chartDays, { foo: { dec: [0, 0, 0], - inc: [0, 0, 0], - total: [0, 0, 0] + inc: [2, 0, 0], + total: [2, 0, 0] }, }); })); @@ -318,8 +318,8 @@ describe('Chart', () => { await testChart.increment(); - const chartHours = await testChart.getChart('hour', 3, 1); - const chartDays = await testChart.getChart('day', 3, 1); + const chartHours = await testChart.getChart('hour', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0))); + const chartDays = await testChart.getChart('day', 3, new Date(Date.UTC(2000, 0, 1, 0, 0, 0))); assert.deepStrictEqual(chartHours, { foo: { @@ -342,10 +342,10 @@ describe('Chart', () => { it('Can updates', async(async () => { await testGroupedChart.increment('alice'); - const aliceChartHours = await testGroupedChart.getChart('hour', 3, 0, 'alice'); - const aliceChartDays = await testGroupedChart.getChart('day', 3, 0, 'alice'); - const bobChartHours = await testGroupedChart.getChart('hour', 3, 0, 'bob'); - const bobChartDays = await testGroupedChart.getChart('day', 3, 0, 'bob'); + const aliceChartHours = await testGroupedChart.getChart('hour', 3, null, 'alice'); + const aliceChartDays = await testGroupedChart.getChart('day', 3, null, 'alice'); + const bobChartHours = await testGroupedChart.getChart('hour', 3, null, 'bob'); + const bobChartDays = await testGroupedChart.getChart('day', 3, null, 'bob'); assert.deepStrictEqual(aliceChartHours, { foo: { @@ -387,8 +387,8 @@ describe('Chart', () => { await testUniqueChart.uniqueIncrement('alice'); await testUniqueChart.uniqueIncrement('bob'); - const chartHours = await testUniqueChart.getChart('hour', 3, 0); - const chartDays = await testUniqueChart.getChart('day', 3, 0); + const chartHours = await testUniqueChart.getChart('hour', 3, null); + const chartDays = await testUniqueChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: [2, 0, 0], @@ -406,8 +406,8 @@ describe('Chart', () => { await testChart.resync(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: { @@ -435,8 +435,8 @@ describe('Chart', () => { await testChart.resync(); - const chartHours = await testChart.getChart('hour', 3, 0); - const chartDays = await testChart.getChart('day', 3, 0); + const chartHours = await testChart.getChart('hour', 3, null); + const chartDays = await testChart.getChart('day', 3, null); assert.deepStrictEqual(chartHours, { foo: {