smartfox 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/lib/smartfox.rb CHANGED
@@ -10,4 +10,13 @@ module SmartFox
10
10
  autoload :Packet, 'smartfox/packet'
11
11
 
12
12
  Logger = Logger.new(STDOUT)
13
+
14
+ class << Logger
15
+ def exception(exception)
16
+ error exception.message
17
+ exception.backtrace.each do |line|
18
+ error " #{line}"
19
+ end
20
+ end
21
+ end
13
22
  end
@@ -12,11 +12,14 @@ class SmartFox::Client
12
12
  CLIENT_VERSION = "1.5.8"
13
13
  CONNECTION_TIMEOUT = 5
14
14
  TRANSPORTS = [ SmartFox::Socket::Connection, SmartFox::BlueBox::Connection ]
15
+ EVENTS = [ :connected, :logged_in ]
15
16
 
16
17
  HEADER_SYSTEM = 'sys'
17
18
  ACTION_VERSION_CHECK = 'verChk'
18
19
  ACTION_API_OK = 'apiOK'
19
20
  ACTION_API_OBSOLETE = 'apiKO'
21
+ ACTION_LOGIN = 'login'
22
+ ACTION_LOGIN_OK = 'logOK'
20
23
 
21
24
  def initialize(options = {})
22
25
  @room_list = {}
@@ -33,11 +36,15 @@ class SmartFox::Client
33
36
  unless @connected
34
37
  TRANSPORTS.each do |transport_class|
35
38
  begin
39
+ started_at = Time.now
36
40
  @transport = transport_class.new(self)
37
41
  @transport.connect
38
- if connected?
39
- return @transport
42
+
43
+ while not connected? and Time.now <= started_at + CONNECTION_TIMEOUT
44
+ Thread.pass
40
45
  end
46
+
47
+ return @transport if connected?
41
48
  rescue
42
49
  end
43
50
  end
@@ -45,6 +52,13 @@ class SmartFox::Client
45
52
  end
46
53
  end
47
54
 
55
+ def disconnect
56
+ if @connected
57
+ @transport.disconnect
58
+ @connected = false
59
+ end
60
+ end
61
+
48
62
  def add_handler(event, &proc)
49
63
  @events[event.to_sym] = [] unless @events[event.to_sym]
50
64
  @events[event.to_sym] << proc
@@ -52,22 +66,43 @@ class SmartFox::Client
52
66
 
53
67
  def connect_succeeded
54
68
  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."
69
+ end
70
+
71
+ def packet_recieved(data)
72
+ begin
73
+ SmartFox::Logger.debug "SmartFox::Client#packet_recieved('#{data}')"
74
+ packet = SmartFox::Packet.parse(data)
75
+ case packet.header
76
+ when HEADER_SYSTEM
77
+ if @connected
78
+ handle_system_packet(packet)
79
+ else
80
+ complete_login(packet)
81
+ end
82
+ when HEADER_EXTENSION
83
+
84
+ end
85
+ rescue => e
86
+ SmartFox::Logger.error "In SmartFox::Client#packet_received"
87
+ SmartFox::Logger.exception e
63
88
  end
64
89
  end
65
90
 
91
+ def login(zone, username, password = nil)
92
+ send_packet(HEADER_SYSTEM, ACTION_LOGIN) do |packet|
93
+ packet.login(:z => zone) do |login|
94
+ login.nick { |nick| nick.cdata! username }
95
+ login.pword { |pword| pword.cdata! password || '' }
96
+ end
97
+ end
98
+ Thread.pass
99
+ end
100
+
66
101
  private
67
102
  def send_packet(header, action, room_id = 0)
68
103
  xml = Builder::XmlMarkup.new()
69
104
  xml.msg(:t => header) do |msg|
70
- msg.body(:action => action, :r => room_id) do |body|
105
+ msg.body(:r => room_id, :action => action) do |body|
71
106
  yield body
72
107
  end
73
108
  end
@@ -76,17 +111,6 @@ class SmartFox::Client
76
111
  @transport.send_data(packet + "\0")
77
112
  end
78
113
 
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
114
  def raise_event(event_name, *params)
91
115
  event = @events[event_name.to_sym]
92
116
  return unless event
@@ -94,4 +118,26 @@ class SmartFox::Client
94
118
  event_handler.call(*params)
95
119
  end
96
120
  end
121
+
122
+ def complete_login(connect_response)
123
+ if connect_response.header == HEADER_SYSTEM and connect_response.action == ACTION_API_OK
124
+ @connected = true
125
+ SmartFox::Logger.info "SmartFox::Client successfully connected with transport #{@transport.inspect}"
126
+ raise_event :connected, self
127
+ else
128
+ raise ApiIncompatibleError if connect_response.action == ACTION_API_OBSOLETE
129
+ raise ConnectionFailureError.new "Did not recieve an expected response from the server."
130
+ end
131
+ end
132
+
133
+ def handle_system_packet(packet)
134
+ case packet.action
135
+ when ACTION_LOGIN_OK
136
+ @username = packet.data['n']
137
+ @moderator = packet.data['mod'] != "0"
138
+ @id = packet.data['id']
139
+ SmartFox::Logger.info "SmartFox::Client logged in as #{@username}"
140
+ raise_event(:logged_in, self)
141
+ end
142
+ end
97
143
  end
@@ -7,7 +7,7 @@ class SmartFox::Packet
7
7
  @header = header
8
8
  @action = action
9
9
  @room = room
10
- @extra = extra
10
+ @data = extra
11
11
  end
12
12
 
13
13
  def self.parse(data)
@@ -11,6 +11,7 @@ class SmartFox::Socket::Connection
11
11
  @event_thread = nil
12
12
  @disconnecting = false
13
13
  @buffer = String.new
14
+ @packets = []
14
15
  end
15
16
 
16
17
  def connect
@@ -26,39 +27,38 @@ class SmartFox::Socket::Connection
26
27
 
27
28
  rescue => e
28
29
  SmartFox::Logger.error "In SmartFox::Socket::Connection#connect:"
29
- SmartFox::Logger.error " #{e.inspect}"
30
+ SmartFox::Logger.exception e
31
+ raise e
30
32
  end
31
33
  end
32
34
 
33
35
  def disconnect
34
36
  @disconnecting = true
35
37
  while @connected
36
- sleep
38
+ Thread.pass
37
39
  end
40
+ @socket.close if @socket
38
41
  end
39
42
 
40
43
  def send_data(data)
41
44
  @socket.write(data)
42
45
  end
43
46
 
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
47
  def event_loop
55
48
  SmartFox::Logger.info "SmartFox::Socket::Connection#event_loop began"
56
49
  ticks = 0
57
50
  until @disconnecting
58
51
  SmartFox::Logger.debug "SmartFox::Socket::Connection#event_loop tick #{ticks}"
59
52
 
60
- @buffer << @socket.readpartial(4096)
53
+ @buffer += @socket.readpartial(4096)
54
+
55
+ while index = @buffer.index("\0")
56
+ @packets << @buffer.slice!(0..index)
57
+ end
61
58
 
59
+ @packets.each { |packet| @client.packet_recieved(packet) }
60
+ @packets.clear
61
+
62
62
  ticks += 1
63
63
  end
64
64
 
data/smartfox.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{smartfox}
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Richard Penwell"]
@@ -41,7 +41,8 @@ Gem::Specification.new do |s|
41
41
  "smartfox.gemspec",
42
42
  "spec/smartfox_spec.rb",
43
43
  "spec/spec.opts",
44
- "spec/spec_helper.rb"
44
+ "spec/spec_helper.rb",
45
+ "spec/waiter.rb"
45
46
  ]
46
47
  s.homepage = %q{http://github.com/penwellr/smartfox}
47
48
  s.rdoc_options = ["--charset=UTF-8"]
@@ -50,7 +51,8 @@ Gem::Specification.new do |s|
50
51
  s.summary = %q{Client library for SmartFoxServer}
51
52
  s.test_files = [
52
53
  "spec/smartfox_spec.rb",
53
- "spec/spec_helper.rb"
54
+ "spec/spec_helper.rb",
55
+ "spec/waiter.rb"
54
56
  ]
55
57
 
56
58
  if s.respond_to? :specification_version then
@@ -1,28 +1,44 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe "Smartfox" do
3
+ describe SmartFox::Client do
4
+ before(:each) do
5
+ @connection = SmartFox::Client.new()
6
+ end
7
+
8
+ after(:each) do
9
+ @connection.disconnect if @connection
10
+ end
11
+
4
12
  it "should create a connection" do
5
- connection = SmartFox::Client.new(:server => 'localhost')
6
- connection.connect
13
+ login_waiter = Waiter.new
14
+ @connection.connect
7
15
  end
8
16
 
9
17
  it "should be connected after calling connect" do
10
- connection = SmartFox::Client.new()
11
- connection.connect
12
- connection.connected?.should be_true
18
+ login_waiter = Waiter.new
19
+ @connection.connect
20
+ @connection.connected?.should be_true
13
21
  end
14
22
 
15
23
  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
24
+ connected_waiter = Waiter.new
25
+ @connection.add_handler(:connected) { |connection| puts "connected_waiter fired"; connected_waiter.fire }
26
+ @connection.connect
27
+ connected_waiter.wait
21
28
  end
22
29
 
23
30
  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)
31
+ TCPSocket.should_receive(:new).once.with('localhost', 9339).and_raise(Errno::ETIMEDOUT)
32
+ lambda { @connection.connect }.should raise_error(SmartFox::Client::ConnectionFailureError)
33
+ end
34
+
35
+ it "should login to the default install" do
36
+ login_waiter = Waiter.new
37
+ @connection.add_handler(:connected) { |connection| connection.login 'simpleChat', 'penwellr' }
38
+ @connection.add_handler(:logged_in) { login_waiter.fire }
39
+ @connection.connect
40
+
41
+ login_waiter.wait(10)
26
42
  end
27
43
 
28
44
  it "should fall back on BlueBox if needed"
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,8 @@ require 'smartfox'
4
4
  require 'spec'
5
5
  require 'spec/autorun'
6
6
 
7
+ require File.join(File.dirname(__FILE__), 'waiter')
8
+
7
9
  SmartFox::Logger.level = Logger::DEBUG
8
10
 
9
11
  Spec::Runner.configure do |config|
data/spec/waiter.rb ADDED
@@ -0,0 +1,25 @@
1
+ class Waiter
2
+ class TimeoutError < Exception; end
3
+
4
+ def initialize
5
+ @fired = false
6
+ end
7
+
8
+ def fire
9
+ @fired = true
10
+ Thread.pass
11
+ end
12
+
13
+ def wait(timeout = 5)
14
+ started_at = Time.now
15
+ while Time.now <= started_at + timeout
16
+ if @fired
17
+ return
18
+ else
19
+ Thread.pass
20
+ end
21
+ end
22
+
23
+ raise TimeoutError
24
+ end
25
+ 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: 27
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Richard Penwell
@@ -97,6 +97,7 @@ files:
97
97
  - spec/smartfox_spec.rb
98
98
  - spec/spec.opts
99
99
  - spec/spec_helper.rb
100
+ - spec/waiter.rb
100
101
  has_rdoc: true
101
102
  homepage: http://github.com/penwellr/smartfox
102
103
  licenses: []
@@ -134,3 +135,4 @@ summary: Client library for SmartFoxServer
134
135
  test_files:
135
136
  - spec/smartfox_spec.rb
136
137
  - spec/spec_helper.rb
138
+ - spec/waiter.rb