Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.

Commit 4efc83f

Browse files
authored
Merge pull request #1158 from OpenBazaar/hot-fixes
Hot fixes
2 parents 558b03d + 6cc701d commit 4efc83f

File tree

11 files changed

+140
-72
lines changed

11 files changed

+140
-72
lines changed

js/languages/en_US.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
"zcashBinaryLabel": "Zcash Binary",
3636
"fullNodeLink": "here",
3737
"zcashBinaryHelper": "A Zcash full node is required. Download a Zcash full node %{fullNodeLink}. Once installed, enter the path to your zcashd binary above.",
38-
"zcashBinaryPlaceholder": "/path/to/zcashd",
3938
"btnBrowse": "Browse",
4039
"btnNext": "Next"
4140
},
@@ -1655,7 +1654,7 @@
16551654
"invalidTorProxy": "The value does not appear to be in the right format. It should be in the format ip-address:port, e.g. 127.0.0.1:9150. The port must be a number between 0 and 65535.",
16561655
"provideWalletCurrency": "Please select a wallet currency.",
16571656
"provideZcashBinaryPath": "Please provide a value.",
1658-
"invalidZcashBinaryPath": "The provided path must be to be a valid exectuable file."
1657+
"invalidZcashBinaryPath": "The provided path must be to be a file on your system."
16591658
},
16601659
"shippingAddressModelErrors": {
16611660
"provideName": "Please provide a name.",

js/models/ServerConfig.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { remote } from 'electron';
33
import LocalStorageSync from '../utils/backboneLocalStorage';
44
import is from 'is_js';
55
import { getCurrencyByCode as getCryptoCurByCode } from '../data/cryptoCurrencies';
6-
import { fileModeToPermissions } from '../utils';
76
import app from '../app';
87
import BaseModel from './BaseModel';
98

@@ -165,7 +164,7 @@ export default class extends BaseModel {
165164
// pass
166165
}
167166

168-
if (!fsStat || !fsStat.isFile() || !fileModeToPermissions(fsStat).execute.owner) {
167+
if (!fsStat || !fsStat.isFile()) {
169168
addError('zcashBinaryPath',
170169
app.polyglot.t('serverConfigModelErrors.invalidZcashBinaryPath'));
171170
}

js/start.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,15 @@ import './utils/exchangeRateSyncer';
3737
import './utils/listingData';
3838
import { launchDebugLogModal, launchSettingsModal } from './utils/modalManager';
3939
import listingDeleteHandler from './startup/listingDelete';
40-
import { fixLinuxZoomIssue, handleLinks } from './startup';
40+
import { fixLinuxZoomIssue, handleLinks, handleServerShutdownRequests } from './startup';
4141
import ConnectionManagement from './views/modals/connectionManagement/ConnectionManagement';
4242
import Onboarding from './views/modals/onboarding/Onboarding';
4343
import WalletSetup from './views/modals/WalletSetup';
4444
import SearchProvidersCol from './collections/search/SearchProviders';
4545
import defaultSearchProviders from './data/defaultSearchProviders';
4646

4747
fixLinuxZoomIssue();
48+
handleServerShutdownRequests();
4849

4950
app.localSettings = new LocalSettings({ id: 1 });
5051
app.localSettings.fetch().fail(() => app.localSettings.save());
@@ -314,7 +315,7 @@ function fetchStartupData() {
314315
.fail((jqXhr) => {
315316
const curConn = getCurrentConnection();
316317

317-
if (!curConn || curConn.status === 'disconnected') {
318+
if (!jqXhr || !curConn || curConn.status !== 'connected') {
318319
// the connection management modal should be up with relevant info
319320
console.error('The startup data fetches failed. Looks like the connection to the ' +
320321
'server was lost.');
@@ -884,12 +885,12 @@ serverConnectEvents.on('connected', (connectedEvent) => {
884885
ipcRenderer.on('close-attempt', (e) => {
885886
const localServer = remote.getGlobal('localServer');
886887

887-
if (localServer.isRunning) {
888+
if (localServer && localServer.isRunning) {
888889
localServer.once('exit', () => e.sender.send('close-confirmed'));
889890
localServer.stop();
890891
}
891892

892-
if (localServer.isStopping) {
893+
if (localServer && localServer.isStopping) {
893894
app.pageNav.navigable = false;
894895
openSimpleMessage(
895896
app.polyglot.t('localServerShutdownDialog.title'),

js/startup/index.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// Putting start-up related one offs here that are too small for their own module and
22
// aren't appropriate to be in any existing module
33

4-
import { screen, shell } from 'electron';
4+
import { screen, shell, ipcRenderer } from 'electron';
5+
import { platform } from 'os';
56
import $ from 'jquery';
67
import { getBody } from '../utils/selectors';
8+
import { getCurrentConnection } from '../utils/serverConnect';
79
import app from '../app';
810
import Backbone from 'backbone';
911
import TorExternalLinkWarning from '../views/modals/TorExternalLinkWarning';
@@ -74,3 +76,39 @@ export function handleLinks() {
7476
e.preventDefault();
7577
});
7678
}
79+
80+
81+
/**
82+
* This function will accept requests from the main process to shutdown the OB server daemon.
83+
* This should only be called on the bundled app on windows. For Linux and OSX, the localServer
84+
* module is able to shut down the daemon via OS signals.
85+
*/
86+
export function handleServerShutdownRequests() {
87+
ipcRenderer.on('server-shutdown', () => {
88+
if (platform() !== 'win32') {
89+
ipcRenderer.send('server-shutdown-fail',
90+
{ reason: 'Not on windows. Use childProcess.kill instead.' });
91+
return;
92+
}
93+
94+
const curConn = getCurrentConnection();
95+
96+
if (!curConn || curConn.status !== 'connected') {
97+
ipcRenderer.send('server-shutdown-fail',
98+
{ reason: 'No server connection' });
99+
return;
100+
}
101+
102+
try {
103+
$.post(app.getServerUrl('ob/shutdown/'))
104+
.fail(xhr => ipcRenderer.send('server-shutdown-fail', {
105+
xhr,
106+
reason: xhr && xhr.responseJSON && xhr.responseJSON.reason || '',
107+
}));
108+
} catch (e) {
109+
ipcRenderer.send('server-shutdown-fail',
110+
{ reason: e.toString() });
111+
return;
112+
}
113+
});
114+
}

js/templates/modals/connectionManagement/configurationForm.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ <h2 class="h3 clrT txUnl txCtr"><%= ob.title %></h2>
9898
<div class="col9">
9999
<% if (ob.errors.zcashBinaryPath) print(ob.formErrorTmpl({ errors: ob.errors.zcashBinaryPath })) %>
100100
<div class="flex gutterH rowSm">
101-
<input class="clrBr clrP js-inputZcashBinaryPath" type="text" name="zcashBinaryPath" placeholder="<%= ob.polyT('walletSetup.zcashBinaryPlaceholder') %>" value="<%= ob.zcashBinaryPath %>" data-field-builtin />
101+
<input class="clrBr clrP js-inputZcashBinaryPath" type="text" name="zcashBinaryPath" placeholder="<%= ob.zcashBinaryPlaceholder %>" value="<%= ob.zcashBinaryPath %>" data-field-builtin />
102102
<button class="btn clrP clrBr form js-browseZcashBinary"><%= ob.polyT('walletSetup.btnBrowse') %></button>
103103
</div>
104104
<div class="clrT2 tx6">

js/utils/index.js

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -202,35 +202,3 @@ export function deparam(queryStr = '') {
202202

203203
return parsed;
204204
}
205-
206-
// https://github.com/mmalecki/mode-to-permissions/blob/master/lib/mode-to-permissions.js
207-
export function fileModeToPermissions(fileMode) {
208-
let mode = fileMode;
209-
210-
if (typeof mode === 'object') {
211-
// Accept `fs.Stats`.
212-
mode = mode.mode;
213-
}
214-
215-
const owner = mode >> 6;
216-
const group = (mode << 3) >> 6;
217-
const others = (mode << 6) >> 6;
218-
219-
return {
220-
read: {
221-
owner: !!(owner & 4),
222-
group: !!(group & 4),
223-
others: !!(others & 4),
224-
},
225-
write: {
226-
owner: !!(owner & 2),
227-
group: !!(group & 2),
228-
others: !!(others & 2),
229-
},
230-
execute: {
231-
owner: !!(owner & 1),
232-
group: !!(group & 1),
233-
others: !!(others & 1),
234-
},
235-
};
236-
}

js/utils/localServer.js

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ipcMain } from 'electron';
12
import _ from 'underscore';
23
import { EOL, platform } from 'os';
34
import { Events } from 'backbone';
@@ -18,15 +19,32 @@ export default class LocalServer {
1819
throw new Error('Please provide an error log path.');
1920
}
2021

22+
if (!options.getMainWindow || typeof options.getMainWindow !== 'function') {
23+
throw new Error('Please provide a function that, if available, returns a mainWindow ' +
24+
'instance.');
25+
}
26+
2127
_.extend(this, Events);
2228
this.serverPath = options.serverPath;
2329
this.serverFilename = options.serverFilename;
2430
this.errorLogPath = options.errorLogPath;
31+
this._getMainWindow = options.getMainWindow;
2532
this._isRunning = false;
2633
this._isStopping = false;
2734
this._debugLog = '';
2835
this._lastStartCommandLineArgs = [];
2936
this.startAfterStop = (...args) => this.start(...args);
37+
38+
ipcMain.on('server-shutdown-fail', (e, data = {}) => {
39+
if (this.isStopping && this.serverSubProcess) {
40+
const reasonInsert = data.reason ? ` (${data.reason})` : '';
41+
const logMsg = `The server shutdown via api request failed${reasonInsert}. ` +
42+
'Will forcibly shutdown.';
43+
44+
this.log(logMsg);
45+
this._forceKill();
46+
}
47+
});
3048
}
3149

3250
get isRunning() {
@@ -48,8 +66,8 @@ export default class LocalServer {
4866
}
4967

5068
start(commandLineArgs = []) {
51-
if (this.pendingStop) {
52-
this.pendingStop.once('exit', () => this.startAfterStop(commandLineArgs));
69+
if (this.isStopping) {
70+
this.serverSubProcess.once('exit', () => this.startAfterStop(commandLineArgs));
5371
const debugInfo = 'Attempt to start server while an existing one' +
5472
' is the process of shutting down. Will start after shut down is complete.';
5573
this.log(debugInfo);
@@ -132,28 +150,46 @@ export default class LocalServer {
132150
return;
133151
}
134152

153+
_forceKill() {
154+
if (platform() !== 'win32') {
155+
throw new Error('For non windows OSs, use childProcess.kill and pass in a signal.');
156+
}
157+
158+
if (!this.isStopping) {
159+
throw new Error('A force kill should only be attempted if you tried stopping via this.stop ' +
160+
'and it failed.');
161+
}
162+
163+
if (this.serverSubProcess) {
164+
this.log('Forcibly shutting down the server via taskkill.');
165+
childProcess.spawn('taskkill', ['/pid', this.serverSubProcess.pid, '/f', '/t']);
166+
}
167+
}
168+
135169
stop() {
136170
if (!this.isRunning) return;
137171

138-
if (this.pendingStop) {
139-
this.pendingStop.removeListener('exit', this.startAfterStop);
172+
if (this.isStopping) {
173+
this.serverSubProcess.removeListener('exit', this.startAfterStop);
140174
return;
141175
}
142176

143177
this._isStopping = true;
144-
this.pendingStop = this.serverSubProcess;
145-
this.pendingStop.once('exit', () => {
146-
this.pendingStop = null;
147-
this._isStopping = false;
148-
});
178+
this.serverSubProcess.once('exit', () => (this._isStopping = false));
149179

150180
this.log('Shutting down server');
151181
console.log('Shutting down server');
152182

153183
if (platform() === 'darwin' || platform() === 'linux') {
154184
this.serverSubProcess.kill('SIGINT');
155185
} else {
156-
this.childProcess.spawn('taskkill', ['/pid', this.serverSubProcess.pid, '/f', '/t']);
186+
const mw = this._getMainWindow();
187+
188+
if (mw) {
189+
mw.webContents.send('server-shutdown');
190+
} else {
191+
this._forceKill();
192+
}
157193
}
158194
}
159195

js/utils/serverConnect.js

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -325,24 +325,50 @@ export default function connect(server, options = {}) {
325325
if (connectAttempt) connectAttempt.cancel();
326326
};
327327

328-
// If we're not connecting to the local bundled server or it's running for a different coin,
329-
// then let's ensure it's stopped.
328+
if (server.get('builtIn') && !localServer) {
329+
// This should never happen to normal users. The only way it would is if you are a dev
330+
// and mucking with localStorage and / or fudging the source for the app to masquerade
331+
// as a bundled app.
332+
throw new Error('A configuration for a built-in server should only be used on ' +
333+
' the bundled app.');
334+
}
335+
336+
const curLocalServerCoin = serverStartArgsToCoin();
337+
let curLocalServerZecBinaryPath = null;
338+
339+
if (localServer) {
340+
if (curLocalServerCoin === 'ZEC') {
341+
const zecIndex = localServer.lastStartCommandLineArgs
342+
.indexOf(serverCurStartArgMap.ZEC);
343+
344+
if (zecIndex !== -1 &&
345+
typeof localServer.lastStartCommandLineArgs[zecIndex + 1] === 'string') {
346+
curLocalServerZecBinaryPath = localServer.lastStartCommandLineArgs[zecIndex + 1];
347+
}
348+
}
349+
}
350+
351+
// If we're not connecting to the local bundled server or it's running with incompatible
352+
// command line arguments, let's ensure it's stopped.
330353
if (localServer && localServer.isRunning &&
331-
(!server.get('builtIn') || serverCurrency !== serverStartArgsToCoin())) {
354+
(
355+
!server.get('builtIn') || serverCurrency !== serverStartArgsToCoin() ||
356+
(serverCurrency === 'ZEC' && server.get('zcashBinaryPath') !== curLocalServerZecBinaryPath)
357+
)) {
332358
deferred.notify({ status: 'stopping-local-server' });
333359
localServer.stop();
334360

335-
if (server.get('builtIn') && serverCurrency !== serverStartArgsToCoin() &&
336-
options.attempts === undefined && options.minAttemptSpacing === undefined &&
361+
if (server.get('builtIn') && options.attempts === undefined &&
362+
options.minAttemptSpacing === undefined &&
337363
options.maxAttemptTime === undefined) {
338364
// If we need to wait for a bundled server to shut down before starting a new instance and
339365
// the user did not pass in override options regarding connection timeouts, we'll bump up the
340366
// defaults to give the shutting down server more time (it may take up to a few minutes).
341367
opts = {
342-
attempts: 36, // works out to 3 minutes total
368+
...opts,
369+
attempts: 60, // works out to 5 minutes total
343370
minAttemptSpacing: 5000,
344371
maxAttemptTime: 5000,
345-
...opts,
346372
};
347373
}
348374
}
@@ -504,14 +530,6 @@ export default function connect(server, options = {}) {
504530
}
505531
};
506532

507-
if (server.get('builtIn') && !localServer) {
508-
// This should never happen to normal users. The only way it would is if you are a dev
509-
// and mucking with localStorage and / or fudging the source for the app to masquerade
510-
// as a bundled app.
511-
throw new Error('A configuration for a built-in server should only be used on ' +
512-
' the bundled app.');
513-
}
514-
515533
if (server.get('useTor')) {
516534
innerConnectNotify('setting-tor-proxy');
517535
innerLog(`Activating a proxy at socks5://${server.get('torProxy')}`);

js/views/modals/WalletSetup.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ export default class extends BaseModal {
3636
}
3737

3838
onClickBrowseZcashBinary() {
39-
remote.dialog.showOpenDialog({ properties: ['openFile', 'openDirectory'] }, e => {
40-
this.getCachedEl('.js-inputZcashBinaryPath').val(e[0] || '');
39+
remote.dialog.showOpenDialog({ properties: ['openFile'] }, e => {
40+
if (e) {
41+
this.getCachedEl('.js-inputZcashBinaryPath').val(e[0] || '');
42+
}
4143
});
4244
}
4345

0 commit comments

Comments
 (0)