rename classes, add irc connection interface
This commit is contained in:
parent
a5c7c22d54
commit
d32ae78c56
@ -9,7 +9,7 @@ Zero dependencies library for creating anything using the IRC protocol - bots, c
|
|||||||
There is an example usage documented in [src/examples/connection-test.ts](https://gitlab.icynet.eu/IcyNetwork/irclib/-/blob/master/src/examples/connection-test.ts), but basically you have two ways to create an IRC client connection:
|
There is an example usage documented in [src/examples/connection-test.ts](https://gitlab.icynet.eu/IcyNetwork/irclib/-/blob/master/src/examples/connection-test.ts), but basically you have two ways to create an IRC client connection:
|
||||||
|
|
||||||
1. Use the `IRCBot` class. This just takes connection options and it uses `IRCSocketConnector` (so it will not work in the browser!)
|
1. Use the `IRCBot` class. This just takes connection options and it uses `IRCSocketConnector` (so it will not work in the browser!)
|
||||||
2. Use the `IRCConnectionWrapper` class directly. To use this, you need to provide your own connector in addition to the options.
|
2. Use the `IRCConnection` class directly. To use this, you need to provide your own connector in addition to the options.
|
||||||
|
|
||||||
### Connection options
|
### Connection options
|
||||||
|
|
||||||
|
20
src/bot.ts
20
src/bot.ts
@ -1,22 +1,30 @@
|
|||||||
import { IRCSocketConnector } from './connector/net.connector';
|
import { IRCSocketConnector } from './connector/net.connector';
|
||||||
import { IRCConnectionWrapper } from './irc';
|
import { IRCConnection } from './irc';
|
||||||
import { IIRCOptions } from './types/irc.interfaces';
|
import { IIRCOptions } from './types/irc.interfaces';
|
||||||
import { formatstr } from './utility/formatstr';
|
import { formatstr } from './utility/formatstr';
|
||||||
|
|
||||||
export class IRCBot extends IRCConnectionWrapper {
|
export class IRCBot extends IRCConnection {
|
||||||
constructor(options: IIRCOptions) {
|
constructor(options: IIRCOptions) {
|
||||||
super(options, IRCSocketConnector);
|
super(options, IRCSocketConnector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the server (`PRIVMSG`)
|
||||||
|
* @param to Recipient, a channel or a nick
|
||||||
|
* @param message Message to send
|
||||||
|
* @param args Additional arguments for message
|
||||||
|
*/
|
||||||
send(to: string, message: string, ...args: any[]) {
|
send(to: string, message: string, ...args: any[]) {
|
||||||
this.write('PRIVMSG %s :%s', to, formatstr(message, ...args));
|
this.write('PRIVMSG %s :%s', to, formatstr(message, ...args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the server (`NOTICE`)
|
||||||
|
* @param to Recipient, a channel or a nick
|
||||||
|
* @param message Message to send
|
||||||
|
* @param args Additional arguments for message
|
||||||
|
*/
|
||||||
notice(to: string, message: string, ...args: any[]) {
|
notice(to: string, message: string, ...args: any[]) {
|
||||||
this.write('NOTICE %s :%s', to, formatstr(message, ...args));
|
this.write('NOTICE %s :%s', to, formatstr(message, ...args));
|
||||||
}
|
}
|
||||||
|
|
||||||
nick(newNick: string) {
|
|
||||||
this.write('NICK %s', newNick);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import net, { Socket } from 'net';
|
import net, { Socket } from 'net';
|
||||||
import tls, { TLSSocket } from 'tls';
|
import tls, { TLSSocket } from 'tls';
|
||||||
import { ConnectorEvents } from '../types/events';
|
import { ConnectorEvents } from '../types/events';
|
||||||
import { IRCConnector } from '../types/impl.interface';
|
import { IIRCConnector } from '../types/impl.interface';
|
||||||
import { formatstr } from '../utility/formatstr';
|
import { formatstr } from '../utility/formatstr';
|
||||||
import { TypedEventEmitter } from '../utility/typed-event-emitter';
|
import { TypedEventEmitter } from '../utility/typed-event-emitter';
|
||||||
|
|
||||||
export class IRCSocketConnector
|
export class IRCSocketConnector
|
||||||
extends TypedEventEmitter<ConnectorEvents>
|
extends TypedEventEmitter<ConnectorEvents>
|
||||||
implements IRCConnector
|
implements IIRCConnector
|
||||||
{
|
{
|
||||||
connected = false;
|
connected = false;
|
||||||
private socket?: Socket | TLSSocket;
|
private socket?: Socket | TLSSocket;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { ConnectorEvents } from '../types/events';
|
import { ConnectorEvents } from '../types/events';
|
||||||
import { IRCConnector } from '../types/impl.interface';
|
import { IIRCConnector } from '../types/impl.interface';
|
||||||
import { formatstr } from '../utility/formatstr';
|
import { formatstr } from '../utility/formatstr';
|
||||||
import { TypedEventEmitter } from '../utility/typed-event-emitter';
|
import { TypedEventEmitter } from '../utility/typed-event-emitter';
|
||||||
|
|
||||||
export class IRCWebSocketConnector
|
export class IRCWebSocketConnector
|
||||||
extends TypedEventEmitter<ConnectorEvents>
|
extends TypedEventEmitter<ConnectorEvents>
|
||||||
implements IRCConnector
|
implements IIRCConnector
|
||||||
{
|
{
|
||||||
connected = false;
|
connected = false;
|
||||||
private socket?: WebSocket;
|
private socket?: WebSocket;
|
||||||
|
84
src/irc.ts
84
src/irc.ts
@ -1,8 +1,9 @@
|
|||||||
import { IRCCommunicatorEvents } from './types/events';
|
import { IRCCommunicatorEvents } from './types/events';
|
||||||
import {
|
import {
|
||||||
IRCCommunicator,
|
IWritableEventEmitter,
|
||||||
IRCConnector,
|
IIRCConnector,
|
||||||
IRCConnectorConstructor,
|
IIRCConnectorConstructor,
|
||||||
|
IIRCWrapper,
|
||||||
} from './types/impl.interface';
|
} from './types/impl.interface';
|
||||||
import {
|
import {
|
||||||
IIRCLine,
|
IIRCLine,
|
||||||
@ -22,42 +23,27 @@ import { TypedEventEmitter } from './utility/typed-event-emitter';
|
|||||||
import { parseWho, WhoResponse } from './utility/who-parser';
|
import { parseWho, WhoResponse } from './utility/who-parser';
|
||||||
import { parseWhois, WhoisResponse } from './utility/whois-parser';
|
import { parseWhois, WhoisResponse } from './utility/whois-parser';
|
||||||
|
|
||||||
export class IRCConnectionWrapper
|
export class IRCConnection
|
||||||
extends TypedEventEmitter<IRCCommunicatorEvents>
|
extends TypedEventEmitter<IRCCommunicatorEvents>
|
||||||
implements IRCCommunicator
|
implements IIRCWrapper
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Channels the bot is currently in.
|
|
||||||
*/
|
|
||||||
public channels: string[] = [];
|
public channels: string[] = [];
|
||||||
|
|
||||||
/**
|
|
||||||
* Current collectors waiting for their reply.
|
|
||||||
*/
|
|
||||||
public queue: IQueue[] = [];
|
public queue: IQueue[] = [];
|
||||||
|
|
||||||
/**
|
|
||||||
* Login success status.
|
|
||||||
*/
|
|
||||||
public authenticated = false;
|
public authenticated = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Information about the IRC server gathered during runtime
|
|
||||||
*/
|
|
||||||
public serverData: IIRCServerData = {
|
public serverData: IIRCServerData = {
|
||||||
name: '',
|
name: '',
|
||||||
supportedModes: {},
|
supportedModes: {},
|
||||||
serverSupports: {},
|
serverSupports: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
private connection?: IRCConnector;
|
private connection?: IIRCConnector;
|
||||||
|
|
||||||
private _supportsDone = false;
|
private _supportsDone = false;
|
||||||
private _lastLineWasSupports = false;
|
private _lastLineWasSupports = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public options: IIRCOptions,
|
public options: IIRCOptions,
|
||||||
public connector: IRCConnectorConstructor,
|
public connector: IIRCConnectorConstructor,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
if (!options.username) {
|
if (!options.username) {
|
||||||
@ -66,14 +52,6 @@ export class IRCConnectionWrapper
|
|||||||
this.handlers();
|
this.handlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a raw command to the server.
|
|
||||||
*
|
|
||||||
* **WARNING:** Line break characters could have an unintended side-effect!
|
|
||||||
* Filter user-generated content!
|
|
||||||
* @param format Command
|
|
||||||
* @param args Command arguments
|
|
||||||
*/
|
|
||||||
write(format: string, ...args: any[]): void {
|
write(format: string, ...args: any[]): void {
|
||||||
this.connection?.write(format, ...args);
|
this.connection?.write(format, ...args);
|
||||||
}
|
}
|
||||||
@ -487,9 +465,6 @@ export class IRCConnectionWrapper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new connection to the configured IRC server.
|
|
||||||
*/
|
|
||||||
public async connect(): Promise<void> {
|
public async connect(): Promise<void> {
|
||||||
if (this.connection) {
|
if (this.connection) {
|
||||||
await this.connection.destroy();
|
await this.connection.destroy();
|
||||||
@ -529,10 +504,6 @@ export class IRCConnectionWrapper
|
|||||||
this.authenticate();
|
this.authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect from the IRC server gracefully, sends `QUIT`.
|
|
||||||
* @param reason Reason for disconnection
|
|
||||||
*/
|
|
||||||
public async disconnect(reason?: string): Promise<void> {
|
public async disconnect(reason?: string): Promise<void> {
|
||||||
if (!this.connected) {
|
if (!this.connected) {
|
||||||
if (this.connection) {
|
if (this.connection) {
|
||||||
@ -554,18 +525,10 @@ export class IRCConnectionWrapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get connection status. `authenticated` is a more reliable indicator
|
|
||||||
* of a successful connection.
|
|
||||||
*/
|
|
||||||
public get connected() {
|
public get connected() {
|
||||||
return this.connection?.connected ?? false;
|
return this.connection?.connected ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a new nickname for self.
|
|
||||||
* @param newNick New nickname
|
|
||||||
*/
|
|
||||||
public setNick(newNick: string): void {
|
public setNick(newNick: string): void {
|
||||||
this.write('NICK %s', newNick);
|
this.write('NICK %s', newNick);
|
||||||
this.emit('nick', {
|
this.emit('nick', {
|
||||||
@ -575,10 +538,6 @@ export class IRCConnectionWrapper
|
|||||||
this.options.nick = newNick;
|
this.options.nick = newNick;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronously ping the server.
|
|
||||||
* @returns Ping in milliseconds
|
|
||||||
*/
|
|
||||||
public async getPing(): Promise<number> {
|
public async getPing(): Promise<number> {
|
||||||
return new Promise<number>((resolve) => {
|
return new Promise<number>((resolve) => {
|
||||||
const sendTime = Date.now();
|
const sendTime = Date.now();
|
||||||
@ -593,11 +552,6 @@ export class IRCConnectionWrapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronous WHOIS query on `nick`
|
|
||||||
* @param nick Nick to query
|
|
||||||
* @returns Parsed WHOIS response object
|
|
||||||
*/
|
|
||||||
public async whois(nick: string): Promise<WhoisResponse> {
|
public async whois(nick: string): Promise<WhoisResponse> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.useCollector(
|
this.useCollector(
|
||||||
@ -608,11 +562,6 @@ export class IRCConnectionWrapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Asynchronous WHO query on `target`
|
|
||||||
* @param target Channel or nick to query
|
|
||||||
* @returns Parsed WHO response object array
|
|
||||||
*/
|
|
||||||
public async who(target: string): Promise<WhoResponse[]> {
|
public async who(target: string): Promise<WhoResponse[]> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.useCollector(
|
this.useCollector(
|
||||||
@ -623,11 +572,6 @@ export class IRCConnectionWrapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of names in a channel asynchronously
|
|
||||||
* @param channel Channel to query
|
|
||||||
* @returns String list of nicks (with mode prefixes preserved)
|
|
||||||
*/
|
|
||||||
public async names(channel: string): Promise<string[]> {
|
public async names(channel: string): Promise<string[]> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.useCollector(
|
this.useCollector(
|
||||||
@ -646,10 +590,6 @@ export class IRCConnectionWrapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of channels asynchronously
|
|
||||||
* @returns Channel list in `[<channel>, <# visible>, <topic>][]` format
|
|
||||||
*/
|
|
||||||
public async list(): Promise<string[][]> {
|
public async list(): Promise<string[][]> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.useCollector(
|
this.useCollector(
|
||||||
@ -669,14 +609,6 @@ export class IRCConnectionWrapper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a collector to the queue.
|
|
||||||
* This is used to grab lines from the server, wait for them
|
|
||||||
* and return them in a callback.
|
|
||||||
* @param collector IRC line collector
|
|
||||||
* @param line Command to send to the server
|
|
||||||
* @param args Arguments to the command
|
|
||||||
*/
|
|
||||||
public useCollector(collector: IQueue, line: string, ...args: any[]) {
|
public useCollector(collector: IQueue, line: string, ...args: any[]) {
|
||||||
this.queue.push(collector);
|
this.queue.push(collector);
|
||||||
this.write(line, ...args);
|
this.write(line, ...args);
|
||||||
|
@ -1,20 +1,124 @@
|
|||||||
export interface IRCCommunicator {
|
import { WhoResponse } from '../utility/who-parser';
|
||||||
|
import { WhoisResponse } from '../utility/whois-parser';
|
||||||
|
import { IIRCOptions, IIRCServerData, IQueue } from './irc.interfaces';
|
||||||
|
|
||||||
|
export interface IWritableEventEmitter {
|
||||||
emit(event: string, ...args: any[]): void;
|
emit(event: string, ...args: any[]): void;
|
||||||
on(event: string, handler: (...args: any[]) => void): void;
|
on(event: string, handler: (...args: any[]) => void): void;
|
||||||
write(format: string, ...args: any[]): void;
|
write(format: string, ...args: any[]): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRCConnector extends IRCCommunicator {
|
export interface IIRCConnector extends IWritableEventEmitter {
|
||||||
|
/**
|
||||||
|
* Current connection status.
|
||||||
|
*/
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
|
/**
|
||||||
|
* Connect the socket to the server.
|
||||||
|
*/
|
||||||
connect(): Promise<void>;
|
connect(): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Forcefully disconnect the socket from the server.
|
||||||
|
*/
|
||||||
destroy(): Promise<void>;
|
destroy(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRCConnectorConstructor {
|
export interface IIRCWrapper extends IWritableEventEmitter {
|
||||||
|
/**
|
||||||
|
* Connection options for the IRC server.
|
||||||
|
*/
|
||||||
|
options: IIRCOptions;
|
||||||
|
/**
|
||||||
|
* The connector to use for connecting to the IRC server.
|
||||||
|
*/
|
||||||
|
connector: IIRCConnectorConstructor;
|
||||||
|
/**
|
||||||
|
* Get connection status. `authenticated` is a more reliable indicator
|
||||||
|
* of a successful connection.
|
||||||
|
*/
|
||||||
|
connected: boolean;
|
||||||
|
/**
|
||||||
|
* Channels the bot is currently in.
|
||||||
|
*/
|
||||||
|
channels: string[];
|
||||||
|
/**
|
||||||
|
* Current collectors waiting for their reply.
|
||||||
|
*/
|
||||||
|
queue: IQueue[];
|
||||||
|
/**
|
||||||
|
* Login success status.
|
||||||
|
*/
|
||||||
|
authenticated: boolean;
|
||||||
|
/**
|
||||||
|
* Information about the IRC server gathered during runtime
|
||||||
|
*/
|
||||||
|
serverData: IIRCServerData;
|
||||||
|
/**
|
||||||
|
* Send a raw command to the server.
|
||||||
|
*
|
||||||
|
* **WARNING:** Line break characters could have an unintended side-effect!
|
||||||
|
* Filter user-generated content!
|
||||||
|
* @param format Command
|
||||||
|
* @param args Command arguments
|
||||||
|
*/
|
||||||
|
write(format: string, ...args: any[]): void;
|
||||||
|
/**
|
||||||
|
* Create a new connection to the configured IRC server.
|
||||||
|
*/
|
||||||
|
connect(): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Disconnect from the IRC server gracefully, sends `QUIT`.
|
||||||
|
* @param reason Reason for disconnection
|
||||||
|
*/
|
||||||
|
disconnect(reason?: string): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Asynchronously ping the server.
|
||||||
|
* @returns Ping in milliseconds
|
||||||
|
*/
|
||||||
|
getPing(): Promise<number>;
|
||||||
|
/**
|
||||||
|
* Asynchronous WHOIS query on `nick`
|
||||||
|
* @param nick Nick to query
|
||||||
|
* @returns Parsed WHOIS response object
|
||||||
|
*/
|
||||||
|
whois(nick: string): Promise<WhoisResponse>;
|
||||||
|
/**
|
||||||
|
* Asynchronous WHO query on `target`
|
||||||
|
* @param target Channel or nick to query
|
||||||
|
* @returns Parsed WHO response object array
|
||||||
|
*/
|
||||||
|
who(target: string): Promise<WhoResponse[]>;
|
||||||
|
/**
|
||||||
|
* Get a list of names in a channel asynchronously
|
||||||
|
* @param channel Channel to query
|
||||||
|
* @returns String list of nicks (with mode prefixes preserved)
|
||||||
|
*/
|
||||||
|
names(channel: string): Promise<string[]>;
|
||||||
|
/**
|
||||||
|
* Get a list of channels asynchronously
|
||||||
|
* @returns Channel list in `[<channel>, <# visible>, <topic>][]` format
|
||||||
|
*/
|
||||||
|
list(): Promise<string[][]>;
|
||||||
|
/**
|
||||||
|
* Add a collector to the queue.
|
||||||
|
* This is used to grab lines from the server, wait for them
|
||||||
|
* and return them in a callback.
|
||||||
|
* @param collector IRC line collector
|
||||||
|
* @param line Command to send to the server
|
||||||
|
* @param args Arguments to the command
|
||||||
|
*/
|
||||||
|
useCollector(collector: IQueue, line: string, ...args: any[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIRCConnectorConstructor {
|
||||||
new (
|
new (
|
||||||
secure: boolean,
|
secure: boolean,
|
||||||
host: string,
|
host: string,
|
||||||
port?: number,
|
port?: number,
|
||||||
opts?: Record<string, unknown>,
|
opts?: Record<string, unknown>,
|
||||||
): IRCConnector;
|
): IIRCConnector;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIRCConnetionConstructor {
|
||||||
|
new (options: IIRCOptions, connector: IIRCConnectorConstructor): IIRCWrapper;
|
||||||
}
|
}
|
||||||
|
@ -161,5 +161,8 @@ export interface IIRCServerData {
|
|||||||
* Supported channel user modes from the server (e.g. `ohv: @%+`)
|
* Supported channel user modes from the server (e.g. `ohv: @%+`)
|
||||||
*/
|
*/
|
||||||
supportedModes: Record<string, string>;
|
supportedModes: Record<string, string>;
|
||||||
|
/**
|
||||||
|
* Name of the IRC network. May not be present.
|
||||||
|
*/
|
||||||
network?: string;
|
network?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IRCConnectionWrapper } from '../../irc';
|
import { IIRCWrapper } from '../../types/impl.interface';
|
||||||
import { modeFromPrefix } from '../mode-from-prefix';
|
import { modeFromPrefix } from '../mode-from-prefix';
|
||||||
import { TypedEventEmitter } from '../typed-event-emitter';
|
import { TypedEventEmitter } from '../typed-event-emitter';
|
||||||
import { WhoResponse } from '../who-parser';
|
import { WhoResponse } from '../who-parser';
|
||||||
@ -11,7 +11,7 @@ import { INicklistChannel } from './nicklist.interfaces';
|
|||||||
export class IRCNickList extends TypedEventEmitter<NickListEvents> {
|
export class IRCNickList extends TypedEventEmitter<NickListEvents> {
|
||||||
public channels: INicklistChannel[] = [];
|
public channels: INicklistChannel[] = [];
|
||||||
|
|
||||||
constructor(public irc: IRCConnectionWrapper) {
|
constructor(public irc: IIRCWrapper) {
|
||||||
super();
|
super();
|
||||||
this.handlers();
|
this.handlers();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IRCConnectionWrapper } from '../irc';
|
import { IRCConnection } from '../irc';
|
||||||
import { INickServOptions } from '../types/irc.interfaces';
|
import { INickServOptions } from '../types/irc.interfaces';
|
||||||
import { Collector } from './collector';
|
import { Collector } from './collector';
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ export class NickServCollector extends Collector {
|
|||||||
export class NickServValidator {
|
export class NickServValidator {
|
||||||
public nickservStore: { [key: string]: INickStore } = {};
|
public nickservStore: { [key: string]: INickStore } = {};
|
||||||
|
|
||||||
constructor(public irc: IRCConnectionWrapper) {
|
constructor(public irc: IRCConnection) {
|
||||||
this.irc.on('leave', ({ nickname }) => {
|
this.irc.on('leave', ({ nickname }) => {
|
||||||
if (this.nickservStore[nickname]) {
|
if (this.nickservStore[nickname]) {
|
||||||
delete this.nickservStore[nickname];
|
delete this.nickservStore[nickname];
|
||||||
|
Loading…
Reference in New Issue
Block a user