rafaelgaspar-sexyprotocol 0.1.1
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/lib/sexyprotocol.rb +6 -0
- data/lib/sexyprotocol/client.rb +37 -0
- data/lib/sexyprotocol/network_controller.rb +53 -0
- data/lib/sexyprotocol/server.rb +54 -0
- data/spec/sexyprotocol/client_spec.rb +25 -0
- data/spec/sexyprotocol/network_controller_spec.rb +71 -0
- data/spec/sexyprotocol/server_spec.rb +24 -0
- metadata +60 -0
data/lib/sexyprotocol.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module SexyProtocol
|
|
2
|
+
class Client
|
|
3
|
+
attr_reader :socket
|
|
4
|
+
attr_reader :network_controller
|
|
5
|
+
|
|
6
|
+
class << self; attr_accessor :network_controller_class; end
|
|
7
|
+
self.network_controller_class = SexyProtocol::NetworkController
|
|
8
|
+
|
|
9
|
+
def self.use_network_controller network_controller_class
|
|
10
|
+
self.network_controller_class = eval(network_controller_class.to_s)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.connect host, port, *args
|
|
14
|
+
new(host, port).connect(*args)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize host, port
|
|
18
|
+
@host = host
|
|
19
|
+
@port = port
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def connect *args
|
|
23
|
+
@socket = TCPSocket.open(@host, @port)
|
|
24
|
+
@network_controller = self.class.network_controller_class.new(@socket, *args).start
|
|
25
|
+
|
|
26
|
+
return self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def close
|
|
30
|
+
@network_controller.close
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def closed?
|
|
34
|
+
@network_controller.closed?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require "socket"
|
|
2
|
+
|
|
3
|
+
module SexyProtocol
|
|
4
|
+
class NetworkController
|
|
5
|
+
attr_reader :socket
|
|
6
|
+
|
|
7
|
+
def initialize socket
|
|
8
|
+
@socket = socket
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def start
|
|
12
|
+
@thread = Thread.new do
|
|
13
|
+
connected if respond_to?(:connected)
|
|
14
|
+
if respond_to?(:received_data)
|
|
15
|
+
until @socket.closed?
|
|
16
|
+
new_data = receive_data
|
|
17
|
+
received_data(new_data) unless new_data.nil?
|
|
18
|
+
end
|
|
19
|
+
disconnected if respond_to?(:disconnected)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
return self
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def received_message message
|
|
27
|
+
puts message
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def close
|
|
31
|
+
@thread.kill unless @thread.nil?
|
|
32
|
+
@socket.close unless @socket.closed?
|
|
33
|
+
disconnected if respond_to?(:disconnected)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def closed?
|
|
37
|
+
@socket.closed?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def send_data data
|
|
41
|
+
@socket.write([data.length].pack("I") + data)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def receive_data
|
|
45
|
+
length_raw_data = @socket.read(4)
|
|
46
|
+
if length_raw_data.nil?
|
|
47
|
+
return nil
|
|
48
|
+
else
|
|
49
|
+
return @socket.read(length_raw_data.unpack("I")[0])
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module SexyProtocol
|
|
2
|
+
class Server
|
|
3
|
+
attr_reader :socket
|
|
4
|
+
attr_reader :network_controllers
|
|
5
|
+
|
|
6
|
+
class << self; attr_accessor :network_controller_class; end
|
|
7
|
+
self.network_controller_class = SexyProtocol::NetworkController
|
|
8
|
+
|
|
9
|
+
def self.use_network_controller network_controller_class
|
|
10
|
+
self.network_controller_class = eval(network_controller_class.to_s)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.listen host, port, *args
|
|
14
|
+
new(host, port).listen(*args)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize host, port
|
|
18
|
+
@host = host
|
|
19
|
+
@port = port
|
|
20
|
+
@network_controllers = []
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def listen *args
|
|
24
|
+
@socket = TCPServer.open(@host, @port)
|
|
25
|
+
|
|
26
|
+
@thread = Thread.new do
|
|
27
|
+
while true
|
|
28
|
+
@network_controllers << self.class.network_controller_class.new(@socket.accept, *args).start
|
|
29
|
+
collect_garbaged_controllers
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
return self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def close
|
|
37
|
+
@thread.kill
|
|
38
|
+
@network_controllers.each do |controller|
|
|
39
|
+
controller.close
|
|
40
|
+
end
|
|
41
|
+
collect_garbaged_controllers
|
|
42
|
+
@socket.close
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def closed?
|
|
46
|
+
@socket.closed?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
def collect_garbaged_controllers
|
|
51
|
+
@network_controllers.delete_if { |controller| controller.closed? }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
dir = File.dirname(__FILE__)
|
|
2
|
+
lib_path = File.expand_path("#{dir}/../../lib")
|
|
3
|
+
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
|
|
4
|
+
require "sexyprotocol"
|
|
5
|
+
|
|
6
|
+
describe SexyProtocol::Client do
|
|
7
|
+
before(:all) do
|
|
8
|
+
@server = TCPServer.open("0.0.0.0", 8000)
|
|
9
|
+
@client = SexyProtocol::Client.connect("localhost", 8000)
|
|
10
|
+
@server.accept
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after(:all) do
|
|
14
|
+
@server.close
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should be able to connect at a given host and port" do
|
|
18
|
+
@client.socket.should_not be_closed
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should be able to disconnect" do
|
|
22
|
+
@client.close
|
|
23
|
+
@client.socket.should be_closed
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
dir = File.dirname(__FILE__)
|
|
2
|
+
lib_path = File.expand_path("#{dir}/../../lib")
|
|
3
|
+
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
|
|
4
|
+
require "sexyprotocol"
|
|
5
|
+
|
|
6
|
+
describe SexyProtocol::NetworkController do
|
|
7
|
+
before(:all) do
|
|
8
|
+
@server = TCPServer.open("0.0.0.0", 8000)
|
|
9
|
+
@client = SexyProtocol::NetworkController.new(TCPSocket.open("localhost", 8000))
|
|
10
|
+
@session = @server.accept
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after(:all) do
|
|
14
|
+
@server.close
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should be able to get the socket" do
|
|
18
|
+
@client.socket.should be_instance_of(TCPSocket)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should be able to send a message" do
|
|
22
|
+
@client.send_data("Hello World!")
|
|
23
|
+
@session.read(16).should ==([12].pack("I") + "Hello World!")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should be able to receive a message" do
|
|
27
|
+
@session.write([12].pack("I") + "Hello World!")
|
|
28
|
+
@client.receive_data.should == "Hello World!"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe SexyProtocol do
|
|
34
|
+
before do
|
|
35
|
+
@server = TCPServer.open("0.0.0.0", 8000)
|
|
36
|
+
@client = SexyProtocol::NetworkController.new(TCPSocket.open("localhost", 8000))
|
|
37
|
+
@session = @server.accept
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
after do
|
|
41
|
+
@server.close
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should be sent connected message when it connects" do
|
|
45
|
+
@client.stub!(:connected)
|
|
46
|
+
@client.should_receive(:connected)
|
|
47
|
+
|
|
48
|
+
@client.start
|
|
49
|
+
sleep 0.01
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should be sent received_message when message is received" do
|
|
53
|
+
@client.stub!(:received_data)
|
|
54
|
+
@client.should_receive(:received_data).with("Hello World!")
|
|
55
|
+
@session.write([12].pack("I") + "Hello World!")
|
|
56
|
+
|
|
57
|
+
@client.start
|
|
58
|
+
sleep 0.01
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should be sent disconnected message when it disconnects" do
|
|
62
|
+
@client.stub!(:disconnected)
|
|
63
|
+
@client.should_receive(:disconnected)
|
|
64
|
+
|
|
65
|
+
@client.start
|
|
66
|
+
sleep 0.01
|
|
67
|
+
|
|
68
|
+
@client.close
|
|
69
|
+
sleep 0.01
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
dir = File.dirname(__FILE__)
|
|
2
|
+
lib_path = File.expand_path("#{dir}/../../lib")
|
|
3
|
+
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
|
|
4
|
+
require "sexyprotocol"
|
|
5
|
+
|
|
6
|
+
describe SexyProtocol::Server do
|
|
7
|
+
it "should be able to receive connections at a given host and port" do
|
|
8
|
+
server = SexyProtocol::Server.listen("0.0.0.0", 8000)
|
|
9
|
+
client = TCPSocket.open("localhost", 8000)
|
|
10
|
+
sleep 0.1
|
|
11
|
+
server.network_controllers[0].should be_instance_of(SexyProtocol::NetworkController)
|
|
12
|
+
server.network_controllers[0].should_not be_closed
|
|
13
|
+
|
|
14
|
+
server.close
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe SexyProtocol do
|
|
19
|
+
it "should be able to get the socket" do
|
|
20
|
+
server = SexyProtocol::Server.listen("0.0.0.0", 8000)
|
|
21
|
+
server.socket.should be_instance_of(TCPServer)
|
|
22
|
+
server.close
|
|
23
|
+
end
|
|
24
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rafaelgaspar-sexyprotocol
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Rafael Gaspar
|
|
8
|
+
- Fernando Cezar
|
|
9
|
+
autorequire: sexyprotocol
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2009-05-16 00:00:00 -07:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies: []
|
|
16
|
+
|
|
17
|
+
description:
|
|
18
|
+
email: rafael.gaspar@gmail.com
|
|
19
|
+
executables: []
|
|
20
|
+
|
|
21
|
+
extensions: []
|
|
22
|
+
|
|
23
|
+
extra_rdoc_files: []
|
|
24
|
+
|
|
25
|
+
files:
|
|
26
|
+
- lib/sexyprotocol.rb
|
|
27
|
+
- lib/sexyprotocol
|
|
28
|
+
- lib/sexyprotocol/client.rb
|
|
29
|
+
- lib/sexyprotocol/server.rb
|
|
30
|
+
- lib/sexyprotocol/network_controller.rb
|
|
31
|
+
has_rdoc: false
|
|
32
|
+
homepage: http://www.github.com/rafaelgaspar/sexyprotocol
|
|
33
|
+
post_install_message:
|
|
34
|
+
rdoc_options: []
|
|
35
|
+
|
|
36
|
+
require_paths:
|
|
37
|
+
- lib
|
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: "0"
|
|
43
|
+
version:
|
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: "0"
|
|
49
|
+
version:
|
|
50
|
+
requirements: []
|
|
51
|
+
|
|
52
|
+
rubyforge_project:
|
|
53
|
+
rubygems_version: 1.2.0
|
|
54
|
+
signing_key:
|
|
55
|
+
specification_version: 2
|
|
56
|
+
summary: An Event-Driven Network Framework for Rapid Network Client and Server Protocol Development.
|
|
57
|
+
test_files:
|
|
58
|
+
- spec/sexyprotocol/client_spec.rb
|
|
59
|
+
- spec/sexyprotocol/server_spec.rb
|
|
60
|
+
- spec/sexyprotocol/network_controller_spec.rb
|