Tweaks to !server numbers. Try to prevent unnecessary API calls.
!server can now also use numbers from the invite of servers with a vanity URL. API calls for the invite and the REST guild endpoint are now memoized. Since Guild.fetchAllMembers() now returns a promise, tweaked refreshMembersIfNeeded() to not make unnecessary API calls if called multiple times in rapid succession.
This commit is contained in:
parent
ba647c69ce
commit
6a5e71d7c1
2 changed files with 61 additions and 9 deletions
|
@ -44,6 +44,7 @@ import {
|
|||
trimLines,
|
||||
UnknownUser,
|
||||
downloadFile,
|
||||
memoize,
|
||||
} from "../utils";
|
||||
import { GuildLogs } from "../data/GuildLogs";
|
||||
import { LogType } from "../data/LogType";
|
||||
|
@ -103,8 +104,8 @@ const SEARCH_ID_RESULTS_PER_PAGE = 50;
|
|||
|
||||
const MAX_CLEAN_COUNT = 150;
|
||||
const MAX_CLEAN_TIME = 1 * DAYS;
|
||||
const CLEAN_COMMAND_DELETE_DELAY = 5000;
|
||||
const MEMBER_REFRESH_FREQUENCY = 10 * 60 * 1000; // How often to do a full member refresh when using !search or !roles --counts
|
||||
const CLEAN_COMMAND_DELETE_DELAY = 5 * SECONDS;
|
||||
const MEMBER_REFRESH_FREQUENCY = 10 * MINUTES; // How often to do a full member refresh when using commands that need it
|
||||
const SEARCH_EXPORT_LIMIT = 1_000_000;
|
||||
|
||||
const activeReloads: Map<string, TextChannel> = new Map();
|
||||
|
@ -137,6 +138,7 @@ export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
|
|||
protected archives: GuildArchives;
|
||||
|
||||
protected lastFullMemberRefresh = 0;
|
||||
protected fullMemberRefreshPromise;
|
||||
protected lastReload;
|
||||
|
||||
public static getStaticDefaultOptions(): IPluginOptions<TConfigSchema> {
|
||||
|
@ -206,9 +208,14 @@ export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
|
|||
}
|
||||
|
||||
protected async refreshMembersIfNeeded() {
|
||||
if (Date.now() < this.lastFullMemberRefresh + MEMBER_REFRESH_FREQUENCY) return;
|
||||
await this.guild.fetchAllMembers();
|
||||
if (Date.now() < this.lastFullMemberRefresh + MEMBER_REFRESH_FREQUENCY) {
|
||||
return this.fullMemberRefreshPromise;
|
||||
}
|
||||
|
||||
this.lastFullMemberRefresh = Date.now();
|
||||
this.fullMemberRefreshPromise = this.guild.fetchAllMembers();
|
||||
|
||||
return this.fullMemberRefreshPromise;
|
||||
}
|
||||
|
||||
@d.command("roles", "[search:string$]", {
|
||||
|
@ -1022,7 +1029,7 @@ export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
|
|||
})
|
||||
@d.permission("can_server")
|
||||
async serverCmd(msg: Message) {
|
||||
await this.guild.fetchAllMembers();
|
||||
await this.refreshMembersIfNeeded();
|
||||
|
||||
const embed: EmbedOptions = {
|
||||
fields: [],
|
||||
|
@ -1051,16 +1058,34 @@ export class UtilityPlugin extends ZeppelinPlugin<TConfigSchema> {
|
|||
`) + embedPadding,
|
||||
});
|
||||
|
||||
const onlineMemberCount = this.guild.members.filter(m => m.status !== "offline").length;
|
||||
const restGuild = await memoize(
|
||||
() => this.bot.getRESTGuild(this.guildId),
|
||||
`getRESTGuild_${this.guildId}`,
|
||||
10 * MINUTES,
|
||||
);
|
||||
|
||||
// For servers with a vanity URL, we can use the numbers from the invite for online count
|
||||
// (which is nowadays usually more accurate for large servers)
|
||||
const invite = this.guild.vanityURL
|
||||
? await memoize(
|
||||
() => this.bot.getInvite(this.guild.vanityURL, true),
|
||||
`getInvite_${this.guild.vanityURL}`,
|
||||
10 * MINUTES,
|
||||
)
|
||||
: null;
|
||||
|
||||
const totalMembers = invite ? invite.memberCount : this.guild.memberCount;
|
||||
|
||||
const onlineMemberCount = invite
|
||||
? invite.presenceCount
|
||||
: this.guild.members.filter(m => m.status !== "offline").length;
|
||||
const offlineMemberCount = this.guild.memberCount - onlineMemberCount;
|
||||
|
||||
const onlineStatusMemberCount = this.guild.members.filter(m => m.status === "online").length;
|
||||
const dndStatusMemberCount = this.guild.members.filter(m => m.status === "dnd").length;
|
||||
const idleStatusMemberCount = this.guild.members.filter(m => m.status === "idle").length;
|
||||
|
||||
const restGuild = await this.bot.getRESTGuild(this.guildId);
|
||||
|
||||
let memberCountTotalLines = `Total: **${formatNumber(this.guild.memberCount)}**`;
|
||||
let memberCountTotalLines = `Total: **${formatNumber(totalMembers)}**`;
|
||||
if (restGuild.maxMembers) {
|
||||
memberCountTotalLines += `\nMax: **${formatNumber(restGuild.maxMembers)}**`;
|
||||
}
|
||||
|
|
|
@ -1049,3 +1049,30 @@ const formatter = new Intl.NumberFormat("en-US");
|
|||
export function formatNumber(numberToFormat: number): string {
|
||||
return formatter.format(numberToFormat);
|
||||
}
|
||||
|
||||
interface IMemoizedItem {
|
||||
createdAt: number;
|
||||
value: any;
|
||||
}
|
||||
|
||||
const memoizeCache: Map<any, IMemoizedItem> = new Map();
|
||||
export function memoize<T>(fn: (...args: any[]) => T, key?, time?): T {
|
||||
const realKey = key ?? fn;
|
||||
|
||||
if (memoizeCache.has(realKey)) {
|
||||
const memoizedItem = memoizeCache.get(realKey);
|
||||
if (!time || memoizedItem.createdAt > Date.now() - time) {
|
||||
return memoizedItem.value;
|
||||
}
|
||||
|
||||
memoizeCache.delete(realKey);
|
||||
}
|
||||
|
||||
const value = fn();
|
||||
memoizeCache.set(realKey, {
|
||||
createdAt: Date.now(),
|
||||
value,
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue