WhoReacted: Make more reliable & don't spam api
This commit is contained in:
parent
bb398970ef
commit
b60f6cb18d
6 changed files with 104 additions and 13 deletions
|
@ -25,7 +25,7 @@ import { find } from "../webpack/webpack";
|
||||||
|
|
||||||
const queue = new Queue();
|
const queue = new Queue();
|
||||||
const setCss = debounce((css: string) => {
|
const setCss = debounce((css: string) => {
|
||||||
queue.add(() => VencordNative.ipc.invoke(IpcEvents.SET_QUICK_CSS, css));
|
queue.push(() => VencordNative.ipc.invoke(IpcEvents.SET_QUICK_CSS, css));
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function launchMonacoEditor() {
|
export async function launchMonacoEditor() {
|
||||||
|
|
|
@ -66,14 +66,14 @@ const settingsWriteQueue = new Queue();
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.GET_QUICK_CSS, () => readCss());
|
ipcMain.handle(IpcEvents.GET_QUICK_CSS, () => readCss());
|
||||||
ipcMain.handle(IpcEvents.SET_QUICK_CSS, (_, css) =>
|
ipcMain.handle(IpcEvents.SET_QUICK_CSS, (_, css) =>
|
||||||
cssWriteQueue.add(() => writeFile(QUICKCSS_PATH, css))
|
cssWriteQueue.push(() => writeFile(QUICKCSS_PATH, css))
|
||||||
);
|
);
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.GET_SETTINGS_DIR, () => SETTINGS_DIR);
|
ipcMain.handle(IpcEvents.GET_SETTINGS_DIR, () => SETTINGS_DIR);
|
||||||
ipcMain.on(IpcEvents.GET_SETTINGS, e => e.returnValue = readSettings());
|
ipcMain.on(IpcEvents.GET_SETTINGS, e => e.returnValue = readSettings());
|
||||||
|
|
||||||
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, s) => {
|
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, s) => {
|
||||||
settingsWriteQueue.add(() => writeFile(SETTINGS_FILE, s));
|
settingsWriteQueue.push(() => writeFile(SETTINGS_FILE, s));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,20 +16,56 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { User } from "discord-types/general";
|
import { ReactionEmoji, User } from "discord-types/general";
|
||||||
|
|
||||||
import ErrorBoundary from "../components/ErrorBoundary";
|
import ErrorBoundary from "../components/ErrorBoundary";
|
||||||
import { Devs } from "../utils/constants";
|
import { Devs } from "../utils/constants";
|
||||||
import { LazyComponent, lazyWebpack } from "../utils/misc";
|
import { LazyComponent, lazyWebpack, sleep, useForceUpdater } from "../utils/misc";
|
||||||
|
import { Queue } from "../utils/Queue";
|
||||||
import definePlugin from "../utils/types";
|
import definePlugin from "../utils/types";
|
||||||
import { filters, findByCode } from "../webpack";
|
import { filters, findByCode } from "../webpack";
|
||||||
import { ChannelStore, React, Tooltip } from "../webpack/common";
|
import { ChannelStore, FluxDispatcher, React, RestAPI, Tooltip } from "../webpack/common";
|
||||||
|
|
||||||
const UserSummaryItem = LazyComponent(() => findByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
|
const UserSummaryItem = LazyComponent(() => findByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
|
||||||
const AvatarStyles = lazyWebpack(filters.byProps("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar"));
|
const AvatarStyles = lazyWebpack(filters.byProps("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar"));
|
||||||
|
|
||||||
const ReactionStore = lazyWebpack(filters.byProps("getReactions"));
|
const ReactionStore = lazyWebpack(filters.byProps("getReactions"));
|
||||||
|
|
||||||
|
const queue = new Queue();
|
||||||
|
|
||||||
|
function fetchReactions(msg: Message, emoji: ReactionEmoji) {
|
||||||
|
const key = emoji.name + (emoji.id ? `:${emoji.id}` : "");
|
||||||
|
return RestAPI.get({
|
||||||
|
url: `/channels/${msg.channel_id}/messages/${msg.id}/reactions/${key}`,
|
||||||
|
query: {
|
||||||
|
limit: 100
|
||||||
|
},
|
||||||
|
oldFormErrors: true
|
||||||
|
})
|
||||||
|
.then(res => FluxDispatcher.dispatch({
|
||||||
|
type: "MESSAGE_REACTION_ADD_USERS",
|
||||||
|
channelId: msg.channel_id,
|
||||||
|
messageId: msg.id,
|
||||||
|
users: res.body,
|
||||||
|
emoji
|
||||||
|
}))
|
||||||
|
.catch(console.error)
|
||||||
|
.finally(() => sleep(250));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReactionsWithQueue(msg: Message, e: ReactionEmoji) {
|
||||||
|
const key = `${msg.id}:${e.name}:${e.id ?? ""}`;
|
||||||
|
const cache = ReactionStore.__getLocalVars().reactions[key] ??= { fetched: false, users: {} };
|
||||||
|
if (!cache.fetched) {
|
||||||
|
queue.unshift(() =>
|
||||||
|
fetchReactions(msg, e)
|
||||||
|
);
|
||||||
|
cache.fetched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache.users;
|
||||||
|
}
|
||||||
|
|
||||||
function makeRenderMoreUsers(users: User[]) {
|
function makeRenderMoreUsers(users: User[]) {
|
||||||
return function renderMoreUsers(_label: string, _count: number) {
|
return function renderMoreUsers(_label: string, _count: number) {
|
||||||
return (
|
return (
|
||||||
|
@ -62,7 +98,7 @@ export default definePlugin({
|
||||||
}],
|
}],
|
||||||
|
|
||||||
renderUsers(props: RootObject) {
|
renderUsers(props: RootObject) {
|
||||||
return (
|
return props.message.reactions.length > 10 ? null : (
|
||||||
<ErrorBoundary noop>
|
<ErrorBoundary noop>
|
||||||
<this._renderUsers {...props} />
|
<this._renderUsers {...props} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
@ -70,8 +106,19 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
_renderUsers({ message, emoji }: RootObject) {
|
_renderUsers({ message, emoji }: RootObject) {
|
||||||
const reactions = ReactionStore.getReactions(message.channel_id, message.id, emoji);
|
const forceUpdate = useForceUpdater();
|
||||||
const users = Object.values(reactions) as User[];
|
React.useEffect(() => {
|
||||||
|
const cb = (e: any) => {
|
||||||
|
if (e.messageId === message.id)
|
||||||
|
forceUpdate();
|
||||||
|
};
|
||||||
|
FluxDispatcher.subscribe("MESSAGE_REACTION_ADD_USERS", cb);
|
||||||
|
|
||||||
|
return () => FluxDispatcher.unsubscribe("MESSAGE_REACTION_ADD_USERS", cb);
|
||||||
|
}, [message.id]);
|
||||||
|
|
||||||
|
const reactions = getReactionsWithQueue(message, emoji);
|
||||||
|
const users = Object.values(reactions).filter(Boolean) as User[];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -79,7 +126,6 @@ export default definePlugin({
|
||||||
>
|
>
|
||||||
<UserSummaryItem
|
<UserSummaryItem
|
||||||
users={users}
|
users={users}
|
||||||
count={users.length}
|
|
||||||
guildId={ChannelStore.getChannel(message.channel_id)?.guild_id}
|
guildId={ChannelStore.getChannel(message.channel_id)?.guild_id}
|
||||||
renderIcon={false}
|
renderIcon={false}
|
||||||
max={5}
|
max={5}
|
||||||
|
|
|
@ -19,9 +19,48 @@
|
||||||
import { Promisable } from "type-fest";
|
import { Promisable } from "type-fest";
|
||||||
|
|
||||||
export class Queue {
|
export class Queue {
|
||||||
private promise: Promise<any> = Promise.resolve();
|
/**
|
||||||
|
* @param maxSize The maximum amount of functions that can be queued at once.
|
||||||
|
* If the queue is full, the oldest function will be removed.
|
||||||
|
*/
|
||||||
|
constructor(public maxSize = Infinity) { }
|
||||||
|
|
||||||
add<T>(func: (lastValue: unknown) => Promisable<T>): Promise<T> {
|
queue = [] as Array<() => Promisable<unknown>>;
|
||||||
return (this.promise = this.promise.then(func));
|
|
||||||
|
private promise?: Promise<any>;
|
||||||
|
|
||||||
|
private next() {
|
||||||
|
const func = this.queue.shift();
|
||||||
|
if (func)
|
||||||
|
this.promise = Promise.resolve()
|
||||||
|
.then(func)
|
||||||
|
.then(() => this.next());
|
||||||
|
else
|
||||||
|
this.promise = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private run() {
|
||||||
|
if (!this.promise)
|
||||||
|
this.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
push<T>(func: () => Promisable<T>) {
|
||||||
|
if (this.size >= this.maxSize)
|
||||||
|
this.queue.shift();
|
||||||
|
|
||||||
|
this.queue.push(func);
|
||||||
|
this.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
unshift<T>(func: () => Promisable<T>) {
|
||||||
|
if (this.size >= this.maxSize)
|
||||||
|
this.queue.pop();
|
||||||
|
|
||||||
|
this.queue.unshift(func);
|
||||||
|
this.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
get size() {
|
||||||
|
return this.queue.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,11 @@ export function useAwaiter<T>(factory: () => Promise<T>, fallbackValue: T | null
|
||||||
return [state.value, state.error, state.pending, () => setSignal(signal + 1)];
|
return [state.value, state.error, state.pending, () => setSignal(signal + 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useForceUpdater() {
|
||||||
|
const [, set] = React.useState(0);
|
||||||
|
return () => set(s => s + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lazy component. The factory method is called on first render. For example useful
|
* A lazy component. The factory method is called on first render. For example useful
|
||||||
* for const Component = LazyComponent(() => findByDisplayName("...").default)
|
* for const Component = LazyComponent(() => findByDisplayName("...").default)
|
||||||
|
|
|
@ -32,6 +32,7 @@ export const Flux = lazyWebpack(filters.byProps("connectStores"));
|
||||||
export let React: typeof import("react");
|
export let React: typeof import("react");
|
||||||
export const ReactDOM: typeof import("react-dom") = lazyWebpack(filters.byProps("createPortal", "render"));
|
export const ReactDOM: typeof import("react-dom") = lazyWebpack(filters.byProps("createPortal", "render"));
|
||||||
|
|
||||||
|
export const RestAPI = lazyWebpack(filters.byProps("getAPIBaseURL", "get"));
|
||||||
export const moment: typeof import("moment") = lazyWebpack(filters.byProps("parseTwoDigitYear"));
|
export const moment: typeof import("moment") = lazyWebpack(filters.byProps("parseTwoDigitYear"));
|
||||||
|
|
||||||
export const MessageStore = lazyWebpack(filters.byProps("getRawMessages")) as Omit<Stores.MessageStore, "getMessages"> & { getMessages(chanId: string): any; };
|
export const MessageStore = lazyWebpack(filters.byProps("getRawMessages")) as Omit<Stores.MessageStore, "getMessages"> & { getMessages(chanId: string): any; };
|
||||||
|
|
Loading…
Reference in a new issue