Example #1
0
function AuthenticationHelp (el) {
  delegate.on(el, 'button', 'click', window.close)

  githubCurrentUser.verify(function (err, verified, username) {
    if (err) {
      var errorWrapperEl = el.querySelector('#error-wrapper')
      var errorEl = el.querySelector('#error')

      errorWrapperEl.style.display = 'block'
      errorEl.innerHTML = err
    }

    var usernameEl = el.querySelector('#username')
    var validKeyEl = el.querySelector('#valid-key')

    usernameEl.innerHTML = username || 'unknown'

    if (typeof verified !== 'undefined') {
      validKeyEl.innerHTML = verified
    } else {
      validKeyEl.innerHTML = ''
    }
  })
}
Example #2
0
function App (el) {
  var self = this
  if (!(self instanceof App)) return new App(el)

  var swarm = window.swarm = Swarm()
  var verify
  user.verify(function (err, verified, username) {
    if (err) return console.error(err.message || err)
    if (verified) {
      self.data.username = username
      swarm.username = username
      verify = ghsign.verifier(username)
    } else {
      self.data.username = '******' + catNames.random() + ')'
    }
  })



  var channelsFound = {}
  swarm.log.ready(function () {
    var usersFound = {}
    var verifiers = {}

    channelsFound.friends = {
      id: 0,
      name: 'friends',
      active: true,
      messages: []
    }
    self.data.channels.push(channelsFound.friends)
    self.data.messages = channelsFound.friends.messages

    var logStream = swarm.log.createReadStream({
      live: true,
      since: Math.max(swarm.log.changes - 500, 0)
    })
    logStream.pipe(through(function (entry, _, next) {
      var basicMessage = JSON.parse(entry.value)
      var userVerify = verifiers[basicMessage.username]

      if (!userVerify && basicMessage.sig) userVerify = verifiers[basicMessage.username] = ghsign.verifier(basicMessage.username)
      if (userVerify && basicMessage.sig) {
        var msg = Buffer.concat([
          new Buffer(basicMessage.username),
          new Buffer(basicMessage.channel ? basicMessage.channel: ''),
          new Buffer(basicMessage.text),
          new Buffer(basicMessage.timestamp.toString())
        ])
        return userVerify(msg, new Buffer(basicMessage.sig, 'base64'), function (err, valid) {
          basicMessage.valid = valid;
          next(null, basicMessage);
        });
      }
      next(null, basicMessage);
    })).pipe(through(function (basicMessage, _, next) {
      var message = richMessage(basicMessage)
      var channelName = message.channel || 'friends'
      var channel = channelsFound[channelName]

      if (!channel) {
        channel = channelsFound[channelName] = {
          id: self.data.channels.length,
          name: channelName,
          active: false,
          messages: []
        }
        self.data.channels.push(channel)
      }

      var anon = /Anonymous/i.test(message.username)

      message.avatar = anon
        ? 'static/Icon.png'
        : 'https://github.com/' + message.username + '.png'
      message.timeago = moment(message.timestamp).fromNow()

      if (self.data.username && !currentWindow.isFocused()) {
        console.log(message.rawText)
        if (message.rawText.indexOf(self.data.username) > -1) {
          new Notification('Mentioned in #' + channel.name, { // eslint-disable-line
            body: message.username + ': ' + message.rawText.slice(0, 20)
          })

          self.setBadge()
        }
      }

      channel.messages.push(message)

      if (!message.anon && message.valid && !usersFound[message.username]) {
        usersFound[message.username] = true
        self.data.users.push({
          name: message.username,
          avatar: message.avatar
        })
      }
      if (!message.anon && !message.valid) {
        message.username = '******' + message.username
      }

      self.views.messages.scrollToBottom()
      next();
    }))
  })

  swarm.on('peer', function (p) {
    self.data.peers++
    eos(p, function () {
      self.data.peers--
    })
  })

  // The mock data model
  self.data = {
    peers: 0,
    username: '******' + catNames.random() + ')',
    channels: [],
    messages: [],
    users: []
  }

  // View instances used in our App
  self.views = {
    channels: new Channels(self),
    composer: new Composer(self),
    messages: new Messages(self),
    users: new Users(self),
    peers: new Peers(self),
    status: new Status(self)
  }

  // Initial DOM tree render
  var tree = self.render()
  var rootNode = createElement(tree)
  el.appendChild(rootNode)

  // Main render loop
  raf(function tick () {
    var newTree = self.render()
    var patches = diff(tree, newTree)
    rootNode = patch(rootNode, patches)
    tree = newTree
    raf(tick)
  })

  self.on('selectChannel', function (selectedChannel) {
    self.data.channels.forEach(function (channel) {
      channel.active = (selectedChannel === channel)
      if (channel.active) self.data.messages = channel.messages
    })
    self.views.messages.scrollToBottom()
  })

  self.on('sendMessage', function (text) {
    text = text.trim()
    if (text.length === 0) return

    var activeChannel = self.data.channels.reduce(function (a, b) {
      return a && a.active ? a : b
    }, null)

    swarm.send({
      username: self.data.username,
      channel: activeChannel && activeChannel.name,
      text: text,
      timestamp: Date.now()
    })
  })

  self.on('addChannel', function (channelName) {
    if (!channelsFound[channelName]) {
      var channel = channelsFound[channelName] = {
        name: channelName,
        id: self.data.channels.length,
        active: false,
        messages: []
      }
      self.data.channels.push(channel)
    }
  })

  // Update friendly "timeago" time string (once per minute)
  setInterval(function () {
    self.data.messages.forEach(function (message) {
      message.timeago = moment(message.timestamp).fromNow()
    })
  }, 60 * 1000)
}
Example #3
0
function App (el) {
  var self = this
  if (!(self instanceof App)) return new App(el)

  var db = levelup('./friendsdb', {db: leveldown})

  db.channels = subleveldown(db, 'channels', {valueEncoding: 'json'})

  // Open links in user's default browser
  delegate.on(el, 'a', 'click', function (e) {
    var href = e.target.getAttribute('href')
    if (/^https?:/.test(href)) {
      e.preventDefault()
      shell.openExternal(href)
    }
  })

  // The mock data model
  self.data = {
    peers: 0,
    username: '******' + catNames.random() + ')',
    channels: [],
    messages: [],
    users: []
  }

  var swarm = window.swarm = Swarm(subleveldown(db, 'swarm'))
  githubCurrentUser.verify(function (err, verified, username) {
    if (err) return console.error(err.message || err)
    if (verified) {
      self.data.username = username
      swarm.username = username
      ghsign.verifier(username)
    }
  })

  var channelsFound = {}
  var usersFound = {}
  var verifiers = {}

  swarm.process(function (entry, cb) {
    var basicMessage = JSON.parse(entry.value)
    var userVerify = verifiers[basicMessage.username]

    var onverify = function () {
      var message = richMessage(basicMessage)
      var channelName = message.channel || 'friends'
      var channel = channelsFound[channelName]

      if (!channel) {
        channel = channelsFound[channelName] = {
          id: self.data.channels.length,
          name: channelName,
          active: false,
          peers: 0,
          messages: []
        }
        self.data.channels.push(channel)
        self.data.activeChannel = channel
      }

      var anon = /Anonymous/i.test(message.username)

      message.avatar = anon
        ? 'static/Icon.png'
        : 'https://github.com/' + message.username + '.png'
      message.timeago = util.timeago(message.timestamp)

      if (self.data.username && !currentWindow.isFocused()) {
        console.log(message.rawText)
        if (message.rawText.indexOf(self.data.username) > -1) {
          new Notification('Mentioned in #' + channel.name, { // eslint-disable-line
            body: message.username + ': ' + message.rawText.slice(0, 20)
          })

          self.setBadge()
        }
      }

      channel.messages.push(message)

      if (!message.anon && message.valid && !usersFound[message.username]) {
        usersFound[message.username] = true
        self.data.users.push({
          name: message.username,
          avatar: message.avatar
        })
      }
      if (!message.anon && !message.valid) {
        message.username = '******' + message.username
      }

      self.views.messages.scrollToBottom()
      cb()
    }
    if (!userVerify && basicMessage.sig) userVerify = verifiers[basicMessage.username] = ghsign.verifier(basicMessage.username)
    if (userVerify && basicMessage.sig) {
      var msg = Buffer.concat([
        new Buffer(basicMessage.username),
        new Buffer(basicMessage.channel ? basicMessage.channel : ''),
        new Buffer(basicMessage.text),
        new Buffer(basicMessage.timestamp.toString())
      ])
      userVerify(msg, new Buffer(basicMessage.sig, 'base64'), function (err, valid) {
        if (err) basicMessage.valid = false
        basicMessage.valid = valid
        onverify()
      })
      return
    }

    onverify()
  })

  swarm.on('peer', function (p, channel) {
    var ch = channelsFound[channel]
    if (ch) ch.peers++
    self.data.peers++
    eos(p, function () {
      if (ch) ch.peers--
      self.data.peers--
    })
  })

  channelsFound.friends = {
    id: 0,
    name: 'friends',
    active: true,
    peers: 0,
    messages: []
  }

  self.data.channels.push(channelsFound.friends)
  self.data.messages = channelsFound.friends.messages
  self.data.activeChannel = channelsFound.friends

  // View instances used in our App
  self.views = {
    channels: new Channels(self),
    composer: new Composer(self),
    messages: new Messages(self),
    users: new Users(self),
    peers: new Peers(self),
    status: new Status(self)
  }

  // Initial DOM tree render
  var tree = self.render()
  var rootNode = createElement(tree)
  el.appendChild(rootNode)

  // Main render loop
  raf(function tick () {
    var newTree = self.render()
    var patches = diff(tree, newTree)
    rootNode = patch(rootNode, patches)
    tree = newTree
    raf(tick)
  })

  self.on('selectChannel', function (selectedChannel) {
    self.data.channels.forEach(function (channel) {
      channel.active = (selectedChannel === channel)
      if (channel.active) {
        self.data.messages = channel.messages
        self.data.activeChannel = channel
        if (channel.name !== 'friends') db.channels.put(channel.name, {name: channel.name, id: channel.id})
      }
    })
    self.views.messages.scrollToBottom()
  })

  self.on('sendMessage', function (text) {
    text = text.trim()
    if (text.length === 0) return

    swarm.send({
      username: self.data.username,
      channel: self.data.activeChannel && self.data.activeChannel.name,
      text: text,
      timestamp: Date.now()
    })
  })

  self.on('addChannel', function (channelName) {
    if (channelName[0] === '#') channelName = channelName.substring(1)
    if (!channelsFound[channelName]) {
      var channel = channelsFound[channelName] = {
        name: channelName,
        id: self.data.channels.length,
        peers: 0,
        active: false,
        messages: []
      }
      self.data.channels.push(channel)
      swarm.addChannel(channelName)
      db.channels.put(channelName, {name: channelName, id: self.data.channels.length})
    }
  })

  self.on('leaveChannel', function (channelName) {
    if (channelName === 'friends') return // can't leave friends for now
    db.channels.del(channelName, function () {
      var channel = channelsFound[channelName]
      if (!channel) return
      var i = self.data.channels.indexOf(channel)
      if (i > -1) self.data.channels.splice(i, 1)
      delete channelsFound[channelName]
      swarm.removeChannel(channelName)
      self.emit('selectChannel', channelsFound.friends)
    })
  })

  // Update friendly "timeago" time string (once per minute)
  setInterval(function () {
    self.data.activeChannel.messages.forEach(function (message) {
      message.timeago = util.timeago(message.timestamp)
    })
  }, 60 * 1000)

  db.channels.createValueStream()
    .on('data', function (data) {
      data.messages = []
      data.peers = 0
      self.data.channels.push(data)
      channelsFound[data.name] = data
      swarm.addChannel(data.name)
    })
}
Example #4
0
function App (el) {
  var self = this
  if (!(self instanceof App)) return new App(el)
  self._notifications = 0

  var db = levelup('./friendsdb', {db: leveldown})

  db.channels = subleveldown(db, 'channels', {valueEncoding: 'json'})

  // Open links in user's default browser
  delegate.on(el, 'a', 'click', function (e) {
    var href = e.target.getAttribute('href')
    if (/^https?:/.test(href)) {
      e.preventDefault()
      shell.openExternal(href)
    } else if (/^#/.test(href)) {
      self.emit('addChannel', href)
    }
  })

  // The mock data model
  self.data = {
    peers: 0,
    username: '******' + catNames.random() + ')',
    channels: [],
    messages: [],
    users: [],
    activeChannel: null
  }

  var swarm = window.swarm = Swarm(subleveldown(db, 'swarm'), {maxPeers: 20})
  var channelsFound = {}
  var usersFound = {}
  var changesOffsets = {}

  // join default channel
  swarm.addChannel('friends')

  githubCurrentUser.verify(function (err, verified, username) {
    if (err || !verified) self.showGitHelp()
    if (err) return console.error(err.message || err)
    if (verified) {
      self.data.username = username
      swarm.username = username

      // Re-create rich messages after we know our username, since we can now do
      // highlights correctly.
      self.data.messages = self.data.messages.map(function (message) {
        return richMessage(message, self.data.username)
      })

      render()
    }
  })

  // clear notifications on focus. TODO: only clear notifications in current channel when we have that
  currentWindow.on('focus', function () {
    self.setBadge(false)
  })

  swarm.process(function (basicMessage, cb) {
    var message = richMessage(basicMessage, self.data.username)
    var channelName = message.channel || 'friends'
    var channel = channelsFound[channelName]

    if (!channel) {
      channel = channelsFound[channelName] = {
        id: self.data.channels.length,
        name: channelName,
        active: false,
        peers: 0,
        messages: []
      }
      self.data.channels.push(channel)
      self.data.activeChannel = channel
    }

    if (!changesOffsets[channel.name]) changesOffsets[channel.name] = swarm.changes(channel.name)

    if (self.data.username && !currentWindow.isFocused()) {
      if (message.text.indexOf(self.data.username) > -1) {
        new Notification('Mentioned in #' + channel.name, { // eslint-disable-line
          body: message.username + ': ' + message.text.slice(0, 20)
        })
        self.setBadge()
      }
    }

    var lastMessage = channel.messages[channel.messages.length - 1]
    if (lastMessage && lastMessage.username === message.username) {
      // Last message came from same user, so merge into the last message
      message = richMessage.mergeMessages(lastMessage, message)
    } else {
      channel.messages.push(message)
    }

    if (!message.anon && message.valid && !usersFound[message.username]) {
      usersFound[message.username] = true
      self.data.users[message.username] = {
        avatar: message.avatar,
        blocked: false
      }
      // Add user names to available autocompletes
      self.views.composer.autocompletes.push(message.username)
    }
    if (!message.anon && !message.valid) {
      message.username = '******' + message.username
    }

    if (changesOffsets[channel.name] <= basicMessage.change) {
      render()
      self.views.messages.scrollToBottom()
    }

    cb()
  })

  swarm.on('peer', function (p, channel) {
    var ch = channelsFound[channel]
    if (ch) ch.peers++
    self.data.peers++
    render()
    eos(p, function () {
      if (ch) ch.peers--
      self.data.peers--
      render()
    })
  })

  channelsFound.friends = {
    id: 0,
    name: 'friends',
    active: true,
    peers: 0,
    messages: []
  }

  self.data.channels.push(channelsFound.friends)
  self.data.messages = channelsFound.friends.messages
  self.data.activeChannel = channelsFound.friends

  // View instances used in our App
  self.views = {
    channels: new Channels(self),
    composer: new Composer(self),
    messages: new Messages(self),
    status: new Status(self),
    users: new Users(self)
  }

  // Initial DOM tree render
  var tree = self.render()
  var rootNode = createElement(tree)
  el.appendChild(rootNode)

  function render () {
    var newTree = self.render()
    var patches = diff(tree, newTree)
    rootNode = patch(rootNode, patches)
    tree = newTree
  }

  self.on('render', render)

  self.on('selectChannel', function (channelName) {
    self.data.channels.forEach(function (channel) {
      channel.active = (channelName === channel.name)
      if (channel.active) {
        self.data.messages = channel.messages
        self.data.activeChannel = channel
        if (channel.name !== 'friends') db.channels.put(channel.name, {name: channel.name, id: channel.id})
      }
    })
    render()
    self.views.composer.focus()
    self.views.messages.scrollToBottom()
  })

  self.on('sendMessage', function (text) {
    text = text.trim()
    if (text.length === 0) return

    swarm.send({
      username: self.data.username,
      channel: self.data.activeChannel && self.data.activeChannel.name,
      text: text,
      timestamp: Date.now()
    })
  })

  self.on('executeCommand', function (commandStr) {
    var words = commandStr.split(' ')
    var command = words[0].substring(1, words[0].length).toLowerCase()

    switch (command) {
      case 'join':
        words.shift()
        var channel = words.join(' ')
        self.emit('addChannel', channel)
        break
      case 'wc':
      case 'part':
      case 'leave':
        self.emit('leaveChannel', self.data.activeChannel.name)
        break
      default:
        console.log('Unrecognized /command: ' + command)
        self.emit('sendMessage', commandStr)
        break
    }
  })

  self.on('addChannel', function (channelName) {
    if (channelName[0] === '#') channelName = channelName.substring(1)
    if (channelName.length === 0) return

    if (!channelsFound[channelName]) {
      var channel = channelsFound[channelName] = {
        name: channelName,
        id: self.data.channels.length,
        peers: 0,
        active: false,
        messages: []
      }
      self.data.channels.push(channel)
      swarm.addChannel(channelName)
      db.channels.put(channelName, {
        name: channelName,
        id: self.data.channels.length
      })
    }
    self.emit('selectChannel', channelName)
  })

  self.on('leaveChannel', function (channelName) {
    if (channelName === 'friends') return // can't leave friends for now
    db.channels.del(channelName, function () {
      var channel = channelsFound[channelName]
      if (!channel) return
      var i = self.data.channels.indexOf(channel)
      if (i > -1) self.data.channels.splice(i, 1)
      delete channelsFound[channelName]
      swarm.removeChannel(channelName)
      self.emit('selectChannel', 'friends')
      render()
    })
  })

  self.on('toggleBlockUser', function (username) {
    var user = self.data.users[username]
    if (user) user.blocked = !user.blocked
    render()
    self.views.messages.scrollToBottom(true)
  })

  self.on('resizeComposer', function (height) {
    self.views.messages.notifyComposerHeight(height)
    render()
  })

  // Update friendly "timeago" time string (once per minute)
  setInterval(function () {
    self.data.activeChannel.messages.forEach(function (message) {
      message.timeago = util.timeago(message.timestamp)
    })
  }, 60 * 1000)

  db.channels.createValueStream()
    .on('data', function (data) {
      data.messages = []
      data.peers = 0
      self.data.channels.push(data)
      channelsFound[data.name] = data
      swarm.addChannel(data.name)
    })
    .on('end', function () {
      render()
    })
}