This commit is contained in:
Max Leiter 2022-06-02 16:10:45 -07:00
parent 95a7a30c41
commit 4c3fcf0e36
No known key found for this signature in database
GPG key ID: A3512F2F2F17EBDA
4 changed files with 137 additions and 4 deletions

View file

@ -9,6 +9,7 @@ import Config, {WebIRC} from "../config";
import STSPolicies from "../plugins/sts";
import ClientCertificate, {ClientCertificateType} from "../plugins/clientCertificate";
import Client from "../client";
import ChatHistoryMiddleware from "../plugins/middleware/chat-history";
/**
* List of keys which should be sent to the client by default.
@ -284,6 +285,8 @@ class Network {
// TODO: this type should be set after setIrcFrameworkOptions
}) as NetworkWithIrcFramework["irc"];
this.irc.use(ChatHistoryMiddleware());
this.setIrcFrameworkOptions(client);
this.irc.requestCap([

View file

@ -0,0 +1,101 @@
import EventEmitter from "events";
import { Client, IRCMiddleware } from "irc-framework";
import { isDate } from "lodash";
const initChatHistoryCommands = (irc: Client) => {
const isEnabled = () => irc.network.supports('draft/chathistory') || irc.network.supports('chathistory');
const messageLimit = () =>
irc.network.options["DRAFT/CHATHISTORY"]
|| irc.network.options.CHATHISTORY || 100;
const getTimestamp = (ts: string | Date) => {
if (isDate(ts)) {
return "timestamp=" + ts.toISOString();
}
return ts;
}
const commands: typeof Client.prototype.chatHistory = {
async latest(target: string, timestamp = "*", limit = messageLimit()) {
// CHATHISTORY LATEST #channel * 50
if (!isEnabled()) {
return;
}
irc.raw(`CHATHISTORY LATEST ${target} ${getTimestamp(timestamp)} ${limit}`);
}
};
irc.chatHistory = commands;
}
const initCallbacks = (irc: Client) => {
const batches: Map<number, ((data?: any) => Promise<void>)> = new Map();
irc.chatHistory.batches = batches;
irc.chatHistory.addCallback = (id, callback) => {
batches.set(id, callback);
}
irc.chatHistory.runCallback = async (id: number) => {
if (batches.has(id)) {
// TODO: investigate typing
await batches.get(id)!();
}
}
}
type BatchResponse = {
id: number,
type: 'chathistory',
params: string[],
commands: string[],
}
const initListeners = (irc: Client) => {
irc.on("batch start chathistory", (data: BatchResponse) => {
irc.chatHistory.batches.set(data.id, new Promise((resolve, reject) => {
irc.chatHistory.addCallback(data.id, () => {
resolve();
});
}
})
irc.on("batch end chathistory", (data: BatchResponse) => {
if (!irc.chatHistory) {
return;
}
// irc.chatHistory.runCallbacks(data.id);
});
}
function ChatHistoryMiddleware(): IRCMiddleware {
return function (irc, raw_events, parsed_events) {
irc.requestCap(['draft/chathistory']);
irc.chatHistory.batches = new Map<string, Promise<void>>();
irc.on("batch end chathistory", (data: BatchResponse) => {
irc.chatHistory.listener.emit("chathistory", data);
});
initCallbacks(irc);
initListeners(irc);
initChatHistoryCommands(irc);
// initChatHistoryListeners(client);
parsed_events.use(theMiddleware);
}
function theMiddleware(command: string, event: any, client: Client, next: () => void) {
next();
}
}
export default ChatHistoryMiddleware;

23
src/plugins/middleware/middleware.d.ts vendored Normal file
View file

@ -0,0 +1,23 @@
import EventEmitter from "events";
// import { Client } from "irc-framework"
type Timestamp = `timestamp=${string}` | `msgid=${string}` | Date;
type LatestTimestamp = "*" | Timestamp;
declare module "irc-framework" {
interface Client {
chatHistory: {
batches: Map<number, Promise<void>>;
addCallback: (id: number, callback: (data?: void | PromiseLike<void>) => Promise<void>) => void;
async runCallback(id: number): void;
async before(target: string, timestamp: Timestamp, limit: number): Promise<any>;
async after(target: string, timestamp: Timestamp, limit: number): Promise<any>;
async latest(target: string, timestamp: LatestTimestamp, limit: number): Promise<any>;
async around(target: string, timestamp: Timestamp, limit: number): Promise<any>;
async between(target: string, timestamp1: Timestamp, timestamp2: Timestamp, limit: number): Promise<any>;
async targets(timestamp1: Timestamp, timestamp2: Timestamp, limit: number): Promise<any>;
async targets(target: string, timestamp: Timestamp): Promise<any>;
}
}
}

View file

@ -5,7 +5,7 @@
// https://raw.githubusercontent.com/eternagame/HTML-Chat/vue-rewrite/src/app/types/modules/irc-framework/irc-framework.d.ts
// TODO: Fix this
declare module "irc-framework" {
import {EventEmitter} from "eventemitter3";
import { EventEmitter } from "eventemitter3";
// import { DuplexStream } from 'stream';
import Connection from "irc-framework/src/transports/websocket";
@ -23,6 +23,8 @@ declare module "irc-framework" {
end: () => void;
};
export type IRCMiddleware = (client: Client, raw_events: Array<string>, parsed_events: any) => void;
export interface MessageEventArgs {
account?: any;
group?: any;
@ -31,7 +33,7 @@ declare module "irc-framework" {
message: string;
nick: string;
reply: (message: string) => void;
tags: {[key: string]: string};
tags: { [key: string]: string };
target: string;
time?: any;
type: "privmsg" | "action"; // TODO
@ -111,6 +113,8 @@ declare module "irc-framework" {
PREFIX: any;
CHANMODES: string;
NICKLEN: string;
'DRAFT/CHATHISTORY': number;
CHATHISTORY: number;
};
cap: {
isEnabled: (cap: string) => boolean;
@ -141,7 +145,9 @@ declare module "irc-framework" {
// TODO
/** Request */ requestCap(capability: string[]): void;
use(a: any): any;
use(a: IRCMiddleware): any;
connect(connect_options?: Record<string, unknown>): void;
@ -227,7 +233,7 @@ declare module "irc-framework" {
match_regex: string,
cb: (event: Event) => any,
message_type: string
): {stop: () => void};
): { stop: () => void };
matchNotice(match_regex: string, cb: (event: Event) => any): void;