2. Checkout tomorrow
• Techniques for distributed high-speed map
tile generation using Mapnik & Node.js by
Simon & Javier @ 13:00 Silver Room
• The State of GeoCouch by Volker @ 15:00
Silver Room
• The new GeoData tool set: CouchDB and
NodeJS by Mick @ 15:30 Silver Room
3. By the end of this you
will know...
• what Node.js is.
• how to write and deploy Node.js servers.
• a bit about coffeescript.
• about the Geostack for Node.js.
• see how to write and deploy a RT geo app.
7. Node.js
• Event based server side JavaScript based on
Google’s V8 Engine
• Event based: good at handling a high
number of concurrent connections
• Trick: make network I/O non-blocking and
make most file I/O asynchronous
8. Blocking vs. non-
blocking
var result = db.query("select...");
// use result
...
db.query("select..", function (result) {
// use result
...
});
9. Non-blocking
• Allows the app to return to the event loop
immediately
• But why isn’t everyone using event loops?
• Require I/O to be non-blocking
• Most libs are blocking
• POSIX async I/O not available
• db bindings have no support for async queries
• async DNS resolution not standard etc.
10. I/O is expensive
• L1 cache 0.5 ns
• Mutex lock/unlock 25 ns
• Main mem. ref. 100 ns
• Send 2K bytes over 1Gbps 20,000 ns
• Read 1MB seq. from mem. 250,000 ns
• Disk seek 10,000,000 ns
• Read 1MB seq. from disk 20,000,000 ns
11. Rough calc.
• Read 30 images serially each 256K:
• 30 seek × 10 ms/seek + 30 × 256K ÷
30MB/s = 560 ms
• Read them in parallel:
• 10 ms/seek + 256K ÷ 30MB/s = 18 ms
12. Speed is important
• Amazon: 100ms extra causes 1% drop in
sales
• Google: 500ms extra causes 20% fewer
searches
• Yahoo: 400ms extra causes 5-9% more
“Back” button clicks
13. Node.js: components
• V8
• libuv: networking layer for all platforms
contains libev, libeio and c-ares
• http_parser: parser for HTTP messages
• openssl
14. Node.js design
• JS designed to be used with an event loop
• Provide a purely evented non-blocking
infrastructure to script highly concurrent
servers
• No direct I/O: there must be a callback
15. Node.js: goals
• Low-level API
• Stream everything
• Built-in support for important protocols
like TCP, DNS, HTTP
• Support HTTP features like Chuncked
requests, Keep-alive, Hang requests etc.
19. Node.js: install (Win)
• Grab the installer from http://nodejs.org/
dist/v0.5.5/node.exe
• Unstable version
• Can be built from source by using Cygwin
but it’s a pain in the ass
20. ➜ cat hello.js
var http = require('http');
var net = require('net');
var c = 0;
http.createServer(function(req, res) {
c++;
res.writeHead(200);
res.end('hello worldn');
}).listen(8000);
net.createServer(function(socket) {
socket.write('connections: ' + c);
socket.end();
}).listen(8001);
➜ node hello.js &
[1] 1879
➜ curl -i http://localhost:8000/
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked
hello world
26. CoffeeScript a quick
intro
• Compiles *.coffee down to JavaScript *.js
• Adds to the good parts of JS and gives
familiarity, safety and readability
• Usually need shorter code to generate the
JS you need.
27. music_style = "Indian"
ask = "Do you like #{music_style} music?"
var ask, music_style;
music_style = "Indian";
ask = "Do you like " + music_style + " music?";
29. # functions
play = (raga) ->
console.log(ragas[raga]['aaroha'])
console.log(ragas[raga]['avaroha'])
null
play('bhupali')
var play;
play = function(raga) {
console.log(ragas[raga]['aaroha']);
console.log(ragas[raga]['avaroha']);
return null;
};
play('bhupali');
30. # Classes
class Event
constructor: (@name, @time, @address, @lat, @lon) ->
var Event;
Event = (function() {
function Event(name, time, address, lat, lon) {
this.name = name;
this.time = time;
this.address = address;
this.lat = lat;
this.lon = lon;
}
return Event;
})();
31. class Event
constructor: (@name, @time, @address, @lat, @lon) ->
class Party extends Event
@celeberation: true
@kind: null
hasBalloons: ->
@kind == "Birthday" ? true : false
32. Event is the name
of the class and
class Event
constructor
constructor: (@name, @time, @address, @lat, @lon) ->
class Party extends Event
@celeberation: true
@kind: null
hasBalloons: ->
@kind == "Birthday" ? true : false
33. Event is the name
of the class and
class Event
constructor
constructor: (@name, @time, @address, @lat, @lon) ->
Inheritance via class Party extends Event
extends @celeberation: true
@kind: null
hasBalloons: ->
@kind == "Birthday" ? true : false
34. Event is the name
of the class and
class Event
constructor
constructor: (@name, @time, @address, @lat, @lon) ->
Inheritance via class Party extends Event
extends @celeberation: true
@kind: null
hasBalloons: ->
Inheritance via
extends @kind == "Birthday" ? true : false
@ defines an instance
variable
35. var Event, Party;
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
Event = (function() {
function Event(name, time, address, lat, lon) {
this.name = name;
this.time = time;
this.address = address;
this.lat = lat;
this.lon = lon;
}
return Event;
})();
Party = (function() {
__extends(Party, Event);
function Party() {
Party.__super__.constructor.apply(this, arguments);
}
Party.celeberation = true;
Party.kind = null;
Party.prototype.hasBalloons = function() {
var _ref;
return (_ref = this.kind === "Birthday") != null ? _ref : {
"true": false
};
};
return Party;
})();
36. try it out
event = new Party("Yo! The big party!",
"Thu, 09/15/2011 6:30pm",
"Hamilton Building, Denver Art Museum")
console.log(event.hasBalloons())
# false
event.kind = "Birthday"
console.log(event.hasBalloons())
# true
39. Node.js: Web
Frameworks
• Express: Sinatra inspired and built on
Connect a middleware layer for Node.js
• SocketStream: a fast Real-time web
framework
48. MongoDB
• v2.0 just out with support for multi-location
objects and polygon within searches
• v1.4+ added support for 2d geo point indexes
to do find near queries.
• can query for points within a bounding box
• v1.7+ added spherical distance query
• use mongoose a MongoDB object tool for
node.js
59. fs = require 'fs' # to read static files
http = require 'http' # http server
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) ->
res.writeHead 200, 'Content-Type': 'text/html'
res.end data, 'utf8'
server.listen(process.env.PORT || 3000)
io = require('socket.io').listen server
io.sockets.on 'connection', (socket) ->
clientId = socket.id
socket.on 'disconnect', (message) ->
# find the client & delete it ...
socket.on 'publish', (message) ->
# ...
socket.on 'broadcast', (message) ->
# find the client and broadcast their message
socket.broadcast.send(chat_data)
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) ->
# create a new user and broadcast their existance
socket.broadcast.emit 'newUser', new_record
60. fs = require 'fs' # to read static files
http = require 'http' # http server
imports
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) ->
res.writeHead 200, 'Content-Type': 'text/html'
res.end data, 'utf8'
server.listen(process.env.PORT || 3000)
io = require('socket.io').listen server
io.sockets.on 'connection', (socket) ->
clientId = socket.id
socket.on 'disconnect', (message) ->
# find the client & delete it ...
socket.on 'publish', (message) ->
# ...
socket.on 'broadcast', (message) ->
# find the client and broadcast their message
socket.broadcast.send(chat_data)
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) ->
# create a new user and broadcast their existence
socket.broadcast.emit 'newUser', new_record
61. fs = require 'fs' # to read static files
http = require 'http' # http server
imports
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) -> serve static http via
res.writeHead 200, 'Content-Type': 'text/html' node
res.end data, 'utf8'
server.listen(process.env.PORT || 3000)
io = require('socket.io').listen server
io.sockets.on 'connection', (socket) ->
clientId = socket.id
socket.on 'disconnect', (message) ->
# find the client & delete it ...
socket.on 'publish', (message) ->
# ...
socket.on 'broadcast', (message) ->
# find the client and broadcast their message
socket.broadcast.send(chat_data)
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) ->
# create a new user and broadcast their existence
socket.broadcast.emit 'newUser', new_record
62. fs = require 'fs' # to read static files
http = require 'http' # http server
imports
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) -> serve static http via
res.writeHead 200, 'Content-Type': 'text/html' node
res.end data, 'utf8'
server.listen(process.env.PORT || 3000) listening port
io = require('socket.io').listen server
io.sockets.on 'connection', (socket) ->
clientId = socket.id
socket.on 'disconnect', (message) ->
# find the client & delete it ...
socket.on 'publish', (message) ->
# ...
socket.on 'broadcast', (message) ->
# find the client and broadcast their message
socket.broadcast.send(chat_data)
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) ->
# create a new user and broadcast their existence
socket.broadcast.emit 'newUser', new_record
63. fs = require 'fs' # to read static files
http = require 'http' # http server
imports
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) -> serve static http via
res.writeHead 200, 'Content-Type': 'text/html' node
res.end data, 'utf8'
server.listen(process.env.PORT || 3000) listening port
io = require('socket.io').listen server bind socket & store
io.sockets.on 'connection', (socket) ->
clientId = socket.id
session
socket.on 'disconnect', (message) ->
# find the client & delete it ...
socket.on 'publish', (message) ->
# ...
socket.on 'broadcast', (message) ->
# find the client and broadcast their message
socket.broadcast.send(chat_data)
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) ->
# create a new user and broadcast their existence
socket.broadcast.emit 'newUser', new_record
64. fs = require 'fs' # to read static files
http = require 'http' # http server
imports
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) -> serve static http via
res.writeHead 200, 'Content-Type': 'text/html' node
res.end data, 'utf8'
server.listen(process.env.PORT || 3000) listening port
io = require('socket.io').listen server bind socket & store
io.sockets.on 'connection', (socket) ->
clientId = socket.id
session
socket.on 'disconnect', (message) ->
disconnect event
# find the client & delete it ... delete the user
socket.on 'publish', (message) ->
# ...
socket.on 'broadcast', (message) ->
# find the client and broadcast their message
socket.broadcast.send(chat_data)
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) ->
# create a new user and broadcast their existence
socket.broadcast.emit 'newUser', new_record
65. fs = require 'fs' # to read static files
http = require 'http' # http server
imports
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) -> serve static http via
res.writeHead 200, 'Content-Type': 'text/html' node
res.end data, 'utf8'
server.listen(process.env.PORT || 3000) listening port
io = require('socket.io').listen server bind socket & store
io.sockets.on 'connection', (socket) ->
clientId = socket.id
session
socket.on 'disconnect', (message) ->
disconnect event
# find the client & delete it ... delete the user
socket.on 'publish', (message) ->
# ... broadcast: verify the
client and broadcast
socket.on 'broadcast', (message) ->
# find the client and broadcast their message the message with
socket.broadcast.send(chat_data) user details
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) ->
# create a new user and broadcast their existence
socket.broadcast.emit 'newUser', new_record
66. fs = require 'fs' # to read static files
http = require 'http' # http server
imports
request = require 'request'
_ = require 'underscore'
server = http.createServer (req, res) ->
fs.readFile "#{__dirname}/map.html", (err, data) -> serve static http via
res.writeHead 200, 'Content-Type': 'text/html' node
res.end data, 'utf8'
server.listen(process.env.PORT || 3000) listening port
io = require('socket.io').listen server bind socket & store
io.sockets.on 'connection', (socket) ->
clientId = socket.id
session
socket.on 'disconnect', (message) ->
disconnect event
# find the client & delete it ... delete the user
socket.on 'publish', (message) ->
# ... broadcast: verify the
client and broadcast
socket.on 'broadcast', (message) ->
# find the client and broadcast their message the message with
socket.broadcast.send(chat_data) user details
# forwards message to all the clients except the one
# that emitted the "broadcast" event
socket.on 'addUser', (message) -> respond to ‘addUser’
# create a new user and broadcast their existence custom event & emit
socket.broadcast.emit 'newUser', new_record
‘newUser’ custom
102. Deployment
• Server with port 22 (ssh) and 80 (http)
• Capistrano deployment tool
• Bluepill, God, Supervisord, Monit, Upstart,
etc. process management tool
103. ➜ cat Capfile
load 'deploy' if respond_to?(:namespace) # cap2 differentiator
load 'config/deploy' # remove this line to skip loading any of the default tasks
➜ cat config/deploy.rb
...
set :use_sudo, true
set :bluepill, '/var/lib/gems/1.8/bin/bluepill'
namespace :deploy do
task :start, :roles => :app, :except => { :no_release => true } do
run "#{try_sudo :as => 'root'} #{bluepill} start #{application}"
end
...
task :create_deploy_to_with_sudo, :roles => :app do
run "#{try_sudo :as => 'root'} mkdir -p #{deploy_to}"
end
task :npm_install, :roles => :app, :except => { :no_release => true } do
run "cd #{release_path} && npm install"
end
end
before 'deploy:setup', 'deploy:create_deploy_to_with_sudo'
after 'deploy:finalize_update', 'deploy:npm_install'
...
➜ cap deploy
105. Deploy to Heroku
➜ cat .gitignore
node_modules
➜ git init
➜ git add .
➜ git commit -m "init"
➜ heroku create --stack cedar
Creating sharp-rain-871... done, stack is cedar
http://sharp-rain-871.herokuapp.com/ | git@heroku.com:sharp-rain-871.git
Git remote heroku added
➜ git push heroku master
...
➜ heroku ps:scale web=1
Scaling web processes... done, now running 1
106. HTML5 Mobile
iOS Android Blackberry IE Opera Firefox webOS Symbian
Geolocation ✓ ✓ ✓ ✓ ✓ ✓ ✓
Web Sockets ✓4.2+ ✓6.1+ ✓ ✓
Web Workers ✓6.0+ ✓ ✓
Web SQL
✓ ✓2.0+ ✓6.0+ ✓ ✓
Store
107. By the end of this you
will know...
• what Node.js is.
• how to write and deploy Node.js servers.
• a bit about coffeescript.
• about the Geostack for Node.js.
• see how to write and deploy a RT geo app.
What is CoffeeScript?\n\nCoffeeScript is a language that compiles down to JavaScript. This means that code in .coffee files are not interpreted at run time, but are compiled beforehand into .js files.\n\nCoffeeScript can be written for all implementations of JavaScript, whether it's for Node.js or the browser.\n\nWhy CoffeeScript?\n\nFirst of all, JavaScript got a bad wrap in the past for the copy-and-paste mentality of the 90's and early 2000's, where no one really knew what was going on. But JavaScript as a language really is great and has a lot to offer.\n\nSaying that, you can get lost in the curly brackets and semi-colons - It can get messy, and sometimes a tad unreadable.\n\nCoffeeScript gets around these issues by adding "syntactic sugar", similar to what Ruby and Python have to offer, which helps us write less code faster, which is also easier to read. Even when it's compiled down, CoffeeScript performs as well as JavaScript, and in some instances the compiled JavaScript has even better performance over hand-written code, due to optimizations CoffeeScript uses that some people may not be aware of. You can actually learn a lot about JavaScript by looking at what CoffeeScript compiles down to, so we encourage you to do that, and ask why CoffeeScript has done things a particular way.\n\n\n
CoffeeScript simply removes global variables. Behind the scenes, CoffeeScript wraps up scripts with anonymous function, keeping the local context, and automatically prefixes all variables assignments with var. For example, take this simple variable assignment in CoffeeScript:\n\nGlobal Variables are possible too.\nIn the root context, this is equal to the global object, and by creating a local exports variable you’re making it really obvious to anyone reading your code exactly which global variables a script is creating.\n\n\n
Object literals can be specified exactly as in JavaScript. However, CoffeeScript makes it easier.\nLikewise, arrays can use whitespace instead of comma separators, although the square brackets ([]) are still required.\n\n
CoffeeScript removes the rather verbose function statement, and replaces it with a thin arrow: –>. Functions can be one liners, or indented on multiple lines. The last expression is implicitly returned. The following two code snippets are equivalent to the third JavaScript code snippet:\nYou can also specify arguments in a pair of parenthesis before the arrow.\nCoffeeScript supports default arguments too, for example:\n
JavaScript doesn't have a class syntax, since it's a class-free, prototypal language. There are a variety of techniques for building classes in JavaScript, which are often verbose and/or wrong in subtle ways. CoffeeScript takes advantage of the fact that "class" is a reserved but unused word in JavaScript, allowing making it very easy to write classes with terse, readable code that implement a class pattern with inheritance. Here's an example from the Coffeescript site:\n\n
In the example above, Event is the name of the class, and also the name of the resultant variable that you can use to create instances. Behind the scenes CoffeeScript is using construction functions, which means you can instantiate classes using the new operator.\n\nDefining constructors (functions that get invoked upon instantiation) is simple, just use a function named constructor. This is akin to using Ruby's initialize or Python's __init__.\n\n\nIn fact, CoffeeScript provides a shorthand for the common pattern of setting instance properties. By prefixing argument's with @, CoffeeScript will automatically set the arguments as instance properties in the constructor. Indeed, this shorthand will also work for normal functions outside classes. The example below is equivalent to the last example, where we set the instance properties manually.\n\n
In the example above, Event is the name of the class, and also the name of the resultant variable that you can use to create instances. Behind the scenes CoffeeScript is using construction functions, which means you can instantiate classes using the new operator.\n\nDefining constructors (functions that get invoked upon instantiation) is simple, just use a function named constructor. This is akin to using Ruby's initialize or Python's __init__.\n\nIn fact, CoffeeScript provides a shorthand for the common pattern of setting instance properties. By prefixing argument's with @, CoffeeScript will automatically set the arguments as instance properties in the constructor. Indeed, this shorthand will also work for normal functions outside classes. The example below is equivalent to the last example, where we set the instance properties manually.\n\n
In the example above, Event is the name of the class, and also the name of the resultant variable that you can use to create instances. Behind the scenes CoffeeScript is using construction functions, which means you can instantiate classes using the new operator.\n\nDefining constructors (functions that get invoked upon instantiation) is simple, just use a function named constructor. This is akin to using Ruby's initialize or Python's __init__.\n\n\nIn fact, CoffeeScript provides a shorthand for the common pattern of setting instance properties. By prefixing argument's with @, CoffeeScript will automatically set the arguments as instance properties in the constructor. Indeed, this shorthand will also work for normal functions outside classes. The example below is equivalent to the last example, where we set the instance properties manually.\n\n
In the example above, Event is the name of the class, and also the name of the resultant variable that you can use to create instances. Behind the scenes CoffeeScript is using construction functions, which means you can instantiate classes using the new operator.\n\nDefining constructors (functions that get invoked upon instantiation) is simple, just use a function named constructor. This is akin to using Ruby's initialize or Python's __init__.\n\n\nIn fact, CoffeeScript provides a shorthand for the common pattern of setting instance properties. By prefixing argument's with @, CoffeeScript will automatically set the arguments as instance properties in the constructor. Indeed, this shorthand will also work for normal functions outside classes. The example below is equivalent to the last example, where we set the instance properties manually.\n\n
Behind the scenes, CoffeeScript is using JavaScript's native prototype to create classes; adding a bit of syntactic sugar for static property inheritance and context persistence. As a developer all that's exposed to you is the class keyword.\n
In the example above, Event is the name of the class, and also the name of the resultant variable that you can use to create instances. Behind the scenes CoffeeScript is using construction functions, which means you can instantiate classes using the new operator.\n\nDefining constructors (functions that get invoked upon instantiation) is simple, just use a function named constructor. This is akin to using Ruby's initialize or Python's __init__.\n\n\nIn fact, CoffeeScript provides a shorthand for the common pattern of setting instance properties. By prefixing argument's with @, CoffeeScript will automatically set the arguments as instance properties in the constructor. Indeed, this shorthand will also work for normal functions outside classes. The example below is equivalent to the last example, where we set the instance properties manually.\n\n
that was very quick but you can get more here.\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
* Think of package.json as an application manifest for a node project. \n\n* Use by npm (node package manager) to describe you application and allow automatic installation of dependencies needed to run you application.\n\n* It describes verions, name and dependencies.\n\n* The most **important** things in your package.json are the *name* and *version* fields. Those are actually required, and your package won't install without them.\n\n### name \n\n* Check the [npm registry](http://registry.npmjs.org) if you are creating a public project.\n\n* Non-url-safe characters will be rejected.\n\n* We are going add socket.io as a dependency.\n
* Think of package.json as an application manifest for a node project. \n\n* Use by npm (node package manager) to describe your application and allow automatic installation of dependencies needed to run your application.\n\n* It describes versions, name and dependencies.\n\n* The most **important** things in your package.json are the *name* and *version* fields. Those are actually required, and your package won't install without them.\n\n### name \n\n* Check the [npm registry](http://registry.npmjs.org) if you are creating a public project.\n\n* Non-url-safe characters will be rejected.\n\n* We are going add socket.io as a dependency.\n
* It describes version, name and dependencies.\n* The most **important** things in your package.json are the *name* and *version* fields. Those are actually required, and your package won't install without them.\n### name \n* Check the [npm registry](http://registry.npmjs.org) if you are creating a public project.\n* Non-url-safe characters will be rejected.\n* We are going add socket.io as a dependency.\n
\n
Structure of the WebSocket Server\n
Structure of the WebSocket Server\n
Structure of the WebSocket Server\n
Structure of the WebSocket Server\n
Structure of the WebSocket Server\n
Structure of the WebSocket Server\n
Structure of the WebSocket Server\n
Structure of the WebSocket Server\n
\n
\n
Socket.IO is the last critical piece in this toolchain. Socket.IO abstracts away the pain of providing realtime connections to almost any browser. It will detect the capabilities of the client and use a variety of transports to facilitate a connection. All we have to do is handle the messaging.\n\nCoffeeScript can be used both on the server, as a command-line compiler based on Node.js/V8, or to run CoffeeScripts directly in the browser. This module contains the main entry functions for tokenizing, parsing, and compiling source CoffeeScript into JavaScript.\n\nIf included on a webpage, it will automatically sniff out, compile, and execute all scripts present in text/coffeescript tags.\n\n\n
CoffeeScript can be used both on the server, as a command-line compiler based on Node.js/V8, or to run CoffeeScripts directly in the browser. This module contains the main entry functions for tokenizing, parsing, and compiling source CoffeeScript into JavaScript.\n\nIf included on a webpage, it will automatically sniff out, compile, and execute all scripts present in text/coffeescript tags.\n\n\n
\n
The first five events — "connect", "disconnect", "reconnecting", "reconnect", and "reconnect_failed" — are emitted by Socket.IO in response to changes in the connection status. We've registered a handler for each in order to expose this information to users.\n\nWe've also added handlers for "message" events. Our "message" handler will be called whenever the server receives a "publish" or "broadcast" event (io.sockets.send and socket.broadcast.send emit "message" events). \n\nAll that remains is to have the client emit appropriate custom events in response to input from users.\n\n
The first five events — "connect", "disconnect", "reconnecting", "reconnect", and "reconnect_failed" — are emitted by Socket.IO in response to changes in the connection status. We've registered a handler for each in order to expose this information to users.\n\nWe've also added handlers for "message" events. Our "message" handler will be called whenever the server receives a "publish" or "broadcast" event (io.sockets.send and socket.broadcast.send emit "message" events). \n\nAll that remains is to have the client emit appropriate custom events in response to input from users.\n\n
All that remains is to have the client emit appropriate custom events in response to input from users. This will give us the basics chat client.\n
All that remains is to have the client emit appropriate custom events in response to input from users. This will give us the basics chat client.\n
# put leaflet in your html\n\n1. leaflet.css, 2. Leaflet JavaScript, 3. mapdiv \n\ninit map\n1. create a map instance, \n2. set its view to the center of \n - Berlin (52.52267, 13.41293)\n - Denver (39.73904, -104.98482)\n3. add a pretty CloudMade tile layer to it\n\nThis will give us something with a map...\n\n
This is what we see..\n
Later I will throw up some ideas on what additional things you can build with the basic building block of an application that we describe in this tutorial. And in this vain I just want to mention that you can get user location via HTML5. Which may be useful for App ideas later.\n\nHTML5 GeoLocation enabled browsers will allow you to access geoLocation via a Javascript API. the simplist way to get location is using a “getCurrentPosition” method which takes a callback function. So lets create a function “get_location()” which simply uses the HTML5 GeoLocation API. We write a callback function too to create a marker with the new position. The callback function receives the device position as parameters.\n\n
This prompts the user for their location in a non-modal way. This makes sure their browsing experience is not interrupted. They can ignore it if they which or say Allow. Allowing will prompt the callback function. Which...\n
Adds a marker to the map\n
\n
\n
\n
\n
\n
Socket.IO is the last critical piece in this toolchain. Socket.IO abstracts away the pain of providing realtime connections to almost any browser. It will detect the capabilities of the client and use a variety of transports to facilitate a connection. All we have to do is handle the messaging.\n\n\n
# Why do this? \nAt the end of this we will deploy our application... and we need a persistence storage with spatial capabilities out in the “Cloud”. We can do this with SpacialDB very easily. \n\nAlthough SpaciaDB's REST API lets you push data directly to the database, sometimes you want to do things on the server before saving to the data. One example would be creating a Real-time websocket powered appilication. Where the a websocket client communicates with the server and the server manages the message broacasting.\n\nSo lets get started. First you need an account on SpacialDB.\n\n# I am signed up lets get a spatial database\n\nAssuming you have the spcialdb gem installed and are signed up to spacialdb (if not its easy `spacaildb signup`). \n\n
\n
\n
\n
\n
On the server side we want to listen for the `addUser` event. In response to the event we want to store the new user in SpacialDB and then emit a `newUser` event with the saved user's details back to the client.\n\nBack at the client we will have to listen for the `newUser` event and take appropriate action.\n\n
\n
\n
\n
\nBack at the client we receive the broadcast and parse the message to find the user's name, location and the message. We can then display that in a popup.\n\n\n
\n
\n
\n
\n
Lets now look at ways to deploy our application live\n