smartfox 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Richard Penwell
1
+ Copyright (c) 2010 Richard Penwell
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -11,6 +11,8 @@ begin
11
11
  gem.homepage = "http://github.com/penwellr/smartfox"
12
12
  gem.authors = ["Richard Penwell"]
13
13
  gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_dependency 'json'
15
+ gem.add_dependency 'builder'
14
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
17
  end
16
18
  Jeweler::GemcutterTasks.new
@@ -43,3 +45,5 @@ Rake::RDocTask.new do |rdoc|
43
45
  rdoc.rdoc_files.include('README*')
44
46
  rdoc.rdoc_files.include('lib/**/*.rb')
45
47
  end
48
+
49
+ task :gem => :build
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.1.0
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'logger'
3
+
4
+ module SmartFox
5
+ class SmartFoxError < Exception; end
6
+
7
+ autoload :Client, 'smartfox/client'
8
+ autoload :Socket, 'smartfox/socket'
9
+ autoload :BlueBox, 'smartfox/blue_box'
10
+ autoload :Packet, 'smartfox/packet'
11
+
12
+ Logger = Logger.new(STDOUT)
13
+ end
@@ -0,0 +1,3 @@
1
+ module SmartFox::BlueBox
2
+ autoload :Connection, 'smartfox/blue_box/connection'
3
+ end
@@ -0,0 +1,2 @@
1
+ class SmartFox::BlueBox::Connection
2
+ end
@@ -0,0 +1,97 @@
1
+ require 'builder'
2
+ require 'libxml'
3
+
4
+ class SmartFox::Client
5
+ class ConnectionFailureError < SmartFox::SmartFoxError; end
6
+ class ApiIncompatibleError < SmartFox::SmartFoxError; end
7
+ class TransportTimeoutError < SmartFox::SmartFoxError; end
8
+
9
+ attr_reader :connected, :room_list, :buddy_list, :server, :port
10
+ alias_method :connected?, :connected
11
+
12
+ CLIENT_VERSION = "1.5.8"
13
+ CONNECTION_TIMEOUT = 5
14
+ TRANSPORTS = [ SmartFox::Socket::Connection, SmartFox::BlueBox::Connection ]
15
+
16
+ HEADER_SYSTEM = 'sys'
17
+ ACTION_VERSION_CHECK = 'verChk'
18
+ ACTION_API_OK = 'apiOK'
19
+ ACTION_API_OBSOLETE = 'apiKO'
20
+
21
+ def initialize(options = {})
22
+ @room_list = {}
23
+ @connected = false
24
+ @buddy_list = []
25
+ @user_id = options[:user_id]
26
+ @user_name = options[:user_name]
27
+ @server = options[:server] || 'localhost'
28
+ @port = options[:port]
29
+ @events = {}
30
+ end
31
+
32
+ def connect()
33
+ unless @connected
34
+ TRANSPORTS.each do |transport_class|
35
+ begin
36
+ @transport = transport_class.new(self)
37
+ @transport.connect
38
+ if connected?
39
+ return @transport
40
+ end
41
+ rescue
42
+ end
43
+ end
44
+ raise ConnectionFailureError.new "Could not negotiate any transport with server."
45
+ end
46
+ end
47
+
48
+ def add_handler(event, &proc)
49
+ @events[event.to_sym] = [] unless @events[event.to_sym]
50
+ @events[event.to_sym] << proc
51
+ end
52
+
53
+ def connect_succeeded
54
+ send_packet(HEADER_SYSTEM, ACTION_VERSION_CHECK) { |x| x.ver(:v => CLIENT_VERSION.delete('.')) }
55
+ connect_response = wait_for_packet(CONNECTION_TIMEOUT)
56
+ if connect_response.header == HEADER_SYSTEM and connect_response.action == ACTION_API_OK
57
+ @connected = true
58
+ SmartFox::Logger.info "SmartFox::Client successfully connected with transport #{@transport.inspect}"
59
+ raise_event :connected, self
60
+ else
61
+ raise ApiIncompatibleError if connect_response.action == ACTION_API_OBSOLETE
62
+ raise ConnectionFailureError.new "Did not recieve an expected response from the server."
63
+ end
64
+ end
65
+
66
+ private
67
+ def send_packet(header, action, room_id = 0)
68
+ xml = Builder::XmlMarkup.new()
69
+ xml.msg(:t => header) do |msg|
70
+ msg.body(:action => action, :r => room_id) do |body|
71
+ yield body
72
+ end
73
+ end
74
+ packet = xml.target!
75
+ SmartFox::Logger.info "SmartFox::Client#send_packet -> #{packet}"
76
+ @transport.send_data(packet + "\0")
77
+ end
78
+
79
+ def wait_for_packet(timeout)
80
+ begin_at = Time.now
81
+ while Time.now <= (begin_at + timeout)
82
+ if @transport.data_available?
83
+ return SmartFox::Packet.parse(@transport.read_packet)
84
+ end
85
+ end
86
+
87
+ raise TransportTimeoutError
88
+ end
89
+
90
+ def raise_event(event_name, *params)
91
+ event = @events[event_name.to_sym]
92
+ return unless event
93
+ event.each do |event_handler|
94
+ event_handler.call(*params)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,41 @@
1
+ require 'libxml'
2
+
3
+ class SmartFox::Packet
4
+ attr_reader :action, :header, :room, :data
5
+
6
+ def initialize(header, action, room = 0, extra = nil)
7
+ @header = header
8
+ @action = action
9
+ @room = room
10
+ @extra = extra
11
+ end
12
+
13
+ def self.parse(data)
14
+ case data[0, 1]
15
+ when '<'
16
+ return parse_xml(data)
17
+ when '{'
18
+ return parse_json(data)
19
+ else
20
+ return parse_string(data)
21
+ end
22
+ end
23
+
24
+ def self.parse_xml(data)
25
+ SmartFox::Logger.debug "SmartFox::Packet#parse_xml('#{data}')"
26
+ document = LibXML::XML::Parser.string(data).parse
27
+ header = document.root['t']
28
+ action = document.root.child['action']
29
+ room = document.root.child['r']
30
+ extra = document.root.child.child
31
+ new(header, action, room, extra)
32
+ end
33
+
34
+ def self.parse_json(data)
35
+ SmartFox::Logger.debug "SmartFox::Packet#parse_json('#{data}')"
36
+ end
37
+
38
+ def self.parse_string(data)
39
+ SmartFox::Logger.debug "SmartFox::Packet#parse_string('#{data}')"
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module SmartFox::Socket
2
+ autoload :Connection, 'smartfox/socket/connection'
3
+ end
@@ -0,0 +1,71 @@
1
+ require 'socket'
2
+
3
+ class SmartFox::Socket::Connection
4
+ DEFAULT_PORT = 9339
5
+ attr_reader :connected
6
+ alias_method :connected?, :connected
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ @connected = false
11
+ @event_thread = nil
12
+ @disconnecting = false
13
+ @buffer = String.new
14
+ end
15
+
16
+ def connect
17
+ begin
18
+ SmartFox::Logger.info "SmartFox::Socket::Connection#connect began"
19
+ @socket = TCPSocket.new(@client.server, @client.port || DEFAULT_PORT)
20
+ # SmartFox sockets will send a cross domain policy, receive this packet
21
+ # before we do anything else or the connection will hang
22
+ @socket.readpartial(4096)
23
+ @connected = true
24
+ @event_thread = Thread.start(self) { |connection| connection.event_loop }
25
+ @client.connect_succeeded
26
+
27
+ rescue => e
28
+ SmartFox::Logger.error "In SmartFox::Socket::Connection#connect:"
29
+ SmartFox::Logger.error " #{e.inspect}"
30
+ end
31
+ end
32
+
33
+ def disconnect
34
+ @disconnecting = true
35
+ while @connected
36
+ sleep
37
+ end
38
+ end
39
+
40
+ def send_data(data)
41
+ @socket.write(data)
42
+ end
43
+
44
+ def data_available?
45
+ not @buffer.empty?
46
+ end
47
+
48
+ def read_packet
49
+ packet = @buffer
50
+ @buffer = ""
51
+ return packet
52
+ end
53
+
54
+ def event_loop
55
+ SmartFox::Logger.info "SmartFox::Socket::Connection#event_loop began"
56
+ ticks = 0
57
+ until @disconnecting
58
+ SmartFox::Logger.debug "SmartFox::Socket::Connection#event_loop tick #{ticks}"
59
+
60
+ @buffer << @socket.readpartial(4096)
61
+
62
+ ticks += 1
63
+ end
64
+
65
+ @connected = false
66
+ end
67
+
68
+ def inspect
69
+ "#<#{self.class.name}:#{object_id} server:#{@client.server} port:#{@client.port || DEFAULT_PORT}>"
70
+ end
71
+ end
@@ -0,0 +1 @@
1
+ main.file=spec/spec_helper.rb
@@ -0,0 +1 @@
1
+ config=Spec
@@ -0,0 +1 @@
1
+ work.dir=/Users/penwellr/Development/smartfox
@@ -0,0 +1,3 @@
1
+ file.reference.smartfox-lib=/Users/penwellr/Development/smartfox/lib
2
+ file.reference.smartfox-spec=/Users/penwellr/Development/smartfox/spec
3
+ platform.active=Ruby
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project-private xmlns="http://www.netbeans.org/ns/project-private/1">
3
+ <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
4
+ </project-private>
File without changes
@@ -0,0 +1,8 @@
1
+ file.reference.smartfox-lib=lib
2
+ file.reference.smartfox-spec=spec
3
+ javac.classpath=
4
+ main.file=smartfox.rb
5
+ platform.active=Ruby
6
+ source.encoding=UTF-8
7
+ src.dir=${file.reference.smartfox-lib}
8
+ test.src.dir=${file.reference.smartfox-spec}
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://www.netbeans.org/ns/project/1">
3
+ <type>org.netbeans.modules.ruby.rubyproject</type>
4
+ <configuration>
5
+ <data xmlns="http://www.netbeans.org/ns/ruby-project/1">
6
+ <name>smartfox</name>
7
+ <source-roots>
8
+ <root id="src.dir"/>
9
+ </source-roots>
10
+ <test-roots>
11
+ <root id="test.src.dir"/>
12
+ </test-roots>
13
+ </data>
14
+ </configuration>
15
+ </project>
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{smartfox}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Richard Penwell"]
12
+ s.date = %q{2010-06-07}
13
+ s.description = %q{Provides a client library for the SmartFox realtime communication server, including BlueBox extensions.}
14
+ s.email = %q{self@richardpenwell.me}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/smartfox.rb",
27
+ "lib/smartfox/blue_box.rb",
28
+ "lib/smartfox/blue_box/connection.rb",
29
+ "lib/smartfox/client.rb",
30
+ "lib/smartfox/packet.rb",
31
+ "lib/smartfox/socket.rb",
32
+ "lib/smartfox/socket/connection.rb",
33
+ "nbproject/configs/Spec.properties",
34
+ "nbproject/private/config.properties",
35
+ "nbproject/private/configs/Spec.properties",
36
+ "nbproject/private/private.properties",
37
+ "nbproject/private/private.xml",
38
+ "nbproject/private/rake-d.txt",
39
+ "nbproject/project.properties",
40
+ "nbproject/project.xml",
41
+ "smartfox.gemspec",
42
+ "spec/smartfox_spec.rb",
43
+ "spec/spec.opts",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+ s.homepage = %q{http://github.com/penwellr/smartfox}
47
+ s.rdoc_options = ["--charset=UTF-8"]
48
+ s.require_paths = ["lib"]
49
+ s.rubygems_version = %q{1.3.7}
50
+ s.summary = %q{Client library for SmartFoxServer}
51
+ s.test_files = [
52
+ "spec/smartfox_spec.rb",
53
+ "spec/spec_helper.rb"
54
+ ]
55
+
56
+ if s.respond_to? :specification_version then
57
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
58
+ s.specification_version = 3
59
+
60
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
61
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
62
+ s.add_runtime_dependency(%q<json>, [">= 0"])
63
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
64
+ else
65
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
66
+ s.add_dependency(%q<json>, [">= 0"])
67
+ s.add_dependency(%q<builder>, [">= 0"])
68
+ end
69
+ else
70
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
71
+ s.add_dependency(%q<json>, [">= 0"])
72
+ s.add_dependency(%q<builder>, [">= 0"])
73
+ end
74
+ end
75
+
@@ -1,7 +1,29 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "Smartfox" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
4
+ it "should create a connection" do
5
+ connection = SmartFox::Client.new(:server => 'localhost')
6
+ connection.connect
6
7
  end
8
+
9
+ it "should be connected after calling connect" do
10
+ connection = SmartFox::Client.new()
11
+ connection.connect
12
+ connection.connected?.should be_true
13
+ end
14
+
15
+ it "should raise the 'connected' event after connecting" do
16
+ connected = false
17
+ connection = SmartFox::Client.new()
18
+ connection.add_handler(:connected) { |connection| connected = true}
19
+ connection.connect
20
+ connected.should be_true
21
+ end
22
+
23
+ it "should fail when attempting to connect to a non-existant server" do
24
+ connection = SmartFox::Client.new(:server => '10.2.3.4')
25
+ lambda { connection.connect }.should raise_error(SmartFox::Client::ConnectionFailureError)
26
+ end
27
+
28
+ it "should fall back on BlueBox if needed"
7
29
  end
@@ -4,6 +4,8 @@ require 'smartfox'
4
4
  require 'spec'
5
5
  require 'spec/autorun'
6
6
 
7
+ SmartFox::Logger.level = Logger::DEBUG
8
+
7
9
  Spec::Runner.configure do |config|
8
10
 
9
11
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartfox
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 0
10
- version: 0.0.0
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Richard Penwell
@@ -34,6 +34,34 @@ dependencies:
34
34
  version: 1.2.9
35
35
  type: :development
36
36
  version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: json
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: builder
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ type: :runtime
64
+ version_requirements: *id003
37
65
  description: Provides a client library for the SmartFox realtime communication server, including BlueBox extensions.
38
66
  email: self@richardpenwell.me
39
67
  executables: []
@@ -51,6 +79,21 @@ files:
51
79
  - Rakefile
52
80
  - VERSION
53
81
  - lib/smartfox.rb
82
+ - lib/smartfox/blue_box.rb
83
+ - lib/smartfox/blue_box/connection.rb
84
+ - lib/smartfox/client.rb
85
+ - lib/smartfox/packet.rb
86
+ - lib/smartfox/socket.rb
87
+ - lib/smartfox/socket/connection.rb
88
+ - nbproject/configs/Spec.properties
89
+ - nbproject/private/config.properties
90
+ - nbproject/private/configs/Spec.properties
91
+ - nbproject/private/private.properties
92
+ - nbproject/private/private.xml
93
+ - nbproject/private/rake-d.txt
94
+ - nbproject/project.properties
95
+ - nbproject/project.xml
96
+ - smartfox.gemspec
54
97
  - spec/smartfox_spec.rb
55
98
  - spec/spec.opts
56
99
  - spec/spec_helper.rb