diff --git a/src/IpfsApiHelper.ts b/src/IpfsApiHelper.ts index b9ecc67..10ebff8 100644 --- a/src/IpfsApiHelper.ts +++ b/src/IpfsApiHelper.ts @@ -3,6 +3,7 @@ import * as Promise from 'bluebird'; import { fromRawData, toDataBuffer, fromRawObject, splitPath } from './statics'; import { multihash } from 'is-ipfs'; import { Readable } from 'stream'; +import set = Reflect.set; export class IpfsApiHelper { public apiClient: any; diff --git a/src/IpfsConnector.js b/src/IpfsConnector.js index 17f37fb..68d2d6c 100644 --- a/src/IpfsConnector.js +++ b/src/IpfsConnector.js @@ -106,7 +106,17 @@ class IpfsConnector extends events_1.EventEmitter { if (!binOk) { return this.emit(constants_1.events.SERVICE_FAILED); } - this._start(); + childProcess.exec(`${this.downloadManager.wrapper.path()} config Addresses.API`, { env: constants_1.options.extra.env }, (error, apiAddress, stderr) => { + if (error) { + this.logger.error(error); + } + if (stderr.includes('ipfs init')) { + this._init(); + return Promise.delay(3000).then(() => this.start()); + } + constants_1.options.apiAddress = apiAddress.trim(); + return this._start(); + }); }); } _start() { @@ -161,5 +171,41 @@ class IpfsConnector extends events_1.EventEmitter { this.options.retry = false; this.process = null; } + getPorts() { + return this.api.apiClient + .config.get('Addresses') + .then((config) => { + const { Swarm, API, Gateway } = config; + const swarm = Swarm[0].split('/').pop(); + const api = API.split('/').pop(); + const gateway = Gateway.split('/').pop(); + return { gateway: gateway, api: api, swarm: swarm }; + }); + } + setPorts(ports, restart = false) { + const setup = []; + if (ports.hasOwnProperty('gateway')) { + setup.push(this.api.apiClient + .config.set('Addresses.Gateway', `/ip4/127.0.0.1/tcp/${ports.gateway}`)); + } + if (ports.hasOwnProperty('api')) { + setup.push(this.api.apiClient + .config.set('Addresses.API', `/ip4/127.0.0.1/tcp/${ports.api}`)); + } + if (ports.hasOwnProperty('swarm')) { + setup.push(this.api.apiClient + .config.set('Addresses.Swarm', [`/ip4/0.0.0.0/tcp/${ports.swarm}`, `/ip6/::/tcp/${ports.swarm}`])); + } + return Promise.all(setup).then((set) => { + if (restart) { + return Promise.resolve(this.stop()).delay(2000) + .then(() => { + this.start(); + return Promise.delay(3000).then(() => set); + }); + } + return set; + }); + } } exports.IpfsConnector = IpfsConnector; diff --git a/src/IpfsConnector.ts b/src/IpfsConnector.ts index d79c5e6..c895399 100644 --- a/src/IpfsConnector.ts +++ b/src/IpfsConnector.ts @@ -17,7 +17,7 @@ export class IpfsConnector extends EventEmitter { private process: childProcess.ChildProcess; private downloadManager = new IpfsBin(); public options = options; - public serviceStatus: { api: boolean, process: boolean } = {process: false, api: false}; + public serviceStatus: { api: boolean, process: boolean } = { process: false, api: false }; private _callbacks = new Map(); private logger: any = console; private _api: IpfsApiHelper; @@ -181,7 +181,20 @@ export class IpfsConnector extends EventEmitter { */ return this.emit(events.SERVICE_FAILED); } - this._start(); + childProcess.exec(`${this.downloadManager.wrapper.path()} config Addresses.API`, + { env: options.extra.env }, + (error, apiAddress, stderr) => { + if (error) { + this.logger.error(error); + } + if (stderr.includes('ipfs init')) { + this._init(); + return Promise.delay(3000).then(() => this.start()); + } + options.apiAddress = apiAddress.trim(); + return this._start(); + }); + } ); } @@ -273,4 +286,50 @@ export class IpfsConnector extends EventEmitter { this.options.retry = false; this.process = null; } + + public getPorts(): { gateway: number, api: number, swarm: number } { + return this.api.apiClient + .config.get('Addresses') + .then((config: any) => { + const { Swarm, API, Gateway } = config; + const swarm = Swarm[0].split('/').pop(); + const api = API.split('/').pop(); + const gateway = Gateway.split('/').pop(); + return { gateway, api, swarm }; + }); + } + + public setPorts(ports: {gateway?: number, api?: number, swarm?: number}, restart = false) { + const setup: any[] = []; + if (ports.hasOwnProperty('gateway')) { + setup.push( + this.api.apiClient + .config.set('Addresses.Gateway', `/ip4/127.0.0.1/tcp/${ports.gateway}`) + ); + } + + if (ports.hasOwnProperty('api')) { + setup.push( + this.api.apiClient + .config.set('Addresses.API', `/ip4/127.0.0.1/tcp/${ports.api}`) + ); + } + + if (ports.hasOwnProperty('swarm')) { + setup.push( + this.api.apiClient + .config.set('Addresses.Swarm', [`/ip4/0.0.0.0/tcp/${ports.swarm}`, `/ip6/::/tcp/${ports.swarm}`]) + ); + } + return Promise.all(setup).then((set: any) => { + if (restart) { + return Promise.resolve(this.stop()).delay(2000) + .then(() => { + this.start(); + return Promise.delay(3000).then(() => set); + }); + } + return set; + }); + } } diff --git a/src/constants.js b/src/constants.js index ef283e0..18f7edd 100644 --- a/src/constants.js +++ b/src/constants.js @@ -18,7 +18,7 @@ exports.options = { args: ['daemon'], executable: '', extra: { - env: Object.assign({}, process.env, { IPFS_PATH: path_1.join(os_1.homedir(), '.ipfs') }), + env: Object.assign({}, { IPFS_PATH: path_1.join(os_1.homedir(), '.ipfs') }), detached: true } }; diff --git a/src/constants.ts b/src/constants.ts index b6b89c3..5d0f53a 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -19,7 +19,7 @@ export const options = { args: ['daemon'], executable: '', extra: { - env: Object.assign({}, process.env, { IPFS_PATH: pathJoin(homedir(), '.ipfs') }), + env: Object.assign({}, { IPFS_PATH: pathJoin(homedir(), '.ipfs') }), detached: true } }; \ No newline at end of file diff --git a/tests/index.js b/tests/index.js index 1a294b9..5f20e99 100644 --- a/tests/index.js +++ b/tests/index.js @@ -65,8 +65,7 @@ describe('IpfsConnector', function () { }); }); it('should start ipfs daemon', function (done) { - instance.setLogger(console); - instance.on(constants.events.SERVICE_STARTED, function () { + instance.once(constants.events.SERVICE_STARTED, function () { expect(instance.serviceStatus.process).to.be.true; done(); }); @@ -76,6 +75,45 @@ describe('IpfsConnector', function () { instance.setConfig('retry', 1); expect(instance.options.retry).to.equal(1); }); + it('should get ipfs config addresses', function (done) { + expect(instance.api).to.exist; + instance.getPorts().then((ports) => { + expect(ports).to.exist; + done(); + }); + }); + it('should set ipfs GATEWAY port', function (done) { + instance.setPorts({gateway: 8092}).then((ports) => { + expect(ports).to.exist; + done(); + }); + }); + + it('should set ipfs API port', function (done) { + instance.setPorts({api: 5041}).then((ports) => { + expect(ports).to.exist; + done(); + }); + }); + + it('should set ipfs SWARM port', function (done) { + instance.setPorts({swarm: 4041}).then((ports) => { + expect(ports).to.exist; + done(); + }); + }); + + it('should restart after setting ports', function (done) { + instance.once(constants.events.SERVICE_STARTED, function () { + expect(instance.serviceStatus.process).to.be.true; + done(); + }); + instance.setPorts({api: 5041, swarm: 4041, gateway: 8040}, true) + .then((ports) => { + expect(ports).to.exist; + }) + }); + it('should add an object to ipfs', function (done) { expect(instance.api).to.be.defined; instance.api.add({ data: '{}' }) @@ -154,7 +192,7 @@ describe('IpfsConnector', function () { }); }); it('should add file to ipfs', function (done) { - const file = fs.readFileSync(filePath); + const file = fs.readFileSync(filePath); instance.api .addFile(file) .then((result)=> { @@ -245,7 +283,7 @@ describe('IpfsConnector', function () { }); }); - it('should reject when root hash is an not ipfs hash', function (done) { + it('should reject when root hash is not an ipfs hash', function (done) { instance.api .resolve('QmTCMGWApewThNp64JBg9yzhiZGKKDHigS2Y45Tyg1H/data/aa') .then(data=> {