Skip to content

Commit

Permalink
node: add setting for changing hsd home directory
Browse files Browse the repository at this point in the history
  • Loading branch information
chikeichan committed Apr 19, 2021
1 parent 42fd4e9 commit c176f74
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 15 deletions.
1 change: 1 addition & 0 deletions app/background/db/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const clientStub = (ipcRendererInjector) => makeClient(ipcRendererInjecto
'put',
'get',
'del',
'getUserDir',
]);
5 changes: 5 additions & 0 deletions app/background/db/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export async function iteratePrefix(prefix, cb) {
await iter.each(cb);
}

export async function getUserDir() {
return app.getPath('userData');
}

function ensureDB() {
if (!db) {
throw new Error('db not open');
Expand All @@ -65,6 +69,7 @@ const methods = {
get,
del,
iteratePrefix,
getUserDir,
};

export async function start(server) {
Expand Down
6 changes: 5 additions & 1 deletion app/background/node/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ export const clientStub = ipcRendererInjector => makeClient(ipcRendererInjector,
'sendRawAirdrop',
'getFees',
'getAverageBlockTime',
'getCoin'
'getCoin',
'setNodeDir',
'setAPIKey',
'getDir',
'getAPIKey',
]);
56 changes: 45 additions & 11 deletions app/background/node/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,52 @@ const Network = require('hsd/lib/protocol/network');

const MIN_FEE = new BigNumber(0.01);
const DEFAULT_BLOCK_TIME = 10 * 60 * 1000;
const HSD_PREFIX_DIR_KEY = 'hsdPrefixDir';
const NODE_API_KEY = 'nodeApiKey';

export class NodeService extends EventEmitter {
constructor() {
super();
}

async getAPIKey() {
const apiKey = await get(NODE_API_KEY);

if (apiKey) return apiKey;

const newKey = crypto.randomBytes(20).toString('hex');
await put(NODE_API_KEY, newKey);
return newKey;
}

async getDir() {
const hsdPrefixDir = await get(HSD_PREFIX_DIR_KEY);

if (hsdPrefixDir) {
return hsdPrefixDir;
}

const newPath = path.join(app.getPath('userData'), 'hsd_data');
await put(HSD_PREFIX_DIR_KEY, newPath);
return newPath;
}

async setNodeDir(dir) {
if (!fs.existsSync(dir)) {
throw new Error(`${dir} does not exist`);
}

await put(HSD_PREFIX_DIR_KEY, dir);
}

this.hsdPrefixDir = path.join(app.getPath('userData'), 'hsd_data');
async setAPIKey(apiKey) {
await put(NODE_API_KEY, apiKey);
}

async configurePaths() {
if (!fs.existsSync(this.hsdPrefixDir)) {
await pify(cb => fs.mkdir(this.hsdPrefixDir, {recursive: true}, cb));
const dir = await this.getDir();
if (!fs.existsSync(dir)) {
await pify(cb => fs.mkdir(dir, {recursive: true}, cb));
}
}

Expand Down Expand Up @@ -56,11 +91,10 @@ export class NodeService extends EventEmitter {
}

const network = Network.get(networkName);
const apiKey = crypto.randomBytes(20).toString('hex');

this.networkName = networkName;
this.network = network;
this.apiKey = apiKey;
this.apiKey = await this.getAPIKey();

this.emit('started', this.networkName, this.network, this.apiKey);
}
Expand All @@ -78,6 +112,8 @@ export class NodeService extends EventEmitter {

console.log(`Starting node on ${this.networkName} network.`);

const dir = await this.getDir();

const hsd = new FullNode({
config: true,
argv: true,
Expand All @@ -89,7 +125,7 @@ export class NodeService extends EventEmitter {
workers: false,
network: this.networkName,
loader: require,
prefix: this.hsdPrefixDir,
prefix: dir,
listen: true,
bip37: true,
indexAddress: true,
Expand Down Expand Up @@ -173,11 +209,6 @@ export class NodeService extends EventEmitter {
return this._execRPC('generatetoaddress', [numblocks, address]);
}

async getAPIKey() {
await this._ensureStarted();
return this.apiKey;
}

async getInfo() {
await this._ensureStarted();
return this.client.getInfo();
Expand Down Expand Up @@ -354,6 +385,9 @@ const methods = {
getFees: () => service.getFees(),
getAverageBlockTime: () => service.getAverageBlockTime(),
getCoin: (hash, index) => service.getCoin(hash, index),
setNodeDir: data => service.setNodeDir(data),
setAPIKey: data => service.setAPIKey(data),
getDir: () => service.getDir(),
};

export async function start(server) {
Expand Down
1 change: 1 addition & 0 deletions app/components/Modal/MiniModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
import classnames from 'classnames';
import './mini-modal.scss';

@withRouter
export class MiniModal extends Component {
static propTypes = {
closeRoute: PropTypes.string,
Expand Down
125 changes: 125 additions & 0 deletions app/pages/Settings/ChangeDirectoryModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, { Component } from "react";
import {MiniModal} from "../../components/Modal/MiniModal";
import {clientStub} from "../../background/node/client";
import c from "classnames";
import {connect} from "react-redux";
import {withRouter} from "react-router-dom";
import Alert from "../../components/Alert";
import dbClient from "../../utils/dbClient";
const nodeClient = clientStub(() => require('electron').ipcRenderer);
const {dialog} = require('electron').remote;


@withRouter
@connect(
null,
null,
)
export default class ChangeDirectoryModal extends Component {
state = {
directory: '',
errorMessage: '',
saving: false,
};

async componentDidMount() {
const directory = await nodeClient.getDir();
const userDir = await dbClient.getUserDir();
this.setState({
originalDirectory: directory,
directory,
userDir,
});
}

reset = async () => {
const {originalDirectory} = this.state;
this.setState({
originalDirectory,
directory: originalDirectory,
});
};

saveDir = async () => {
const {directory} = this.state;
this.setState({ saving: true });
try {
await nodeClient.setNodeDir(directory);
} catch (e) {
this.setState({
errorMessage: e.message,
});
}

this.setState({
saving: false,
directory,
originalDirectory: directory,
});
};

pickDirectory = async () => {
let savePath = dialog.showOpenDialogSync({
properties: ["openDirectory", "promptToCreate", "createDirectory"],
});

this.setState({ directory: savePath[0] });
};

render() {
const { errorMessage, directory, originalDirectory, userDir, saving } = this.state;

return (
<MiniModal
closeRoute="/settings/connection"
title="Change HSD Directory"
>
<Alert type="warning">
This will only change your hsd home directory. Your other data, such as user setting and wallet data, will still be saved in <i>{userDir}</i>.
</Alert>
<div className="settings__input-row">
<div className="settings__input-title">
Home Directory
<a onClick={this.pickDirectory}>
Pick Directory
</a>
</div>
<input
type="text"
className="settings__input"
value={directory}
onChange={e => this.setState({
directory: e.target.value,
errorMessage: '',
})}
/>
</div>
{
errorMessage && (
<div className="rpc-modal-warning">
{errorMessage}
</div>
)
}
<div className="settings__row settings__row--centered">
<button
className="settings__secondary-btn"
onClick={this.reset}
disabled={originalDirectory === directory}
>
Cancel
</button>
<button
className={c('settings__btn', {
'settings__btn--confirm': saving,
})}
onClick={this.saveDir}
disabled={errorMessage || originalDirectory === directory}
>
Change Directory
</button>
</div>
</MiniModal>
)
}
}
24 changes: 23 additions & 1 deletion app/pages/Settings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ import BackupListingModal from "./BackupListingModal";
import fs from "fs";
const {dialog} = require('electron').remote;
import {clientStub as sClientStub} from "../../background/shakedex/client";
import ChangeDirectoryModal from "./ChangeDirectoryModal";
import dbClient from "../../utils/dbClient";
import {clientStub} from "../../background/node/client";

const analytics = aClientStub(() => require('electron').ipcRenderer);
const shakedex = sClientStub(() => require('electron').ipcRenderer);
const nodeClient = clientStub(() => require('electron').ipcRenderer);

@withRouter
@connect(
Expand Down Expand Up @@ -91,9 +95,15 @@ export default class Settings extends Component {
}
}

componentDidMount() {
async componentDidMount() {
analytics.screenView('Settings');
this.props.fetchWalletAPIKey();
const directory = await nodeClient.getDir();
const userDir = await dbClient.getUserDir();
this.setState({
directory,
userDir,
});
}

onDownload = async () => {
Expand Down Expand Up @@ -428,6 +438,17 @@ export default class Settings extends Component {
</button>,
isRunning || isTestingCustomRPC || isChangingNodeStatus,
)}
{this.renderSection(
'HSD Home Directory',
<div>
<div><small>User Directory: {this.state.userDir}</small></div>
<div><small>HSD Directory: {this.state.directory}</small></div>
</div>,
'Change Directory',
() => history.push("/settings/connection/changeDirectory"),
null,
isRunning || isChangingNodeStatus,
)}
{this.renderSection(
'Network type',
(
Expand Down Expand Up @@ -483,6 +504,7 @@ export default class Settings extends Component {
<Route path="/settings/wallet/reveal-seed" component={RevealSeedModal} />
<Route path="/settings/wallet/zap-txs" component={ZapTXsModal} />
<Route path="/settings/connection/configure" component={CustomRPCConfigModal} />
<Route path="/settings/connection/changeDirectory" component={ChangeDirectoryModal} />
<Route path="/settings/wallet/view-api-key">
<MiniModal
closeRoute="/settings/wallet"
Expand Down
12 changes: 10 additions & 2 deletions app/pages/Settings/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,19 @@
}

&__input-title {
@extend %row-nowrap;
cursor: default;
font-size: .8125rem;
font-weight: bold;
margin-left: .25rem;
margin-bottom: .25rem;
margin: 0 .25rem .25rem;
width: 100%;

a {
flex: 1 1 auto;
text-align: right;
color: $azure-blue;
cursor: pointer;
}
}

&__input {
Expand Down

0 comments on commit c176f74

Please sign in to comment.