network-facade 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/network-facade/base.rb +54 -18
- data/lib/network-facade/config.rb +1 -1
- data/lib/network-facade/rest.rb +119 -0
- data/lib/network-facade.rb +70 -6
- metadata +3 -2
data/lib/network-facade/base.rb
CHANGED
@@ -30,34 +30,36 @@ module Base
|
|
30
30
|
@@klass ||= {}
|
31
31
|
if defined? @@uri and not @@uri.nil?
|
32
32
|
@@klass[klass] = URI.parse(@@uri)
|
33
|
-
@@klass[klass].path
|
34
|
-
|
33
|
+
if @@klass[klass].path.empty? or @@klass[klass].path == '/'
|
34
|
+
@@klass[klass].path = '/' + klass.name.downcase
|
35
|
+
end
|
35
36
|
end
|
36
37
|
@@uri = nil
|
37
38
|
end
|
38
39
|
|
39
40
|
def initialize(options = {})
|
40
41
|
@options = options
|
41
|
-
|
42
|
-
URI
|
42
|
+
if @options[:uri]
|
43
|
+
@uri ||= URI.parse(@options[:uri])
|
44
|
+
elsif @@klass[self.class]
|
45
|
+
@uri ||= @@klass[self.class]
|
46
|
+
else
|
47
|
+
@uri ||= URI::Generic.new('nf', nil, nil, nil, nil, '/' + self.class.name.downcase, nil, nil, nil)
|
48
|
+
end
|
43
49
|
@uri.host = @options[:host] if @options[:host]
|
44
50
|
@uri.port = @options[:port] if @options[:port]
|
45
51
|
@uri.path = @options[:path] if @options[:path]
|
46
52
|
@uri.query = @options[:query] if @options[:query]
|
47
53
|
@uri.userinfo = @options[:userinfo] if @options[:userinfo]
|
48
54
|
@mutex = Mutex.new
|
55
|
+
require 'zlib' if @options[:compress]
|
49
56
|
end
|
50
57
|
|
51
58
|
def method_missing(name, *args)
|
52
59
|
NetworkFacade.log(:debug, "Method called with #{args.inspect}", "#{self.class}##{name}")
|
53
60
|
begin
|
54
|
-
|
55
|
-
|
56
|
-
@client.write(size)
|
57
|
-
@client.write(data)
|
58
|
-
size = @client.read(4).unpack('N').first
|
59
|
-
data = @client.read(size)
|
60
|
-
result = Marshal.load(data)
|
61
|
+
__write__([@uri.path[1..-1], name, args])
|
62
|
+
result = __read__
|
61
63
|
if result.is_a? Exception
|
62
64
|
NetworkFacade.log(:info, "Exception occured : #{result.inspect}", "#{self.class}##{name}")
|
63
65
|
result.backtrace.collect! do |line|
|
@@ -72,11 +74,31 @@ module Base
|
|
72
74
|
retry
|
73
75
|
end
|
74
76
|
end
|
77
|
+
|
78
|
+
def __read__
|
79
|
+
size = @client.read(4).unpack('N').first
|
80
|
+
NetworkFacade.log(:debug, "Read #{size + 4} bytes", @uri)
|
81
|
+
data = @client.read(size)
|
82
|
+
data = Zlib::Inflate.inflate(data) if @options[:compress]
|
83
|
+
Marshal.load(data)
|
84
|
+
end
|
85
|
+
|
86
|
+
def __write__(data)
|
87
|
+
data = Marshal.dump(data)
|
88
|
+
data = Zlib::Deflate.deflate(data, Zlib::FINISH) if @options[:compress]
|
89
|
+
NetworkFacade.log(:debug, "Write #{data.size + 4} bytes", @uri)
|
90
|
+
size = [data.size].pack('N')
|
91
|
+
@client.write(size)
|
92
|
+
@client.write(data)
|
93
|
+
@client.flush
|
94
|
+
end
|
95
|
+
|
75
96
|
end
|
76
97
|
|
77
98
|
class Server
|
78
99
|
def initialize(options = {})
|
79
100
|
@options = options
|
101
|
+
require 'zlib' if @options[:compress]
|
80
102
|
@fd = [@options[:server]]
|
81
103
|
@objs = {}
|
82
104
|
end
|
@@ -115,10 +137,7 @@ module Base
|
|
115
137
|
size = nil
|
116
138
|
data = nil
|
117
139
|
begin
|
118
|
-
|
119
|
-
raise EOFError if size.nil?
|
120
|
-
size = size.unpack('N').first
|
121
|
-
data = Marshal.load(client.read(size))
|
140
|
+
data = read(client)
|
122
141
|
result = nil
|
123
142
|
begin
|
124
143
|
if @objs[data[0]].respond_to? data[1]
|
@@ -132,9 +151,7 @@ module Base
|
|
132
151
|
NetworkFacade.log(:info, "Error occured when executing #{data[1].inspect} with #{data[2].inspect}", client_id(client))
|
133
152
|
NetworkFacade.log(:info, $!)
|
134
153
|
end
|
135
|
-
|
136
|
-
client.write([result.size].pack('N'))
|
137
|
-
client.write(result)
|
154
|
+
write(client, result)
|
138
155
|
rescue Exception
|
139
156
|
NetworkFacade.log(:info, "Close connection", client_id(client))
|
140
157
|
client.close
|
@@ -144,6 +161,25 @@ module Base
|
|
144
161
|
end
|
145
162
|
end
|
146
163
|
end
|
164
|
+
|
165
|
+
def read(client)
|
166
|
+
size = client.read(4)
|
167
|
+
raise EOFError if size.nil?
|
168
|
+
size = size.unpack('N').first
|
169
|
+
NetworkFacade.log(:debug, "Read #{size + 4} bytes", client_id(client))
|
170
|
+
data = client.read(size)
|
171
|
+
data = Zlib::Inflate.inflate(data) if @options[:compress]
|
172
|
+
Marshal.load(data)
|
173
|
+
end
|
174
|
+
|
175
|
+
def write(client, data)
|
176
|
+
data = Marshal.dump(data)
|
177
|
+
data = Zlib::Deflate.deflate(data, Zlib::FINISH) if @options[:compress]
|
178
|
+
NetworkFacade.log(:debug, "Write #{data.size + 4} bytes", client_id(client))
|
179
|
+
client.write([data.size].pack('N'))
|
180
|
+
client.write(data)
|
181
|
+
client.flush
|
182
|
+
end
|
147
183
|
end
|
148
184
|
|
149
185
|
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'cgi'
|
3
|
+
require 'rubygems'
|
4
|
+
begin
|
5
|
+
require 'xml/libxml'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rexml/document'
|
8
|
+
end
|
9
|
+
begin
|
10
|
+
require 'json'
|
11
|
+
rescue
|
12
|
+
# Do nothing
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
module NetworkFacade
|
17
|
+
module REST
|
18
|
+
|
19
|
+
def self.Client(uri = nil)
|
20
|
+
Client.uri = uri
|
21
|
+
Client
|
22
|
+
end
|
23
|
+
|
24
|
+
class Client < Base::Client
|
25
|
+
def initialize(options = {})
|
26
|
+
super
|
27
|
+
@cookies = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(name, *args)
|
31
|
+
|
32
|
+
# Build query string
|
33
|
+
params = args.first || {}
|
34
|
+
raise "Params must be an Hash table" unless params.is_a? Hash
|
35
|
+
qs = params.keys.collect do |k|
|
36
|
+
"#{k}=#{CGI::escape(params[k].to_s)}"
|
37
|
+
end.join('&')
|
38
|
+
|
39
|
+
# Cutom method mapping defined ?
|
40
|
+
if @options[:mapping] and @options[:mapping][name]
|
41
|
+
@uri.path = @options[:mapping][name]
|
42
|
+
end
|
43
|
+
|
44
|
+
format = @options[:append_slash] ? '%s/?%s' : '%s?%s'
|
45
|
+
Net::HTTP.start(@uri.host, @uri.port) do |http|
|
46
|
+
|
47
|
+
# Build header fields
|
48
|
+
header = @options[:header] || {}
|
49
|
+
header['User-Agent'] = @options[:user_agent] || NetworkFacade::NAME + '/' + NetworkFacade::VERSION
|
50
|
+
unless @cookies.empty?
|
51
|
+
header['Cookie'] = @cookies.keys.collect do |k|
|
52
|
+
"#{k}=#{@cookies[k]}"
|
53
|
+
end.join('; ')
|
54
|
+
end
|
55
|
+
|
56
|
+
# Build request path
|
57
|
+
if @options[:method] == :path
|
58
|
+
path = format % [ "#{@uri.path}/#{name}", qs ]
|
59
|
+
elsif @options[:method] == :param and @options[:method_param]
|
60
|
+
path = format % [ @uri.path, "#{qs}&#{@options[:method_param]}=#{CGI::escape(name.to_s)}" ]
|
61
|
+
else
|
62
|
+
path = format % [ @uri.path, qs ]
|
63
|
+
end
|
64
|
+
|
65
|
+
# POST or GET
|
66
|
+
if @options[:post].is_a? Array and @options[:post].include? name
|
67
|
+
req = Net::HTTP::Post.new(path, header)
|
68
|
+
req.form_data = params
|
69
|
+
else
|
70
|
+
req = Net::HTTP::Get.new(path, header)
|
71
|
+
NetworkFacade.log(:info, "GET #{req.path}")
|
72
|
+
end
|
73
|
+
res = http.request(req)
|
74
|
+
|
75
|
+
# Remember cookies
|
76
|
+
CGI::Cookie::parse(res['set-cookie']).each do |k,v|
|
77
|
+
next if k == 'path' or k == 'expires'
|
78
|
+
@cookies[k] = v.value
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return the correct data
|
82
|
+
case res.code
|
83
|
+
when '200'
|
84
|
+
case res.content_type
|
85
|
+
when /xml/
|
86
|
+
if defined? XML
|
87
|
+
parser = XML::Parser.new
|
88
|
+
parser.string = res.body
|
89
|
+
data = parser.parse
|
90
|
+
else
|
91
|
+
data = REXML::Document.new(res.body)
|
92
|
+
end
|
93
|
+
when /json/
|
94
|
+
if defined? JSON
|
95
|
+
data = JSON.parse res.body
|
96
|
+
else
|
97
|
+
data = res.body
|
98
|
+
end
|
99
|
+
when /php/
|
100
|
+
#TODO: http://php.net/serialize, http://hurring.com/code/perl/serialize/
|
101
|
+
raise "Not implemented yet"
|
102
|
+
else
|
103
|
+
data = res.body
|
104
|
+
end
|
105
|
+
when /3\d\d/
|
106
|
+
# FIXME
|
107
|
+
raise "Redirection not supported yet"
|
108
|
+
else
|
109
|
+
NetworkFacade.log(:error, "An error occured when calling #{name} (returned code = #{res.code})")
|
110
|
+
end
|
111
|
+
|
112
|
+
# Return the header if asked
|
113
|
+
@options[:header] ? [res.to_hash, data] : data
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
data/lib/network-facade.rb
CHANGED
@@ -8,49 +8,113 @@ require 'network-facade/base'
|
|
8
8
|
require 'network-facade/tcp'
|
9
9
|
require 'network-facade/unix'
|
10
10
|
require 'network-facade/ssl'
|
11
|
+
require 'network-facade/rest'
|
11
12
|
require 'network-facade/defaults'
|
12
13
|
|
13
14
|
if __FILE__ == $0
|
14
15
|
NetworkFacade.log = STDERR
|
15
16
|
|
16
|
-
case ARGV.
|
17
|
+
case ARGV.shift
|
17
18
|
#=======================<client>==============================#
|
18
19
|
when 'client-tcp-uri'
|
19
|
-
|
20
|
+
|
21
|
+
class Foo < NetworkFacade::Client 'nf://localhost:5042'
|
20
22
|
end
|
21
23
|
f = Foo.new
|
22
24
|
p f.bar
|
25
|
+
|
23
26
|
when 'client-tcp-class'
|
27
|
+
|
24
28
|
class Foo < NetworkFacade::Client
|
25
29
|
end
|
26
|
-
f = Foo.new(:host => '
|
27
|
-
p f.
|
30
|
+
f = Foo.new(:host => 'localhost', :port => 5042)
|
31
|
+
p f.big
|
32
|
+
|
28
33
|
when 'client-unix'
|
34
|
+
|
29
35
|
class Foo < NetworkFacade::Unix::Client
|
30
36
|
end
|
31
37
|
f = Foo.new
|
32
38
|
p f.bar
|
39
|
+
|
33
40
|
when 'client-ssl'
|
34
|
-
|
41
|
+
|
42
|
+
class Foo < NetworkFacade::SSL::Client 'nf://localhost:5044'
|
35
43
|
end
|
36
44
|
f = Foo.new(:ca => '../cert/ca.cert',
|
37
45
|
:cert => '../cert/client.cert',
|
38
46
|
:key => '../cert/client.key')
|
39
47
|
p f.bar
|
48
|
+
|
49
|
+
when 'client-tcp-compress'
|
50
|
+
|
51
|
+
class Foo < NetworkFacade::Client
|
52
|
+
end
|
53
|
+
p Foo.new(:compress => true).big
|
54
|
+
|
55
|
+
when 'client-rest-rtm'
|
56
|
+
|
57
|
+
class Foo < NetworkFacade::REST::Client 'http://www.rememberthemilk.com/services/rest/'
|
58
|
+
end
|
59
|
+
|
60
|
+
f = Foo.new
|
61
|
+
p f.call(:method => 'rtm.test.echo', :api_key => ARGV.first, :foo => 'bar')
|
62
|
+
|
63
|
+
f = Foo.new(:method => :param, :method_param => 'method')
|
64
|
+
p f.send('rtm.test.echo', :api_key => ARGV.first, :foo => 'bar')
|
65
|
+
|
66
|
+
when 'client-rest-netvibes'
|
67
|
+
|
68
|
+
class Foo < NetworkFacade::REST::Client 'http://www.netvibes.com'
|
69
|
+
end
|
70
|
+
f = Foo.new(:mapping => {
|
71
|
+
:login => '/user/signIn.php',
|
72
|
+
:load => '/get/userData.php',
|
73
|
+
:save => '/save/userData.php'
|
74
|
+
}, :post => [:login, :save])
|
75
|
+
|
76
|
+
p f.login(:email => 'paillerosse@lescampeurs.org', :password => ARGV.first)
|
77
|
+
p f.load
|
78
|
+
|
79
|
+
when 'client-rest-flickr'
|
80
|
+
|
81
|
+
class Foo < NetworkFacade::REST::Client 'http://api.flickr.com/services/rest/'
|
82
|
+
end
|
83
|
+
|
84
|
+
f = Foo.new
|
85
|
+
p f.call(:method => 'flickr.test.echo', :api_key => ARGV.first, :foo => 'bar')
|
86
|
+
|
87
|
+
when 'client-rest-digg'
|
88
|
+
|
89
|
+
class Foo < NetworkFacade::REST::Client 'http://services.digg.com'
|
90
|
+
end
|
91
|
+
f = Foo.new(:mapping => {
|
92
|
+
:apple_stories => '/stories/topic/apple',
|
93
|
+
:me => '/user/pyros'
|
94
|
+
})
|
95
|
+
p f.apple_stories(:appkey => 'http://network-facade.rubyforge.org', :count => 3)
|
96
|
+
p f.apple_stories(:appkey => 'http://network-facade.rubyforge.org', :count => 3, :type => :json)
|
97
|
+
p f.me(:appkey => 'http://network-facade.rubyforge.org')
|
98
|
+
|
40
99
|
#=======================</client>=============================#
|
41
100
|
else
|
42
101
|
class Foo
|
43
102
|
def bar
|
44
103
|
42
|
45
104
|
end
|
105
|
+
def big
|
106
|
+
(Time.now.to_s + "\n") * 10
|
107
|
+
end
|
46
108
|
def error
|
47
109
|
raise "Error"
|
48
110
|
end
|
49
111
|
end
|
50
|
-
case ARGV.
|
112
|
+
case ARGV.shift
|
51
113
|
#=======================<server>==============================#
|
52
114
|
when 'server-tcp'
|
53
115
|
NetworkFacade::Server.new.add(Foo.new).start
|
116
|
+
when 'server-tcp-compress'
|
117
|
+
NetworkFacade::Server.new(:compress => true).add(Foo.new).start
|
54
118
|
when 'server-unix'
|
55
119
|
NetworkFacade::Unix::Server.new.add(Foo.new).start
|
56
120
|
when 'server-ssl'
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: network-facade
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2007-05-
|
6
|
+
version: "0.2"
|
7
|
+
date: 2007-05-03 00:00:00 +02:00
|
8
8
|
summary: Object-oriented netwotk facade
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- lib/network-facade/base.rb
|
36
36
|
- lib/network-facade/defaults.rb
|
37
37
|
- lib/network-facade/ssl.rb
|
38
|
+
- lib/network-facade/rest.rb
|
38
39
|
- lib/network-facade.rb
|
39
40
|
test_files: []
|
40
41
|
|