git ssb

1+

Daan Patchwork / patchwork



Tree: 4d9f238ff73f7136cd292da88f06c17fe1a8c445

Files: 4d9f238ff73f7136cd292da88f06c17fe1a8c445 / index.js

8960 bytesRaw
1process.on('uncaughtException', function (err) {
2 console.log(err)
3 process.exit()
4})
5
6const electron = require('electron')
7const openWindow = require('./lib/window')
8
9const Path = require('path')
10const defaultMenu = require('electron-default-menu')
11const WindowState = require('electron-window-state')
12const Menu = electron.Menu
13const extend = require('xtend')
14const ssbKeys = require('ssb-keys')
15
16const windows = {
17 dialogs: new Set()
18}
19let ssbConfig = null
20let quitting = false
21
22/**
23 * It's not possible to run two instances of patchwork as it would create two
24 * ssb-server instances that conflict on the same port. Before opening patchwork,
25 * we check if it's already running and if it is we focus the existing window
26 * rather than opening a new instance.
27 */
28function quitIfAlreadyRunning () {
29 if (!electron.app.requestSingleInstanceLock()) {
30 console.log('Patchwork is already running!')
31 console.log('Please close the existing instance before starting a new one.')
32 return electron.app.quit()
33 }
34 electron.app.on('second-instance', () => {
35 // Someone tried to run a second instance, we should focus our window.
36 if (windows.main) {
37 if (windows.main.isMinimized()) windows.main.restore()
38 windows.main.focus()
39 }
40 })
41}
42
43const config = {
44 server: !(process.argv.includes('-g') || process.argv.includes('--use-global-ssb'))
45}
46// a flag so we don't start git-ssb-web if a custom path is passed in
47if (process.argv.includes('--path')) {
48 config.customPath = true
49}
50
51quitIfAlreadyRunning()
52
53electron.app.on('ready', () => {
54 setupContext(process.env.ssb_appname || 'ssb', {
55 server: !(process.argv.includes('-g') || process.argv.includes('--use-global-ssb'))
56 }, () => {
57 const browserWindow = openMainWindow()
58
59 browserWindow.on('app-command', (e, cmd) => {
60 switch (cmd) {
61 case 'browser-backward': {
62 browserWindow.webContents.send('goBack')
63 break
64 }
65 case 'browser-forward': {
66 browserWindow.webContents.send('goForward')
67 break
68 }
69 }
70 })
71
72 const menu = defaultMenu(electron.app, electron.shell)
73
74 menu.splice(4, 0, {
75 label: 'Navigation',
76 submenu: [
77 {
78 label: 'Activate Search Field',
79 accelerator: 'CmdOrCtrl+L',
80 click: () => {
81 browserWindow.webContents.send('activateSearch')
82 }
83 },
84 {
85 label: 'Back',
86 accelerator: 'CmdOrCtrl+[',
87 click: () => {
88 browserWindow.webContents.send('goBack')
89 }
90 },
91 {
92 label: 'Forward',
93 accelerator: 'CmdOrCtrl+]',
94 click: () => {
95 browserWindow.webContents.send('goForward')
96 }
97 },
98 {
99 type: 'separator'
100 },
101 {
102 label: 'Settings',
103 accelerator: 'CmdOrCtrl+,',
104 click: () => {
105 browserWindow.webContents.send('goToSettings')
106 }
107 }
108 ]
109 })
110
111 const view = menu.find(x => x.label === 'View')
112 view.submenu = [
113 { role: 'reload' },
114 { role: 'toggledevtools' },
115 { type: 'separator' },
116 { role: 'resetzoom' },
117 { role: 'zoomin', accelerator: 'CmdOrCtrl+=' },
118 { role: 'zoomout', accelerator: 'CmdOrCtrl+-' },
119 { type: 'separator' },
120 { role: 'togglefullscreen' }
121 ]
122 const help = menu.find(x => x.label === 'Help')
123 help.submenu = [
124 {
125 label: 'Learn More',
126 click () { require('electron').shell.openExternal('https://scuttlebutt.nz') }
127 }
128 ]
129 if (process.platform === 'darwin') {
130 const win = menu.find(x => x.label === 'Window')
131 win.submenu = [
132 { role: 'minimize' },
133 { role: 'zoom' },
134 { role: 'close', label: 'Close' },
135 { type: 'separator' },
136 { role: 'front' }
137 ]
138 }
139
140 Menu.setApplicationMenu(Menu.buildFromTemplate(menu))
141 })
142
143 electron.app.on('activate', function () {
144 if (windows.main) {
145 windows.main.show()
146 }
147 })
148
149 electron.app.on('before-quit', function () {
150 quitting = true
151 })
152
153 electron.ipcMain.handle('navigation-menu-popup', (event, data) => {
154 const {items, x, y} = data
155 const window = event.sender
156 const factor = event.sender.zoomFactor
157 const menuItems = buildMenu(items, window)
158 const menu = electron.Menu.buildFromTemplate(menuItems);
159 menu.popup({
160 window,
161 x: Math.round(x * factor),
162 y: Math.round(y * factor) + 4,
163 });
164 })
165
166 electron.ipcMain.handle('consoleLog', (ev, o) => console.log(o))
167 electron.ipcMain.handle('consoleError', (ev, o) => console.error(o))
168 electron.ipcMain.handle('badgeCount', (ev, count) => {
169 electron.app.badgeCount = count;
170 });
171 electron.ipcMain.on('exit', (ev, code) => process.exit(code))
172
173})
174
175function openServerDevTools () {
176 if (windows.background) {
177 windows.background.webContents.openDevTools({ mode: 'detach' })
178 }
179}
180
181function buildMenu(items, window) {
182 const result = []
183 for (let item of items) {
184 switch (item.type) {
185 case 'separator':
186 result.push(item)
187 break
188 case 'submenu':
189 result.push({
190 ...item,
191 submenu: buildMenu(item.submenu, window),
192 })
193 break
194 case 'normal':
195 result.push({
196 ...item,
197 click: () => navigateTo(item.target)
198 })
199 break
200 default:
201 throw Error(`Unknown menu item of type "${item.type}": ${JSON.stringify(item, null, 2)}`);
202 }
203 }
204 return result
205}
206
207function navigateTo(target) {
208 if (windows?.main) {
209 windows.main.send('navigate-to', target)
210 }
211}
212
213function openMainWindow () {
214 if (!windows.main) {
215 const windowState = WindowState({
216 defaultWidth: 1024,
217 defaultHeight: 768
218 })
219 windows.main = openWindow(ssbConfig, Path.join(__dirname, 'lib', 'main-window.js'), {
220 minWidth: 800,
221 x: windowState.x,
222 y: windowState.y,
223 width: windowState.width,
224 height: windowState.height,
225 titleBarStyle: 'hiddenInset',
226 autoHideMenuBar: true,
227 title: 'Patchwork',
228 show: true,
229 backgroundColor: '#EEE',
230 icon: Path.join(__dirname, 'assets/icon.png'),
231 },
232 openServerDevTools,
233 navigateTo,
234 )
235
236 windowState.manage(windows.main)
237 windows.main.setSheetOffset(40)
238 windows.main.on('close', function (e) {
239 if (!quitting && process.platform === 'darwin') {
240 e.preventDefault()
241 windows.main.hide()
242 }
243 })
244 windows.main.on('closed', function () {
245 windows.main = null
246 if (process.platform !== 'darwin') electron.app.quit()
247 })
248 }
249 return windows.main
250}
251
252function setupContext (appName, opts, cb) {
253 ssbConfig = require('ssb-config/inject')(appName, extend({
254 port: 8008,
255 blobsPort: 8989, // matches ssb-ws
256 friends: { // not using ssb-friends (sbot/contacts fixes hops at 2, so this setting won't do anything)
257 dunbar: 150,
258 hops: 2 // down from 3
259 }
260 }, opts))
261
262 // disable gossip auto-population from {type: 'pub'} messages as we handle this manually in sbot/index.js
263 if (!ssbConfig.gossip) ssbConfig.gossip = {}
264 ssbConfig.gossip.autoPopulate = false
265
266 ssbConfig.keys = ssbKeys.loadOrCreateSync(Path.join(ssbConfig.path, 'secret'))
267
268 const keys = ssbConfig.keys
269 const pubkey = keys.id.slice(1).replace(`.${keys.curve}`, '')
270
271 if (process.platform === 'win32') {
272 // fix offline on windows by specifying 127.0.0.1 instead of localhost (default)
273 ssbConfig.remote = `net:127.0.0.1:${ssbConfig.port}~shs:${pubkey}`
274 } else {
275 const socketPath = Path.join(ssbConfig.path, 'socket')
276 ssbConfig.connections.incoming.unix = [{ scope: 'device', transform: 'noauth' }]
277 ssbConfig.remote = `unix:${socketPath}:~noauth:${pubkey}`
278 }
279
280 // Support rooms
281 ssbConfig.connections.incoming.tunnel = [{ scope: 'public', transform: 'shs' }]
282 ssbConfig.connections.outgoing.tunnel = [{ transform: 'shs' }]
283
284 // Support DHT invites (only as a client, for now)
285 ssbConfig.connections.outgoing.dht = [{ transform: 'shs' }]
286
287 const redactedConfig = JSON.parse(JSON.stringify(ssbConfig))
288 redactedConfig.keys.private = null
289 console.dir(redactedConfig, { depth: null })
290
291 if (opts.server === false) {
292 cb && cb()
293 } else {
294 electron.ipcMain.once('server-started', function (ev, config) {
295 ssbConfig = config
296 cb && cb()
297 })
298 windows.background = openWindow(ssbConfig, Path.join(__dirname, 'lib', 'server-process.js'), {
299 connect: false,
300 center: true,
301 fullscreen: false,
302 fullscreenable: false,
303 height: 150,
304 maximizable: false,
305 minimizable: false,
306 resizable: false,
307 show: false,
308 skipTaskbar: true,
309 title: 'patchwork-server',
310 useContentSize: true,
311 width: 150
312 })
313 // windows.background.on('close', (ev) => {
314 // ev.preventDefault()
315 // windows.background.hide()
316 // })
317 }
318}
319

Built with git-ssb-web