commit
						91f1c3a10a
					
				
					 8 changed files with 260 additions and 79 deletions
				
			
		
							
								
								
									
										144
									
								
								cli/migration/8.0.0.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								cli/migration/8.0.0.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,144 @@
 | 
			
		|||
const { default: Stats } = require('../../built/models/stats');
 | 
			
		||||
const { default: User } = require('../../built/models/user');
 | 
			
		||||
const { default: Note } = require('../../built/models/note');
 | 
			
		||||
const { default: DriveFile } = require('../../built/models/drive-file');
 | 
			
		||||
 | 
			
		||||
const now = new Date();
 | 
			
		||||
const y = now.getFullYear();
 | 
			
		||||
const m = now.getMonth();
 | 
			
		||||
const d = now.getDate();
 | 
			
		||||
const h = now.getHours();
 | 
			
		||||
const date = new Date(y, m, d, h);
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
	await Stats.update({}, {
 | 
			
		||||
		$set: {
 | 
			
		||||
			span: 'day'
 | 
			
		||||
		}
 | 
			
		||||
	}, {
 | 
			
		||||
		multi: true
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const localUsersCount = await User.count({
 | 
			
		||||
		host: null
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const remoteUsersCount = await User.count({
 | 
			
		||||
		host: { $ne: null }
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const localNotesCount = await Note.count({
 | 
			
		||||
		'_user.host': null
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const remoteNotesCount = await Note.count({
 | 
			
		||||
		'_user.host': { $ne: null }
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const localDriveFilesCount = await DriveFile.count({
 | 
			
		||||
		'metadata._user.host': null
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const remoteDriveFilesCount = await DriveFile.count({
 | 
			
		||||
		'metadata._user.host': { $ne: null }
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const localDriveFilesSize = await DriveFile
 | 
			
		||||
		.aggregate([{
 | 
			
		||||
			$match: {
 | 
			
		||||
				'metadata._user.host': null,
 | 
			
		||||
				'metadata.deletedAt': { $exists: false }
 | 
			
		||||
			}
 | 
			
		||||
		}, {
 | 
			
		||||
			$project: {
 | 
			
		||||
				length: true
 | 
			
		||||
			}
 | 
			
		||||
		}, {
 | 
			
		||||
			$group: {
 | 
			
		||||
				_id: null,
 | 
			
		||||
				usage: { $sum: '$length' }
 | 
			
		||||
			}
 | 
			
		||||
		}])
 | 
			
		||||
		.then(aggregates => {
 | 
			
		||||
			if (aggregates.length > 0) {
 | 
			
		||||
				return aggregates[0].usage;
 | 
			
		||||
			}
 | 
			
		||||
			return 0;
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
	const remoteDriveFilesSize = await DriveFile
 | 
			
		||||
		.aggregate([{
 | 
			
		||||
			$match: {
 | 
			
		||||
				'metadata._user.host': { $ne: null },
 | 
			
		||||
				'metadata.deletedAt': { $exists: false }
 | 
			
		||||
			}
 | 
			
		||||
		}, {
 | 
			
		||||
			$project: {
 | 
			
		||||
				length: true
 | 
			
		||||
			}
 | 
			
		||||
		}, {
 | 
			
		||||
			$group: {
 | 
			
		||||
				_id: null,
 | 
			
		||||
				usage: { $sum: '$length' }
 | 
			
		||||
			}
 | 
			
		||||
		}])
 | 
			
		||||
		.then(aggregates => {
 | 
			
		||||
			if (aggregates.length > 0) {
 | 
			
		||||
				return aggregates[0].usage;
 | 
			
		||||
			}
 | 
			
		||||
			return 0;
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
	await Stats.insert({
 | 
			
		||||
		date: date,
 | 
			
		||||
		span: 'hour',
 | 
			
		||||
		users: {
 | 
			
		||||
			local: {
 | 
			
		||||
				total: localUsersCount,
 | 
			
		||||
				diff: 0
 | 
			
		||||
			},
 | 
			
		||||
			remote: {
 | 
			
		||||
				total: remoteUsersCount,
 | 
			
		||||
				diff: 0
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		notes: {
 | 
			
		||||
			local: {
 | 
			
		||||
				total: localNotesCount,
 | 
			
		||||
				diff: 0,
 | 
			
		||||
				diffs: {
 | 
			
		||||
					normal: 0,
 | 
			
		||||
					reply: 0,
 | 
			
		||||
					renote: 0
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			remote: {
 | 
			
		||||
				total: remoteNotesCount,
 | 
			
		||||
				diff: 0,
 | 
			
		||||
				diffs: {
 | 
			
		||||
					normal: 0,
 | 
			
		||||
					reply: 0,
 | 
			
		||||
					renote: 0
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		drive: {
 | 
			
		||||
			local: {
 | 
			
		||||
				totalCount: localDriveFilesCount,
 | 
			
		||||
				totalSize: localDriveFilesSize,
 | 
			
		||||
				diffCount: 0,
 | 
			
		||||
				diffSize: 0
 | 
			
		||||
			},
 | 
			
		||||
			remote: {
 | 
			
		||||
				totalCount: remoteDriveFilesCount,
 | 
			
		||||
				totalSize: remoteDriveFilesSize,
 | 
			
		||||
				diffCount: 0,
 | 
			
		||||
				diffSize: 0
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	console.log('done');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
main();
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
{
 | 
			
		||||
	"name": "misskey",
 | 
			
		||||
	"author": "syuilo <i@syuilo.com>",
 | 
			
		||||
	"version": "7.4.1",
 | 
			
		||||
	"version": "8.0.0",
 | 
			
		||||
	"clientVersion": "1.0.8790",
 | 
			
		||||
	"codename": "nighthike",
 | 
			
		||||
	"main": "./built/index.js",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,8 @@ export interface IStats {
 | 
			
		|||
 | 
			
		||||
	date: Date;
 | 
			
		||||
 | 
			
		||||
	span: 'day' | 'hour';
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * ユーザーに関する統計
 | 
			
		||||
	 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ export default async (username: string, _host: string, option?: any): Promise<IU
 | 
			
		|||
	const host = toUnicode(hostAscii);
 | 
			
		||||
 | 
			
		||||
	if (config.host == host) {
 | 
			
		||||
		return await User.findOne({ usernameLower });
 | 
			
		||||
		return await User.findOne({ usernameLower, host: null });
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let user = await User.findOne({ usernameLower, host }, option);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ export default (params: any) => new Promise(async (res, rej) => {
 | 
			
		|||
	const d = now.getDate();
 | 
			
		||||
 | 
			
		||||
	const stats = await Stats.find({
 | 
			
		||||
		span: 'day',
 | 
			
		||||
		date: {
 | 
			
		||||
			$gt: new Date(y - 1, m, d)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +45,7 @@ export default (params: any) => new Promise(async (res, rej) => {
 | 
			
		|||
			} else {
 | 
			
		||||
				chart.unshift({
 | 
			
		||||
					date: day,
 | 
			
		||||
					span: 'day',
 | 
			
		||||
					users: {
 | 
			
		||||
						local: {
 | 
			
		||||
							total: 0,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,11 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
 | 
			
		|||
		return rej('followee not found');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	await cancelFollowRequest(followee, user);
 | 
			
		||||
	try {
 | 
			
		||||
		await cancelFollowRequest(followee, user);
 | 
			
		||||
	} catch (e) {
 | 
			
		||||
		return rej(e);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send response
 | 
			
		||||
	res(await pack(followee._id, user));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,15 @@ export default async function(followee: IUser, follower: IUser) {
 | 
			
		|||
		deliver(follower as ILocalUser, content, followee.inbox);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const request = await FollowRequest.findOne({
 | 
			
		||||
		followeeId: followee._id,
 | 
			
		||||
		followerId: follower._id
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	if (request == null) {
 | 
			
		||||
		throw 'request not found';
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	await FollowRequest.remove({
 | 
			
		||||
		followeeId: followee._id,
 | 
			
		||||
		followerId: follower._id
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,89 +5,46 @@ import { IDriveFile } from '../models/drive-file';
 | 
			
		|||
 | 
			
		||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
 | 
			
		||||
 | 
			
		||||
async function getTodayStats(): Promise<IStats> {
 | 
			
		||||
async function getCurrentStats(span: 'day' | 'hour'): Promise<IStats> {
 | 
			
		||||
	const now = new Date();
 | 
			
		||||
	const y = now.getFullYear();
 | 
			
		||||
	const m = now.getMonth();
 | 
			
		||||
	const d = now.getDate();
 | 
			
		||||
	const today = new Date(y, m, d);
 | 
			
		||||
	const h = now.getHours();
 | 
			
		||||
 | 
			
		||||
	// 今日の統計
 | 
			
		||||
	const todayStats = await Stats.findOne({
 | 
			
		||||
		date: today
 | 
			
		||||
	const current =
 | 
			
		||||
		span == 'day' ? new Date(y, m, d) :
 | 
			
		||||
		span == 'hour' ? new Date(y, m, d, h) :
 | 
			
		||||
		null;
 | 
			
		||||
 | 
			
		||||
	// 現在(今日または今のHour)の統計
 | 
			
		||||
	const currentStats = await Stats.findOne({
 | 
			
		||||
		span: span,
 | 
			
		||||
		date: current
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// 日付が変わってから、初めてのチャート更新なら
 | 
			
		||||
	if (todayStats == null) {
 | 
			
		||||
	if (currentStats) {
 | 
			
		||||
		return currentStats;
 | 
			
		||||
	} else {
 | 
			
		||||
		// 集計期間が変わってから、初めてのチャート更新なら
 | 
			
		||||
		// 最も最近の統計を持ってくる
 | 
			
		||||
		// * 例えば集計期間が「日」である場合で考えると、
 | 
			
		||||
		// * 昨日何もチャートを更新するような出来事がなかった場合は、
 | 
			
		||||
		//   統計がそもそも作られずドキュメントが存在しないということがあり得るため、
 | 
			
		||||
		//   「昨日の」と決め打ちせずに「もっとも最近の」とします
 | 
			
		||||
		const mostRecentStats = await Stats.findOne({}, {
 | 
			
		||||
		// * 統計がそもそも作られずドキュメントが存在しないということがあり得るため、
 | 
			
		||||
		// * 「昨日の」と決め打ちせずに「もっとも最近の」とします
 | 
			
		||||
		const mostRecentStats = await Stats.findOne({
 | 
			
		||||
			span: span
 | 
			
		||||
		}, {
 | 
			
		||||
			sort: {
 | 
			
		||||
				date: -1
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		// 統計が存在しなかったら
 | 
			
		||||
		// * Misskeyインスタンスを建てて初めてのチャート更新時など
 | 
			
		||||
		if (mostRecentStats == null) {
 | 
			
		||||
			// 空の統計を作成
 | 
			
		||||
		if (mostRecentStats) {
 | 
			
		||||
			// 現在の統計を初期挿入
 | 
			
		||||
			const data: Omit<IStats, '_id'> = {
 | 
			
		||||
				date: today,
 | 
			
		||||
				users: {
 | 
			
		||||
					local: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0
 | 
			
		||||
					},
 | 
			
		||||
					remote: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				notes: {
 | 
			
		||||
					local: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0,
 | 
			
		||||
						diffs: {
 | 
			
		||||
							normal: 0,
 | 
			
		||||
							reply: 0,
 | 
			
		||||
							renote: 0
 | 
			
		||||
						}
 | 
			
		||||
					},
 | 
			
		||||
					remote: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0,
 | 
			
		||||
						diffs: {
 | 
			
		||||
							normal: 0,
 | 
			
		||||
							reply: 0,
 | 
			
		||||
							renote: 0
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				drive: {
 | 
			
		||||
					local: {
 | 
			
		||||
						totalCount: 0,
 | 
			
		||||
						totalSize: 0,
 | 
			
		||||
						diffCount: 0,
 | 
			
		||||
						diffSize: 0
 | 
			
		||||
					},
 | 
			
		||||
					remote: {
 | 
			
		||||
						totalCount: 0,
 | 
			
		||||
						totalSize: 0,
 | 
			
		||||
						diffCount: 0,
 | 
			
		||||
						diffSize: 0
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			const stats = await Stats.insert(data);
 | 
			
		||||
 | 
			
		||||
			return stats;
 | 
			
		||||
		} else {
 | 
			
		||||
			// 今日の統計を初期挿入
 | 
			
		||||
			const data: Omit<IStats, '_id'> = {
 | 
			
		||||
				date: today,
 | 
			
		||||
				span: span,
 | 
			
		||||
				date: current,
 | 
			
		||||
				users: {
 | 
			
		||||
					local: {
 | 
			
		||||
						total: mostRecentStats.users.local.total,
 | 
			
		||||
| 
						 | 
				
			
			@ -136,20 +93,83 @@ async function getTodayStats(): Promise<IStats> {
 | 
			
		|||
 | 
			
		||||
			const stats = await Stats.insert(data);
 | 
			
		||||
 | 
			
		||||
			return stats;
 | 
			
		||||
		} else {
 | 
			
		||||
			// 統計が存在しなかったら
 | 
			
		||||
			// * Misskeyインスタンスを建てて初めてのチャート更新時など
 | 
			
		||||
 | 
			
		||||
			// 空の統計を作成
 | 
			
		||||
			const emptyStat: Omit<IStats, '_id'> = {
 | 
			
		||||
				span: span,
 | 
			
		||||
				date: current,
 | 
			
		||||
				users: {
 | 
			
		||||
					local: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0
 | 
			
		||||
					},
 | 
			
		||||
					remote: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				notes: {
 | 
			
		||||
					local: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0,
 | 
			
		||||
						diffs: {
 | 
			
		||||
							normal: 0,
 | 
			
		||||
							reply: 0,
 | 
			
		||||
							renote: 0
 | 
			
		||||
						}
 | 
			
		||||
					},
 | 
			
		||||
					remote: {
 | 
			
		||||
						total: 0,
 | 
			
		||||
						diff: 0,
 | 
			
		||||
						diffs: {
 | 
			
		||||
							normal: 0,
 | 
			
		||||
							reply: 0,
 | 
			
		||||
							renote: 0
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				drive: {
 | 
			
		||||
					local: {
 | 
			
		||||
						totalCount: 0,
 | 
			
		||||
						totalSize: 0,
 | 
			
		||||
						diffCount: 0,
 | 
			
		||||
						diffSize: 0
 | 
			
		||||
					},
 | 
			
		||||
					remote: {
 | 
			
		||||
						totalCount: 0,
 | 
			
		||||
						totalSize: 0,
 | 
			
		||||
						diffCount: 0,
 | 
			
		||||
						diffSize: 0
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			const stats = await Stats.insert(emptyStat);
 | 
			
		||||
 | 
			
		||||
			return stats;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		return todayStats;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function update(inc: any) {
 | 
			
		||||
	const stats = await getTodayStats();
 | 
			
		||||
function update(inc: any) {
 | 
			
		||||
	getCurrentStats('day').then(stats => {
 | 
			
		||||
		Stats.findOneAndUpdate({
 | 
			
		||||
			_id: stats._id
 | 
			
		||||
		}, {
 | 
			
		||||
			$inc: inc
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	await Stats.findOneAndUpdate({
 | 
			
		||||
		_id: stats._id
 | 
			
		||||
	}, {
 | 
			
		||||
		$inc: inc
 | 
			
		||||
	getCurrentStats('hour').then(stats => {
 | 
			
		||||
		Stats.findOneAndUpdate({
 | 
			
		||||
			_id: stats._id
 | 
			
		||||
		}, {
 | 
			
		||||
			$inc: inc
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue