import installExtension, { REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer'; import { app, session, BrowserWindow, ipcMain } from 'electron'; import express from 'express'; import cors from 'cors'; import RPC from 'discord-rpc'; import { createProxyMiddleware } from 'http-proxy-middleware'; const PORT = 39511; const statics: string[] = []; let server: any; // This allows TypeScript to pick up the magic constant that's auto-generated by Forge's Webpack // plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on // whether you're running in development or production). declare const MAIN_WINDOW_WEBPACK_ENTRY: string; // Handle creating/removing shortcuts on Windows when installing/uninstalling. if (require('electron-squirrel-startup')) { // eslint-disable-line global-require app.quit(); } app.commandLine.appendSwitch('disable-web-security'); app.commandLine.appendSwitch('disable-site-isolation-trials'); const createWindow = (): void => { session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => { // We abuse the `iframe` name attribute to sneak in the target URL, to later use as a proxy target details.requestHeaders['X-Ace-ProxyTarget'] = details.frame.name; callback({ requestHeaders: details.requestHeaders, }); }); // Create the browser window. const mainWindow = new BrowserWindow({ width: 1200, height: 800, fullscreenable: true, frame: false, icon: 'extraResources/icon.ico', webPreferences: { webSecurity: false, nodeIntegration: true, enableRemoteModule: true, contextIsolation: false, }, }); mainWindow.setMenuBarVisibility(false); // and load the index.html of the app. mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY); installExtension(REACT_DEVELOPER_TOOLS) .then((name) => console.log(`Added Extension: ${name}`)) .catch((err) => console.log('An error occurred: ', err)); // Open the DevTools. mainWindow.webContents.openDevTools(); }; // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', createWindow); ipcMain.on('load-project', (event, arg) => { if (server) server.close(() => console.log('server closed')); statics.push(arg); server = express(); server.use(cors()); statics.forEach((s) => server.use(express.static(s))); server.use(createProxyMiddleware({ target: 'http://localhost:9696/', router: (req) => req.header('X-Ace-ProxyTarget'), changeOrigin: false, })); server = server.listen(PORT); }); // Quit when all windows are closed, except on macOS. There, it's common // for applications and their menu bar to stay active until the user quits // explicitly with Cmd + Q. app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); // Discord RPC Handling const DISCORD_CLIENT_ID = '891850893530652712'; const client = new RPC.Client({ transport: 'ipc' }); console.log('Logging in to Discord RPC...'); // Log in to RPC with client id client.login({ clientId: DISCORD_CLIENT_ID }).catch(console.error); // Handle state updates from renderer ipcMain.on('set-rpc-state', (_, state: string) => { client.setActivity({ largeImageKey: 'ace-icon-large', state, }); }); ipcMain.on('set-rpc-state-with-time', (_, state: string, startTimestamp) => { client.setActivity({ largeImageKey: 'ace-icon-large', state, startTimestamp, }); }); ipcMain.on('update-rpc-permission', (_, allowed: boolean) => { if (allowed) { client.setActivity({ largeImageKey: 'ace-icon-large', state: 'Idling', }); } else { client.clearActivity(); } });