mirror of
https://github.com/thelounge/thelounge.git
synced 2024-06-15 20:15:11 +02:00
feat(irc framework): support (client) tags
It is now possible to receive, send and process client tags in general using the IRC framework. This is useful for many client-oriented IRCv3 features: typing, reacts, replies, channel contexts, etc.
This commit is contained in:
parent
9f05a75c39
commit
ab678f1ef5
|
@ -35,6 +35,7 @@
|
||||||
"../server/models/user.ts",
|
"../server/models/user.ts",
|
||||||
"../server/models/msg.ts",
|
"../server/models/msg.ts",
|
||||||
"../server/models/prefix.ts",
|
"../server/models/prefix.ts",
|
||||||
|
"../server/models/client-tags.ts",
|
||||||
"./js/helpers/fullnamemap.json",
|
"./js/helpers/fullnamemap.json",
|
||||||
"./js/helpers/simplemap.json",
|
"./js/helpers/simplemap.json",
|
||||||
"../webpack.config.ts",
|
"../webpack.config.ts",
|
||||||
|
|
36
server/models/client-tags.ts
Normal file
36
server/models/client-tags.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
export enum ClientTagKey {
|
||||||
|
// https://ircv3.net/specs/client-tags/reply
|
||||||
|
DRAFT_REPLY = "draft/reply",
|
||||||
|
// https://ircv3.net/specs/client-tags/react
|
||||||
|
DRAFT_REACT = "draft/react",
|
||||||
|
// https://ircv3.net/specs/client-tags/channel-context
|
||||||
|
DRAFT_CHANNEL_CONTEXT = "draft/channel-context",
|
||||||
|
|
||||||
|
// https://ircv3.net/specs/client-tags/typing.html
|
||||||
|
TYPING = "typing",
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClientTags {
|
||||||
|
reaction?: string;
|
||||||
|
repliedTo?: string;
|
||||||
|
channelContext?: string;
|
||||||
|
rawTags: Record<string, string>;
|
||||||
|
|
||||||
|
public constructor(rawClientTags: Record<string, string>) {
|
||||||
|
this.rawTags = rawClientTags;
|
||||||
|
|
||||||
|
this.reaction = this.get(ClientTagKey.DRAFT_REACT);
|
||||||
|
this.repliedTo = this.get(ClientTagKey.DRAFT_REPLY);
|
||||||
|
this.channelContext = this.get(ClientTagKey.DRAFT_CHANNEL_CONTEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: string): string | undefined {
|
||||||
|
return this.rawTags[`+${key}`];
|
||||||
|
}
|
||||||
|
|
||||||
|
public has(key: string): boolean {
|
||||||
|
return Object.prototype.hasOwnProperty.call(this.rawTags, `+${key}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import {LinkPreview} from "../plugins/irc-events/link";
|
import {LinkPreview} from "../plugins/irc-events/link";
|
||||||
import User from "./user";
|
import User from "./user";
|
||||||
|
import {ClientTags} from "./client-tags";
|
||||||
|
|
||||||
export type UserInMessage = Partial<User> & {
|
export type UserInMessage = Partial<User> & {
|
||||||
mode: string;
|
mode: string;
|
||||||
|
@ -18,6 +19,7 @@ export enum MessageType {
|
||||||
LOGIN = "login",
|
LOGIN = "login",
|
||||||
LOGOUT = "logout",
|
LOGOUT = "logout",
|
||||||
MESSAGE = "message",
|
MESSAGE = "message",
|
||||||
|
TAGMSG = "tagmsg",
|
||||||
MODE = "mode",
|
MODE = "mode",
|
||||||
MODE_CHANNEL = "mode_channel",
|
MODE_CHANNEL = "mode_channel",
|
||||||
MODE_USER = "mode_user", // RPL_UMODEIS
|
MODE_USER = "mode_user", // RPL_UMODEIS
|
||||||
|
@ -61,6 +63,8 @@ class Msg {
|
||||||
gecos!: string;
|
gecos!: string;
|
||||||
account!: boolean;
|
account!: boolean;
|
||||||
|
|
||||||
|
client_tags: ClientTags;
|
||||||
|
|
||||||
// these are all just for error:
|
// these are all just for error:
|
||||||
error!: string;
|
error!: string;
|
||||||
nick!: string;
|
nick!: string;
|
||||||
|
@ -87,6 +91,8 @@ class Msg {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.client_tags = new ClientTags({});
|
||||||
|
|
||||||
_.defaults(this, attr, {
|
_.defaults(this, attr, {
|
||||||
from: {},
|
from: {},
|
||||||
id: 0,
|
id: 0,
|
||||||
|
|
|
@ -5,8 +5,22 @@ import Helper from "../../helper";
|
||||||
import {IrcEventHandler} from "../../client";
|
import {IrcEventHandler} from "../../client";
|
||||||
import Chan, {ChanType} from "../../models/chan";
|
import Chan, {ChanType} from "../../models/chan";
|
||||||
import User from "../../models/user";
|
import User from "../../models/user";
|
||||||
|
import {ClientTags} from "../../models/client-tags";
|
||||||
|
|
||||||
const nickRegExp = /(?:\x03[0-9]{1,2}(?:,[0-9]{1,2})?)?([\w[\]\\`^{|}-]+)/g;
|
const nickRegExp = /(?:\x03[0-9]{1,2}(?:,[0-9]{1,2})?)?([\w[\]\\`^{|}-]+)/g;
|
||||||
|
type MessageData = {
|
||||||
|
nick: string;
|
||||||
|
hostname: string;
|
||||||
|
ident: string;
|
||||||
|
target: string;
|
||||||
|
type: MessageType;
|
||||||
|
time: number;
|
||||||
|
tags: Record<string, string>;
|
||||||
|
text?: string;
|
||||||
|
from_server?: boolean;
|
||||||
|
message: string;
|
||||||
|
group?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default <IrcEventHandler>function (irc, network) {
|
export default <IrcEventHandler>function (irc, network) {
|
||||||
const client = this;
|
const client = this;
|
||||||
|
@ -26,6 +40,11 @@ export default <IrcEventHandler>function (irc, network) {
|
||||||
handleMessage(data);
|
handleMessage(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
irc.on("tagmsg", function (data) {
|
||||||
|
data.type = MessageType.TAGMSG;
|
||||||
|
// TODO: handleTagMessage(data);
|
||||||
|
});
|
||||||
|
|
||||||
irc.on("privmsg", function (data) {
|
irc.on("privmsg", function (data) {
|
||||||
data.type = MessageType.MESSAGE;
|
data.type = MessageType.MESSAGE;
|
||||||
handleMessage(data);
|
handleMessage(data);
|
||||||
|
@ -37,18 +56,7 @@ export default <IrcEventHandler>function (irc, network) {
|
||||||
handleMessage(data);
|
handleMessage(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleMessage(data: {
|
function handleMessage(data: MessageData) {
|
||||||
nick: string;
|
|
||||||
hostname: string;
|
|
||||||
ident: string;
|
|
||||||
target: string;
|
|
||||||
type: MessageType;
|
|
||||||
time: number;
|
|
||||||
text?: string;
|
|
||||||
from_server?: boolean;
|
|
||||||
message: string;
|
|
||||||
group?: string;
|
|
||||||
}) {
|
|
||||||
let chan: Chan | undefined;
|
let chan: Chan | undefined;
|
||||||
let from: User;
|
let from: User;
|
||||||
let highlight = false;
|
let highlight = false;
|
||||||
|
@ -131,6 +139,7 @@ export default <IrcEventHandler>function (irc, network) {
|
||||||
from: from,
|
from: from,
|
||||||
highlight: highlight,
|
highlight: highlight,
|
||||||
users: [],
|
users: [],
|
||||||
|
client_tags: new ClientTags(data.tags),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (showInActive) {
|
if (showInActive) {
|
||||||
|
|
18
server/types/modules/irc-framework.d.ts
vendored
18
server/types/modules/irc-framework.d.ts
vendored
|
@ -31,7 +31,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: Record<string, string>;
|
||||||
target: string;
|
target: string;
|
||||||
time?: any;
|
time?: any;
|
||||||
type: "privmsg" | "action" | "notice" | "wallops";
|
type: "privmsg" | "action" | "notice" | "wallops";
|
||||||
|
@ -44,6 +44,7 @@ declare module "irc-framework" {
|
||||||
ident: string;
|
ident: string;
|
||||||
nick: string;
|
nick: string;
|
||||||
time?: any;
|
time?: any;
|
||||||
|
tags: Record<string, string>;
|
||||||
}
|
}
|
||||||
export interface KickEventArgs {
|
export interface KickEventArgs {
|
||||||
kicked: string;
|
kicked: string;
|
||||||
|
@ -176,10 +177,23 @@ declare module "irc-framework" {
|
||||||
|
|
||||||
sendMessage(commandName: string, target: string, message: string): string[];
|
sendMessage(commandName: string, target: string, message: string): string[];
|
||||||
|
|
||||||
|
sendMessage(
|
||||||
|
commandName: string,
|
||||||
|
target: string,
|
||||||
|
message: string,
|
||||||
|
tags: Record<string, string> = {}
|
||||||
|
): string[];
|
||||||
|
|
||||||
say(target: string, message: string): string[];
|
say(target: string, message: string): string[];
|
||||||
|
|
||||||
|
say(target: string, message: string, tags: Record<string, string>): string[];
|
||||||
|
|
||||||
notice(target: string, message: string): string[];
|
notice(target: string, message: string): string[];
|
||||||
|
|
||||||
|
notice(target: string, message: string, tags: Record<string, string>): string[];
|
||||||
|
|
||||||
|
tagmsg(target: string, tags: Record<string, string> = {}): string[];
|
||||||
|
|
||||||
join(channel: string, key?: string): void;
|
join(channel: string, key?: string): void;
|
||||||
|
|
||||||
part(channel: string, message?: string): void;
|
part(channel: string, message?: string): void;
|
||||||
|
@ -292,7 +306,7 @@ declare module "irc-framework" {
|
||||||
|
|
||||||
reply(e: any): any;
|
reply(e: any): any;
|
||||||
|
|
||||||
tags: Record<string, unknown>;
|
tags: Record<string, string>;
|
||||||
|
|
||||||
// any
|
// any
|
||||||
time?: any;
|
time?: any;
|
||||||
|
|
Loading…
Reference in a new issue