Permalink
Browse files

Lots of changes

  • Loading branch information...
1 parent f492549 commit e7e00861b084d75a7bdb151ab96220ee745717a4 @marekjelen marekjelen committed Feb 6, 2012
Showing with 837 additions and 737 deletions.
  1. +2 −2 bin/wildcloud-websockets
  2. +3 −3 lib/wildcloud/websockets/engine.rb
  3. +137 −0 lib/wildcloud/websockets/handler.rb
  4. +7 −9 lib/wildcloud/websockets/{websockets/handlers → handler}/authorize.rb
  5. +155 −0 lib/wildcloud/websockets/handler/base_handler.rb
  6. +17 −14 lib/wildcloud/websockets/{websockets/handlers → handler}/eventsource.rb
  7. +61 −0 lib/wildcloud/websockets/handler/htmlfile.rb
  8. +15 −17 lib/wildcloud/websockets/{websockets/handlers → handler}/iframe.rb
  9. +8 −10 lib/wildcloud/websockets/{websockets/handlers → handler}/index.rb
  10. +19 −23 lib/wildcloud/websockets/{websockets/handlers/xhr_streaming.rb → handler/info.rb}
  11. +7 −9 lib/wildcloud/websockets/{websockets/handlers → handler}/publish.rb
  12. +88 −0 lib/wildcloud/websockets/handler/websockets.rb
  13. +62 −0 lib/wildcloud/websockets/handler/xhr_polling.rb
  14. +66 −0 lib/wildcloud/websockets/handler/xhr_send.rb
  15. +46 −0 lib/wildcloud/websockets/handler/xhr_streaming.rb
  16. +58 −0 lib/wildcloud/websockets/java.rb
  17. +86 −0 lib/wildcloud/websockets/server.rb
  18. +0 −240 lib/wildcloud/websockets/websockets/handler.rb
  19. +0 −54 lib/wildcloud/websockets/websockets/handlers/htmlfile.rb
  20. +0 −46 lib/wildcloud/websockets/websockets/handlers/info.rb
  21. +0 −81 lib/wildcloud/websockets/websockets/handlers/websockets.rb
  22. +0 −54 lib/wildcloud/websockets/websockets/handlers/xhr_polling.rb
  23. +0 −65 lib/wildcloud/websockets/websockets/handlers/xhr_send.rb
  24. +0 −55 lib/wildcloud/websockets/websockets/java.rb
  25. +0 −55 lib/wildcloud/websockets/websockets/server.rb
View
@@ -18,7 +18,7 @@ require 'rubygems'
$: << File.expand_path('../../lib', __FILE__)
-require 'wildcloud/websockets/websockets/server'
+require 'wildcloud/websockets/server'
-@server = Wildcloud::Websockets::Websockets::Server.new
+@server = Wildcloud::Websockets::Server.new
@server.start
@@ -72,13 +72,13 @@ def add_socket(socket_id, session_id, socket)
@sockets[socket_id][:sockets][session_id] = socket
- message, @deliveries[socket_id] = @deliveries[socket_id], []
- publish(socket_id, message)
+ #message, @deliveries[socket_id] = @deliveries[socket_id], []
+ #publish(socket_id, message)
end
def remove_socket(socket_id, session_id, socket)
return nil unless @sockets.key?(socket_id)
- @sockets[socket_id][:sockets].delete(session_id)
+ @sockets[socket_id][:sockets].delete_if { |k,v| v == socket }
end
def publish(socket_id, message)
@@ -0,0 +1,137 @@
+# Copyright 2011 Marek Jelen
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'multi_json'
+
+require 'wildcloud/websockets/handler/base_handler'
+require 'wildcloud/websockets/handler/authorize'
+require 'wildcloud/websockets/handler/eventsource'
+require 'wildcloud/websockets/handler/htmlfile'
+require 'wildcloud/websockets/handler/iframe'
+require 'wildcloud/websockets/handler/index'
+require 'wildcloud/websockets/handler/info'
+require 'wildcloud/websockets/handler/publish'
+require 'wildcloud/websockets/handler/websockets'
+require 'wildcloud/websockets/handler/xhr_polling'
+require 'wildcloud/websockets/handler/xhr_send'
+require 'wildcloud/websockets/handler/xhr_streaming'
+
+module Wildcloud
+ module Websockets
+
+ class Connection < SimpleChannelUpstreamHandler
+
+ attr_accessor :chunked
+
+ # Netty related methods
+
+ def messageReceived(context, event)
+ @written_data ||= 0
+ @opened ||= true
+
+ if event.message.kind_of?(Fixnum)
+ @written_data += event.message
+ if @opened and @written_data > 4096
+ puts "Closed based on message size #{@written_data}"
+ @opened = false
+ @channel.write(ChannelBuffers::EMPTY_BUFFER).addListener(ChannelFutureListener::CLOSE)
+ end
+ return
+ end
+
+ @channel = context.channel
+ request = event.message
+
+ # Websockets frames are handled differently
+ return handle_websockets_frame(request) if request.kind_of?(WebSocketFrame)
+
+ # Routing
+ case
+ when match = /^\/([^\/]+)\/([^\/\.]+)\/([^\/\.]+)\/websocket$/.match(request.uri)
+ @handler = Handler::Websockets.new
+ @handler.socket_id = match[1]
+ @handler.session_id = match[3]
+ when match = /^\/authorize\/([^\/]+)\/([^\/]+)$/.match(request.uri)
+ @handler = Handler::Authorize.new
+ @handler.application_id = match[1]
+ @handler.client_id = match[2]
+ when match = /^\/publish\/([^\/]+)(\/([^\/]+))?$/.match(request.uri)
+ @handler = Handler::Publish.new
+ @handler.socket_id = match[1]
+ @handler.session_id = match[2]
+ when match = /^\/([^\/]+)\/info$/.match(request.uri)
+ @handler = Handler::Info.new
+ @handler.socket_id = match[1]
+ when match = /^\/([^\/]+)\/iframe(-[a-zA-Z0-9\.\-]*)?\.html(\?t=(.*))?$/.match(request.uri)
+ @handler = Handler::Iframe.new
+ @handler.socket_id = match[1]
+ when match = /^\/([^\/]+)\/([^\/\.]+)\/([^\/\.]+)\/htmlfile(\?c=(.*))?$/.match(request.uri)
+ @handler = Handler::Htmlfile.new
+ @handler.socket_id = match[1]
+ @handler.session_id = match[3]
+ @handler.parameters[:callback] = match[5]
+ when match = /^\/([^\/]+)\/([^\/\.]+)\/([^\/\.]+)\/eventsource$/.match(request.uri)
+ @handler = Handler::Eventsource.new
+ @handler.socket_id = match[1]
+ @handler.session_id = match[3]
+ when match = /^\/([^\/]+)\/([^\/\.]+)\/([^\/\.]+)\/xhr_streaming$/.match(request.uri)
+ @handler = Handler::XhrStreaming.new
+ @handler.socket_id = match[1]
+ @handler.session_id = match[3]
+ when match = /^\/([^\/]+)\/([^\/\.]+)\/([^\/\.]+)\/xhr$/.match(request.uri)
+ @handler = Handler::XhrPolling.new
+ @handler.socket_id = match[1]
+ @handler.session_id = match[3]
+ when match = /^\/([^\/]+)\/([^\/\.]+)\/([^\/\.]+)\/xhr_send$/.match(request.uri)
+ @handler = Handler::XhrSend.new
+ @handler.socket_id = match[1]
+ @handler.session_id = match[3]
+ when match = /^\/([^\/]+)(\/)?$/.match(request.uri)
+ @handler = Handler::Index.new
+ @handler.socket_id = match[1]
+ else
+ return @channel.write(DefaultHttpResponse.new(HttpVersion::HTTP_1_1, HttpResponseStatus::NOT_FOUND)).addListener(ChannelFutureListener.CLOSE)
+ end
+ @handler.connection = self
+ @handler.channel = @channel
+ @handler.request = request
+ @handler.setup
+ @handler.send("handle_#{request.get_method.to_s.downcase}")
+ end
+
+ def channelClosed(context, event)
+ @handler.on_closed_connection if @handler
+ end
+
+ def exceptionCaught(context, event)
+ puts event.cause.message
+ puts event.cause.backtrace
+ #java.lang.System.exit(1)
+ end
+
+ def write(data, close = false, options = {})
+ if data.kind_of?(String)
+ data = ChannelBuffers.wrapped_buffer(data.to_java_bytes)
+ data = DefaultHttpChunk.new(data) if @chunked
+ end
+ if @opened
+ @future = @channel.write(data)
+ @future.addListener(ChannelFutureListener.CLOSE) if close
+ end
+ end
+
+ end
+
+ end
+end
@@ -14,17 +14,15 @@
module Wildcloud
module Websockets
- module Websockets
- module Handlers
- module Authorize
-
- def handle_authorize(app_id, user_id)
- socket_id = Engine.instance.authorize(app_id, user_id)
- response_set_content(socket_id, true)
- response_send_header(true)
- end
+ module Handler
+ class Authorize < BaseHandler
+ def handle_authorize(app_id, user_id)
+ socket_id = Engine.instance.authorize(app_id, user_id)
+ response_set_content(socket_id, true)
+ response_send_header(true)
end
+
end
end
end
@@ -0,0 +1,155 @@
+# Copyright 2011 Marek Jelen
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'wildcloud/websockets/engine'
+
+module Wildcloud
+ module Websockets
+ module Handler
+
+ class BaseHandler
+
+ def self.etag
+ @etag ||= Time.now.to_i.to_s
+ end
+
+ attr_accessor :application_id, :client_id, :socket_id, :session_id
+ attr_accessor :request, :channel, :connection, :parameters
+
+ def initialize
+ @parameters ||= {}
+ end
+
+ # HTTP headers management
+
+ def set_status(code)
+ @response.status = HttpResponseStatus.valueOf(code)
+ end
+
+ def get_header(name)
+ @request.get_header(name)
+ end
+
+ def set_headers(headers = {})
+ headers.each do |name, value|
+ @response.set_header(name, value)
+ end
+ end
+
+ def remove_header(name)
+ @response.remove_header(name)
+ end
+
+ def set_no_cache
+ set_headers 'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0'
+ end
+
+ def set_strong_cache
+ @response.set_header('Access-Control-Max-Age', '10000001')
+ @response.set_header('Cache-Control', 'public, max-age=31536000, must-revalidate')
+ @response.set_header('etag', BaseHandler.etag) # ToDo: etags
+ @response.set_header('Expires', Time.now.to_s) # ToDo: in future
+ end
+
+
+ # HTTP content management
+
+ def send_response(close = false)
+ @connection.write(@response, close)
+ end
+
+ def set_content(data, length = false)
+ @response.set_content(ChannelBuffers.wrapped_buffer(data.to_java_bytes))
+ HttpHeaders.set_content_length(@response, data.size) if length
+ end
+
+ def send_content(data, close = false)
+ @connection.write(data, close)
+ end
+
+ def get_content
+ @request.content.to_string(Charset.for_name('UTF-8'))
+ end
+
+ def set_chunked
+ @connection.chunked = true
+ @response.set_chunked(true)
+ set_headers 'Transfer-Encoding' => 'chunked'
+ end
+
+
+ # Logic
+
+ def setup
+ @close_after_message ||= false
+ @response = DefaultHttpResponse.new(HttpVersion::HTTP_1_1, HttpResponseStatus::OK)
+ set_headers 'Access-Control-Allow-Credentials' => 'true',
+ 'Access-Control-Allow-Origin' => 'http://localhost',
+ 'Connection' => 'Keep-Alive',
+ 'Content-Type' => 'application/json; charset=UTF-8',
+ 'Set-Cookie' => "#{get_header('Cookie') or 'JSESSIONID=dummy'};path=/"
+ end
+
+ def call(message)
+ message = [message.to_s] unless message.kind_of?(Array)
+ message = "a#{MultiJson.encode(message)}"
+
+ puts "Publishing #{message} for #{@request.uri}"
+
+ message = encode_message(message)
+
+ if @close_after_message
+ @connection.write(message, true)
+ else
+ @connection.write(message)
+ end
+
+ end
+
+ def close(reason, code = 3000)
+ @connection.write(encode_close(reason, code), true)
+ end
+
+ def encode_close(reason, code)
+ "c[#{code},\"#{reason}\"]\n"
+ end
+
+ def encode_message(message)
+ message
+ end
+
+
+ # Callbacks
+
+ def on_new_connection
+ puts "New connection #{@socket_id} (#{self.class.name})"
+ Engine.instance.add_socket(@socket_id, @session_id, self)
+ end
+
+ def on_message(message)
+ puts "New message #{message.inspect} on socket #{@socket_id} (#{self.class.name})"
+ Engine.instance.on_message(@socket_id, message)
+ end
+
+ def on_closed_connection
+ puts "Closed connection #{@socket_id} (#{self.class.name})"
+ Engine.instance.remove_socket(@socket_id, @session_id, self)
+ end
+
+
+ end
+
+ end
+ end
+end
@@ -14,25 +14,28 @@
module Wildcloud
module Websockets
- module Websockets
- module Handlers
- module Eventsource
+ module Handler
+ class Eventsource < BaseHandler
- def handle_eventsource(socket_id, server_id, session_id)
- @response.set_header('Content-Type', 'text/event-stream; charset=UTF-8')
- response_no_cache
- response_send_header
+ def handle_get
+ set_headers 'Content-Type' => 'text/event-stream; charset=UTF-8'
+ set_no_cache
+ set_chunked
- response_send_content("\r\n")
- response_send_content("data: o\r\n\r\n")
+ send_response
- @type = :eventsource
- @socket_id = socket_id
- @session_id = session_id
- on_new_connection(@socket_id, session_id, self)
- end
+ send_content("\r\n")
+ send_content("data: o\r\n\r\n")
+ on_new_connection
end
+
+ def encode_message(message)
+ message = "data: #{message}\r\n\r\n"
+ puts "EventSource: encoding: #{message.inspect}"
+ message
+ end
+
end
end
end
Oops, something went wrong.

0 comments on commit e7e0086

Please sign in to comment.