Permalink
Browse files

quick dump

  • Loading branch information...
mmckegg committed Oct 27, 2016
0 parents commit 572440feaf959755763efb726087066a6f5b29db
Showing with 907 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +26 −0 README.md
  3. +124 −0 api/index.js
  4. +5 −0 assets/base.html
  5. +1 −0 assets/img/emoji
  6. +100 −0 index.js
  7. +44 −0 lib/context-menu.js
  8. +1 −0 lib/h.js
  9. +13 −0 lib/make-single-instance.js
  10. +60 −0 lib/serve-blobs.js
  11. +13 −0 lib/ssb-server.js
  12. +92 −0 lib/window.js
  13. +116 −0 main-window.js
  14. +33 −0 package.json
  15. +101 −0 styles/base.mcss
  16. +19 −0 styles/index.js
  17. +158 −0 styles/main-window.mcss
@@ -0,0 +1 @@
+node_modules
@@ -0,0 +1,26 @@
+patchwork-next
+===
+
+Very early **work-in-progress** attempt at remaking [Patchwork](https://github.com/ssbc/patchwork) using [patchbay](https://github.com/dominictarr/patchbay) and UX/ideas from [ferment](https://github.com/mmckegg/ferment).
+
+The goal is to make a standalone, easy to install, "social" view into the ssb world.
+
+## Install and run
+
+```shell
+$ git clone https://github.com/mmckegg/patchwork-next
+$ cd patchwork-next
+$ npm install
+$ npm start
+```
+
+## TODO
+
+- [ ] Preserve scroll on back button
+- [ ] Main navigation buttons
+- [ ] Easy navigation sidebar
+- [ ] Contacts sidebar
+- [ ] Lots of styling
+- [ ] Compressed feed (the algorithm :wink:)
+ - [ ] Thread previews in feed [figure out how to do this streaming]
+- [ ] Add more todos!
@@ -0,0 +1,124 @@
+var pull = require('pull-stream')
+var ssbKeys = require('ssb-keys')
+var ref = require('ssb-ref')
+
+function Hash (onHash) {
+ var buffers = []
+ return pull.through(function (data) {
+ buffers.push('string' === typeof data
+ ? new Buffer(data, 'utf8')
+ : data
+ )
+ }, function (err) {
+ if(err && !onHash) throw err
+ var b = buffers.length > 1 ? Buffer.concat(buffers) : buffers[0]
+ var h = '&'+ssbKeys.hash(b)
+ onHash && onHash(err, h)
+ })
+}
+//uncomment this to use from browser...
+//also depends on having ssb-ws installed.
+//var createClient = require('ssb-lite')
+
+var createFeed = require('ssb-feed')
+var cache = CACHE = {}
+
+module.exports = function (sbot, opts) {
+ var connection_status = []
+ var keys = opts.keys
+
+ var internal = {
+ getLatest: function (id, cb) {
+ sbot.getLatest(id, cb)
+ },
+ add: function (msg, cb) {
+ sbot.add(msg, cb)
+ }
+ }
+
+ var feed = createFeed(internal, keys, {remote: true})
+
+ setImmediate((x) => {
+ connection_status.forEach(fn => fn())
+ })
+
+ return {
+ connection_status: connection_status,
+ sbot_blobs_add: function (cb) {
+ return pull(
+ Hash(function (err, id) {
+ if(err) return cb(err)
+ //completely UGLY hack to tell when the blob has been sucessfully written...
+ var start = Date.now(), n = 5
+ ;(function next () {
+ setTimeout(function () {
+ sbot.blobs.has(id, function (err, has) {
+ if(has) return cb(null, id)
+ if(n--) next()
+ else cb(new Error('write failed'))
+ })
+ }, Date.now() - start)
+ })()
+ }),
+ sbot.blobs.add()
+ )
+ },
+ sbot_links: function (query) {
+ return sbot.links(query)
+ },
+ sbot_links2: function (query) {
+ return sbot.links2.read(query)
+ },
+ sbot_query: function (query) {
+ return sbot.query.read(query)
+ },
+ sbot_log: function (opts) {
+ return pull(
+ sbot.createLogStream(opts),
+ pull.through(function (e) {
+ CACHE[e.key] = CACHE[e.key] || e.value
+ })
+ )
+ },
+ sbot_user_feed: function (opts) {
+ return sbot.createUserStream(opts)
+ },
+ sbot_get: function (key, cb) {
+ if(CACHE[key]) cb(null, CACHE[key])
+ else sbot.get(key, function (err, value) {
+ if(err) return cb(err)
+ cb(null, CACHE[key] = value)
+ })
+ },
+ sbot_gossip_peers: function (cb) {
+ sbot.gossip.peers(cb)
+ },
+ //liteclient won't have permissions for this
+ sbot_gossip_connect: function (opts, cb) {
+ sbot.gossip.connect(opts, cb)
+ },
+ sbot_publish: function (content, cb) {
+ if(content.recps)
+ content = ssbKeys.box(content, content.recps.map(function (e) {
+ return ref.isFeed(e) ? e : e.link
+ }))
+ else if(content.mentions)
+ content.mentions.forEach(function (mention) {
+ if(ref.isBlob(mention.link)) {
+ sbot.blobs.push(mention.link, function (err) {
+ if(err) console.error(err)
+ })
+ }
+ })
+
+ feed.add(content, function (err, msg) {
+ if(err) console.error(err)
+ else if(!cb) console.log(msg)
+ cb && cb(err, msg)
+ })
+ },
+ sbot_whoami: function (cb) {
+ sbot.whoami(cb)
+ }
+ }
+}
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html>
+ <head></head>
+ <body></body>
+</html>
100 index.js
@@ -0,0 +1,100 @@
+process.on('uncaughtException', function (err) {
+ console.log(err)
+ process.exit()
+})
+
+var electron = require('electron')
+var openWindow = require('./lib/window')
+var createSbot = require('./lib/ssb-server')
+var serveBlobs = require('./lib/serve-blobs')
+var makeSingleInstance = require('./lib/make-single-instance')
+var pull = require('pull-stream')
+var pullFile = require('pull-file')
+var Path = require('path')
+var fs = require('fs')
+var defaultMenu = require('electron-default-menu')
+var Menu = electron.Menu
+var dataUriToBuffer = require('data-uri-to-buffer')
+var extend = require('xtend')
+var ssbKeys = require('ssb-keys')
+
+var windows = {
+ dialogs: new Set()
+}
+
+var context = null
+if (process.argv.includes('--use-global-ssb') || process.argv.includes('-g')) {
+ context = setupContext('ssb', {
+ server: false
+ })
+} else {
+ makeSingleInstance(windows, openMainWindow)
+ context = setupContext('ssb')
+}
+
+electron.ipcMain.on('add-blob', (ev, id, path, cb) => {
+ pull(
+ path.startsWith('data:') ? pull.values([dataUriToBuffer(path)]) : pullFile(path),
+ context.sbot.blobs.add((err, hash) => {
+ if (err) return ev.sender.send('response', id, err)
+ ev.sender.send('response', id, null, hash)
+ })
+ )
+})
+
+electron.app.on('ready', function () {
+ Menu.setApplicationMenu(Menu.buildFromTemplate(defaultMenu(electron.app, electron.shell)))
+ openMainWindow()
+})
+
+electron.app.on('activate', function (e) {
+ openMainWindow()
+})
+
+function openMainWindow () {
+ if (!windows.main) {
+ windows.main = openWindow(context, Path.join(__dirname, 'main-window.js'), {
+ minWidth: 800,
+ width: 1024,
+ height: 768,
+ titleBarStyle: 'hidden-inset',
+ title: 'Ferment',
+ show: true,
+ backgroundColor: '#444',
+ webPreferences: {
+ experimentalFeatures: true
+ },
+ icon: './ferment-logo.png'
+ })
+ windows.main.setSheetOffset(40)
+ windows.main.on('closed', function () {
+ windows.main = null
+ })
+ }
+}
+
+function setupContext (appName, opts) {
+ var ssbConfig = require('ssb-config/inject')(appName, extend({
+ port: 8008,
+ blobsPort: 7777
+ }, opts))
+
+ if (opts && opts.server === false) {
+ return {
+ config: ssbConfig
+ }
+ } else {
+ ssbConfig.keys = ssbKeys.loadOrCreateSync(Path.join(ssbConfig.path, 'secret'))
+ var context = {
+ sbot: createSbot(ssbConfig),
+ config: ssbConfig
+ }
+ ssbConfig.manifest = context.sbot.getManifest()
+ serveBlobs(context)
+ fs.writeFileSync(Path.join(ssbConfig.path, 'manifest.json'), JSON.stringify(ssbConfig.manifest))
+ console.log(`Address: ${context.sbot.getAddress()}`)
+ return context
+ }
+
+ return ssbConfig
+}
@@ -0,0 +1,44 @@
+var electron = require('electron')
+var Menu = electron.remote.Menu
+var MenuItem = electron.remote.MenuItem
+var BrowserWindow = electron.remote.BrowserWindow
+
+window.addEventListener('contextmenu', function (e) {
+ module.exports(null, null, e)
+}, false)
+
+module.exports = function (context, item, ev) {
+ ev.preventDefault()
+ ev.stopPropagation()
+ var menu = new Menu()
+ menu.append(new MenuItem({
+ label: 'Reload',
+ click: function (item, focusedWindow) {
+ if (focusedWindow) {
+ focusedWindow.reload()
+ }
+ }
+ }))
+ menu.append(new MenuItem({
+ type: 'separator'
+ }))
+ menu.append(new MenuItem({
+ label: 'Inspect Element',
+ click: function () {
+ var x = ev.clientX
+ var y = ev.clientY
+ BrowserWindow.getFocusedWindow().inspectElement(x, y)
+ }
+ }))
+
+ if (item && item.id) {
+ menu.append(new MenuItem({
+ label: 'Copy SSB ID',
+ click: function () {
+ electron.clipboard.writeText(item.id)
+ }
+ }))
+ }
+
+ menu.popup(electron.remote.getCurrentWindow())
+}
@@ -0,0 +1 @@
+module.exports = require('micro-css/h')(require('@mmckegg/mutant/html-element'))
@@ -0,0 +1,13 @@
+var electron = require('electron')
+module.exports = function (windows, openMainWindow) {
+ if (electron.app.makeSingleInstance((commandLine, workingDirectory) => {
+ if (windows.main) {
+ if (windows.main.isMinimized()) windows.main.restore()
+ windows.main.focus()
+ } else {
+ openMainWindow()
+ }
+ })) {
+ electron.app.quit()
+ }
+}
@@ -0,0 +1,60 @@
+var pull = require('pull-stream')
+var cat = require('pull-cat')
+var toPull = require('stream-to-pull-stream')
+var ident = require('pull-identify-filetype')
+var mime = require('mime-types')
+var URL = require('url')
+var http = require('http')
+
+module.exports = function (context, cb) {
+ return http.createServer(ServeBlobs(context.sbot)).listen(context.config.blobsPort, cb)
+}
+
+function ServeBlobs (sbot) {
+ return function (req, res, next) {
+ var parsed = URL.parse(req.url, true)
+ var hash = decodeURIComponent(parsed.pathname.slice(1))
+ sbot.blobs.want(hash, function (_, has) {
+ if (!has) return respond(res, 404, 'File not found')
+ // optional name override
+ if (parsed.query.name) {
+ res.setHeader('Content-Disposition', 'inline; filename=' + encodeURIComponent(parsed.query.name))
+ }
+
+ // serve
+ res.setHeader('Content-Security-Policy', BlobCSP())
+ respondSource(res, sbot.blobs.get(hash), false)
+ })
+ }
+}
+
+function respondSource (res, source, wrap) {
+ if (wrap) {
+ res.writeHead(200, {'Content-Type': 'text/html'})
+ pull(
+ cat([
+ pull.once('<html><body><script>'),
+ source,
+ pull.once('</script></body></html>')
+ ]),
+ toPull.sink(res)
+ )
+ } else {
+ pull(
+ source,
+ ident(function (type) {
+ if (type) res.writeHead(200, {'Content-Type': mime.lookup(type)})
+ }),
+ toPull.sink(res)
+ )
+ }
+}
+
+function respond (res, status, message) {
+ res.writeHead(status)
+ res.end(message)
+}
+
+function BlobCSP () {
+ return 'default-src none; sandbox'
+}
@@ -0,0 +1,13 @@
+module.exports = require('scuttlebot')
+ .use(require('scuttlebot/plugins/master'))
+ .use(require('scuttlebot/plugins/gossip'))
+ .use(require('scuttlebot/plugins/friends'))
+ .use(require('scuttlebot/plugins/replicate'))
+ .use(require('ssb-blobs'))
+ .use(require('scuttlebot/plugins/invite'))
+ .use(require('scuttlebot/plugins/block'))
+ .use(require('scuttlebot/plugins/local'))
+ .use(require('scuttlebot/plugins/logging'))
+ .use(require('scuttlebot/plugins/private'))
+ .use(require('ssb-links'))
+ .use(require('ssb-query'))
Oops, something went wrong.

0 comments on commit 572440f

Please sign in to comment.