Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: analytics #1068

Merged
merged 14 commits into from
Sep 12, 2019
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.5.5",
"auto-launch": "^5.0.5",
"countly-sdk-nodejs": "^19.8.0",
"electron-serve": "^0.3.0",
"electron-store": "^4.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
2 changes: 2 additions & 0 deletions src/webui/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { screen, BrowserWindow, ipcMain, app, session } from 'electron'
import { join } from 'path'
import { URL } from 'url'
import serve from 'electron-serve'
import openExternal from './open-external'
import logger from '../common/logger'
Expand Down Expand Up @@ -76,6 +77,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: () => {}
}
}