From eecdcebb01dfabc5d8012c4b865079afa1a46722 Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Tue, 27 Oct 2020 14:42:49 -0400 Subject: [PATCH] Adds caching to public servers Also fixes bug found by Tropical regarding confirming close with live update enabled. --- .eslintrc | 1 + src/builtins/customcss.js | 1 + src/builtins/emotes/emotes.js | 22 +---- src/structs/psconnection.js | 128 +++++++++++++++++--------- src/ui/publicservers/menu.js | 27 +----- src/ui/settings/components/search.jsx | 13 ++- 6 files changed, 103 insertions(+), 89 deletions(-) diff --git a/.eslintrc b/.eslintrc index dc148d58..c7e3905e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -107,6 +107,7 @@ "Proxy": "readonly", "Set": "readonly", "WeakMap": "readonly", + "Map": "readonly", "Promise": "readonly", "ace": "readonly", "Reflect": "readonly", diff --git a/src/builtins/customcss.js b/src/builtins/customcss.js index 3d7dae5d..db35b8c9 100644 --- a/src/builtins/customcss.js +++ b/src/builtins/customcss.js @@ -148,6 +148,7 @@ export default new class CustomCSS extends Builtin { children: editor, confirmClose: () => { if (!editorRef || !editorRef.current) return false; + if (Settings.get("settings", "customcss", "liveUpdate")) return false; return editorRef.current.hasUnsavedChanges; }, confirmationText: Strings.CustomCSS.confirmationText diff --git a/src/builtins/emotes/emotes.js b/src/builtins/emotes/emotes.js index e3cf69c2..1ba5ee7c 100644 --- a/src/builtins/emotes/emotes.js +++ b/src/builtins/emotes/emotes.js @@ -273,24 +273,4 @@ export default new class EmoteModule extends Builtin { for (const cat of categories) DataStore.invalidateCache("emotes", cat); this.loadEmoteData(); } -}; - - -// (async () => { -// const emoteData = await new Promise(resolve => { -// const req = require("request"); -// req.get({url: "https://twitchemotes.com/api_cache/v3/global.json", json: true}, (err, resp, parsedData) => { -// for (const emote in parsedData) { -// if (emote.length < 4 || window.bemotes.includes(emote)) { -// delete parsedData[emote]; -// continue; -// } -// parsedData[emote] = parsedData[emote].id; -// } -// resolve(parsedData); -// }); -// }); -// const fs = require("fs"); -// fs.writeFileSync("Z:\\Programming\\BetterDiscordStuff\\BetterDiscordApp\\data\\emotes\\global.json", JSON.stringify(emoteData)); -// return emoteData; -// })(); \ No newline at end of file +}; \ No newline at end of file diff --git a/src/structs/psconnection.js b/src/structs/psconnection.js index 91b2350c..6a98e385 100644 --- a/src/structs/psconnection.js +++ b/src/structs/psconnection.js @@ -6,44 +6,96 @@ const InviteActions = WebpackModules.getByProps("acceptInvite"); const BrowserWindow = require("electron").remote.BrowserWindow; +const betterDiscordServer = { + name: "BetterDiscord", + members: 55000, + categories: ["community", "programming", "support"], + description: "Official BetterDiscord server for plugins, themes, support, etc", + identifier: "86004744966914048", + iconUrl: "https://cdn.discordapp.com/icons/86004744966914048/292e7f6bfff2b71dfd13e508a859aedd.webp", + nativejoin: true, + invite_code: "BJD2yvJ", + pinned: true, + insertDate: 1517806800 +}; -export default class PublicServersConnection { +export default new class PublicServersConnection { - static get endPoint() {return "https://search.discordservers.com";} - static get joinEndPoint() {return "https://j.discordservers.com";} - static get connectEndPoint() {return "https://auth.discordservers.com/info";} + constructor() { + this.cache = new Map(); + this.cache.set("featured", [betterDiscordServer]); + this.cache.set("popular", []); + this.cache.set("keywords", []); + this.cache.set("accessToken", ""); - static getDefaultAvatar() { + window.debugPS = this; + } + + get endPoint() {return "https://search.discordservers.com";} + get joinEndPoint() {return "https://j.discordservers.com";} + get connectEndPoint() {return "https://auth.discordservers.com/info";} + + getDefaultAvatar() { return AvatarDefaults.DEFAULT_AVATARS[Math.floor(Math.random() * 5)]; } - static hasJoined(id) { + hasJoined(id) { return SortedGuildStore.getFlattenedGuildIds().includes(id); } - static search({term = "", keyword = "", from = 0} = {}) { - const request = require("request"); - return new Promise(resolve => { - const queries = []; - if (keyword) queries.push(`keyword=${keyword.replace(/ /g, "%20").toLowerCase()}`); - if (term) queries.push(`term=${term.replace(/ /g, "%20")}`); - if (from) queries.push(`from=${from}`); - const query = `?${queries.join("&")}`; - request.get({url: `${this.endPoint}${query}${query ? "&schema=new" : "?schema=new"}`, json: true}, (err, resp, data) => { - if (err) return resolve(null); - const next = data.size + data.from; - resolve({ - servers: data.results, - size: data.size, - from: data.from, - total: data.total, - next: next >= data.total ? null : next - }); - }); - }); + async search({term = "", keyword = "", from = 0} = {}) { + if (this.cache.has(term + keyword + from)) return this.cache.get(term + keyword + from); + + const queries = []; + if (keyword) queries.push(`keyword=${keyword.replace(/ /g, "%20").toLowerCase()}`); + if (term) queries.push(`term=${term.replace(/ /g, "%20")}`); + if (from) queries.push(`from=${from}`); + const query = `?${queries.join("&")}`; + + try { + const response = await fetch(`${this.endPoint}${query}`, {method: "GET"}); + const data = await response.json(); + const next = data.size + data.from; + const results = { + servers: data.results, + size: data.size, + from: data.from, + total: data.total, + next: next >= data.total ? null : next + }; + this.cache.set(term + keyword + from, results); + return results; + } + catch (error) { + return null; + } } - static async join(id, native = false) { + async getDashboard() { + const cachedKeywords = this.cache.get("keywords"); + if (cachedKeywords && cachedKeywords.length) return {featured: this.cache.get("featured"), popular: this.cache.get("popular"), keywords: cachedKeywords}; + try { + const response = await fetch(`${this.endPoint}/dashboard`, {method: "GET"}); + const data = await response.json(); + + const featuredFirst = data.results[0].key === "featured"; + const featuredServers = data.results[featuredFirst ? 0 : 1].response.hits; + const popularServers = data.results[featuredFirst ? 1 : 0].response.hits; + const mainKeywords = data.mainKeywords.map(k => k.charAt(0).toUpperCase() + k.slice(1)).sort(); + + featuredServers.unshift(betterDiscordServer); + + this.cache.set("featured", featuredServers); + this.cache.set("popular", popularServers); + this.cache.set("keywords", mainKeywords); + return {featured: this.cache.get("featured"), popular: this.cache.get("popular"), keywords: this.cache.get("keywords")}; + } + catch (error) { + return {featured: this.cache.get("featured"), popular: this.cache.get("popular"), keywords: this.cache.get("keywords")}; + } + } + + async join(id, native = false) { if (native) return InviteActions.acceptInvite(id); try { await fetch(`${this.joinEndPoint}/${id}`,{ @@ -62,7 +114,7 @@ export default class PublicServersConnection { } } - static async checkConnection() { + async checkConnection() { try { const response = await fetch(this.connectEndPoint, { method: "GET", @@ -82,20 +134,7 @@ export default class PublicServersConnection { } } - static async getDashboard() { - try { - const response = await fetch(`${this.endPoint}/dashboard`, { - method: "GET" - }); - const data = await response.json(); - return data; - } - catch (error) { - return false; - } - } - - static connect() { + connect() { return new Promise(resolve => { const joinWindow = new BrowserWindow(this.windowOptions); const url = `https://auth.discordservers.com/connect?scopes=guilds.join&previousUrl=${this.connectEndPoint}`; @@ -108,7 +147,7 @@ export default class PublicServersConnection { }); } - static get windowOptions() { + get windowOptions() { return { width: 490, height: 500, @@ -125,5 +164,4 @@ export default class PublicServersConnection { } }; } - -} +}; diff --git a/src/ui/publicservers/menu.js b/src/ui/publicservers/menu.js index 80ff1f50..17f53f16 100644 --- a/src/ui/publicservers/menu.js +++ b/src/ui/publicservers/menu.js @@ -11,19 +11,6 @@ const SettingsView = WebpackModules.getByDisplayName("SettingsView"); const GuildActions = WebpackModules.getByProps("transitionToGuildSync"); const LayerManager = WebpackModules.getByProps("popLayer"); -const betterDiscordServer = { - name: "BetterDiscord", - members: 55000, - categories: ["community", "programming", "support"], - description: "Official BetterDiscord server for plugins, themes, support, etc", - identifier: "86004744966914048", - iconUrl: "https://cdn.discordapp.com/icons/86004744966914048/292e7f6bfff2b71dfd13e508a859aedd.webp", - nativejoin: true, - invite_code: "BJD2yvJ", - pinned: true, - insertDate: 1517806800 -}; - export default class PublicServers extends React.Component { constructor(props) { @@ -67,19 +54,15 @@ export default class PublicServers extends React.Component { async getDashboard() { const dashboardData = await Connection.getDashboard(); - const featuredFirst = dashboardData.results[0].key === "featured"; - const featuredServers = dashboardData.results[featuredFirst ? 0 : 1].response.hits; - const popularServers = dashboardData.results[featuredFirst ? 1 : 0].response.hits; - const mainKeywords = dashboardData.mainKeywords.map(k => k.charAt(0).toUpperCase() + k.slice(1)).sort(); - - featuredServers.unshift(betterDiscordServer); - this.featured = featuredServers; - this.popular = popularServers; - this.keywords = mainKeywords; + this.featured = dashboardData.featured; + this.popular = dashboardData.popular; + this.keywords = dashboardData.keywords; this.setState({loading: false}); this.changeTab(this.state.tab); + + if (!this.keywords || !this.keywords.length) Modals.showConfirmationModal("Connection Error", "There was an error connecting to DiscordServers.com, it's possible their website/api is down. Please try again later."); } async connect() { diff --git a/src/ui/settings/components/search.jsx b/src/ui/settings/components/search.jsx index 21686612..eefdeb5d 100644 --- a/src/ui/settings/components/search.jsx +++ b/src/ui/settings/components/search.jsx @@ -2,9 +2,20 @@ import {React} from "modules"; import SearchIcon from "../../icons/search"; export default class Search extends React.Component { + constructor(props) { + super(props); + this.state = {value: this.props.value}; + this.onChange = this.onChange.bind(this); + } + + onChange(e) { + this.setState({value: e.target.value}); + if (this.props.onChange) this.props.onChange(e); + } + render() { return
- +
; }