Skip to content
This repository has been archived by the owner on Jul 25, 2023. It is now read-only.

Commit

Permalink
release 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
FlysoftBeta committed Jul 18, 2023
1 parent 64d40a6 commit c3d4b4d
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 41 deletions.
14 changes: 6 additions & 8 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
export const id = "no-revoked-message" as const;

export const defaults: PluginConfig = {
switchConfigItem: false,
anotherSwitchConfigItem: false,
inputConfigItem: "默认值",
dropdownConfigItem: "A",
maxMessagesCount: 10000,
maxRevokedMessagesCount: 5000,
autoSaveDuration: 120,
};
export function getPluginConfig(config: Config | undefined) {
return Object.assign({}, defaults, config?.[id] || {});
}

export interface PluginConfig {
switchConfigItem: boolean;
anotherSwitchConfigItem: boolean;
inputConfigItem: string;
dropdownConfigItem: "A" | "B" | "C";
maxMessagesCount: 100 | 1000 | 5000 | 10000 | 20000 | 50000 | 100000;
maxRevokedMessagesCount: 100 | 1000 | 5000 | 10000 | 20000 | 50000 | 100000;
autoSaveDuration: 60 | 120 | 300;
}
export type Config = {
[X in typeof id]?: Partial<PluginConfig>;
Expand Down
110 changes: 106 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,112 @@
import { env, interrupt } from "qqntim/main";
import { getPluginConfig } from "./config";
import * as qqntim from "qqntim/main";
import { randomUUID } from "crypto";
import { app } from "electron";
import { s } from "./utils/sep";
import { modules } from "qqntim/main";
const { fs } = modules;

export default class Entry implements QQNTim.Entry.Main {
private messages = new Map<string, any>();
private revokedMessages = new Map<string, any>();
private changesRequested = false;
constructor() {
const config = getPluginConfig(qqntim.env.config.plugins.config);
console.log("[Template] Hello world!", qqntim);
console.log("[Template] 当前插件配置:", config);
const config = getPluginConfig(env.config.plugins.config);

interrupt.ipc(
(args) => {
args?.[1]?.[0]?.payload?.msgList?.forEach((msg) => {
const id = msg.msgId;
this.messages.set(id, msg);
if (this.messages.size > config.maxMessagesCount)
for (const [id] of this.messages.entries()) {
this.messages.delete(id);
break;
}
});
},
{ eventName: "ns-ntApi", cmdName: "nodeIKernelMsgListener/onRecvMsg", direction: "out", type: "request" },
);

interrupt.ipc(
(args) => {
if (args?.[1]?.[0]?.payload?.msgList)
args[1][0].payload.msgList = args[1][0].payload.msgList.map((msg) => {
const id = msg.msgId;
if (msg.elements[0]?.grayTipElement?.revokeElement && !msg.elements[0].grayTipElement.revokeElement.isSelfOperate) {
const storedMsg = this.messages.get(id);
this.revokedMessages.set(id, storedMsg);
if (this.revokedMessages.size > config.maxRevokedMessagesCount)
for (const [id] of this.revokedMessages.entries()) {
this.revokedMessages.delete(id);
break;
}
this.changesRequested = true;
return storedMsg;
}
return msg;
});
},
{ eventName: "ns-ntApi", cmdName: "nodeIKernelMsgListener/onMsgInfoListUpdate", direction: "out", type: "request" },
);

interrupt.ipc(
(args) => {
const processMsg = (msg) => {
const id = msg.msgId;
const storedMsg = this.revokedMessages.get(id);
if (storedMsg)
return {
...storedMsg,
elements: [
...storedMsg.elements,
{
elementType: 1,
elementId: randomUUID(),
textElement: {
content: "\n(已被撤回)",
atType: 0,
atUid: "0",
atTinyId: "0",
atNtUid: "",
subElementType: 0,
atChannelId: "0",
},
},
],
};
return msg;
};
if (args?.[1]?.[0]?.payload?.msgList) args[1][0].payload.msgList = args[1][0].payload.msgList.map(processMsg);
else if (args?.[1]?.msgList) args[1].msgList = args[1].msgList.map(processMsg);
},
{ eventName: "ns-ntApi", direction: "out" },
);

const dataFile = `${env.path.dataDir}${s}revoked-messages.json`;
if (fs.existsSync(dataFile)) {
this.revokedMessages = new Map(fs.readJSONSync(dataFile));
console.log(`[NoRevokedMessages] 已成功从 ${dataFile} 加载 ${this.revokedMessages.size} 条被撤回的消息`);
}

const saveChanges = async () => {
if (!this.changesRequested) return;
this.changesRequested = false;
console.log(`[NoRevokedMessages] 正在保存撤回已消息数据到 ${dataFile}`);
await fs.writeJSON(dataFile, Array.from(this.revokedMessages));
};
const scheduleSaveChanges = () => {
setTimeout(async () => {
await saveChanges();
scheduleSaveChanges();
}, config.autoSaveDuration * 1000);
};
scheduleSaveChanges();
app.on("before-quit", (event) => {
if (this.changesRequested) {
event.preventDefault();
saveChanges().then(() => app.quit());
}
});
}
}
11 changes: 1 addition & 10 deletions src/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1 @@
import { getPluginConfig } from "./config";
import * as qqntim from "qqntim/renderer";

export default class Entry implements QQNTim.Entry.Renderer {
constructor() {
const config = getPluginConfig(qqntim.env.config.plugins.config);
console.log("[Template] Hello world!", qqntim);
console.log("[Template] 当前插件配置:", config);
}
}
export default class Entry implements QQNTim.Entry.Renderer {}
57 changes: 38 additions & 19 deletions src/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,60 @@ import { getPluginConfig } from "./config";
export default class Entry implements QQNTim.Entry.Renderer {
constructor() {
// 如果不需要设置界面,将下一行注释掉即可;如果需要在设置项目旁边加一个小图标,请将 `undefined` 改为一段 HTML 代码(可以是 `<svg>`, `<img>` 等等)。
defineSettingsPanels(["模板插件设置", SettingsPanel, undefined]);
defineSettingsPanels(["防撤回插件", SettingsPanel, undefined]);
}
}

function SettingsPanel({ config: _config, setConfig: _setConfig }: QQNTim.Settings.PanelProps) {
const [pluginConfig, setPluginConfig] = usePluginConfig(_config, _setConfig);
const currentPluginConfigString = useMemo(() => JSON.stringify(getPluginConfig(env.config.plugins.config)), []);

return (
<>
<SettingsSection title="插件设置">
<SettingsBox>
<SettingsBoxItem title="当前生效的插件配置:" description={[currentPluginConfigString]} />
<SettingsBoxItem title="开关" description={["这是一个开关。", `当前状态为:${pluginConfig.switchConfigItem ? "开" : "关"}`]}>
<Switch checked={pluginConfig.switchConfigItem} onToggle={(state) => setPluginConfig("switchConfigItem", state)} />
<SettingsBoxItem title="暂存的最大消息数量" description={["指定允许暂存的最大消息数量。当数量到达设定值时,将会清除最早的消息。防撤回对已经被清除的消息无效。"]}>
<Dropdown
items={[
[100 as const, "100 条"],
[1000 as const, "1000 条"],
[5000 as const, "5000 条"],
[10000 as const, "10000 条"],
[20000 as const, "20000 条"],
[50000 as const, "50000 条"],
[100000 as const, "100000 条"],
]}
selected={pluginConfig.maxMessagesCount}
onChange={(state) => setPluginConfig("maxMessagesCount", state)}
width="200px"
/>
</SettingsBoxItem>
{pluginConfig.switchConfigItem && (
<SettingsBoxItem title="另一个开关" description={["这是另一个开关。", `当前状态为:${pluginConfig.anotherSwitchConfigItem ? "开" : "关"}`]}>
<Switch checked={pluginConfig.anotherSwitchConfigItem} onToggle={(state) => setPluginConfig("anotherSwitchConfigItem", state)} />
</SettingsBoxItem>
)}
<SettingsBoxItem title="下拉菜单" description={["这是一个下拉菜单。", `当前状态为:${pluginConfig.dropdownConfigItem}`]}>
<SettingsBoxItem title="允许的最大被撤回消息数量" description={["指定允许存储的最大被撤回消息数量。当数量到达设定值时,将会清除最早的消息。"]}>
<Dropdown
items={[
["A" as const, "我是 A 选项"],
["B" as const, "我是 B 选项"],
["C" as const, "我是 C 选项"],
[100 as const, "100 条"],
[1000 as const, "1000 条"],
[5000 as const, "5000 条"],
[10000 as const, "10000 条"],
[20000 as const, "20000 条"],
[50000 as const, "50000 条"],
[100000 as const, "100000 条"],
]}
selected={pluginConfig.dropdownConfigItem}
onChange={(state) => setPluginConfig("dropdownConfigItem", state)}
width="150px"
selected={pluginConfig.maxRevokedMessagesCount}
onChange={(state) => setPluginConfig("maxRevokedMessagesCount", state)}
width="200px"
/>
</SettingsBoxItem>
<SettingsBoxItem title="输入框" description={["这是一个输入框。", `当前状态为:${pluginConfig.inputConfigItem}`]} isLast={true}>
<Input value={pluginConfig.inputConfigItem} onChange={(state) => setPluginConfig("inputConfigItem", state)} />
<SettingsBoxItem title="自动保存时间间隔" description={["指定自动保存已撤回消息的时间间隔。"]}>
<Dropdown
items={[
[60 as const, "1 分钟"],
[120 as const, "2 分钟"],
[300 as const, "5 分钟"],
]}
selected={pluginConfig.autoSaveDuration}
onChange={(state) => setPluginConfig("autoSaveDuration", state)}
width="200px"
/>
</SettingsBoxItem>
</SettingsBox>
</SettingsSection>
Expand Down
1 change: 1 addition & 0 deletions src/utils/sep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { sep as s } from "path";

0 comments on commit c3d4b4d

Please sign in to comment.