Skip to content

Commit

Permalink
feat(ctx): AppContext is self-contained
Browse files Browse the repository at this point in the history
fixes #1177
  • Loading branch information
SgtPooki committed Apr 28, 2022
1 parent 4528b5b commit ab6a04c
Show file tree
Hide file tree
Showing 15 changed files with 146 additions and 68 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ assets/webui
*.nupkg
*.bak
assets/build/snap-hooks
.envrc
.tool-versions
.vscode
6 changes: 5 additions & 1 deletion src/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ const { join } = require('path')
const { app } = require('electron')
const { existsSync, mkdirSync } = require('fs')

module.exports = async function (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
module.exports = async function (ctx) {
// workaround: recursive mkdir https://github.com/Countly/countly-sdk-nodejs/pull/14
const countlyDataDir = join(app.getPath('userData'), 'countly-data')
if (!existsSync(countlyDataDir)) {
Expand Down
10 changes: 9 additions & 1 deletion src/argv-files-handler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const fs = require('fs-extra')
const addToIpfs = require('./add-to-ipfs')

/**
*
* @param {Awaited<import('./context')>} ctx
*/
async function argvHandler (argv, ctx) {
let handled = false

Expand All @@ -25,7 +29,11 @@ async function argvHandler (argv, ctx) {
return handled
}

module.exports = async function (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
module.exports = async function (ctx) {
// Checks current proccess
await argvHandler(process.argv, ctx)
}
Expand Down
14 changes: 11 additions & 3 deletions src/auto-updater/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ function isAutoUpdateSupported () {
let updateNotification = null // must be a global to avoid gc
let feedback = false

function setup (ctx = require('../context')) {
/**
*
* @param {Awaited<import('../context')>} ctx
*/
function setup (ctx) {
// we download manually in 'update-available'
autoUpdater.autoDownload = false
autoUpdater.autoInstallOnAppQuit = true
Expand Down Expand Up @@ -149,7 +153,11 @@ async function checkForUpdates () {
ipcMain.emit('updatingEnded')
}

module.exports = async function (ctx = require('../context')) {
/**
*
* @param {Awaited<import('../context')>} ctx
*/
module.exports = async function (ctx) {
if (['test', 'development'].includes(process.env.NODE_ENV)) {
ctx.manualCheckForUpdates = () => {
showDialog({
Expand All @@ -167,7 +175,7 @@ module.exports = async function (ctx = require('../context')) {
return
}

setup(ctx = require('../context'))
setup(ctx)

checkForUpdates() // background check

Expand Down
43 changes: 28 additions & 15 deletions src/context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
// @ts-check
const setupI18n = require('./i18n')
const setupDaemon = require('./daemon')
const setupWebUI = require('./webui')
const setupAppMenu = require('./app-menu')
const setupAutoUpdater = require('./auto-updater')
const setupTray = require('./tray')
const setupAnalytics = require('./analytics')
const handleError = require('./handleError')

/**
* @typedef createDaemonResponse
Expand Down Expand Up @@ -38,21 +46,26 @@ const context = {
}

/**
* @type {ProxyHandler<AppContext>}
* @function
* @param {AppContext} target
* @param {string|symbol} property
* @param {any} value
* @param {any} receiver
*
* This is only temporary, in order to catch any unnecessary setting of properties, and also to document the order of them.
* @type {Promise<AppContext>}
*/
const contextSetterProxyHandler = {
set (target, property, value, receiver) {
console.log(`property: `, property);
const ctx = (async () => {
try {
await setupAnalytics(context) // ctx.countlyDeviceId
await setupI18n()
await setupAppMenu()

return true
}
}
await setupWebUI(context) // ctx.webui, launchWebUI
await setupAutoUpdater(context) // ctx.manualCheckForUpdates
await setupTray(context) // ctx.tray
await setupDaemon(context) // ctx.getIpfsd, startIpfs, stopIpfs, restartIpfs
} catch (err) {
handleError(err)
}

return context
})()

module.exports = new Proxy(context, contextSetterProxyHandler)
/**
* @type {Promise<AppContext>}
*/
module.exports = ctx
12 changes: 10 additions & 2 deletions src/custom-ipfs-binary.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ const dock = require('./utils/dock')

const SETTINGS_KEY = 'binaryPath'

async function setCustomBinary (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
async function setCustomBinary (ctx) {
await dock.run(async () => {
logger.info('[custom binary] request to change')
let opt = showDialog({
Expand Down Expand Up @@ -57,7 +61,11 @@ async function setCustomBinary (ctx = require('./context')) {
})
}

function clearCustomBinary (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
function clearCustomBinary (ctx) {
store.delete(SETTINGS_KEY)
logger.info('[custom binary] cleared')

Expand Down
8 changes: 6 additions & 2 deletions src/daemon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ const logger = require('../common/logger')
const { STATUS } = require('./consts')
const createDaemon = require('./daemon')

module.exports = async function (ctx = require('../context')) {
/**
*
* @param {Awaited<import('../context')>} ctx
*/
module.exports = async function (ctx) {
let ipfsd = null
let status = null
let wasOnline = null
Expand All @@ -23,7 +27,7 @@ module.exports = async function (ctx = require('../context')) {
}

if (!ipfsd) {
await ipfsNotRunningDialog(ctx = require('../context'))
await ipfsNotRunningDialog(ctx)
}

return ipfsd
Expand Down
20 changes: 20 additions & 0 deletions src/handleError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const logger = require('./common/logger')
const { criticalErrorDialog } = require('./dialogs')

/**
*
* @param {Error} err
* @returns
*/
function handleError (err) {
// Ignore network errors that might happen during the
// execution.
if (err.stack.includes('net::')) {
return
}

logger.error(err)
criticalErrorDialog(err)
}

module.exports = handleError
37 changes: 5 additions & 32 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,18 @@ if (process.env.NODE_ENV === 'test') {
}

const fixPath = require('fix-path')
const { criticalErrorDialog } = require('./dialogs')
const logger = require('./common/logger')
const setupProtocolHandlers = require('./protocol-handlers')
const setupI18n = require('./i18n')
const setupNpmOnIpfs = require('./npm-on-ipfs')
const setupDaemon = require('./daemon')
const setupWebUI = require('./webui')
const setupAutoLaunch = require('./auto-launch')
const setupAutoGc = require('./automatic-gc')
const setupPubsub = require('./enable-pubsub')
const setupNamesysPubsub = require('./enable-namesys-pubsub')
const setupTakeScreenshot = require('./take-screenshot')
const setupAppMenu = require('./app-menu')
const setupArgvFilesHandler = require('./argv-files-handler')
const setupAutoUpdater = require('./auto-updater')
const setupTray = require('./tray')
const setupIpfsOnPath = require('./ipfs-on-path')
const setupAnalytics = require('./analytics')
const setupSecondInstance = require('./second-instance')
const ctx = require('./context')
const appContext = require('./context')
const handleError = require('./handleError')

// Hide Dock
if (app.dock) app.dock.hide()
Expand All @@ -43,22 +35,10 @@ fixPath()
if (!app.requestSingleInstanceLock()) {
process.exit(0)
}

app.on('will-finish-launching', () => {
setupProtocolHandlers(ctx)
app.on('will-finish-launching', async () => {
setupProtocolHandlers(await appContext)
})

function handleError (err) {
// Ignore network errors that might happen during the
// execution.
if (err.stack.includes('net::')) {
return
}

logger.error(err)
criticalErrorDialog(err)
}

process.on('uncaughtException', handleError)
process.on('unhandledRejection', handleError)

Expand All @@ -71,14 +51,7 @@ async function run () {
}

try {
await setupAnalytics(ctx) // ctx.countlyDeviceId
await setupI18n(ctx)
await setupAppMenu(ctx)

await setupWebUI(ctx) // ctx.webui, launchWebUI
await setupAutoUpdater(ctx) // ctx.manualCheckForUpdates
await setupTray(ctx) // ctx.tray
await setupDaemon(ctx) // ctx.getIpfsd, startIpfs, stopIpfs, restartIpfs
const ctx = await appContext

await Promise.all([
setupArgvFilesHandler(ctx),
Expand Down
9 changes: 7 additions & 2 deletions src/npm-on-ipfs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ const npmBin = IS_WIN ? 'npm.cmd' : 'npm'

const CONFIG_KEY = 'experiments.npmOnIpfs'

// Deprecated in February 2021. Remove soon.
module.exports = function (ctx = require('../context')) {
/**
* Deprecated in February 2021. Remove soon.
*
* @deprecated
* @param {Awaited<import('../context')>} ctx
*/
module.exports = function (ctx) {
if (store.get(CONFIG_KEY, null) === true) {
logger.info('[npm on ipfs] deprecated, removing')
store.delete(CONFIG_KEY)
Expand Down
10 changes: 9 additions & 1 deletion src/protocol-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ function parseAddr (addr) {
return toUri(addr.toString().includes('/http') ? addr : addr.encapsulate('/http'))
}

/**
*
* @param {Awaited<import('./context')>} ctx
*/
async function parseUrl (url, ctx) {
const ipfsd = ctx.getIpfsd ? await ctx.getIpfsd(true) : null
let base = 'https://ipfs.io'
Expand Down Expand Up @@ -43,7 +47,11 @@ async function argvHandler (argv, ctx) {
return handled
}

module.exports = function (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
module.exports = function (ctx) {
// Handle if the app started running now, and a link
// was sent to be handled.
argvHandler(process.argv, ctx)
Expand Down
6 changes: 5 additions & 1 deletion src/second-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ const { app } = require('electron')
const { argvHandler: protocolHandler } = require('./protocol-handlers')
const { argvHandler: filesHandler } = require('./argv-files-handler')

module.exports = async function (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
module.exports = async function (ctx) {
app.on('second-instance', async (_, argv) => {
if (await protocolHandler(argv, ctx)) {
return
Expand Down
18 changes: 15 additions & 3 deletions src/take-screenshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ function onError (e) {
})
}

function handleScreenshot (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
function handleScreenshot (ctx) {
const { getIpfsd, launchWebUI } = ctx

return async (_, output) => {
Expand Down Expand Up @@ -99,13 +103,21 @@ function handleScreenshot (ctx = require('./context')) {
}
}

function takeScreenshot (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
function takeScreenshot (ctx) {
const { webui } = ctx
logger.info('[screenshot] taking screenshot')
webui.webContents.send('screenshot')
}

module.exports = function (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
module.exports = function (ctx) {
setupGlobalShortcut({
confirmationDialog: {
title: i18n.t('enableGlobalTakeScreenshotShortcut.title'),
Expand Down
10 changes: 7 additions & 3 deletions src/tray.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ function buildCheckbox (key, label) {
* or other OSes and must be registered globally. They still collide with global
* accelerator. Please see ../utils/setup-global-shortcut.js for more info.
*
* @param {import('./context')} ctx
* @param {Awaited<import('./context')>} ctx
*
* @returns {import('electron').Menu} Electron.CrossProcessExports.Menu
*/
function buildMenu (ctx = require('./context')) {
function buildMenu (ctx) {
return Menu.buildFromTemplate([
...[
['ipfsIsStarting', 'yellow'],
Expand Down Expand Up @@ -240,7 +240,11 @@ function icon (color) {
// https://www.electronjs.org/docs/faq#my-apps-tray-disappeared-after-a-few-minutes
let tray = null

module.exports = function (ctx = require('./context')) {
/**
*
* @param {Awaited<import('./context')>} ctx
*/
module.exports = async function (ctx) {
logger.info('[tray] starting')
tray = new Tray(icon(off))
let menu = null
Expand Down
Loading

0 comments on commit ab6a04c

Please sign in to comment.