summaryrefslogtreecommitdiff
path: root/src/misc
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-07-07 19:19:00 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-07-07 19:19:00 +0900
commitaa4ef6745ad798bd7d4f05cb397ef1dd85279814 (patch)
treed34ded516f52b91c4ff1a5443776ce22d8f483f0 /src/misc
parentRefactorijg (diff)
downloadsharkey-aa4ef6745ad798bd7d4f05cb397ef1dd85279814.tar.gz
sharkey-aa4ef6745ad798bd7d4f05cb397ef1dd85279814.tar.bz2
sharkey-aa4ef6745ad798bd7d4f05cb397ef1dd85279814.zip
Refactorng
Diffstat (limited to 'src/misc')
-rw-r--r--src/misc/acct/parse.ts4
-rw-r--r--src/misc/acct/render.ts5
-rw-r--r--src/misc/cafy-id.ts33
-rw-r--r--src/misc/cli/indicator.ts35
-rw-r--r--src/misc/cli/progressbar.ts85
-rw-r--r--src/misc/dependencyInfo.ts33
-rw-r--r--src/misc/environmentInfo.ts14
-rw-r--r--src/misc/get-note-summary.ts50
-rw-r--r--src/misc/get-notification-summary.ts28
-rw-r--r--src/misc/get-reaction-emoji.ts14
-rw-r--r--src/misc/get-user-name.ts5
-rw-r--r--src/misc/get-user-summary.ts18
-rw-r--r--src/misc/logger.ts53
-rw-r--r--src/misc/machineInfo.ts16
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)`);
+ }
+}