mirror of
https://github.com/thelounge/thelounge.git
synced 2024-05-02 06:33:19 +02:00
progress
This commit is contained in:
parent
4c3fcf0e36
commit
4eea858a14
|
@ -8,6 +8,7 @@
|
||||||
highlight: message.highlight || focused,
|
highlight: message.highlight || focused,
|
||||||
'previous-source': isPreviousSource,
|
'previous-source': isPreviousSource,
|
||||||
},
|
},
|
||||||
|
batchType,
|
||||||
]"
|
]"
|
||||||
:data-type="message.type"
|
:data-type="message.type"
|
||||||
:data-command="message.command"
|
:data-command="message.command"
|
||||||
|
@ -97,6 +98,12 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped css>
|
||||||
|
.batch-type-chathistory {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {computed, defineComponent, PropType} from "vue";
|
import {computed, defineComponent, PropType} from "vue";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
@ -153,6 +160,14 @@ export default defineComponent({
|
||||||
return "message-" + props.message.type;
|
return "message-" + props.message.type;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const batchType = computed(() => {
|
||||||
|
if (props.message.batch) {
|
||||||
|
return `batch-type-${props.message.batch?.type}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
const isAction = () => {
|
const isAction = () => {
|
||||||
return typeof MessageTypes["message-" + props.message.type] !== "undefined";
|
return typeof MessageTypes["message-" + props.message.type] !== "undefined";
|
||||||
};
|
};
|
||||||
|
@ -163,6 +178,7 @@ export default defineComponent({
|
||||||
messageTimeLocale,
|
messageTimeLocale,
|
||||||
messageComponent,
|
messageComponent,
|
||||||
isAction,
|
isAction,
|
||||||
|
batchType,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -74,6 +74,13 @@ class Msg {
|
||||||
statusmsgGroup!: string;
|
statusmsgGroup!: string;
|
||||||
params!: string[];
|
params!: string[];
|
||||||
|
|
||||||
|
batch?: {
|
||||||
|
id: number;
|
||||||
|
type: string;
|
||||||
|
params: string[];
|
||||||
|
commands: any[];
|
||||||
|
};
|
||||||
|
|
||||||
constructor(attr?: Partial<Msg>) {
|
constructor(attr?: Partial<Msg>) {
|
||||||
// Some properties need to be copied in the Msg object instead of referenced
|
// Some properties need to be copied in the Msg object instead of referenced
|
||||||
if (attr) {
|
if (attr) {
|
||||||
|
|
|
@ -29,6 +29,11 @@ export default <IrcEventHandler>function (irc, network) {
|
||||||
} else if (data.nick === irc.user.nick) {
|
} else if (data.nick === irc.user.nick) {
|
||||||
chan.state = ChanState.JOINED;
|
chan.state = ChanState.JOINED;
|
||||||
|
|
||||||
|
// Don't react to our own join
|
||||||
|
if (data.batch?.type !== "chathistory") {
|
||||||
|
network.irc.chatHistory.latest(chan.name);
|
||||||
|
}
|
||||||
|
|
||||||
client.emit("channel:state", {
|
client.emit("channel:state", {
|
||||||
chan: chan.id,
|
chan: chan.id,
|
||||||
state: chan.state,
|
state: chan.state,
|
||||||
|
|
|
@ -41,6 +41,8 @@ export default <IrcEventHandler>function (irc, network) {
|
||||||
type: MessageType;
|
type: MessageType;
|
||||||
time: number;
|
time: number;
|
||||||
text: string;
|
text: string;
|
||||||
|
// TODO: type
|
||||||
|
batch?: any;
|
||||||
message: string;
|
message: string;
|
||||||
group?: string;
|
group?: string;
|
||||||
}) {
|
}) {
|
||||||
|
@ -50,6 +52,10 @@ export default <IrcEventHandler>function (irc, network) {
|
||||||
let showInActive = false;
|
let showInActive = false;
|
||||||
const self = data.nick === irc.user.nick;
|
const self = data.nick === irc.user.nick;
|
||||||
|
|
||||||
|
if (data.batch?.type === "chathistory") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Some servers send messages without any nickname
|
// Some servers send messages without any nickname
|
||||||
if (!data.nick) {
|
if (!data.nick) {
|
||||||
data.from_server = true;
|
data.from_server = true;
|
||||||
|
@ -126,6 +132,7 @@ export default <IrcEventHandler>function (irc, network) {
|
||||||
from: from,
|
from: from,
|
||||||
highlight: highlight,
|
highlight: highlight,
|
||||||
users: [],
|
users: [],
|
||||||
|
batch: data.batch || undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (showInActive) {
|
if (showInActive) {
|
||||||
|
|
|
@ -1,14 +1,48 @@
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
import { Client, IRCMiddleware } from "irc-framework";
|
import {Client, IRCMiddleware} from "irc-framework";
|
||||||
import { isDate } from "lodash";
|
import {isDate} from "lodash";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const initChatHistoryCommands = (irc: Client) => {
|
const initChatHistoryCommands = (irc: Client) => {
|
||||||
const isEnabled = () => irc.network.supports('draft/chathistory') || irc.network.supports('chathistory');
|
const waitForResponse = async <T>(
|
||||||
|
firstResponse: string,
|
||||||
|
response: string,
|
||||||
|
handler: (data: T) => void,
|
||||||
|
timeout = 5000
|
||||||
|
) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let id: string;
|
||||||
|
|
||||||
|
irc.chatHistory.eventbus.on(firstResponse, (data) => {
|
||||||
|
id = data.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: improve typing
|
||||||
|
const handleData = (
|
||||||
|
data: T & {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
console.log(`[response:${response}] [id:${data.id}] [key:${id}]`);
|
||||||
|
if (data.id === id) {
|
||||||
|
console.log(id, "handled.");
|
||||||
|
resolve(handler(data));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
irc.chatHistory.eventbus.on(response, handleData);
|
||||||
|
|
||||||
|
// setTimeout(() => {
|
||||||
|
// console.log(`[${response}] [${key}] timeout`);
|
||||||
|
// irc.chatHistory.eventbus.off(response, handleData);
|
||||||
|
// reject(new Error("timeout"));
|
||||||
|
// }, timeout);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const isEnabled = () =>
|
||||||
|
irc.network.supports("draft/chathistory") || irc.network.supports("chathistory");
|
||||||
const messageLimit = () =>
|
const messageLimit = () =>
|
||||||
irc.network.options["DRAFT/CHATHISTORY"]
|
irc.network.options["DRAFT/CHATHISTORY"] || irc.network.options.CHATHISTORY || 100;
|
||||||
|| irc.network.options.CHATHISTORY || 100;
|
|
||||||
|
|
||||||
const getTimestamp = (ts: string | Date) => {
|
const getTimestamp = (ts: string | Date) => {
|
||||||
if (isDate(ts)) {
|
if (isDate(ts)) {
|
||||||
|
@ -16,82 +50,97 @@ const initChatHistoryCommands = (irc: Client) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ts;
|
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;
|
irc.chatHistory.latest = async (target, timestamp = "*", limit = messageLimit()) => {
|
||||||
}
|
// CHATHISTORY LATEST #channel * 50
|
||||||
|
if (!isEnabled()) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
const processedTimestamp = getTimestamp(timestamp);
|
||||||
|
|
||||||
// irc.chatHistory.runCallbacks(data.id);
|
irc.raw(`CHATHISTORY LATEST ${target} ${processedTimestamp} ${limit}`);
|
||||||
});
|
return waitForResponse<BatchResponse>("batch:start", "batch:end", (data) => data.commands);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
irc.chatHistory.before = (target, timestamp, limit = messageLimit()) => {
|
||||||
|
// CHATHISTORY BEFORE <target> <timestamp=YYYY-MM-DDThh:mm:ss.sssZ | msgid=1234> <limit>
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const processedTimestamp = getTimestamp(timestamp);
|
||||||
|
|
||||||
|
irc.raw(`CHATHISTORY BEFORE ${target} ${processedTimestamp} ${limit}`);
|
||||||
|
return waitForResponse<BatchResponse>("batch:start", "batch:end", (data) => data.commands);
|
||||||
|
};
|
||||||
|
|
||||||
|
irc.chatHistory.after = (target, timestamp, limit = messageLimit()) => {
|
||||||
|
// CHATHISTORY AFTER <target> <timestamp=YYYY-MM-DDThh:mm:ss.sssZ | msgid=1234> <limit>
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const processedTimestamp = getTimestamp(timestamp);
|
||||||
|
|
||||||
|
irc.raw(`CHATHISTORY AFTER ${target} ${processedTimestamp} ${limit}`);
|
||||||
|
return waitForResponse<BatchResponse>("batch:start", "batch:end", (data) => data.commands);
|
||||||
|
};
|
||||||
|
|
||||||
|
irc.chatHistory.around = (target, timestamp, limit = messageLimit()) => {
|
||||||
|
// CHATHISTORY AROUND <target> <timestamp=YYYY-MM-DDThh:mm:ss.sssZ | msgid=1234> <limit>
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const processedTimestamp = getTimestamp(timestamp);
|
||||||
|
|
||||||
|
irc.raw(`CHATHISTORY AROUND ${target} ${processedTimestamp} ${limit}`);
|
||||||
|
return waitForResponse<BatchResponse>("batch:start", "batch:end", (data) => data.commands);
|
||||||
|
};
|
||||||
|
|
||||||
|
irc.chatHistory.between = (target, timestamp1, timestamp2, limit = messageLimit()) => {
|
||||||
|
// CHATHISTORY BETWEEN <target> <timestamp1=YYYY-MM-DDThh:mm:ss.sssZ | msgid=1234> <timestamp2=YYYY-MM-DDThh:mm:ss.sssZ | msgid=1234> <limit>
|
||||||
|
if (!isEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const processedTimestamp = getTimestamp(timestamp1);
|
||||||
|
const processedTimestamp2 = getTimestamp(timestamp2);
|
||||||
|
|
||||||
|
irc.raw(
|
||||||
|
`CHATHISTORY BETWEEN ${target} ${processedTimestamp} ${processedTimestamp2} ${limit}`
|
||||||
|
);
|
||||||
|
return waitForResponse<BatchResponse>("batch:start", "batch:end", (data) => data.commands);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type BatchResponse = {
|
||||||
|
id: string;
|
||||||
|
type: "chathistory";
|
||||||
|
params: string[];
|
||||||
|
commands: string[];
|
||||||
|
};
|
||||||
|
|
||||||
function ChatHistoryMiddleware(): IRCMiddleware {
|
function ChatHistoryMiddleware(): IRCMiddleware {
|
||||||
return function (irc, raw_events, parsed_events) {
|
return function (irc, raw_events, parsed_events) {
|
||||||
irc.requestCap(['draft/chathistory']);
|
//@ts-ignore
|
||||||
|
irc.chatHistory = {
|
||||||
|
eventbus: new EventEmitter(),
|
||||||
|
};
|
||||||
|
|
||||||
irc.chatHistory.batches = new Map<string, Promise<void>>();
|
irc.requestCap(["draft/chathistory", "draft/event-playback", "draft/chathistory-targets"]);
|
||||||
|
|
||||||
|
irc.on("batch start chathistory", (data: BatchResponse) => {
|
||||||
irc.on("batch end chathistory", (data: BatchResponse) => {
|
console.log("batch start chathistory");
|
||||||
irc.chatHistory.listener.emit("chathistory", data);
|
irc.chatHistory.eventbus.emit("batch:start", data);
|
||||||
|
});
|
||||||
|
|
||||||
|
irc.on("batch end chathistory", (data: BatchResponse) => {
|
||||||
|
console.log("batch end chathistory", data);
|
||||||
|
irc.chatHistory.eventbus.emit("batch:end", data);
|
||||||
});
|
});
|
||||||
|
|
||||||
initCallbacks(irc);
|
|
||||||
initListeners(irc);
|
|
||||||
initChatHistoryCommands(irc);
|
initChatHistoryCommands(irc);
|
||||||
// initChatHistoryListeners(client);
|
irc.chatHistory.eventbus = new EventEmitter();
|
||||||
parsed_events.use(theMiddleware);
|
parsed_events.use(theMiddleware);
|
||||||
}
|
};
|
||||||
|
|
||||||
function theMiddleware(command: string, event: any, client: Client, next: () => void) {
|
function theMiddleware(command: string, event: any, client: Client, next: () => void) {
|
||||||
next();
|
next();
|
||||||
|
|
26
src/plugins/middleware/middleware.d.ts
vendored
26
src/plugins/middleware/middleware.d.ts
vendored
|
@ -7,17 +7,19 @@ type LatestTimestamp = "*" | Timestamp;
|
||||||
declare module "irc-framework" {
|
declare module "irc-framework" {
|
||||||
interface Client {
|
interface Client {
|
||||||
chatHistory: {
|
chatHistory: {
|
||||||
batches: Map<number, Promise<void>>;
|
eventbus: EventEmitter;
|
||||||
addCallback: (id: number, callback: (data?: void | PromiseLike<void>) => Promise<void>) => void;
|
before(target: string, timestamp: Timestamp, limit?: number): void;
|
||||||
async runCallback(id: number): void;
|
after(target: string, timestamp: Timestamp, limit?: number): void;
|
||||||
|
latest(target: string, timestamp?: LatestTimestamp, limit?: number): void;
|
||||||
async before(target: string, timestamp: Timestamp, limit: number): Promise<any>;
|
around(target: string, timestamp: Timestamp, limit?: number): void;
|
||||||
async after(target: string, timestamp: Timestamp, limit: number): Promise<any>;
|
between(
|
||||||
async latest(target: string, timestamp: LatestTimestamp, limit: number): Promise<any>;
|
target: string,
|
||||||
async around(target: string, timestamp: Timestamp, limit: number): Promise<any>;
|
timestamp1: Timestamp,
|
||||||
async between(target: string, timestamp1: Timestamp, timestamp2: Timestamp, limit: number): Promise<any>;
|
timestamp2: Timestamp,
|
||||||
async targets(timestamp1: Timestamp, timestamp2: Timestamp, limit: number): Promise<any>;
|
limit?: number
|
||||||
async targets(target: string, timestamp: Timestamp): Promise<any>;
|
): void;
|
||||||
}
|
targets(timestamp1: Timestamp, timestamp2: Timestamp, limit?: number): void;
|
||||||
|
targets(target: string, timestamp: Timestamp): void;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
src/types/modules/irc-framework.d.ts
vendored
18
src/types/modules/irc-framework.d.ts
vendored
|
@ -5,7 +5,7 @@
|
||||||
// https://raw.githubusercontent.com/eternagame/HTML-Chat/vue-rewrite/src/app/types/modules/irc-framework/irc-framework.d.ts
|
// https://raw.githubusercontent.com/eternagame/HTML-Chat/vue-rewrite/src/app/types/modules/irc-framework/irc-framework.d.ts
|
||||||
// TODO: Fix this
|
// TODO: Fix this
|
||||||
declare module "irc-framework" {
|
declare module "irc-framework" {
|
||||||
import { EventEmitter } from "eventemitter3";
|
import {EventEmitter} from "eventemitter3";
|
||||||
// import { DuplexStream } from 'stream';
|
// import { DuplexStream } from 'stream';
|
||||||
import Connection from "irc-framework/src/transports/websocket";
|
import Connection from "irc-framework/src/transports/websocket";
|
||||||
|
|
||||||
|
@ -23,7 +23,11 @@ declare module "irc-framework" {
|
||||||
end: () => void;
|
end: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type IRCMiddleware = (client: Client, raw_events: Array<string>, parsed_events: any) => void;
|
export type IRCMiddleware = (
|
||||||
|
client: Client,
|
||||||
|
raw_events: Array<string>,
|
||||||
|
parsed_events: any
|
||||||
|
) => void;
|
||||||
|
|
||||||
export interface MessageEventArgs {
|
export interface MessageEventArgs {
|
||||||
account?: any;
|
account?: any;
|
||||||
|
@ -33,7 +37,7 @@ declare module "irc-framework" {
|
||||||
message: string;
|
message: string;
|
||||||
nick: string;
|
nick: string;
|
||||||
reply: (message: string) => void;
|
reply: (message: string) => void;
|
||||||
tags: { [key: string]: string };
|
tags: {[key: string]: string};
|
||||||
target: string;
|
target: string;
|
||||||
time?: any;
|
time?: any;
|
||||||
type: "privmsg" | "action"; // TODO
|
type: "privmsg" | "action"; // TODO
|
||||||
|
@ -47,6 +51,7 @@ declare module "irc-framework" {
|
||||||
ident: string;
|
ident: string;
|
||||||
nick: string;
|
nick: string;
|
||||||
time?: any;
|
time?: any;
|
||||||
|
batch?: any;
|
||||||
}
|
}
|
||||||
export interface KickEventArgs {
|
export interface KickEventArgs {
|
||||||
kicked: string;
|
kicked: string;
|
||||||
|
@ -72,6 +77,7 @@ declare module "irc-framework" {
|
||||||
time?: any;
|
time?: any;
|
||||||
channel?: string;
|
channel?: string;
|
||||||
kicked?: string;
|
kicked?: string;
|
||||||
|
batch?: any;
|
||||||
}
|
}
|
||||||
interface Mode {
|
interface Mode {
|
||||||
mode: string;
|
mode: string;
|
||||||
|
@ -113,7 +119,7 @@ declare module "irc-framework" {
|
||||||
PREFIX: any;
|
PREFIX: any;
|
||||||
CHANMODES: string;
|
CHANMODES: string;
|
||||||
NICKLEN: string;
|
NICKLEN: string;
|
||||||
'DRAFT/CHATHISTORY': number;
|
"DRAFT/CHATHISTORY": number;
|
||||||
CHATHISTORY: number;
|
CHATHISTORY: number;
|
||||||
};
|
};
|
||||||
cap: {
|
cap: {
|
||||||
|
@ -145,8 +151,6 @@ declare module "irc-framework" {
|
||||||
// TODO
|
// TODO
|
||||||
/** Request */ requestCap(capability: string[]): void;
|
/** Request */ requestCap(capability: string[]): void;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
use(a: IRCMiddleware): any;
|
use(a: IRCMiddleware): any;
|
||||||
|
|
||||||
connect(connect_options?: Record<string, unknown>): void;
|
connect(connect_options?: Record<string, unknown>): void;
|
||||||
|
@ -233,7 +237,7 @@ declare module "irc-framework" {
|
||||||
match_regex: string,
|
match_regex: string,
|
||||||
cb: (event: Event) => any,
|
cb: (event: Event) => any,
|
||||||
message_type: string
|
message_type: string
|
||||||
): { stop: () => void };
|
): {stop: () => void};
|
||||||
|
|
||||||
matchNotice(match_regex: string, cb: (event: Event) => any): void;
|
matchNotice(match_regex: string, cb: (event: Event) => any): void;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue