diff --git a/src/common/time.ts b/src/common/time.ts
index 29cad1e..c20bf03 100644
--- a/src/common/time.ts
+++ b/src/common/time.ts
@@ -37,25 +37,25 @@ export function readableTime(timems: number): string {
const time = Math.floor(timems);
if (time < 60) {
- return zf(time) + 's';
+ return zf(Math.floor(time)) + 's';
} else if (time < 3600) {
- return zf(time / 60) +
- 'm ' + zf(time % 60) + 's';
+ return zf(Math.floor(time / 60)) +
+ 'm ' + zf(Math.floor(time % 60)) + 's';
} else if (time < 86400) {
- return zf(time / 3600) +
- 'h ' + zf((time % 3600) / 60) +
- 'm ' + zf((time % 3600) % 60) + 's';
+ return zf(Math.floor(time / 3600)) +
+ 'h ' + zf(Math.floor((time % 3600) / 60)) +
+ 'm ' + zf(Math.floor((time % 3600) % 60)) + 's';
} else if (time < 31536000) {
- return (time / 86400) +
- 'd ' + zf((time % 86400) / 3600) +
- 'h ' + zf((time % 3600) / 60) +
- 'm ' + zf((time % 3600) % 60) + 's';
+ return (Math.floor(time / 86400)) +
+ 'd ' + zf(Math.floor((time % 86400) / 3600)) +
+ 'h ' + zf(Math.floor((time % 3600) / 60)) +
+ 'm ' + zf(Math.floor((time % 3600) % 60)) + 's';
} else {
- return (time / 31536000) +
- 'y ' + zf((time % 31536000) / 86400) +
- 'd ' + zf((time % 86400) / 3600) +
- 'h ' + zf((time % 3600) / 60) +
- 'm ' + zf((time % 3600) % 60) + 's';
+ return (Math.floor(time / 31536000)) +
+ 'y ' + zf(Math.floor((time % 31536000) / 86400)) +
+ 'd ' + zf(Math.floor((time % 86400) / 3600)) +
+ 'h ' + zf(Math.floor((time % 3600) / 60)) +
+ 'm ' + zf(Math.floor((time % 3600) % 60)) + 's';
}
}
diff --git a/src/plugin/plugin.ts b/src/plugin/plugin.ts
index 682fa15..ea2a841 100644
--- a/src/plugin/plugin.ts
+++ b/src/plugin/plugin.ts
@@ -11,6 +11,7 @@ export interface IPlugin {
export class Plugin implements IPlugin {
public service: Service | null = null;
+ protected on = this.addEventListener;
constructor(
public manifest: IPluginManifest,
diff --git a/src/types/message-format.ts b/src/types/message-format.ts
index 8fc1371..655b20d 100644
--- a/src/types/message-format.ts
+++ b/src/types/message-format.ts
@@ -19,8 +19,11 @@
or any hex value prepended with #
Formats:
+ action
+ code
+ multicode (multiline code)
bold
- italic
+ italics
emphasis
strike
underline
@@ -211,3 +214,74 @@ export class Formatter {
}
}
+export class HTMLFormatter extends Formatter {
+ public formatting: Method = {
+ code: {start: '', end: '
'},
+ action: {start: '', end: ''},
+ bold: {start: '', end: ''},
+ italics: {start: '', end: ''},
+ emphasis: {start: '', end: ''},
+ underline: {start: '', end: ''},
+ multicode: {start: '
', end: '
'},
+ };
+
+ constructor() {
+ super(true, true);
+ }
+
+ public color(color: string, msg: string): string {
+ return `${msg}`;
+ }
+
+ public format(method: string, msg: string): string {
+ if (!this.formatting[method]) {
+ return msg;
+ }
+
+ if (this.formatting[method].start && this.formatting[method].end) {
+ return this.formatting[method].start + msg + this.formatting[method].end;
+ } else {
+ return this.formatting[method] + msg + this.formatting[method];
+ }
+ }
+
+ public strip(msg: string): string {
+ return msg.replace(/<\/?[^>]+(>|$)/g, '');
+ }
+}
+
+export class MarkdownFormatter extends Formatter {
+ public formatting: Method = {
+ code: {start: '`', end: '`'},
+ bold: {start: '**', end: '*'},
+ action: {start: '*', end: '*'},
+ italics: {start: '*', end: '*'},
+ emphasis: {start: '*', end: '*'},
+ underline: {start: '__', end: '__'},
+ multicode: {start: '```', end: '```'},
+ };
+
+ constructor() {
+ super(true, false);
+ }
+
+ public color(color: string, msg: string): string {
+ return msg;
+ }
+
+ public format(method: string, msg: string): string {
+ if (!this.formatting[method]) {
+ return msg;
+ }
+
+ if (this.formatting[method].start && this.formatting[method].end) {
+ return this.formatting[method].start + msg + this.formatting[method].end;
+ } else {
+ return this.formatting[method] + msg + this.formatting[method];
+ }
+ }
+
+ public strip(msg: string): string {
+ return msg;
+ }
+}
diff --git a/src/types/message.ts b/src/types/message.ts
index 5ceac50..31b1efc 100644
--- a/src/types/message.ts
+++ b/src/types/message.ts
@@ -1,8 +1,5 @@
-import { IPlugin } from '../plugin/plugin';
import { Protocol } from './protocol';
-// TODO: Source specification to support plugin services.
-
export enum EMessageType {
message = 0,
roomJoin = 1,
@@ -12,24 +9,89 @@ export enum EMessageType {
edit = 5,
}
+/**
+ * Message target specification. ID and name are mandatory,
+ * and they could be the same, depending on the protocol.
+ */
export interface IMessageTarget {
id: string;
name: string;
server?: string;
}
+/**
+ * Message format
+ */
export interface IMessage {
+ /**
+ * Uniquely identify this message
+ */
id?: any;
+ /**
+ * Type of the message. See EMessageType
+ */
type: EMessageType;
+ /**
+ * Data included in the message. Could be an object or a string.
+ * Use `text` to get text value.
+ */
data: any;
+ /**
+ * Text value of the message.
+ */
+ text: string;
+ /**
+ * Source protocol of the message.
+ */
source: Protocol;
+ /**
+ * If the sender has not registered themselves.
+ * Applicable to, for example, NickServ of IRC.
+ */
guest?: boolean;
+ /**
+ * The room where the message was sent in.
+ */
target?: IMessageTarget;
+ /**
+ * Information about the sender.
+ */
sender?: IMessageTarget;
+ /**
+ * Full ID of the sender (`plugin/protocol/id`).
+ */
fullSenderID?: string;
+ /**
+ * Full ID of the room (`plugin/protocol/(s:server)/id`).
+ */
fullRoomID?: string;
+ /**
+ * The time the message was sent.
+ */
time: Date;
+ /**
+ * True if the message is a direct message to the bot.
+ */
direct?: boolean;
+ /**
+ * True when resolve has been called at least once.
+ */
resolved: boolean;
+ /**
+ * Bot's response to this message. Will be passed to the protocol,
+ * which usually sends it through the formatter and then to the service
+ * it is connected to.
+ * @param args Message data
+ */
resolve(...args: any[]): void;
+
+ /**
+ * Insert a mention into the response
+ * @param target UserTarget to mention (i.e. `msg.sender`)
+ */
+ mention(target: IMessageTarget): string;
+
+ kick?(reason: string): void;
+ ban?(reason: string): void;
+ mute?(reason: string): void;
}
diff --git a/src/types/protocol.ts b/src/types/protocol.ts
index 4adb07a..60ce8b1 100644
--- a/src/types/protocol.ts
+++ b/src/types/protocol.ts
@@ -2,7 +2,7 @@ import { randomBytes } from 'crypto';
import { EventEmitter } from 'events';
import { IPlugin } from '../plugin';
-import { IMessage } from './message';
+import { IMessage, IMessageTarget } from './message';
import { Formatter } from './message-format';
export class Protocol extends EventEmitter {
@@ -22,6 +22,12 @@ export class Protocol extends EventEmitter {
// This should be set to true when the protocol fails for any reason
public failed = false;
+ // This should identify the bot itself
+ public me: IMessageTarget = {
+ id: '',
+ name: '',
+ };
+
constructor(public plugin: IPlugin, public config: any) {
super();
this.passEvents();