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': '', '/mode': 0755 }
+  //   }
+  // }
+  //
+  listAsTree () {
+    function hashmapize (obj, path, val) {
+      var nodes = path.split('/')
+      var i = 0
+
+      for (; i < nodes.length - 1; i++) {
+        var node = nodes[i]
+        if (obj[node] === undefined) {
+          obj[node] = {}
+        }
+        obj = obj[node]
+      }
+
+      obj[nodes[i]] = val
+    }
+
+    var tree = {}
+
+    var self = this
+    // This does not include '.remix.config', because it is filtered
+    // inside list().
+    Object.keys(this.list()).forEach(function (path) {
+      hashmapize(tree, path, {
+        '/readonly': self.isReadOnly(path),
+        '/content': self.get(path)
+      })
+    })
+    return tree
+  }
+}
+
+module.exports = SwarmExplorer
diff --git a/src/app/files/file-explorer.js b/src/app/files/file-explorer.js
index fedeee587c..410fe4da0a 100755
--- a/src/app/files/file-explorer.js
+++ b/src/app/files/file-explorer.js
@@ -410,9 +410,6 @@ function expandPathTo (li) {
 
 fileExplorer.prototype.init = function () {
   var files = this.files.listAsTree()
-  if (!Object.keys(files).length) {
-    files[this.files.type] = {} // default
-  }
   var element = this.treeView.render(files)
   element.className = css.fileexplorer
   element.events = this.events
diff --git a/src/app/panels/file-panel.js b/src/app/panels/file-panel.js
index a1c3adf0bb..4c82a169ad 100644
--- a/src/app/panels/file-panel.js
+++ b/src/app/panels/file-panel.js
@@ -128,6 +128,10 @@ function filepanel (appAPI, filesProvider) {
   var self = this
   var fileExplorer = new FileExplorer(appAPI, filesProvider['browser'])
   var fileSystemExplorer = new FileExplorer(appAPI, filesProvider['localhost'])
+  var swarmExplorer = new FileExplorer(appAPI, filesProvider['swarm'])
+  var githubExplorer = new FileExplorer(appAPI, filesProvider['github'])
+  var gistExplorer = new FileExplorer(appAPI, filesProvider['gist'])
+
   var dragbar = yo`
` function remixdDialog () { @@ -174,6 +178,9 @@ function filepanel (appAPI, filesProvider) {
${fileExplorer.init()}
+
${swarmExplorer.init()}
+
${githubExplorer.init()}
+
${gistExplorer.init()}
${dragbar} @@ -221,6 +228,18 @@ function filepanel (appAPI, filesProvider) { appAPI.switchFile(path) }) + swarmExplorer.events.register('focus', function (path) { + appAPI.switchFile(path) + }) + + githubExplorer.events.register('focus', function (path) { + appAPI.switchFile(path) + }) + + gistExplorer.events.register('focus', function (path) { + appAPI.switchFile(path) + }) + self.render = function render () { return element } function uploadFile (event) { @@ -326,7 +345,7 @@ function filepanel (appAPI, filesProvider) { } function toGist () { - packageFiles(filesProvider['browser'], (error, packaged) => { + packageFiles(filesProvider['gist'], (error, packaged) => { if (error) { console.log(error) } else { diff --git a/src/app/tabs/compile-tab.js b/src/app/tabs/compile-tab.js index c3fc5edaee..0d32accb47 100644 --- a/src/app/tabs/compile-tab.js +++ b/src/app/tabs/compile-tab.js @@ -436,6 +436,9 @@ function compileTab (container, appAPI, appEvents, opts) { } else { modalDialogCustom.alert(yo`Metadata published successfully.
The Swarm address of the metadata file is available in the contract details.
`) } + }, function (item) { + // triggered each time there's a new verified publish (means hash correspond) + appAPI.fileProvider('swarm').addReadOnly(item.hash, item.content) }) } } diff --git a/src/config.js b/src/config.js index b4380662d5..b42959fa43 100644 --- a/src/config.js +++ b/src/config.js @@ -33,7 +33,13 @@ function Config (storage) { this.ensureStorageUpdated = function (key) { if (key === 'currentFile') { - if (this.items[key] && this.items[key] !== '' && this.items[key].indexOf('browser/') !== 0 && this.items[key].indexOf('localhost/') !== 0) { + if (this.items[key] && this.items[key] !== '' && + this.items[key].indexOf('browser/') !== 0 && + this.items[key].indexOf('localhost/') !== 0 && + this.items[key].indexOf('swarm/') !== 0 && + this.items[key].indexOf('gist/') !== 0 && + this.items[key].indexOf('github/') !== 0 && + this.items[key].indexOf('ipfs/') !== 0) { this.items[key] = 'browser/' + this.items[key] } }