1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

move ipc server to main process

This commit is contained in:
Dick Choi
2016-08-23 00:52:33 +09:00
parent cff3fdae6e
commit 17223db3ea
14 changed files with 146 additions and 512 deletions

View File

@@ -133,7 +133,7 @@ class NoteDetail extends React.Component {
/>
<button styleName='tabView-top-mode'
>
{mode.label}
{mode == null ? null : mode}
</button>
</div>
{snippet.mode === 'markdown'

View File

@@ -13,7 +13,7 @@ function killFinder () {
finderWindow.removeAllListeners()
if (global.process.platform === 'darwin') {
// Only OSX has another app process.
app.quit()
nodeIpc.of.node.emit('quit-from-finder')
} else {
finderWindow.close()
}
@@ -26,7 +26,7 @@ function toggleFinder () {
finderWindow.hide()
Menu.sendActionToFirstResponder('hide:')
} else {
nodeIpc.of.node.emit('request-data')
nodeIpc.of.node.emit('request-data-from-finder')
finderWindow.show()
}
} else {
@@ -34,17 +34,10 @@ function toggleFinder () {
finderWindow.blur()
finderWindow.hide()
} else {
nodeIpc.of.node.emit('request-data')
nodeIpc.of.node.emit('request-data-from-finder')
finderWindow.show()
finderWindow.focus()
}
// if (!finderWindow.isMinimized()) {
// finderWindow.minimize()
// } else {
// nodeIpc.of.node.emit('request-data')
// finderWindow.restore()
// finderWindow.focus()
// }
}
}
@@ -62,9 +55,10 @@ nodeIpc.connectTo(
console.log('disconnected')
})
nodeIpc.of.node.on('open-finder', function (payload) {
nodeIpc.of.node.on('open-finder', function () {
toggleFinder()
})
ipcRenderer.on('open-finder-from-tray', function () {
toggleFinder()
})
@@ -87,15 +81,15 @@ nodeIpc.connectTo(
})
nodeIpc.of.node.on('config-renew', function (payload) {
console.log('config', payload)
if (payload.ui.theme === 'dark') {
const { config } = payload
if (config.ui.theme === 'dark') {
document.body.setAttribute('data-theme', 'dark')
} else {
document.body.setAttribute('data-theme', 'default')
}
store.default.dispatch({
type: 'SET_CONFIG',
config: payload
config: config
})
})

View File

@@ -1,138 +0,0 @@
import _ from 'lodash'
import moment from 'moment'
import dataStore from './dataStore'
import { request, SERVER_URL } from './api'
import clientKey from './clientKey'
const electron = require('electron')
const version = electron.remote.app.getVersion()
function isSameDate (a, b) {
a = moment(a).utcOffset(+540).format('YYYYMMDD')
b = moment(b).utcOffset(+540).format('YYYYMMDD')
return a === b
}
export function init () {
let records = getAllRecords()
if (records == null) {
saveAllRecords([])
}
emit(null)
postRecords()
if (window != null) {
window.addEventListener('online', postRecords)
window.setInterval(postRecords, 1000 * 60 * 60 * 24)
}
}
export function getAllRecords () {
return JSON.parse(localStorage.getItem('activityRecords'))
}
export function saveAllRecords (records) {
localStorage.setItem('activityRecords', JSON.stringify(records))
}
/*
Post all records(except today)
and remove all posted records
*/
export function postRecords (data) {
if (process.env.NODE_ENV !== 'production') {
console.log('post failed - NOT PRODUCTION ')
return
}
let records = getAllRecords()
records = records.filter(record => {
return !isSameDate(new Date(), record.date)
})
if (records.length === 0) {
console.log('No records to post')
return
}
console.log('posting...', records)
let input = {
clientKey: clientKey.get(),
records
}
return request.post(SERVER_URL + 'apis/activity')
.send(input)
.then(res => {
let records = getAllRecords()
let todayRecord = _.find(records, record => {
return isSameDate(new Date(), record.date)
})
if (todayRecord != null) saveAllRecords([todayRecord])
else saveAllRecords([])
})
.catch(err => {
console.error(err)
})
}
export function emit (type, data = {}) {
let records = getAllRecords()
let index = _.findIndex(records, record => {
return isSameDate(new Date(), record.date)
})
let todayRecord
if (index < 0) {
todayRecord = {date: new Date()}
records.push(todayRecord)
}
else todayRecord = records[index]
switch (type) {
case 'ARTICLE_CREATE':
case 'ARTICLE_UPDATE':
case 'ARTICLE_DESTROY':
case 'FOLDER_CREATE':
case 'FOLDER_UPDATE':
case 'FOLDER_DESTROY':
case 'FINDER_OPEN':
case 'FINDER_COPY':
case 'MAIN_DETAIL_COPY':
case 'ARTICLE_SHARE':
todayRecord[type] = todayRecord[type] == null
? 1
: todayRecord[type] + 1
break
}
// Count ARTICLE_CREATE and ARTICLE_UPDATE again by syntax
if (type === 'ARTICLE_UPDATE' && data.mode != null) {
let recordKey = type + '_BY_SYNTAX'
if (todayRecord[recordKey] == null) todayRecord[recordKey] = {}
todayRecord[recordKey][data.mode] = todayRecord[recordKey][data.mode] == null
? 1
: todayRecord[recordKey][data.mode] + 1
}
let storeData = dataStore.getData()
todayRecord.FOLDER_COUNT = storeData && _.isArray(storeData.folders) ? storeData.folders.length : 0
todayRecord.ARTICLE_COUNT = storeData && _.isArray(storeData.articles) ? storeData.articles.length : 0
todayRecord.CLIENT_VERSION = version
todayRecord.SYNTAX_COUNT = storeData && _.isArray(storeData.articles) ? storeData.articles.reduce((sum, article) => {
if (sum[article.mode] == null) sum[article.mode] = 1
else sum[article.mode]++
return sum
}, {}) : 0
saveAllRecords(records)
}
export default {
init,
emit,
postRecords
}

View File

@@ -1,156 +0,0 @@
import keygen from './keygen'
import _ from 'lodash'
const electron = require('electron')
const remote = electron.remote
const jetpack = require('fs-jetpack')
const path = require('path')
let defaultContent = 'Boost is a brand new note App for programmers.\n\n> 下に日本語版があります。\n\n# \u25CEfeature\n\nBoost has some preponderant functions for efficient engineer\'s task.See some part of it.\n\n1. classify information by\u300CFolders\u300D\n2. deal with great variety of syntax\n3. Finder function\n\n\uFF0A\u3000\uFF0A\u3000\uFF0A\u3000\uFF0A\n\n# 1. classify information by \u300CFolders\u300D- access the information you needed easily.\n\n\u300CFolders\u300D which on the left side bar. Press plus button now. flexible way of classification.\n- Create Folder every language or flamework\n- Make Folder for your own casual memos\n\n# 2. Deal with a great variety of syntax \u2013 instead of your brain\nSave handy all information related with programming\n- Use markdown and gather api specification\n- Well using module and snippet\n\nSave them on Boost, you don\'t need to rewrite or re-search same code again.\n\n# 3. Load Finder function \u2013 now you don\'t need to spell command by hand typing.\n\n**Shift +ctrl+tab** press buttons at same time.\nThen, the window will show up for search Boost contents that instant.\n\nUsing cursor key to chose, press enter, cmd+v to paste and\u2026 please check it out by your own eye.\n\n- Such command spl or linux which programmers often use but troublesome to hand type\n\n- (Phrases commonly used for e-mail or customer support)\n\nWe support preponderant efficiency\n\n\uFF0A\u3000\uFF0A\u3000\uFF0A\u3000\uFF0A\n\n## \u25CEfor more information\nFrequently updated with this blog ( http:\/\/blog-jp.b00st.io )\n\nHave wonderful programmer life!\n\n## Hack your memory**\n\n\n\n# 日本語版\n\n**Boost**は全く新しいエンジニアライクのノートアプリです。\n\n# ◎特徴\nBoostはエンジニアの仕事を圧倒的に効率化するいくつかの機能を備えています。\nその一部をご紹介します。\n1. Folderで情報を分類\n2. 豊富なsyantaxに対応\n3. Finder機能\n\n\n   \n\n# 1. Folderで情報を分類、欲しい情報にすぐアクセス。\n左側のバーに存在する「Folders」。\n今すぐプラスボタンを押しましょう。\n分類の仕方も自由自在です。\n- 言語やフレームワークごとにFolderを作成\n- 自分用のカジュアルなメモをまとめる場としてFolderを作成\n\n\n# 2. 豊富なsyntaxに対応、自分の脳の代わりに。\nプログラミングに関する情報を全て、手軽に保存しましょう。\n- mdで、apiの仕様をまとめる\n- よく使うモジュールやスニペット\n\nBoostに保存しておくことで、何度も同じコードを書いたり調べたりする必要がなくなります。\n\n# 3. Finder機能を搭載、もうコマンドを手打ちする必要はありません。\n**「shift+ctrl+tab」** を同時に押してみてください。\nここでは、一瞬でBoostの中身を検索するウィンドウを表示させることができます。\n\n矢印キーで選択、Enterを押し、cmd+vでペーストすると…続きはご自身の目でお確かめください。\n- sqlやlinux等の、よく使うが手打ちが面倒なコマンド\n- (メールやカスタマーサポート等でよく使うフレーズ)\n\n私たちは、圧倒的な効率性を支援します。\n\   \n\n\n## ◎詳しくは\nこちらのブログ( http://blog-jp.b00st.io )にて随時更新しています。\n\nそれでは素晴らしいエンジニアライフを\n\n## Hack your memory'
let data = null
function getLocalPath () {
return path.join(remote.app.getPath('userData'), 'local.json')
}
function forgeInitialRepositories () {
let defaultRepo = {
key: keygen(),
name: 'local',
type: 'userData',
user: {
name: 'New user'
}
}
if (process.platform === 'darwin') {
defaultRepo.user.name = remote.process.env.USER
} else if (process.platform === 'win32') {
defaultRepo.user.name = remote.process.env.USERNAME
}
return [defaultRepo]
}
function getRepositories () {
let raw = localStorage.getItem('repositories')
try {
let parsed = JSON.parse(raw)
if (!_.isArray(parsed)) {
throw new Error('repositories data is corrupted. re-init data.')
}
return parsed
} catch (e) {
console.log(e)
let newRepos = forgeInitialRepositories()
saveRepositories(newRepos)
return newRepos
}
}
function saveRepositories (repos) {
localStorage.setItem('repositories', JSON.stringify(repos))
}
export function getUser (repoName) {
if (repoName == null) {
return getRepositories()[0]
}
return null
}
export function saveUser (repoName, user) {
let repos = getRepositories()
if (repoName == null) {
Object.assign(repos[0].user, user)
}
saveRepositories(repos)
}
export function init () {
// set repositories info
getRepositories()
data = jetpack.read(getLocalPath(), 'json')
if (data == null) {
let defaultFolder = {
name: 'default',
key: keygen()
}
let defaultArticle = {
title: 'About Boost',
tags: ['boost', 'intro'],
content: defaultContent,
mode: 'markdown',
key: keygen(),
FolderKey: defaultFolder.key,
createdAt: new Date(),
updatedAt: new Date()
}
data = {
articles: [defaultArticle],
folders: [defaultFolder],
version: '0.4'
}
saveData()
}
}
export function getData (forceRead) {
if (forceRead) {
try {
data = jetpack.read(getLocalPath(), 'json')
} catch (e) {}
}
return data
}
let timer = null
let isSaving = false
let saveAgain = false
function saveData () {
timer = null
isSaving = true
jetpack.writeAsync(getLocalPath(), data)
.then(function () {
isSaving = false
if (saveAgain) {
saveAgain = false
queueSave()
}
})
}
function queueSave () {
if (!isSaving) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(saveData, 500)
} else {
saveAgain = true
}
}
export function setArticles (articles) {
if (!_.isArray(articles)) throw new Error('Articles must be an array')
let data = getData()
data.articles = articles
queueSave()
}
export function setFolders (folders) {
if (!_.isArray(folders)) throw new Error('Folders must be an array')
let data = getData()
data.folders = folders
queueSave()
}
export default {
getUser,
saveUser,
init,
getData,
setArticles,
setFolders
}

View File

@@ -12,7 +12,6 @@ import _ from 'lodash'
import ConfigManager from 'browser/main/lib/ConfigManager'
import modal from 'browser/main/lib/modal'
import InitModal from 'browser/main/modals/InitModal'
import ipc from 'browser/main/lib/ipc'
class Main extends React.Component {
constructor (props) {

View File

@@ -4,14 +4,12 @@ import store from './store'
import React from 'react'
import ReactDOM from 'react-dom'
require('!!style!css!stylus?sourceMap!./global.styl')
import activityRecord from 'browser/lib/activityRecord'
import { Router, Route, IndexRoute, IndexRedirect, hashHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
require('./lib/ipcClient')
const electron = require('electron')
const ipc = electron.ipcRenderer
activityRecord.init()
ipc.send('check-update', 'check-update')
window.addEventListener('online', function () {
ipc.send('check-update', 'check-update')

View File

@@ -2,7 +2,7 @@ import _ from 'lodash'
const OSX = global.process.platform === 'darwin'
const electron = require('electron')
const { remote } = electron
const { ipcRenderer } = electron
const defaultConfig = {
zoom: 1,
@@ -73,9 +73,8 @@ function set (updates) {
document.body.setAttribute('data-theme', 'default')
}
remote.getCurrentWindow().webContents.send('config-renew', {
config: get(),
silent: false
ipcRenderer.send('config-renew', {
config: get()
})
}

View File

@@ -1,139 +0,0 @@
import store from 'browser/main/store'
import ConfigManager from 'browser/main/lib/ConfigManager'
const nodeIpc = require('node-ipc')
const { remote, ipcRenderer } = require('electron')
const { app, Menu } = remote
const path = require('path')
nodeIpc.config.id = 'node'
nodeIpc.config.retry = 1500
nodeIpc.config.silent = true
console.log('Initializing IPC Server')
// TODO: IPC SERVER WILL BE MOVED TO MAIN PROCESS FROM MAIN WINDOW PROCESS(RENDERER)
nodeIpc.serve(
path.join(app.getPath('userData'), 'boostnote.service'),
function () {
console.log('IPC Server Started')
ipcRenderer.on('open-finder', function () {
console.log('Open finder')
nodeIpc.server.broadcast('open-finder')
})
/** Quit Sequence
1. `quit-app` Main process -> Main window by Electron IPC
2. `quit-finder-app` Main window -> Finder window by Node IPC(socket)
3. Finder window (and Finder main process: OSX only) killed by remote API
4. `quit-finder-app-confirm` Finder window -> Main window by NodeIPC
5. `quit-app-confirm` Main window -> Main process by Electron IPC
6. Main process discard close preventer and terminate Main window and itself.
If the platform is a linux without cinnamon, the app will skip 2.-4. because it doesn't launch finder window.
`quit-app` will fires directly `quit-app-confirm`.
*/
ipcRenderer.on('quit-app', function () {
// Finder app exists only in the linux with cinnamon.
if (global.process.env.platform === 'linux' && global.process.env.DESKTOP_SESSION !== 'cinnamon') {
ipcRenderer.send('quit-app-confirm')
return
}
let confirmHandler = function () {
ipcRenderer.send('quit-app-confirm')
}
nodeIpc.server.on('quit-finder-app-confirm', confirmHandler)
setTimeout(() => {
nodeIpc.server.removeListener('quit-finder-app-confirm', confirmHandler)
}, 1000)
nodeIpc.server.broadcast('quit-finder-app')
})
/** Update Sequence
1. `update-ready` Main process -> Main window by Electron IPC
2. `update-app` Main window -> Main window by Electron IPC
3. `quit-finder-app` Main window -> Finder window by Node IPC
4. Finder window (and Finder main process: OSX only) killed by remote API
5. `quit-finder-app-confirm` Finder window -> Main window by NodeIPC
6. `update-app-confirm` Main window -> Main process by Electron IPC
7. Main process discard close preventer and start updating.
Handlers of 1. and 2. can be found in StatusBar component.
*/
ipcRenderer.on('update-app', function () {
// Linux app doesn't support auto updater
if (global.process.env.platform === 'linux') {
return
}
let confirmHandler = function () {
ipcRenderer.send('update-app-confirm')
}
nodeIpc.server.on('quit-finder-app-confirm', confirmHandler)
setTimeout(() => {
nodeIpc.server.removeListener('quit-finder-app-confirm', confirmHandler)
}, 1000)
nodeIpc.server.broadcast('quit-finder-app')
})
ipcRenderer.on('update-found', function () {
console.log('Update found')
})
let config = ConfigManager.get()
nodeIpc.server.broadcast('config-renew', config)
ipcRenderer.send('config-renew', {
config: config,
silent: true
})
ipcRenderer.on('config-renew', function (e, data) {
nodeIpc.server.broadcast('config-renew', data.config)
ipcRenderer.send('config-renew', data)
})
nodeIpc.server.on('open-main-from-finder', function () {
let mainWindow = remote.getCurrentWindow()
console.log('open main from finder')
if (mainWindow.isFocused()) {
if (global.process.platform === 'darwin') {
Menu.sendActionToFirstResponder('hide:')
} else {
mainWindow.minimize()
}
} else {
if (global.process.platform === 'darwin') {
mainWindow.show()
} else {
mainWindow.minimize()
mainWindow.restore()
}
}
})
nodeIpc.server.on('quit-from-finder', function () {
ipcRenderer.send('quit-app-confirm')
})
nodeIpc.server.on('connect', function (socket) {
console.log('connected')
nodeIpc.server.broadcast('config-renew', ConfigManager.get())
socket.on('close', function () {
console.log('socket dead')
})
})
nodeIpc.server.on('error', function (err) {
console.error('Node IPC error', err)
})
nodeIpc.server.on('request-data', function (data, socket) {
let state = store.getState()
nodeIpc.server.broadcast('throttle-data', {
storages: state.storages,
notes: state.notes
})
})
}
)
const ipc = {
}
nodeIpc.server.start()
module.exports = ipc

View File

@@ -0,0 +1,39 @@
import ConfigManager from './ConfigManager'
import store from 'browser/main/store'
const nodeIpc = require('node-ipc')
const { remote, ipcRenderer } = require('electron')
const { app } = remote
const path = require('path')
nodeIpc.config.id = 'main'
nodeIpc.config.retry = 1500
nodeIpc.config.silent = true
nodeIpc.connectTo(
'node',
path.join(app.getPath('userData'), 'boostnote.service'),
function () {
nodeIpc.of.node.on('error', function (err) {
console.log(err)
})
nodeIpc.of.node.on('connect', function () {
console.log('Conncted successfully')
ipcRenderer.send('config-renew', {config: ConfigManager.get()})
})
nodeIpc.of.node.on('disconnect', function () {
console.log('disconnected')
})
nodeIpc.of.node.on('request-data-from-finder', function () {
console.log('throttle')
var data = store.getState()
nodeIpc.of.node.emit('throttle-data', {
storages: data.storages,
notes: data.notes
})
})
}
)
module.exports = nodeIpc

View File

@@ -54,6 +54,7 @@ trayMenu.append(new MenuItem({
finderWindow.webContents.send('open-main-from-tray')
}
}))
if (process.env.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon') {
trayMenu.append(new MenuItem({
label: 'Open Finder window',
@@ -62,6 +63,7 @@ if (process.env.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamo
}
}))
}
trayMenu.append(new MenuItem({
label: 'Quit',
click: function () {

View File

@@ -1,52 +0,0 @@
const electron = require('electron')
const ipc = electron.ipcMain
const Menu = electron.Menu
const globalShortcut = electron.globalShortcut
const mainWindow = require('./main-window')
function toggleFinder () {
mainWindow.webContents.send('open-finder', {})
}
function toggleMain () {
if (mainWindow.isFocused()) {
if (process.platform === 'darwin') {
Menu.sendActionToFirstResponder('hide:')
} else {
mainWindow.minimize()
}
} else {
if (process.platform === 'darwin') {
mainWindow.show()
} else {
mainWindow.minimize()
mainWindow.restore()
}
}
}
ipc.on('config-renew', (e, payload) => {
globalShortcut.unregisterAll()
var { config } = payload
var errors = []
try {
globalShortcut.register(config.hotkey.toggleFinder, toggleFinder)
} catch (err) {
errors.push('toggleFinder')
}
try {
globalShortcut.register(config.hotkey.toggleMain, toggleMain)
} catch (err) {
errors.push('toggleMain')
}
if (!config.silent) {
if (errors.length === 0) {
mainWindow.webContents.send('APP_SETTING_DONE', {})
} else {
mainWindow.webContents.send('APP_SETTING_ERROR', {
message: 'Failed to apply hotkey: ' + errors.join(' ')
})
}
}
})

89
lib/ipcServer.js Normal file
View File

@@ -0,0 +1,89 @@
const nodeIpc = require('node-ipc')
const { app, Menu, globalShortcut, ipcMain } = require('electron')
const path = require('path')
const mainWindow = require('./main-window')
nodeIpc.config.id = 'node'
nodeIpc.config.retry = 1500
nodeIpc.config.silent = true
function toggleMainWindow () {
switch (global.process.platform) {
case 'darwin':
if (mainWindow.isFocused()) {
Menu.sendActionToFirstResponder('hide:')
} else {
mainWindow.show()
}
return
default:
if (mainWindow.isFocused()) {
mainWindow.minimize()
} else {
mainWindow.minimize()
mainWindow.restore()
}
}
}
function toggleFinder () {
nodeIpc.server.broadcast('open-finder')
}
ipcMain.on('config-renew', (e, payload) => {
nodeIpc.server.broadcast('config-renew', payload)
globalShortcut.unregisterAll()
var { config } = payload
var errors = []
try {
globalShortcut.register(config.hotkey.toggleFinder, toggleFinder)
} catch (err) {
errors.push('toggleFinder')
}
try {
globalShortcut.register(config.hotkey.toggleMain, toggleMainWindow)
} catch (err) {
errors.push('toggleMain')
}
if (!config.silent) {
if (errors.length === 0) {
mainWindow.webContents.send('APP_SETTING_DONE', {})
} else {
mainWindow.webContents.send('APP_SETTING_ERROR', {
message: 'Failed to apply hotkey: ' + errors.join(' ')
})
}
}
})
nodeIpc.serve(
path.join(app.getPath('userData'), 'boostnote.service'),
function () {
nodeIpc.server.on('open-main-from-finder', toggleMainWindow)
nodeIpc.server.on('quit-from-finder', function () {
app.quit()
})
nodeIpc.server.on('connect', function (socket) {
nodeIpc.log('ipc server >> socket joinned'.rainbow)
socket.on('close', function () {
nodeIpc.log('ipc server >> socket closed'.rainbow)
})
})
nodeIpc.server.on('error', function (err) {
nodeIpc.log('Node IPC error'.rainbow, err)
})
nodeIpc.server.on('request-data-from-finder', function () {
nodeIpc.server.broadcast('request-data-from-finder')
})
nodeIpc.server.on('throttle-data', function (payload) {
nodeIpc.server.broadcast('throttle-data', payload)
})
}
)
module.exports = nodeIpc

View File

@@ -8,7 +8,7 @@ const ChildProcess = require('child_process')
const _ = require('lodash')
const GhReleases = require('electron-gh-releases')
// electron.crashReporter.start()
require('./ipc')
var ipcServer = null
var mainWindow = null
var finderWindow = null
@@ -112,8 +112,8 @@ app.on('ready', function () {
}, 1000 * 60 * 60)
checkUpdate()
require('./hotkey')
ipcServer = require('./ipcServer')
ipcServer.server.start()
})
module.exports = app

View File

@@ -2,7 +2,6 @@ const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const path = require('path')
const ipc = require('./ipc')
var mainWindow = new BrowserWindow({
width: 1080,