import { exec } from 'child_process'; import { Color, yellow } from 'colors'; import { createWriteStream, exists, mkdir, readFile, unlink, writeFile } from 'fs'; import * as nodemailer from 'nodemailer'; import { MailOptions } from 'nodemailer/lib/json-transport'; import * as path from 'path'; import { rimraf } from 'rimraf'; import { ExecOptions } from 'shelljs'; import * as Mail from 'nodemailer/lib/mailer'; const projectRoot = path.resolve(__dirname, '../../'); export function pathFromRoot(relative?: string) { if (!relative) { return projectRoot; } return path.resolve(projectRoot, relative); } export async function fileDescriptorFromStream(filePath: string) { const logStream = createWriteStream(filePath); return new Promise(resolve => { logStream.on('open', resolve); }); } export const commandLine = (command: string, fromDirectory?: string) => new Promise((resolve, reject) => { const options: ExecOptions = {}; if (fromDirectory) { options.cwd = fromDirectory ? path.resolve(projectRoot, fromDirectory) : projectRoot; } exec(command, options, (err, stdout) => (err ? reject(err) : resolve(stdout))); }); export const readTextFile = (relativePath: string) => { const target = path.resolve(__dirname, relativePath); return new Promise((resolve, reject) => { readFile(target, (err, data) => (err ? reject(err) : resolve(data.toString()))); }); }; export const writeTextFile = (relativePath: string, contents: any) => { const target = path.resolve(__dirname, relativePath); return new Promise((resolve, reject) => { writeFile(target, contents, err => (err ? reject(err) : resolve())); }); }; export type Messager = (outcome: { result: T | undefined; error: Error | null }) => string; export interface LogData { startMessage: string; // if you care about the execution informing your log, you can pass in a function that takes in the result and a potential error and decides what to write endMessage: string | Messager; action: () => T | Promise; color?: Color; } function logHelper(content: string, color: Color | string) { if (typeof color === 'string') { console.log(color, content); } else { console.log(color(content)); } } let current = Math.ceil(Math.random() * 20); export async function logExecution({ startMessage, endMessage, action, color }: LogData): Promise { let result: T | undefined; let error: Error | null = null; const resolvedColor = color || `\x1b[${31 + (++current % 6)}m%s\x1b[0m`; logHelper(`${startMessage}...`, resolvedColor); try { result = await action(); } catch (e: any) { error = e; } finally { logHelper(typeof endMessage === 'string' ? endMessage : endMessage({ result, error }), resolvedColor); } return result; } export function logPort(listener: string, port: number) { console.log(`${listener} listening on port ${yellow(String(port))}`); } export function msToTime(duration: number) { const milliseconds = Math.floor((duration % 1000) / 100); const seconds = Math.floor((duration / 1000) % 60); const minutes = Math.floor((duration / (1000 * 60)) % 60); const hours = Math.floor((duration / (1000 * 60 * 60)) % 24); const hoursS = hours < 10 ? '0' + hours : hours; const minutesS = minutes < 10 ? '0' + minutes : minutes; const secondsS = seconds < 10 ? '0' + seconds : seconds; return hoursS + ':' + minutesS + ':' + secondsS + '.' + milliseconds; } export const createIfNotExists = async (filePath: string) => { if ( await new Promise(resolve => { exists(filePath, resolve); }) ) { return true; } return new Promise(resolve => { mkdir(filePath, error => resolve(error === null)); }); }; export async function Prune(rootDirectory: string): Promise { // const error = await new Promise(resolve => rimraf(rootDirectory).then(resolve)); await new Promise(resolve => { rimraf(rootDirectory).then(() => resolve()); }); // return error === null; return true; } export const Destroy = (mediaPath: string) => new Promise(resolve => { unlink(mediaPath, error => resolve(error === null)); }); export namespace Email { const smtpTransport = nodemailer.createTransport({ service: 'Gmail', auth: { user: 'browndashptc@gmail.com', pass: 'TsarNicholas#2', }, }); export interface DispatchOptions { to: T; subject: string; content: string; attachments?: Mail.Attachment | Mail.Attachment[]; } export interface DispatchFailure { recipient: string; error: Error; } export async function dispatchAll({ to, subject, content, attachments }: DispatchOptions) { const failures: DispatchFailure[] = []; await Promise.all( to.map(async recipient => { const resolved = attachments ? ('length' in attachments ? attachments : [attachments]) : undefined; const error = await Email.dispatch({ to: recipient, subject, content, attachments: resolved }); if (error !== null) { failures.push({ recipient, error, }); } }) ); return failures.length ? failures : undefined; } export async function dispatch({ to, subject, content, attachments }: DispatchOptions): Promise { const mailOptions = { to, from: 'browndashptc@gmail.com', subject, text: `Hello ${to.split('@')[0]},\n\n${content}`, attachments, } as MailOptions; return new Promise(resolve => { smtpTransport.sendMail(mailOptions, resolve); }); } }