Permalink
Browse files

0.2.1

  • Loading branch information...
1 parent ca821eb commit 0fa47c30762fcdfd1b5f23c2b1544e72588b7e69 Owen Barnes committed Sep 4, 2011
View
@@ -1,3 +1,15 @@
+0.2.1 / 2011-09-04
+==================
+
+* When receiving an event sent to a channel the channel name is now passed to the second argument. Updated docs
+* HTTP API now refuses POST data above 8Mb to prevent running out of memory. Limit can be configured with SS.config.api.post_max_size_kb
+* We now take advantage of connect.staticCache() in Connect 1.7.0 for increased performance
+* Upgraded Socket.IO to 0.8.3
+* New projects now include an empty package.json file
+* Added the public/assets directory to the default .gitignore file
+* Few tweaks to /config/app.coffee and /config/http.coffee
+
+
0.2.0 / 2011-08-31
==================
View
@@ -1,7 +1,7 @@
![SocketStream!](https://github.com/socketstream/socketstream/raw/master/new_project/public/images/logo.png)
-Latest release: 0.2.0 ([view changelog](https://github.com/socketstream/socketstream/blob/master/HISTORY.md))
+Latest release: 0.2.1 ([view changelog](https://github.com/socketstream/socketstream/blob/master/HISTORY.md))
Twitter: [@socketstream](http://twitter.com/#!/socketstream)
Google Group: http://groups.google.com/group/socketstream
@@ -2,21 +2,40 @@
In addition to the `SS.publish.user()` method documented in Example 3 within the README, there are two additional publish commands which allow you to easily message users in bulk.
-To send a notification to all users (for example to let everyone know the system is going down for maintenance), use the broadcast method:
+
+#### Broadcasting
+
+To send a notification to every connected client (for example to let everyone know the system is going down for maintenance), use the broadcast method:
``` coffee-script
SS.publish.broadcast('flash', {type: 'notification', message: 'Notice: This service is going down in 10 minutes'})
```
+
+Receive the event in the browser with:
+
+``` coffee-script
+SS.events.on 'flash', (msg) ->
+ alert(msg.message)
+```
+
+#### Private Channels
-Sometimes you may prefer to send events to a sub-set of connected users, for example if you have a chat apps with multiple rooms. SocketStream has a cool feature called Private Channels which let you do just that across multiple servers with minimum overhead.
+Sometimes you'll want to send events to a sub-set of connected users. For example, if you have a chat app with multiple rooms. SocketStream supports Private Channels which let you do just that.
The syntax is similar to the command above with an extra initial argument specifying the channel name (or names as an array):
``` coffee-script
SS.publish.channel(['disney', 'kids'], 'newMessage', {from: 'mickymouse', message: 'Has anyone seen Tom?'})
```
-
-Users can subscribe to an unlimited number of channels using the following commands (which must be run inside your /app/server code). E.g:
+
+Receive these events in the browser in the usual way. Note: If the event was sent to a channel, the channel name is passed to the second argument:
+
+``` coffee-script
+SS.events.on 'newMessage', (msg, channel_name) ->
+ console.log "The following message was sent to the #{channel_name} channel:", msg
+```
+
+Clients can subscribe to an unlimited number of channels using the following commands (which must be run inside your /app/server code). E.g:
``` coffee-script
@session.channel.subscribe('disney') # note: multiple channel names can be passed as an array
@@ -34,8 +34,7 @@ methods =
disconnect: (obj, session, cb) ->
SS.events.emit 'client:disconnect', session
- # A heartbeat is sent every X seconds by clients
- # We will work to make this method faster in the future
+ # A heartbeat is sent every SS.config.client.heartbeat_interval seconds by connected clients
heartbeat: (obj, session, cb) ->
SS.users.online.confirm(session.user_id) if SS.users.online && session.user_id
SS.events.emit 'client:heartbeat', session
View
@@ -76,11 +76,12 @@ setDefaults = ->
### OPTIONAL MODULES ###
- # Configures the HTTP request-based API
+ # HTTP request-based API
api:
enabled: true
prefix: 'api' # defines the URL namespace
https_only: false # only allow API requests over HTTPS
+ post_max_size_kb: 8192 # 8Mb HTTP POST body size limit
auth:
basic:
module_name: false # replace this with the name of the authentication module. false = basic auth disabled
Oops, something went wrong.
Oops, something went wrong.
@@ -26,13 +26,14 @@ SS.events =
_events: {}
- on: (name, funct) ->
+ on: (name, fn) ->
@_events[name] = [] unless @_events[name]?
- @_events[name].push(funct)
+ @_events[name].push(fn)
- emit: (name, params) ->
+ emit: ->
+ [name, params...] = arguments
if @_events[name]
- event(params) for event in @_events[name]
+ event.apply(event, params) for event in @_events[name]
else
console.error "Error: Received incoming '#{name}' event but no event handlers registered"
@@ -151,10 +152,11 @@ SS.socket.on 'reload', ->
### MAIN RESPONDERS ####
# Respond to incoming events
-SS.socket.on 'event', (msg) ->
+SS.socket.on 'event', (msg, destination) ->
data = JSON.parse(msg)
- log 2, "=> #{data.event}"
- SS.events.emit(data.event, data.params)
+ info = destination && (' [' + destination + ']') || ''
+ log 2, "=> #{data.event}#{info}"
+ SS.events.emit(data.event, data.params, destination)
# Respond to Real Time Model requests
SS.socket.on 'rtm', (msg) ->
@@ -17,6 +17,8 @@ server = require('../utils.coffee')
rpc = new (require('../../rpc/connection.coffee')).Client('api')
+post_limit = SS.config.api.post_max_size_kb
+
# Connect middleware handler
module.exports = ->
@@ -43,30 +45,32 @@ module.exports = ->
# Process an API Request
process = (request, response, url, actions) ->
-
- try
- params = parseParams(url)
- format = request.ss.parsedURL.extension || 'html'
-
- # Check format is supported
- throw 'Invalid output format. Supported formats: ' + formatters.keys().join(', ') unless formatters.keys().include(format)
+ params = parseParams(url)
+ format = request.ss.parsedURL.extension || 'html'
- post_data = ''
- request.on 'data', (chunk) -> post_data += chunk.toString()
- request.on 'end', ->
+ request.on 'error', (e) ->
+ request.invalid = true # would love to know how to stop 'end' being called without doing this
+ server.showError(response, e)
+ SS.log.error.exception(e)
- # Generate request for back end and send
- obj = {responder: 'server', method: actions.join('.'), params: params}
- obj.post = post_data if post_data.length > 0
+ request.on 'end', ->
+ return if request.invalid
- # Execute the request and deliver the response once it returns
- rpc.send obj, (result) ->
+ # Generate request for back end and send
+ obj = {responder: 'server', method: actions.join('.'), params: params}
+ obj.post = post_data if post_data?.length > 0
+
+ # Execute the request and deliver the response once it returns
+ rpc.send obj, (result) ->
+ try
reply(result, response, format)
-
- catch e
- server.showError(response, e)
- SS.log.error.exception(e)
-
+ catch e
+ request.emit 'error', e
+
+ checkOutputFormat(request, format)
+ post_data = processPostData(request) if request.method == 'POST'
+
+
# Formats and deliver the object
reply = (data, response, format) ->
formatters[format](data, response)
@@ -84,6 +88,26 @@ parseParams = (url) ->
catch e
throw new Error('Unable to parse params. Check syntax.')
+# Make sure we can return a response in the format requested
+checkOutputFormat = (request, format) ->
+ formats_supported = Object.keys(formatters)
+ request.emit 'error', new Error('Invalid output format. Supported formats: ' + formats_supported.join(', ')) unless formats_supported.include(format)
+
+# Listen for incoming HTTP post data, cutting off if necessary so we don't run out of memory
+processPostData = (request) ->
+ overLimit = (bytes) ->
+ bytes >= (post_limit * 1024) && request.emit('error', new Error("HTTP POST exceeded #{post_limit}kb. Adjust limit with SS.config.api.post_max_limit_kb"))
+
+ # Check headers first for speed
+ overLimit(request.headers['content-length'])
+
+ # Then stream the data in, checking as we go as we can't always trust the client to send an accurate header
+ out = ''
+ request.on 'data', (chunk) ->
+ return false if request.invalid
+ !overLimit(out.length) && out += chunk.toString()
+ out
+
### TODO: Fix this or replace it ###
@@ -43,7 +43,5 @@ dispatchMultiple = (name, message) ->
for socket_id, socket of SS.io.sockets.sockets
try
if (name == 'Channels' && socket.ss.session.channels.include(destination)) or (name == 'Users' && socket.ss.session.user_id == destination)
- sockets_to_message.push(socket) unless socket.disconnected or sockets_to_message.include(socket)
+ socket.emit('event', message, destination) unless socket.disconnected
- # Deliver message to each socket
- sockets_to_message.forEach (socket) -> socket.emit('event', message)
View
@@ -41,7 +41,7 @@ exports.init = (load_project = false) ->
SS.version = SS.internal.package_json.version
# Set client file version. Bumping this automatically triggers re-compilation of lib assets when a user upgrades
- SS.client.version = '0.2.0'
+ SS.client.version = '0.2.1'
# Set environment
env = process.env.SS_ENV || 'development'
@@ -27,7 +27,7 @@ class exports.Client extends Connection
@transport.listen (obj) =>
# Output message for debugging
- @debug && console.log("RPC Client: Msg in via #{@transport_type}:", obj)
+ @debug && console.log("RPC Client: Msg in via #{@transport_type} transport:", obj)
# All messages in MUST include an ID field containing the same number contained in the request
if obj.id
@@ -50,7 +50,7 @@ class exports.Client extends Connection
obj.origin = @name
# Output message for debugging
- @debug && console.log("RPC Client: Msg to be sent via #{@transport_type}:", obj)
+ @debug && console.log("RPC Client: Msg to be sent via #{@transport_type} transport:", obj)
# Send to back end
@transport.send(obj)
View
@@ -2,4 +2,5 @@
node_modules
dump.rdb
npm-debug.log
-/tmp
+tmp
+public/assets
@@ -17,18 +17,13 @@ exports.config =
port: 443
domain: "www.socketstream.org"
- # HTTP(S) request-based API
+ # HTTP(S) request-based API module
api:
enabled: true
prefix: 'api'
https_only: false
- # Show customizable 'Incompatible Browser' page if browser does not support websockets
- browser_check:
- enabled: false
- strict: true
-
- # Load balancing. Uncomment and set suitable TCP values for your network once you're ready to run across multiple boxes
+ # Load balancing. Install ZeroMQ (type 'socketstream help' for info) then set suitable TCP values for your network once you're ready to run across multiple boxes
#cluster:
# sockets:
# fe_main: "tcp://10.0.0.10:9000"
@@ -4,13 +4,10 @@
# Version 2.0
# This file defines how incoming HTTP requests are handled
-# Note: The default configuration will probably change a lot in the future. Be warned!
-
# CUSTOM MIDDLEWARE
# Hook-in your own custom HTTP middleware to modify or respond to requests before they're passed to the SocketStream HTTP stack
-# See README for more details and example middleware code
custom = ->
@@ -29,7 +26,7 @@ exports.primary =
[
#connect.logger() # example of calling in-built connect middleware. be sure to install connect in THIS project and uncomment out the line above
#require('connect-i18n')() # example of using 3rd-party middleware from https://github.com/senchalabs/connect/wiki
- #custom() # example of using your own custom middleware (using the example above)
+ #custom # example of using your own custom middleware (using the example above)
]
# Stack for Secondary Server
View
@@ -0,0 +1,10 @@
+{
+ "name": "My new SocketStream app",
+ "description": "An awesome real time application",
+ "version": "0.1.0",
+ "author": "Me <me@mydomain.com>",
+ "engines": { "node": ">= 0.4.0 < 0.5.0" },
+ "dependencies": {
+ "socketstream": "~>0.2.0"
+ }
+}
View
@@ -1,7 +1,7 @@
{
"name": "socketstream",
"description": "A phenomenally fast real-time web framework for Node.js",
- "version": "0.2.0",
+ "version": "0.2.1",
"homepage": "http://www.socketstream.org",
"author": "Owen Barnes <owen@socketstream.org>",
"contributors": [
@@ -11,9 +11,9 @@
],
"dependencies": {
"coffee-script": "= 1.1.2",
- "socket.io": "= 0.8.2",
+ "socket.io": "= 0.8.3",
"redis": "= 0.6.7",
- "connect": "= 1.6.2",
+ "connect": "= 1.7.0",
"jade": "= 0.14.2",
"stylus": "= 0.15.1",
"uglify-js": "= 1.0.6",
Oops, something went wrong.

0 comments on commit 0fa47c3

Please sign in to comment.