diff --git a/lib/boards-api.js b/lib/boards-api.js index e3f165c..81ecef7 100644 --- a/lib/boards-api.js +++ b/lib/boards-api.js @@ -10,6 +10,7 @@ Needs to be browserified to work in the browser var EventEmitter = require('wolfy87-eventemitter') var asyncjs = require('async') var semver = require('semver') +var wreck = require('wreck') function asObj (str, done) { if (str.toString) str = str.toString() @@ -257,6 +258,31 @@ BoardsAPI.prototype.deleteComment = function (hash, parent, done) { this.delete({ what: 'comment', hash, parent }, done) } +BoardsAPI.prototype.cat = function (path, done) { + if (this.limited) { + // Download via gateway + if (path.indexOf('/ipfs/') !== 0) path = '/ipfs/' + path + wreck.get(path, (err, res, payload) => { + console.log('GET:', err, res, payload) + if (payload.toString) payload = payload.toString() + done(err, payload) + }) + } else { + // Download via http api + this.ipfs.cat(path, done) + } +} + +BoardsAPI.prototype.ls = function (path, done) { + if (this.limited) { + // Download via gateway not yet implemented :( + done('this operation is not supported in limited mode') + } else { + // Download via http api + this.ipfs.ls(path, done) + } +} + BoardsAPI.prototype.backupCache = function () { if (window && window.localStorage !== undefined) { // Use localStorage to store the IPNS cache @@ -700,6 +726,15 @@ BoardsAPI.prototype.getUserCommentList = function (parent, user, done) { return this.ee } +BoardsAPI.prototype.isRunningFromGateway = function () { + if (!window) return false + return window.location.pathname.indexOf('/ipfs/') === 0 +} + +BoardsAPI.prototype.isNode = function () { + return process && process.env +} + // API for publishing content and managing to be done later... // Initialize API @@ -708,9 +743,15 @@ BoardsAPI.prototype.init = function (done) { this.ipfs.id((err, res) => { if (err) { console.log('Error while getting OWN ID:', err) + if (this.isRunningFromGateway()) { + console.log('Running in limited mode') + this.limited = true + } else console.log('Limited mode not available') this.ee.emit('error', err) - this.ee.emit('init', err) - if (done && done.apply) done(err) + this.ee.emit('init', err, this.limited) + if (done && done.apply) { + done(err, this.limited) + } } else if (res.ID) { console.log('I am', res.ID) this.id = res.ID diff --git a/package.json b/package.json index b48b3b6..c48e721 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "html-webpack-plugin": "~1.7.0", "https-browserify": "0.0.1", "ipfs-api": "github:ipfs/js-ipfs-api#ba85b3b", + "glob-stream": "5.2.0", "json-loader": "~0.5.4", "lodash.sortedindex": "~3.1.1", "markdown-loader": "^0.1.7", diff --git a/webapp/app.jsx b/webapp/app.jsx index 0c01faa..e4a7389 100644 --- a/webapp/app.jsx +++ b/webapp/app.jsx @@ -28,6 +28,7 @@ var CommentPage = require('commentpage.jsx')(boards) var ProfileEditor = require('profile-editor.jsx')(boards) var BoardEditor = require('board-editor.jsx')(boards) var PostEditor = require('post-editor.jsx')(boards) +var Status = require('status.jsx')(boards) // Define Main Components @@ -103,6 +104,7 @@ ReactDOM.render( + , document.getElementById('root') diff --git a/webapp/components/navbar.jsx b/webapp/components/navbar.jsx index 97792e6..79bfb45 100644 --- a/webapp/components/navbar.jsx +++ b/webapp/components/navbar.jsx @@ -29,7 +29,7 @@ module.exports = function (boardsAPI) { } else if (this.state.loading) { return } else { - return + return } }, render: function () { diff --git a/webapp/pages/getipfs.jsx b/webapp/pages/getipfs.jsx index 757a767..1365e04 100644 --- a/webapp/pages/getipfs.jsx +++ b/webapp/pages/getipfs.jsx @@ -3,62 +3,69 @@ var Link = require('react-router').Link var Icon = require('icon.jsx') module.exports = React.createClass({ - getInitialState: function () { + getInitialState () { return {} }, - componentWillReceiveProps: function (props) { - if (props.api) { - this.checkStatus(props.api) - } - }, - componentDidMount: function () { - this.checkStatus(this.props.api) - }, - checkStatus: function (boards) { - if (boards) { - if (!this.isMounted()) return - if (boards.isInit) { - this.setState({ connected: true }) - } else { - if (boards.init_error) { - this.setState({ error: boards.init_error }) - } else { - boards.getEventEmitter().on('init', error => { - if (!this.isMounted()) return - if (error) { - this.setState({ error }) - } else { - this.setState({ connected: true }) - clearTimeout(this.timer) - } - }) - } - } - } else this.startTimer() - }, - componentWillUnmount: function () { + componentWillUnmount () { if (this.timer) clearTimeout(this.timer) }, - startTimer: function () { + componentWillReceiveProps (props) { + this.init(props) + }, + componentDidMount () { + this.init(this.props) + }, + init (props) { + var boards = props.api + if (this.timer) clearTimeout(this.timer) + if (boards) { + boards.getEventEmitter().on('init', (err, limited) => { + if (!this.isMounted()) return + if (err) { + this.setState({ error: true, limited }) + } else { + this.setState({ connected: true }) + } + }) + if (boards.isInit) { + this.setState({ connected: true }) + } else if (boards.limited) { + this.setState({ error: true, limited: true }) + } else this.startTimer() + } else this.startTimer() + }, + startTimer () { + console.log('start timer') this.timer = setTimeout(_ => { - if (this.isMounted()) { - console.log('Connection to go-ipfs has timed out (probably due to CORS)') + console.log('Connection to go-ipfs has timed out (probably due to CORS)') + if (this.isMounted() && !this.state.connected && !this.state.limited) { this.setState({ long: true }) - this.checkStatus() + this.init(this.props) } }, 5000) }, - render: function () { + getContent () { + if (this.state.limited) { + return
+

You're running in limited mode

+

Sorry, but at the moment an external application is needed to fully take advantage of the app

+

Only a few features are available in limited mode.

+
Why am I running in limited mode?
+
+ } else { + return
+

Connection to IPFS not available

+

Sorry, but at the moment an external application is needed to try the Prototype

+

Tip: you can also run in limited mode by loading the app from an IPFS Gateway.

+
+ } + }, + render () { var opt = require('options.jsx').get() if (this.state.error || this.state.long) { return ( -
-

Connection to IPFS not available

-

Sorry, but at the moment an external application is needed to try the Prototype

-
-
Error Message
-

{this.state.error || 'connection to go-ipfs failed'}

-
+
+ {this.getContent()}

You don't have an IPFS node running at {opt.addr}:{opt.port} or it is not reachable. The IPFS Boards prototype requires a full IPFS node. Please start one by following the go-ipfs documentation.

diff --git a/webapp/pages/status.jsx b/webapp/pages/status.jsx new file mode 100644 index 0000000..3b05dc4 --- /dev/null +++ b/webapp/pages/status.jsx @@ -0,0 +1,16 @@ +var React = require('react') +var GetIPFS = require('getipfs.jsx') + +module.exports = function (boardsAPI) { + return React.createClass({ + getInitialState () { + return { } + }, + componentDidMount () { + boardsAPI.use(api => this.setState({ api })) + }, + render () { + return + } + }) +}