Load network apps manifests as contentHash (no coding) (#3235)

* Add mobx

* Use mobx store for dapps

* Cleanup hidden reads

* Remove (now) unused hidden.js

* _ denotes internal functions

* s/visibleApps/visible/

* AddDapps now use the mobx store as well

* Move modalOpen state to store

* Simplify

* Complete master merge

* Remove extra indirection

* Remove unneeded check

* Readability improvements

* Remove final debug info

* Load network manifests from the network

* Swallow manifest errors

* introduce fetchManifest
This commit is contained in:
Jaco Greeff 2016-11-07 18:08:16 +01:00 committed by Arkadiy Paronyan
parent 418474ad27
commit 6ab6c0709d
3 changed files with 128 additions and 93 deletions

View File

@ -57,4 +57,8 @@ export default class DappReg {
getContent (id) {
return this.meta(id, 'CONTENT');
}
getManifest (id) {
return this.meta(id, 'MANIFEST');
}
}

View File

@ -44,12 +44,6 @@ export default class Dapp extends Component {
let src = null;
switch (app.type) {
case 'builtin':
const dapphost = process.env.NODE_ENV === 'production' && !app.secure
? `${dappsUrl}/ui`
: '';
src = `${dapphost}/${app.url}.html`;
break;
case 'local':
src = `${dappsUrl}/${app.id}/`;
break;
@ -57,7 +51,10 @@ export default class Dapp extends Component {
src = `${dappsUrl}/${app.contentHash}/`;
break;
default:
console.error('unknown type', app.type);
const dapphost = process.env.NODE_ENV === 'production' && !app.secure
? `${dappsUrl}/ui`
: '';
src = `${dapphost}/${app.url}.html`;
break;
}

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import { action, computed, observable } from 'mobx';
import Contracts from '../../contracts';
@ -63,21 +62,6 @@ const builtinApps = [
}
];
// TODO: This is just since we are moving gavcoin to its own repo, for a proper network solution
// we need to pull the network apps from the dapp registry. (Builtins & local apps unaffected)
// TODO: Manifest needs to be pulled from the content as well, however since the content may or may
// not be available locally (and refreshes work for index, and will give a 503), we are putting it
// in here. This part needs to be cleaned up.
const networkApps = [
{
id: '0xd798a48831b4ccdbc71de206a1d6a4aa73546c7b6f59c22a47452af414dc64d6',
name: 'GAVcoin',
description: 'Manage your GAVcoins, the hottest new property in crypto',
author: 'Gavin Wood',
version: '1.0.0'
}
];
export default class DappsStore {
@observable apps = [];
@observable hidden = [];
@ -118,93 +102,143 @@ export default class DappsStore {
: '';
}
@action _fetch () {
_fetch () {
Promise
.all([
this._fetchLocal(),
this._fetchRegistry()
])
.then(([localApps, registryApps]) => {
this.apps = []
.concat(localApps)
.concat(registryApps)
.filter((app) => app.id)
.sort((a, b) => (a.name || '').localeCompare(b.name || ''));
})
.catch((error) => {
console.warn('DappStore:fetch', error);
});
}
_fetchRegistry () {
const { dappReg } = Contracts.get();
return dappReg
.count()
.then((_count) => {
const count = _count.toNumber();
const promises = [];
for (let index = 0; index < count; index++) {
promises.push(dappReg.at(index));
}
return Promise.all(promises);
})
.then((appsInfo) => {
const appIds = appsInfo.map(([appId, owner]) => {
return this._api.util.bytesToHex(appId);
});
return Promise
.all([
Promise.all(appIds.map((appId) => dappReg.getImage(appId))),
Promise.all(appIds.map((appId) => dappReg.getContent(appId))),
Promise.all(appIds.map((appId) => dappReg.getManifest(appId)))
])
.then(([imageIds, contentIds, manifestIds]) => {
return appIds.map((appId, index) => {
const app = builtinApps.find((ba) => ba.id === appId) || {
id: appId,
contentHash: this._api.util.bytesToHex(contentIds[index]).substr(2),
manifestHash: this._api.util.bytesToHex(manifestIds[index]).substr(2),
type: 'network'
};
app.image = hashToImageUrl(imageIds[index]);
app.type = app.type || 'builtin';
return app;
});
});
})
.then((apps) => {
return Promise
.all(apps.map((app) => {
return app.manifestHash
? this._fetchManifest(app.manifestHash)
: null;
}))
.then((manifests) => {
return apps.map((app, index) => {
const manifest = manifests[index];
if (manifest) {
app.manifestHash = null;
Object.keys(manifest)
.filter((key) => key !== 'id')
.forEach((key) => {
app[key] = manifest[key];
});
}
return app;
});
})
.then((apps) => {
return apps.filter((app) => {
return !app.manifestHash && app.id;
});
});
})
.catch((error) => {
console.warn('DappsStore:fetchRegistry', error);
});
}
_fetchManifest (manifestHash, count = 0) {
return fetch(`${this._getHost()}/api/content/${manifestHash}/`)
.then((response) => {
if (response.ok) {
return response.json();
}
if (count < 1) {
return this._fetchManifest(manifestHash, count + 1);
}
return null;
})
.catch(() => {
if (count < 1) {
return this._fetchManifest(manifestHash, count + 1);
}
return null;
});
}
_fetchLocal () {
return fetch(`${this._getHost()}/api/apps`)
.then((response) => {
return response.ok
? response.json()
: [];
})
.catch((error) => {
console.warn('DappsStore:fetch', error);
return [];
})
.then((_localApps) => {
const localApps = _localApps
.filter((app) => !['ui'].includes(app.id))
.then((localApps) => {
return localApps
.filter((app) => app && app.id && !['ui'].includes(app.id))
.map((app) => {
app.type = 'local';
return app;
});
return this._api.parity
.registryAddress()
.then((registryAddress) => {
if (new BigNumber(registryAddress).eq(0)) {
return [];
}
const _builtinApps = builtinApps
.map((app) => {
app.type = 'builtin';
return app;
});
return networkApps
.map((app) => {
app.type = 'network';
return app;
})
.concat(_builtinApps);
})
.then((registryApps) => {
return registryApps
.concat(localApps)
.sort((a, b) => (a.name || '').localeCompare(b.name || ''));
});
})
.then((apps) => {
return Promise
.all([
Promise.all(apps.map((app) => dappReg.getImage(app.id))),
Promise.all(apps.map((app) => dappReg.getContent(app.id)))
])
.then(([images, content]) => {
this.apps = apps.map((app, index) => {
return Object.assign(app, {
image: hashToImageUrl(images[index]),
contentHash: this._api.util.bytesToHex(content[index]).substr(2)
});
});
});
})
.catch((error) => {
console.warn('DappsStore:fetch', error);
console.warn('DappsStore:fetchLocal', error);
});
}
_manifest (app, contentHash) {
fetch(`${this.getHost()}/${contentHash}/manifest.json`)
.then((response) => {
return response.ok
? response.json()
: {};
})
.then((manifest) => {
Object.keys.forEach((key) => {
app[key] = manifest[key];
});
return app;
})
.catch((error) => {
console.warn('DappsStore:manifest', error);
});
}
@action _readHiddenApps () {
_readHiddenApps () {
const stored = localStorage.getItem('hiddenApps');
if (stored) {