angr

writings from zac anger, who is not all that angry

getting up and running with nw.js really super quickly

February 14, 2016 — Zac Anger

There are basically two main ways to build a desktop app in JS: Electron (formerly called 'Atom-Shell') and NW.js (formerly called 'Node-Webkit'). Electron's really swell, probably offers more options overall, and has a cleaner way of keeping Node and client-side code separate. NW.js is a heckuva lot easier, overall, though.

This is what I've been using to build and run Pharaoh: https://github.com/nwjs/nw-builder

There's also a nifty sort of version manager for NW.js here: https://www.npmjs.com/package/nwjs , which worked a little more smoothly out of the box, but gave me issues when trying to get Node integration to work.

To get up and running with NW.js using nw-builder, you basically just need to put the relevant information in your package.json. The relevant info on that is all here: https://github.com/nwjs/nw.js/wiki/Manifest-format but mostly it's just something like

"window": {
  "height": 800,
  "width": 1200,
  "title": "my app"
}

et cetera. The main field (which usually has, like, server/index.js or whatever in it), needs to be what NW.js is pointed to. That can be an HTML file ("main": "./client/public/index.html" or whatever) or a URL (if you're serving the app, especially locally--this is how Atom, Brackets, LightTable, etc. do things, except using Electron).

That's basically it, I think. There are a lot of great Yeoman generators and stuff to scaffold out NW.js apps, but they're mostly overkill.

Using nw-builder makes things pretty simple. npm i -g nw-builder, then just run nwbuild -h to see the options. (I use nwbuild -r . in the project root/wherever the relevant package.json is, to run the app).

Their docs are really good, and there's a crapload of options and neat stuff you can do: https://github.com/nwjs/nw.js/wiki

tags: nwjs, desktop, node, electron, app

so, tweet it?  

basic auth

February 12, 2016 — Zac Anger
  • Basic HTTP:
    • restricted based on system user/pass
    • http://zacanger:encryptedpassword@zacanger.com
  • Form-based:
    • restricted based on cookies
    • success = stored cookie on client
    • POST whatever.com/login (headers)
  • Token-based:
    • requests with auth token
    • https://foo.bar/whatever?auth_token=asdfghjkl123456789
  • OAuth
    • rate limited, expired, revoked server-side
  • Passport
    • this is, clearly, the preferred method, both with devmtn and with express in general, i feel

read more...

tags: auth, node, js, passport

so, tweet it?  

node-fs basics

February 12, 2016 — Zac Anger

this is another one that'll be presented just as a giant code block.

// using files in node
var fs = require('fs')
var buf = new Buffer(1024)

// reading asynchronously
fs.readFile('foo.md', function(err, data){
  if(err){
    return console.error(err)
  }
  console.log('async read: ' + data.toString())
})
// and synchronously
var data = fs.readFileSync('foo.md')
console.log('sync read: ' + data.toString())
console.log('#############\n')

// opening
// fs.open(path, flags[, mode], cb)
// flags can be r (r), r (rw), rs (r synchronously), rs+ (rw, sync),
// w (write), wx (fails if file exists), w+ (rw, creates file (or truncates existing)),
// wx+ (fails if path exists), a (append), ax (fails if path exists),
// a+ (file for read & append), ax+ (fails if path exists)
console.log('opening file')
fs.open('foo.md', 'r+', function(err, fd){
  if(err){
    return console.error(err)
  }
  console.log('opened')
})

// information about files
// fs.stat(path, callback)
// .isFile() returns true if file, .isDirectory returns true if dir,
// isBlockDevice returns true if block device, isCharacterDevice...,
// isSymbolicLink ..., isFifo, isSocket
console.log('getting file info')
fs.stat('foo.md', function(err, stats){
  if(err){
    return console.error(err)
  }
  console.log(stats)
  console.log('got yer file')
  console.log('symlink? ' +  stats.isSymbolicLink)
  console.log('char? ' + stats.isCharacterDevice)
})

// writing: fs.writeFile(filename, data[, options], cb)
console.log('gonna write a file')
fs.writeFile('bar.md', 'stuff!', function(err){
  if(err){return console.error(err)}
  console.log('written!')
  console.log('reading that now')
  fs.readFile('bar.md', function(err, data){
    if(err){return console.error(err)}
    console.log('async read: ' data.toString())
  })
})

// closing: fs.close(fd, callback)
console.log('opening file')
fs.open('bar.md', 'r+', function(err, fd){
  if(err){return console.error(err)}
  console.log('opened')
  console.log('reading it')
  fs.read(fd, buf, 0, buf.length, 0 function(err, bytes){
    if(err){console.log(err)}
    if(bytes > 0){console.log(buf.slice(0, bytes).toString())}
    fs.close(fd, function(err){
      if(err){console.log(err)
    }
    console.log('closed!')
    })
  })
})

// truncating: fs.ftruncate(fd, len, cb)
// ... meh

// deleting: fs.unlink(path, cb)
console.log('gonna DELETE a file!')
fs.unlink('bar.md', function(err){if(err){return console.error(err)}
console.log('deleted!')})

// mkdir: fs.mkdir(path[, mode], cb)
fs.mkdir('./test', function(err){
  if(err){return console.error(err)}
  console.log('created a directory at \'test\'')
})
fs.mkdir('./asdf', function(err){
  if(err){return console.error(err)}
  console.log('created one called \'asdf\', too!')
})
// fs.readdir(path, cb)
fs.readdir('./', function(err, files){
  if(err){return console.error(err)}
  files.forEach(function(file){
    console.log(file)
  })
})

// fs.rmdir(path, cb)
fs.rmdir('./asdf', function(err){
  if(err){return console.error(err)}
  fs.readdir('./', function(err, files){
    if(err){return console.error(err)}
    files.forEach(function(file){
      console.log(file)
    })
  })
})

// there are a whole bunch of other methods, but i feel like this is good enough for now, yes?

tags: node, fs, node-fs, javascript, basics

so, tweet it?  

Node Notes

February 03, 2016 — Zac Anger

I really enjoy node. This is all pretty disorganized. It's also all one giant code block, since I took the 'notes' bit in comments. The repos mentioned are here and here. Yay.

read more...

tags: node, notes

so, tweet it?  

email from node

January 28, 2016 — Zac Anger

nodemailer and nodemailer-smtp-transport

var transporter = nodemailer.createTransport(
  smtpTransport('smtps://foo@thing.com:asdf@bar.com'))
var transport = nodemailer.createTransport(smtpTransport({
  host: 'host'
, port: foo
, auth: {
    user: 'username'
  , pass: 'password'
  }
}))
transporter.sendMail(mailOptions, function(err, info){
  if(error){res.send(error)}
  else{res.send(info)}
})

using a service, we're just sending the bare instructions there from the front-end, so sendgrid or whatever would take care of the actual compiling, rendering, and all that nonsense. (remember the blogs on tinyletter or whatever, about how to even make your email acceptable? hmmm....)

sendgrid, mandrill, and mailgun are the big ones. sendgrid is a little less likely to throw your emails in spam. 12k per month or something like that (with daily cap of maybe 400-ish) for free. they have a slight delay when you sign up, maybe a few hours. obvs we'd likely want to do our own server/service for large-scale, but the analytics available on these things are worth it...? (see: pb:tag/analytics.)

to use sendgrid we'd need to npm i -S sendgrid. then we're using fs.readFile(), i suppose, to work with things on the disk. (note that this could also be in streams, and it could also be in a db....) sendgrid can work with some templating on the back end, though it evidently doesn't inline your css for you.... ah, i see, it looks like zurb's got a tool for that (of course--they've got a tool for everything). i think tinyletter has one, too.

there are yeoman generators for all this stuff. why do the dirty work yourself?

zero and rabbit are things. i guess rabbitmq is currently the more popular one?

tags: email, node

so, tweet it?  

Auth with Passport and Express

January 23, 2016 — Zac Anger

Passport/Flash Issues

npm i -S express-flash, and var flash = require('express-flash') in your app.app.use(flash())`.

So, make a route in your app/routes/config file, wherever you're keeping those, something like app.get('/forgot', function(req, res){res.render('forgot', {user: req.user})}), assuming you have some html with a form that POSTs, and input for the email.

This assumes async and nodemailer, plus a mailing service (like sendgrid or gmail or whatever).

app.post('/forgot', function(req, res, next){
  async.waterfall([
    function(done){
      crypto.randomBytes(20, function(err, buf){
        var token = buf.toString('hex')
        done(err, token)
      })
    },
    function(token, done){
      User.findOne({email: req.body.email}, function(err, user){
        if(!user){
          req.flash('error', 'no account!')
          return res.redirect('/forgot')
        }
        user.resetPasswordToken   = token
        user.resetPasswordExpires = Date.now() + 3600000
        user.save(function(err){
          done(err, token, user)
        })
      })
    },
    function(token, user, done){
      var smptTransport = nodemailer.createTransport('SMTP', {
        service: 'foo',
        auth: {user: 'your username for the service', pass: 'your pass for the service'}
      })
      var mailOptions = {
        to: user.email,
        from: 'learny-app@thing.bar',
        subject: 'reset yer passwerd, yo'.
        text: 'hey, click the thingy and stuff, right here, to reset yer passwerd: http://' + req.headers.post + '/forgot/' + token '\n' + ' .'
      }
      smtpTransport.sendMail(mailOptions, function(err){
        req.flash('info', 'email sent to ' + user.email + ' to reset yer passwyrd.')
        done(err, 'done')
      })
    }
  ],
  function(err){
    if(err) return next(err)
    res.redirect('/forgot')
  })
})
app.get('/reset/:token', function(req, res{
  User.findOne({resetPasswordToken: req.params.token, resetPasswordExpires: $gt: Date.now()}), function(err, user){
    if(!user){
      req.flash('error', 'invalid password reset token')
      return res.redirect('/forgot')
    }
    res.render('reset', {
      user.req.user
    })
  })
})
app.post('/reset/:token', function(req, res){
  async.waterfall([
    function(done) {
      User.findOne({resetPasswordToken: req.params.token, resetPasswordExpires: {$gt: Date.now()}}, function(err, user){
        if(!user){
          req.flash('error', 'nope, nope nope.')
          return res.redirect('back')
        }
        user.password = req.body.password
        user.resetPasswordToken = undefined
        user.resetPasswordExpires = undefined
        user.save(function(err){
          req.logIn(user, function(err){
            done(err, user)
          })
        })
      })
    },
    function(user, done){
      var smtpTransport = nodemailer.createTransport('SMTP', {
        service: 'quux',
        auth: {
          user: 'same as above',
          pass: 'same as above'
        }
      })
      var mailOptions = {
        to: user.email,
        from: 'learnythingy@stuff.baz',
        subject: 'changed pw!',
        text: 'heyo,\n\n' +
          'account ' + user.email + ''s password was changed \n'
      }
      smtpTransport.sendMail(mailOptions, function(err){
        req.flash('success', 'pw changed')
        done(err)
      })
    }
  ], function(err){
    res.redirect('/')
  })
})

read more...

tags: passport, express, node, auth, authentication, local, login

so, tweet it?  

Electron and NW.js

January 15, 2016 — Zac Anger

Electron (formerly known as Atom Shell) and NW.js (formerly known as Node Webkit) are similar projects that bring Javascript to the desktop. They're both based on browser runtimes. Electron is sponsored by Github, and uses libchromiumcontent and Webkit 537 (as of Autumn 2015). NW.js is sponsored by Intel and uses Chromium and Blink/Webkit 537. They both use the V8 JS engine (from Chrome), are fully open source (MIT Licensed), can access a variety of open and licensed codecs, work on Unix-like systems (and, with a little extra work, on Windows), and can use Flash (in Electron's case, through the Pepper plugin). The biggest difference I've had in working with them is that Electron, being currently more popular (likely because of the Github support, and the popularity of the Atom editor, which is built on Electron) is usually closer to the current version of Chromium, and NW.js is usually a few versions behind. Electron seems to have a lot more community activity around it right now, too, so there are a lot of useful NPM packages like Electron-Prebuilt (and a lite version) and Electron-Packager (and an interactive version!). Electron also needs a Javascript entry point, which looks something like this:

var app           = require('app')  
  , BrowserWindow = require('browser-window')  
require('crash-reporter').start()  

var mainWindow = null  

app.on('window-all-closed', function(){  
  if(process.platform != 'darwin'){  
      app.quit()  
  }  
})  
app.on('ready', function(){  
  mainWindow = new BrowserWindow({  
    width                : 1200  
  , height               : 800  
  , 'accept-first-mouse' : true  
  , 'title-bar-style'    : 'hidden'  
  , 'node-integration'   : false  
  })  
  mainWindow.loadUrl('http://127.0.0.1:9090')  
  mainWindow.on('closed', function(){  
    mainWindow = null  
  })  
})  

That 'node-integration' line is really important if you want to use certain client-side libraries like Angular or jQuery that use the word 'module;' your stuff will just completely break without it.

NW.js, on the other hand, can just be pointed at your index.html, and that's enough to get started. That's really convenient, but for my own uses I've found that Electron has a lot more options. Its binaries are significantly larger, but there are evidently ways to cut them down. Don't count on being able to build an Electron app in less than a hundred megs, though.

If you're doing something small, like a text editor or some other little widgety kind of app, you'd probably still be better off with Qt or GTK--you can write a full text editor in GTK-Webkit with Python in less than 16kb, and that's if need a full rich-text interface with buttons and such. But for larger apps, and especially for apps you've already written for the browser, NW.js and Electron are both really great options. If you're going to be relying on a lot of the Node environment, Electron's got a better interface to Node because of its separated rendering and browser engines, but you do have to keep in mind that you'll be limited as to what client-side libraries you can use.

tags: nwjs, electron, desktop, js, javascript, apps, node

so, tweet it?  

Express vs Koa vs Hapi

December 30, 2015 — Zac Anger

Express vs Koa vs Hapi

Quick little comparison of the three. Express is clearly the most commonly used, but I'm inclined to jump to Koa whenever I can. The simple fact that the guy who initially started Express passed that off to a company to maintain and instead works on Koa, now (which he also started), says to me that maybe Koa's the right way to go.

Okay, so all three are Sinatra-alikes for Node.

Express was started in 2009, and is now maintained by StrongLoop, the Node API company.

Koa was started in 2013, and rather than a 'server-side web development framework build on node.js' (that's Express), Koa is 'expressive middleware for node.js using generators ... to make writing web applications and REST APIs more enjoyable.' It's super small, too--around 400 SLOC.

Hapi was started in 2011, and was originally built on Express. The original author still maintains it, backed by the original company (...Wal...Mart...). It's no longer Express-based, because 'configuration is better than code ... business logic must be isolated from the transport layer...', so, there's that.

Making things happen:

    // express
    const express = require('express')
      , app = express()
      , port = 3000
    // etc, we already know all this
    app.listen(port) // http.createServer() basically

    // koa
    const koa = require('koa')
      , app = koa()
      , port = 3000
    const server = app.listen(port, function(){
      console.log('listening on ' + port)
    }) // well, THAT looks super familiar, huh?

    //hapi
    const Hapi = require('hapi')
      , server = new Hapi.Server()
    server.connection({port:3000})
    server.start(() => {
      console.log('server over yonder on ', server.info.uri)
    }) // that takes a weee bit more work, there.
    ```

    routing:
    ```javascript
    app.get('/', function(req, res){res.send('hi')})

    app.use(function *(){this.body = 'hi'}) // so, koa uses es6 generators.
        // the context (this) is node's `request` and `response`, wrapped up
        // `this.body` can be string, buffer, stream, object, or null

    server.route({
      method : 'GET',
      path: '/',
      handler: function(request, reply){
        reply('hi') // holy boilerplate, batman
      }
    })

read more...

tags: express, koa, js, hapi, server, node, framework

so, tweet it?  

Finally almost done with Angular...

November 11, 2015 — Zac Anger

Look. I don't have anything against Angular on, like, a philosophical level. Or metaphysical. Or personal. I'm just not impressed. An MVC framework that makes templating easier and makes a lot of other things much more complicated? Client-side rendering? Bogging down browsers doing the heavy lifting so servers can respond a little faster? Very cool features. Very innovative. The year is 2008 and Javascript is starting to come into its own. Open source front-end libraries and frameworks are starting to pop up. Github was just founded. Angular is epic, right?

read more...

tags: javascript, school, markdown, angular, node, bitching, lots-of-bitching, god-i-bitch-a-lot

so, tweet it?  

zac anger?