diff --git a/src/app.js b/src/app.js index bfa93d61f8..e1f4e521e6 100644 --- a/src/app.js +++ b/src/app.js @@ -36,6 +36,7 @@ var handleImports = require('./app/compiler/compiler-imports') var FileManager = require('./app/files/fileManager') var ContextualListener = require('./app/editor/contextualListener') var ContextView = require('./app/editor/contextView') +var BasicReadOnlyExplorer = require('./app/files/basicReadOnlyExplorer') var styleGuide = remixLib.ui.styleGuide var styles = styleGuide() @@ -111,6 +112,10 @@ class App { self._api.filesProviders = {} self._api.filesProviders['browser'] = new Browserfiles(fileStorage) self._api.filesProviders['localhost'] = new SharedFolder(new Remixd()) + self._api.filesProviders['swarm'] = new BasicReadOnlyExplorer('swarm') + self._api.filesProviders['github'] = new BasicReadOnlyExplorer('github') + self._api.filesProviders['gist'] = new BasicReadOnlyExplorer('gist') + self._api.filesProviders['ipfs'] = new BasicReadOnlyExplorer('ipfs') self._view = {} self._components = {} self.data = { @@ -195,10 +200,10 @@ function run () { if (provider && provider.exists(url)) { return provider.get(url, cb) } - handleImports.import(url, (error, content) => { + handleImports.import(url, (error, content, cleanUrl, type) => { if (!error) { // FIXME: at some point we should invalidate the browser cache - filesProviders['browser'].addReadOnly(url, content) + filesProviders[type].addReadOnly(cleanUrl, content) cb(null, content) } else { cb(error) @@ -548,6 +553,9 @@ function run () { fileProviderOf: (path) => { return fileManager.fileProviderOf(path) }, + fileProvider: (name) => { + return self._api.filesProviders[name] + }, getBalance: (address, callback) => { udapp.getBalance(address, (error, balance) => { if (error) { diff --git a/src/app/compiler/compiler-imports.js b/src/app/compiler/compiler-imports.js index 29d86b8087..23e728fb6d 100644 --- a/src/app/compiler/compiler-imports.js +++ b/src/app/compiler/compiler-imports.js @@ -8,7 +8,7 @@ module.exports = { return $.getJSON('https://api.github.com/repos/' + root + '/contents/' + path) .done(function (data) { if ('content' in data) { - cb(null, base64.decode(data.content)) + cb(null, base64.decode(data.content), root + '/' + path) } else { cb('Content not received') } @@ -21,7 +21,7 @@ module.exports = { handleSwarmImport: function (url, cb) { swarmgw.get(url, function (err, content) { - cb(err, content) + cb(err, content, url) }) }, @@ -31,7 +31,7 @@ module.exports = { return $.ajax({ type: 'GET', url: 'https://gateway.ipfs.io/' + url }) .done(function (data) { - cb(null, data) + cb(null, data, url) }) .fail(function (xhr, text, err) { // NOTE: on some browsers, err equals to '' for certain errors (such as offline browser) @@ -41,9 +41,9 @@ module.exports = { import: function (url, cb) { var handlers = [ - { match: /^(https?:\/\/)?(www.)?github.com\/([^/]*\/[^/]*)\/(.*)/, handler: (match, cb) => { this.handleGithubCall(match[3], match[4], cb) } }, - { match: /^(bzz[ri]?:\/\/?.*)$/, handler: (match, cb) => { this.handleSwarmImport(match[1], cb) } }, - { match: /^(ipfs:\/\/?.+)/, handler: (match, cb) => { this.handleIPFS(match[1], cb) } } + { type: 'github', match: /^(https?:\/\/)?(www.)?github.com\/([^/]*\/[^/]*)\/(.*)/, handler: (match, cb) => { this.handleGithubCall(match[3], match[4], cb) } }, + { type: 'swarm', match: /^(bzz[ri]?:\/\/?.*)$/, handler: (match, cb) => { this.handleSwarmImport(match[1], cb) } }, + { type: 'ipfs', match: /^(ipfs:\/\/?.+)/, handler: (match, cb) => { this.handleIPFS(match[1], cb) } } ] var found = false @@ -57,13 +57,13 @@ module.exports = { found = true $('#output').append($('
').append($('').text('Loading ' + url + ' ...'))) - handler.handler(match, function (err, content) { + handler.handler(match, function (err, content, cleanUrl) { if (err) { - cb('Unable to import "' + url + '": ' + err) + cb('Unable to import "' + cleanUrl + '": ' + err) return } - cb(null, content) + cb(null, content, cleanUrl, handler.type) }) } }) diff --git a/src/app/contract/publishOnSwarm.js b/src/app/contract/publishOnSwarm.js index d3284d5a71..1155a2fbb7 100644 --- a/src/app/contract/publishOnSwarm.js +++ b/src/app/contract/publishOnSwarm.js @@ -3,10 +3,14 @@ var async = require('async') var swarmgw = require('swarmgw') -module.exports = (contract, appAPI, cb) => { +module.exports = (contract, appAPI, cb, swarmVerifiedPublishCallBack) => { // gather list of files to publish var sources = [] + try { + contract.metadata = JSON.stringify(JSON.parse(contract.metadata), null, '\t') + } catch (e) {} + sources.push({ content: contract.metadata, hash: contract.metadataHash @@ -49,7 +53,10 @@ module.exports = (contract, appAPI, cb) => { } else { // publish the list of sources in order, fail if any failed async.eachSeries(sources, function (item, cb) { - swarmVerifiedPublish(item.content, item.hash, cb) + swarmVerifiedPublish(item.content, item.hash, (error) => { + if (!error && swarmVerifiedPublishCallBack) swarmVerifiedPublishCallBack(item) + cb(error) + }) }, cb) } }) diff --git a/src/app/files/basicReadOnlyExplorer.js b/src/app/files/basicReadOnlyExplorer.js new file mode 100644 index 0000000000..5285da3930 --- /dev/null +++ b/src/app/files/basicReadOnlyExplorer.js @@ -0,0 +1,102 @@ +'use strict' +var EventManager = require('remix-lib').EventManager + +class SwarmExplorer { + constructor (type) { + this.event = new EventManager() + this.files = {} + this.type = type + } + + close (cb) { + this.files = {} + cb() + } + + init (cb) { + this.files = {} + } + + exists (path) { + if (!this.files) return false + return this.files[path] !== undefined + } + + get (path, cb) { + var content = this.files[path] + if (cb) { + cb(null, content) + } + return content + } + + set (path, content, cb) { + return true + } + + addReadOnly (path, content) { + this.files[this.type + '/' + path] = content + this.event.trigger('fileAdded', [this.type + '/' + path, true]) + return true + } + + isReadOnly (path) { + return true + } + + remove (path) { + delete this.files[path] + } + + rename (oldPath, newPath, isFolder) { + return true + } + + list () { + return this.files + } + + // + // Tree model for files + // { + // 'a': { }, // empty directory 'a' + // 'b': { + // 'c': {}, // empty directory 'b/c' + // 'd': { '/readonly': true, '/content': 'Hello World' } // files 'b/c/d' + // 'e': { '/readonly': false, '/path': 'b/c/d' } // symlink to 'b/c/d' + // 'f': { '/readonly': false, '/content': '