bertclient 0.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.
Files changed (2) hide show
  1. data/lib/bertclient.rb +114 -0
  2. metadata +55 -0
data/lib/bertclient.rb ADDED
@@ -0,0 +1,114 @@
1
+ require 'openssl'
2
+ require 'bert'
3
+ require 'resolv-replace' # TCPSocket
4
+
5
+ module BERT
6
+ class Client
7
+ class RPCError < StandardError; end
8
+ class NoSuchModule < RPCError; end
9
+ class NoSuchFunction < RPCError; end
10
+ class UserError < RPCError; end
11
+ class UnknownError < RPCError; end
12
+ class InvalidResponse < RPCError; end
13
+ class BadHeader < RPCError; end
14
+ class BadData < RPCError; end
15
+
16
+ def initialize(opts={})
17
+ @host = opts[:host] || 'localhost'
18
+ @port = opts[:port] || 9999
19
+ @ssl = opts[:ssl] || false
20
+ @verify_ssl = opts.has_key?(:verify_ssl) ? opts[:verify_ssl] : true
21
+ @socket = {}
22
+ connect
23
+ end
24
+
25
+ def call(mod, fun, *args)
26
+ response = cast_or_call(:call, mod, fun, *args)
27
+ return response[1] if response[0] == :reply
28
+
29
+ handle_error(response)
30
+ end
31
+
32
+ def cast(mod, fun, *args)
33
+ response = cast_or_call(:cast, mod, fun, *args)
34
+ return nil if response[0] == :noreply
35
+
36
+ handle_error(response)
37
+ end
38
+
39
+ # Wrapper for both cast and call mechanisms
40
+ def cast_or_call(cc, mod, fun, *args)
41
+ req = t[cc, mod.to_sym, fun.to_sym, args]
42
+ write_berp(req)
43
+ read_berp
44
+ end
45
+
46
+ # See bert-rpc.org for error response mechanisms
47
+ def handle_error(response)
48
+ unless response[0] == :error
49
+ raise InvalidReponse, "Expected error response, got: #{response.inspect}"
50
+ end
51
+
52
+ type, code, klass, detail, backtrace = response[1]
53
+ case type
54
+ when :server
55
+ if code == 1
56
+ raise NoSuchModule
57
+ elsif code == 2
58
+ raise NoSuchFunction
59
+ else
60
+ raise UnknownError, "Unknown server error: #{response.inspect}"
61
+ end
62
+ when :user
63
+ raise UserError.new("#{klass}: #{detail}\n#{backtrace.join()}")
64
+ when :protocol
65
+ if code == 1
66
+ raise BadHeader
67
+ elsif code == 2
68
+ raise BadData
69
+ else
70
+ raise UnknownError, "Unknown protocol error: #{reponse.inspect}"
71
+ end
72
+ else
73
+ raise UnknownError, "Unknown error: #{response.inspect}"
74
+ end
75
+ end
76
+
77
+ def socket
78
+ @socket[Thread.current]
79
+ end
80
+
81
+ # Open socket to service, use SSL if necessary
82
+ def connect
83
+ sock = TCPSocket.new(@host, @port)
84
+ if @ssl
85
+ sock = OpenSSL::SSL::SSLSocket.new(sock)
86
+ sock.sync_close = true
87
+ sock.connect
88
+ sock.post_connection_check(@host) if @verify_ssl
89
+ end
90
+ @socket[Thread.current] = sock
91
+ true
92
+ end
93
+
94
+ # Reads a new berp from the socket and returns the decoded object
95
+ def read_berp
96
+ length = socket.read(4).unpack('N')[0]
97
+ data = socket.read(length)
98
+ BERT.decode(data)
99
+ end
100
+
101
+ # Accepts a Ruby object, converts to a berp and sends through the socket
102
+ def write_berp(obj)
103
+ socket.write(Client.create_berp(obj))
104
+ end
105
+
106
+ # Accepts a Ruby object and returns an encoded berp
107
+ def Client.create_berp(obj)
108
+ data = BERT.encode(obj)
109
+ length = [data.bytesize].pack('N')
110
+ "#{length}#{data}"
111
+ end
112
+ end
113
+
114
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bertclient
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Jared Kuolt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-03-23 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: BERT::Client is a threadsafe BERT-RPC client with support for persistent connections, ssl, and it currently exposes BERT-RPC's cast and call
17
+ email: luckythetourist@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/bertclient.rb
26
+ has_rdoc: true
27
+ homepage: http://github.com/luckythetourist/bertclient
28
+ licenses: []
29
+
30
+ post_install_message:
31
+ rdoc_options: []
32
+
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: "0"
40
+ version:
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ requirements: []
48
+
49
+ rubyforge_project: bertclient
50
+ rubygems_version: 1.3.5
51
+ signing_key:
52
+ specification_version: 3
53
+ summary: A threadsafe BERT-RPC client with ssl support and persistent connections
54
+ test_files: []
55
+