Skip to content

Commit

Permalink
feat: analytics (#1068)
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Henrique Dias <hacdias@gmail.com>
  • Loading branch information
hacdias authored Sep 12, 2019
1 parent ecd06e1 commit a884bb9
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 14 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"clean:webui": "shx rm -rf assets/webui/",
"build": "run-s build:*",
"build:webui": "run-s build:webui:*",
"build:webui:download": "npx ipfs-or-gateway -c QmYcP4sp1nraBiCYi6i9kqdaKobrK32yyMpTrM5JDA8a2C -p assets/webui/ -t 360000 --verbose",
"build:webui:download": "npx ipfs-or-gateway -c QmXiJ7c7MmYB1zzTDy2QsnTpkgokT8V6f1zrLzLktDkyHt -p assets/webui/ -t 360000 --verbose",
"build:webui:minimize": "shx rm -rf assets/webui/static/js/*.map && shx rm -rf assets/webui/static/css/*.map",
"build:babel": "babel src --out-dir out --copy-files --source-maps",
"build:binaries": "electron-builder --publish onTag"
Expand Down Expand Up @@ -77,6 +77,7 @@
"dependencies": {
"@babel/runtime": "^7.6.0",
"auto-launch": "^5.0.5",
"countly-sdk-nodejs": "^19.8.0",
"electron-serve": "^0.3.0",
"electron-store": "^5.0.0",
"electron-updater": "^4.1.2",
Expand Down
2 changes: 1 addition & 1 deletion src/add-to-ipfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default async function ({ getIpfsd, launchWebUI }, file) {
return
}

logger.info(`[add to ipfs] started ${file}`)
logger.info(`[add to ipfs] started ${file}`, { withAnalytics: 'ADD_VIA_DESKTOP' })
ipfsd.api.addFromFs(file, { recursive: true }, async (err, result) => {
if (err) {
logger.error(`[add to ipfs] ${err.toString()}`)
Expand Down
22 changes: 22 additions & 0 deletions src/analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Countly from 'countly-sdk-nodejs'
import { ipcMain } from 'electron'
import { COUNTLY_KEY } from './common/consts'

export default async function (ctx) {
Countly.init({
url: 'https://countly.ipfs.io',
app_key: COUNTLY_KEY,
debug: process.env.NODE_ENV === 'development',
require_consent: true
})

ctx.countlyDeviceId = Countly.device_id

ipcMain.on('countly.addConsent', (_, consent) => {
Countly.add_consent(consent)
})

ipcMain.on('countly.removeConsent', (_, consent) => {
Countly.remove_consent(consent)
})
}
45 changes: 44 additions & 1 deletion src/common/logger.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { createLogger, format, transports } from 'winston'
import { join } from 'path'
import { app } from 'electron'
import { performance } from 'perf_hooks'
import Countly from 'countly-sdk-nodejs'

const { combine, splat, timestamp, printf } = format
const logsPath = app.getPath('userData')
Expand Down Expand Up @@ -37,4 +39,45 @@ const logger = createLogger({

logger.info(`[meta] logs can be found on ${logsPath}`)

export default logger
export default {
start: (msg, opts = {}) => {
const start = performance.now()
logger.info(`${msg} STARTED`)

return {
end: () => {
const seconds = (performance.now() - start) / 1000

if (opts.withAnalytics) {
Countly.add_event({
key: opts.withAnalytics,
count: 1,
dur: seconds
})
}

logger.info(`${msg} FINISHED ${seconds}s`)
},
fail: (err) => {
Countly.log_error(err)
logger.error(`${msg} ${err.toString()}`)
}
}
},

info: (msg, opts = {}) => {
if (opts.withAnalytics) {
Countly.add_event({
key: opts.withAnalytics,
count: 1
})
}

logger.info(msg)
},

error: (err) => {
Countly.log_error(err)
logger.error(err)
}
}
4 changes: 4 additions & 0 deletions src/create-toggler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ipcMain } from 'electron'
import store from './common/store'
import logger from './common/logger'

export default function ({ webui }, settingsOption, activate) {
ipcMain.on('config.toggle', async (_, opt) => {
Expand All @@ -14,6 +15,9 @@ export default function ({ webui }, settingsOption, activate) {
if (await activate(newValue, oldValue)) {
store.set(settingsOption, newValue)
success = true

const action = newValue ? 'enabled' : 'disabled'
logger.info(`[${settingsOption}] ${action}`)
}

webui.webContents.send('config.changed', {
Expand Down
8 changes: 4 additions & 4 deletions src/daemon/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export default async function (ctx) {
return
}

const log = logger.start('[ipfsd] start daemon', { withAnalytics: 'DAEMON_START' })
const config = store.get('ipfsConfig')
logger.info('[ipfsd] starting daemon')
updateStatus(STATUS.STARTING_STARTED)

if (config.path) {
Expand All @@ -70,7 +70,7 @@ export default async function (ctx) {
writeIpfsPath(config.path)
}

logger.info('[ipfsd] daemon started')
log.end()
updateStatus(STATUS.STARTING_FINISHED)
} catch (err) {
logger.error(`[ipfsd] ${err.toString}`)
Expand All @@ -83,7 +83,7 @@ export default async function (ctx) {
return
}

logger.info('[ipfsd] stopping daemon')
const log = logger.start('[ipfsd] stop daemon', { withAnalytics: 'DAEMON_STOP' })
updateStatus(STATUS.STOPPING_STARTED)

if (!fs.pathExists(join(ipfsd.repoPath, 'config'))) {
Expand All @@ -97,7 +97,7 @@ export default async function (ctx) {
// give ipfs 3s to stop. An unclean shutdown is preferable to making the
// user wait, and taking longer prevents the update mechanism from working.
await ipfsd.stop(180)
logger.info('[ipfsd] daemon stopped')
log.end()
updateStatus(STATUS.STOPPING_FINISHED)
} catch (err) {
logger.error(`[ipfsd] ${err.toString}`)
Expand Down
2 changes: 1 addition & 1 deletion src/download-hash.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export async function downloadHash (ctx) {
let files

try {
logger.info(`[hash download] downloading ${text}: started`)
logger.info(`[hash download] downloading ${text}: started`, { withAnalytics: 'DOWNLOAD_HASH' })
files = await ipfsd.api.get(text)
logger.info(`[hash download] downloading ${text}: completed`)
} catch (err) {
Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import setupArgvFilesHandler from './argv-files-handler'
import setupAutoUpdater from './auto-updater'
import setupTray from './tray'
import setupIpfsOnPath from './ipfs-on-path'
import setupAnalytics from './analytics'

// Hide Dock
if (app.dock) app.dock.hide()
Expand Down Expand Up @@ -53,6 +54,7 @@ async function run () {
}

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

Expand Down
2 changes: 1 addition & 1 deletion src/move-repository-location.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function ({ stopIpfs, startIpfs }) {

config.path = newDir
store.set('ipfsConfig', config)
logger.info('[move repository] configuration updated')
logger.info('[move repository] configuration updated', { withAnalytics: 'MOVE_REPOSITORY' })

showDialog({
title: i18n.t('moveRepositorySuccessDialog.title'),
Expand Down
3 changes: 0 additions & 3 deletions src/setup-global-shortcut.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { globalShortcut, ipcMain } from 'electron'
import createToggler from './create-toggler'
import logger from './common/logger'
import store from './common/store'
import { IS_MAC } from './common/consts'

Expand All @@ -12,10 +11,8 @@ export default function (ctx, { settingsOption, accelerator, action }) {

if (value === true) {
globalShortcut.register(accelerator, action)
logger.info(`[${settingsOption}] shortcut enabled`)
} else {
globalShortcut.unregister(accelerator)
logger.info(`[${settingsOption}] shortcut disabled`)
}

return true
Expand Down
2 changes: 1 addition & 1 deletion src/take-screenshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function handleScreenshot (ctx) {
baseName += '.png'
}

logger.info(`[screenshot] started: writing screenshots to ${baseName}`)
logger.info(`[screenshot] started: writing screenshots to ${baseName}`, { withAnalytics: 'SCREENSHOT_TAKEN' })
let lastImage = null

for (const { name, image } of output) {
Expand Down
1 change: 1 addition & 0 deletions src/webui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export default async function (ctx) {

const url = new URL('/', 'webui://-')
url.hash = '/'
url.searchParams.set('deviceId', ctx.countlyDeviceId)

function updateLanguage () {
url.searchParams.set('lng', store.get('language'))
Expand Down
19 changes: 19 additions & 0 deletions src/webui/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ ipcRenderer.on('updatedPage', (_, url) => {
window.ipfsDesktop = {
countlyAppKey: COUNTLY_KEY,

countlyDeviceId: urlParams.get('deviceId'),

countlyActions: [
'ADD_VIA_DESKTOP',
'DAEMON_START',
'DAEMON_STOP',
'DOWNLOAD_HASH',
'MOVE_REPOSITORY',
'SCREENSHOT_TAKEN'
],

version: VERSION,

onConfigChanged: (listener) => {
Expand Down Expand Up @@ -75,6 +86,14 @@ window.ipfsDesktop = {
resolve(files)
})
})
},

removeConsent: (consent) => {
ipcRenderer.send('countly.removeConsent', consent)
},

addConsent: (consent) => {
ipcRenderer.send('countly.addConsent', consent)
}
}

Expand Down
5 changes: 4 additions & 1 deletion test/unit/create-toggler.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@ import dirtyChai from 'dirty-chai'
import mockElectron from './mocks/electron'
import mockStore from './mocks/store'
import mockWebUI from './mocks/webui'
import mockLogger from './mocks/logger'

const proxyquire = require('proxyquire').noCallThru()
chai.use(dirtyChai)

describe('Create toggler', () => {
const option = 'OPT'
let electron, store, webui, createToggler
let electron, store, webui, createToggler, logger

beforeEach(() => {
electron = mockElectron()
store = mockStore()
webui = mockWebUI()
logger = mockLogger()
createToggler = proxyquire('../../src/create-toggler', {
electron: electron,
'./common/logger': logger,
'./common/store': store
}).default
})
Expand Down
7 changes: 7 additions & 0 deletions test/unit/mocks/logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function () {
return {
start: () => {},
info: () => {},
error: () => {}
}
}

0 comments on commit a884bb9

Please sign in to comment.