diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2018-07-07 19:19:00 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2018-07-07 19:19:00 +0900 |
| commit | aa4ef6745ad798bd7d4f05cb397ef1dd85279814 (patch) | |
| tree | d34ded516f52b91c4ff1a5443776ce22d8f483f0 /src/misc | |
| parent | Refactorijg (diff) | |
| download | sharkey-aa4ef6745ad798bd7d4f05cb397ef1dd85279814.tar.gz sharkey-aa4ef6745ad798bd7d4f05cb397ef1dd85279814.tar.bz2 sharkey-aa4ef6745ad798bd7d4f05cb397ef1dd85279814.zip | |
Refactorng
Diffstat (limited to 'src/misc')
| -rw-r--r-- | src/misc/acct/parse.ts | 4 | ||||
| -rw-r--r-- | src/misc/acct/render.ts | 5 | ||||
| -rw-r--r-- | src/misc/cafy-id.ts | 33 | ||||
| -rw-r--r-- | src/misc/cli/indicator.ts | 35 | ||||
| -rw-r--r-- | src/misc/cli/progressbar.ts | 85 | ||||
| -rw-r--r-- | src/misc/dependencyInfo.ts | 33 | ||||
| -rw-r--r-- | src/misc/environmentInfo.ts | 14 | ||||
| -rw-r--r-- | src/misc/get-note-summary.ts | 50 | ||||
| -rw-r--r-- | src/misc/get-notification-summary.ts | 28 | ||||
| -rw-r--r-- | src/misc/get-reaction-emoji.ts | 14 | ||||
| -rw-r--r-- | src/misc/get-user-name.ts | 5 | ||||
| -rw-r--r-- | src/misc/get-user-summary.ts | 18 | ||||
| -rw-r--r-- | src/misc/logger.ts | 53 | ||||
| -rw-r--r-- | src/misc/machineInfo.ts | 16 |
14 files changed, 393 insertions, 0 deletions
diff --git a/src/misc/acct/parse.ts b/src/misc/acct/parse.ts new file mode 100644 index 0000000000..0c00fccef6 --- /dev/null +++ b/src/misc/acct/parse.ts @@ -0,0 +1,4 @@ +export default (acct: string) => { + const splitted = acct.split('@', 2); + return { username: splitted[0], host: splitted[1] || null }; +}; diff --git a/src/misc/acct/render.ts b/src/misc/acct/render.ts new file mode 100644 index 0000000000..20031883d3 --- /dev/null +++ b/src/misc/acct/render.ts @@ -0,0 +1,5 @@ +import { IUser } from '../../models/user'; + +export default (user: IUser) => { + return user.host === null ? user.username : `${user.username}@${user.host}`; +}; diff --git a/src/misc/cafy-id.ts b/src/misc/cafy-id.ts new file mode 100644 index 0000000000..f3e1f5251b --- /dev/null +++ b/src/misc/cafy-id.ts @@ -0,0 +1,33 @@ +import * as mongo from 'mongodb'; +import { Context } from 'cafy'; + +export const isAnId = (x: any) => mongo.ObjectID.isValid(x); +export const isNotAnId = (x: any) => !isAnId(x); + +/** + * ID + */ +export default class ID extends Context<mongo.ObjectID> { + constructor() { + super(); + + this.transform = v => { + if (isAnId(v) && !mongo.ObjectID.prototype.isPrototypeOf(v)) { + return new mongo.ObjectID(v); + } else { + return v; + } + }; + + this.push(v => { + if (!mongo.ObjectID.prototype.isPrototypeOf(v) && isNotAnId(v)) { + return new Error('must-be-an-id'); + } + return true; + }); + } + + public getType() { + return super.getType('string'); + } +} diff --git a/src/misc/cli/indicator.ts b/src/misc/cli/indicator.ts new file mode 100644 index 0000000000..3e23f9b274 --- /dev/null +++ b/src/misc/cli/indicator.ts @@ -0,0 +1,35 @@ +import * as readline from 'readline'; + +/** + * Indicator + */ +export default class { + private clock: NodeJS.Timer; + + constructor(text: string) { + let i = 0; // Dots counter + + draw(); + this.clock = setInterval(draw, 300); + + function draw(): void { + cll(); + i = (i + 1) % 4; + const dots = new Array(i + 1).join('.'); + process.stdout.write(text + dots); // Write text + } + } + + public end(): void { + clearInterval(this.clock); + cll(); + } +} + +/** + * Clear current line + */ +function cll(): void { + readline.clearLine(process.stdout, 0); // Clear current text + readline.cursorTo(process.stdout, 0, null); // Move cursor to the head of line +} diff --git a/src/misc/cli/progressbar.ts b/src/misc/cli/progressbar.ts new file mode 100644 index 0000000000..72496fdedc --- /dev/null +++ b/src/misc/cli/progressbar.ts @@ -0,0 +1,85 @@ +import { EventEmitter } from 'events'; +import * as readline from 'readline'; +import chalk from 'chalk'; + +/** + * Progress bar + */ +export default class extends EventEmitter { + public max: number; + public value: number; + public text: string; + private indicator: number; + + constructor(max: number, text: string = null) { + super(); + this.max = max; + this.value = 0; + this.text = text; + this.indicator = 0; + this.draw(); + + const iclock = setInterval(() => { + this.indicator = (this.indicator + 1) % 4; + this.draw(); + }, 200); + + this.on('complete', () => { + clearInterval(iclock); + }); + } + + public increment(): void { + this.value++; + this.draw(); + + // Check if it is fulfilled + if (this.value === this.max) { + this.indicator = null; + + cll(); + process.stdout.write(`${this.render()} -> ${chalk.bold('Complete')}\n`); + + this.emit('complete'); + } + } + + public draw(): void { + const str = this.render(); + cll(); + process.stdout.write(str); + } + + private render(): string { + const width = 30; + const t = this.text ? `${this.text} ` : ''; + + const v = Math.floor((this.value / this.max) * width); + const vs = new Array(v + 1).join('*'); + + const p = width - v; + const ps = new Array(p + 1).join(' '); + + const percentage = Math.floor((this.value / this.max) * 100); + const percentages = chalk.gray(`(${percentage} %)`); + + let i: string; + switch (this.indicator) { + case 0: i = '-'; break; + case 1: i = '\\'; break; + case 2: i = '|'; break; + case 3: i = '/'; break; + case null: i = '+'; break; + } + + return `${i} ${t}[${vs}${ps}] ${this.value} / ${this.max} ${percentages}`; + } +} + +/** + * Clear current line + */ +function cll(): void { + readline.clearLine(process.stdout, 0); // Clear current text + readline.cursorTo(process.stdout, 0, null); // Move cursor to the head of line +} diff --git a/src/misc/dependencyInfo.ts b/src/misc/dependencyInfo.ts new file mode 100644 index 0000000000..89af0d20fb --- /dev/null +++ b/src/misc/dependencyInfo.ts @@ -0,0 +1,33 @@ +import Logger from './logger'; +import { execSync } from 'child_process'; + +export default class { + private logger: Logger; + + constructor() { + this.logger = new Logger('Deps'); + } + + public showAll(): void { + this.show('MongoDB', 'mongo --version', x => x.match(/^MongoDB shell version:? (.*)\r?\n/)); + this.show('Redis', 'redis-server --version', x => x.match(/v=([0-9\.]*)/)); + this.show('ImageMagick', 'magick -version', x => x.match(/^Version: ImageMagick (.+?)\r?\n/)); + } + + public show(serviceName: string, command: string, transform: (x: string) => RegExpMatchArray): void { + try { + // ステータス0以外のときにexecSyncはstderrをコンソール上に出力してしまうので + // プロセスからのstderrをすべて無視するように stdio オプションをセット + const x = execSync(command, { stdio: ['pipe', 'pipe', 'ignore'] }); + const ver = transform(x.toString()); + if (ver != null) { + this.logger.info(`${serviceName} ${ver[1]} found`); + } else { + this.logger.warn(`${serviceName} not found`); + this.logger.warn(`Regexp used for version check of ${serviceName} is probably messed up`); + } + } catch (e) { + this.logger.warn(`${serviceName} not found`); + } + } +} diff --git a/src/misc/environmentInfo.ts b/src/misc/environmentInfo.ts new file mode 100644 index 0000000000..e6084cde0e --- /dev/null +++ b/src/misc/environmentInfo.ts @@ -0,0 +1,14 @@ +import Logger from './logger'; + +export default class { + public static show(): void { + const env = process.env.NODE_ENV; + const logger = new Logger('Env'); + logger.info(typeof env == 'undefined' ? 'NODE_ENV is not set' : `NODE_ENV: ${env}`); + + if (env !== 'production') { + logger.warn('The environment is not in production mode'); + logger.warn('Do not use for production purpose'); + } + } +} diff --git a/src/misc/get-note-summary.ts b/src/misc/get-note-summary.ts new file mode 100644 index 0000000000..ec7c74cf9f --- /dev/null +++ b/src/misc/get-note-summary.ts @@ -0,0 +1,50 @@ +/** + * 投稿を表す文字列を取得します。 + * @param {*} note (packされた)投稿 + */ +const summarize = (note: any): string => { + if (note.deletedAt) { + return '(削除された投稿)'; + } + + if (note.isHidden) { + return '(非公開の投稿)'; + } + + let summary = ''; + + // 本文 + summary += note.text ? note.text : ''; + + // メディアが添付されているとき + if (note.media.length != 0) { + summary += ` (${note.media.length}つのメディア)`; + } + + // 投票が添付されているとき + if (note.poll) { + summary += ' (投票)'; + } + + // 返信のとき + if (note.replyId) { + if (note.reply) { + summary += ` RE: ${summarize(note.reply)}`; + } else { + summary += ' RE: ...'; + } + } + + // Renoteのとき + if (note.renoteId) { + if (note.renote) { + summary += ` RP: ${summarize(note.renote)}`; + } else { + summary += ' RP: ...'; + } + } + + return summary.trim(); +}; + +export default summarize; diff --git a/src/misc/get-notification-summary.ts b/src/misc/get-notification-summary.ts new file mode 100644 index 0000000000..71d4973ce9 --- /dev/null +++ b/src/misc/get-notification-summary.ts @@ -0,0 +1,28 @@ +import getUserName from './get-user-name'; +import getNoteSummary from './get-note-summary'; +import getReactionEmoji from './get-reaction-emoji'; + +/** + * 通知を表す文字列を取得します。 + * @param notification 通知 + */ +export default function(notification: any): string { + switch (notification.type) { + case 'follow': + return `${getUserName(notification.user)}にフォローされました`; + case 'mention': + return `言及されました:\n${getUserName(notification.user)}「${getNoteSummary(notification.note)}」`; + case 'reply': + return `返信されました:\n${getUserName(notification.user)}「${getNoteSummary(notification.note)}」`; + case 'renote': + return `Renoteされました:\n${getUserName(notification.user)}「${getNoteSummary(notification.note)}」`; + case 'quote': + return `引用されました:\n${getUserName(notification.user)}「${getNoteSummary(notification.note)}」`; + case 'reaction': + return `リアクションされました:\n${getUserName(notification.user)} <${getReactionEmoji(notification.reaction)}>「${getNoteSummary(notification.note)}」`; + case 'poll_vote': + return `投票されました:\n${getUserName(notification.user)}「${getNoteSummary(notification.note)}」`; + default: + return `<不明な通知タイプ: ${notification.type}>`; + } +} diff --git a/src/misc/get-reaction-emoji.ts b/src/misc/get-reaction-emoji.ts new file mode 100644 index 0000000000..c661205379 --- /dev/null +++ b/src/misc/get-reaction-emoji.ts @@ -0,0 +1,14 @@ +export default function(reaction: string): string { + switch (reaction) { + case 'like': return '👍'; + case 'love': return '❤️'; + case 'laugh': return '😆'; + case 'hmm': return '🤔'; + case 'surprise': return '😮'; + case 'congrats': return '🎉'; + case 'angry': return '💢'; + case 'confused': return '😥'; + case 'pudding': return '🍮'; + default: return ''; + } +} diff --git a/src/misc/get-user-name.ts b/src/misc/get-user-name.ts new file mode 100644 index 0000000000..acd5e6626d --- /dev/null +++ b/src/misc/get-user-name.ts @@ -0,0 +1,5 @@ +import { IUser } from '../models/user'; + +export default function(user: IUser): string { + return user.name || '名無し'; +} diff --git a/src/misc/get-user-summary.ts b/src/misc/get-user-summary.ts new file mode 100644 index 0000000000..625caf1f7e --- /dev/null +++ b/src/misc/get-user-summary.ts @@ -0,0 +1,18 @@ +import { IUser, isLocalUser } from '../models/user'; +import getAcct from '../misc/acct/render'; +import getUserName from './get-user-name'; + +/** + * ユーザーを表す文字列を取得します。 + * @param user ユーザー + */ +export default function(user: IUser): string { + let string = `${getUserName(user)} (@${getAcct(user)})\n` + + `${user.notesCount}投稿、${user.followingCount}フォロー、${user.followersCount}フォロワー\n`; + + if (isLocalUser(user)) { + string += `場所: ${user.profile.location}、誕生日: ${user.profile.birthday}\n`; + } + + return string + `「${user.description}」`; +} diff --git a/src/misc/logger.ts b/src/misc/logger.ts new file mode 100644 index 0000000000..fae1042c39 --- /dev/null +++ b/src/misc/logger.ts @@ -0,0 +1,53 @@ +import chalk, { Chalk } from 'chalk'; + +export type LogLevel = 'Error' | 'Warn' | 'Info'; + +function toLevelColor(level: LogLevel): Chalk { + switch (level) { + case 'Error': return chalk.red; + case 'Warn': return chalk.yellow; + case 'Info': return chalk.blue; + } +} + +export default class Logger { + private domain: string; + + constructor(domain: string) { + this.domain = domain; + } + + public static log(level: LogLevel, message: string): void { + const color = toLevelColor(level); + const time = (new Date()).toLocaleTimeString('ja-JP'); + console.log(`[${time} ${color.bold(level.toUpperCase())}]: ${message}`); + } + + public static error(message: string): void { + Logger.log('Error', message); + } + + public static warn(message: string): void { + Logger.log('Warn', message); + } + + public static info(message: string): void { + Logger.log('Info', message); + } + + public log(level: LogLevel, message: string): void { + Logger.log(level, `[${this.domain}] ${message}`); + } + + public error(message: string): void { + this.log('Error', message); + } + + public warn(message: string): void { + this.log('Warn', message); + } + + public info(message: string): void { + this.log('Info', message); + } +} diff --git a/src/misc/machineInfo.ts b/src/misc/machineInfo.ts new file mode 100644 index 0000000000..0c189cc7ca --- /dev/null +++ b/src/misc/machineInfo.ts @@ -0,0 +1,16 @@ +import * as os from 'os'; +import Logger from './logger'; + +export default class { + public static show(): void { + const totalmem = (os.totalmem() / 1024 / 1024 / 1024).toFixed(1); + const freemem = (os.freemem() / 1024 / 1024 / 1024).toFixed(1); + const logger = new Logger('Machine'); + logger.info(`Hostname: ${os.hostname()}`); + logger.info(`Platform: ${process.platform}`); + logger.info(`Architecture: ${process.arch}`); + logger.info(`Node.js: ${process.version}`); + logger.info(`CPU: ${os.cpus().length}core`); + logger.info(`MEM: ${totalmem}GB (available: ${freemem}GB)`); + } +} |