rserve-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +3 -0
- data/Manifest.txt +31 -0
- data/README.txt +50 -0
- data/Rakefile +14 -0
- data/lib/rserve.rb +14 -0
- data/lib/rserve/connection.rb +138 -0
- data/lib/rserve/engine.rb +40 -0
- data/lib/rserve/packet.rb +31 -0
- data/lib/rserve/protocol.rb +183 -0
- data/lib/rserve/protocol/rexpfactory.rb +360 -0
- data/lib/rserve/rexp.rb +234 -0
- data/lib/rserve/rexp/double.rb +46 -0
- data/lib/rserve/rexp/genericvector.rb +29 -0
- data/lib/rserve/rexp/integer.rb +49 -0
- data/lib/rserve/rexp/list.rb +33 -0
- data/lib/rserve/rexp/logical.rb +48 -0
- data/lib/rserve/rexp/string.rb +33 -0
- data/lib/rserve/rexp/symbol.rb +26 -0
- data/lib/rserve/rexp/vector.rb +23 -0
- data/lib/rserve/rlist.rb +124 -0
- data/lib/rserve/talk.rb +123 -0
- data/spec/rserve_connection_spec.rb +43 -0
- data/spec/rserve_double_spec.rb +55 -0
- data/spec/rserve_integer_spec.rb +55 -0
- data/spec/rserve_packet_spec.rb +19 -0
- data/spec/rserve_protocol_spec.rb +75 -0
- data/spec/rserve_rexpfactory_spec.rb +44 -0
- data/spec/rserve_spec.rb +18 -0
- data/spec/rserve_talk_spec.rb +73 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +4 -0
- metadata +149 -0
- metadata.gz.sig +0 -0
data.tar.gz.sig
ADDED
Binary file
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
lib/rserve.rb
|
6
|
+
lib/rserve/connection.rb
|
7
|
+
lib/rserve/engine.rb
|
8
|
+
lib/rserve/packet.rb
|
9
|
+
lib/rserve/protocol.rb
|
10
|
+
lib/rserve/protocol/rexpfactory.rb
|
11
|
+
lib/rserve/rexp.rb
|
12
|
+
lib/rserve/rexp/double.rb
|
13
|
+
lib/rserve/rexp/genericvector.rb
|
14
|
+
lib/rserve/rexp/integer.rb
|
15
|
+
lib/rserve/rexp/list.rb
|
16
|
+
lib/rserve/rexp/logical.rb
|
17
|
+
lib/rserve/rexp/string.rb
|
18
|
+
lib/rserve/rexp/symbol.rb
|
19
|
+
lib/rserve/rexp/vector.rb
|
20
|
+
lib/rserve/rlist.rb
|
21
|
+
lib/rserve/talk.rb
|
22
|
+
spec/rserve_connection_spec.rb
|
23
|
+
spec/rserve_double_spec.rb
|
24
|
+
spec/rserve_integer_spec.rb
|
25
|
+
spec/rserve_packet_spec.rb
|
26
|
+
spec/rserve_protocol_spec.rb
|
27
|
+
spec/rserve_rexpfactory_spec.rb
|
28
|
+
spec/rserve_spec.rb
|
29
|
+
spec/rserve_talk_spec.rb
|
30
|
+
spec/spec.opts
|
31
|
+
spec/spec_helper.rb
|
data/README.txt
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
= rserve-client
|
2
|
+
|
3
|
+
* http://github.com/clbustos/Rserve-Ruby-client
|
4
|
+
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
Ruby client for Rserve, a Binary R server (http://www.rforge.net/Rserve/).
|
9
|
+
|
10
|
+
Follows closely the new Java client API, but maintains all Ruby conventions when possible.
|
11
|
+
|
12
|
+
Connection to Rserve not yet developed, but between June-July 2010 the system should be operational.
|
13
|
+
|
14
|
+
== SYNOPSIS:
|
15
|
+
|
16
|
+
require 'rserve'
|
17
|
+
con=Rserve::Connection.new
|
18
|
+
con.eval("x<-renorm(1)")
|
19
|
+
=> #<Rserve::REXP::Double:0x000000011a13c8
|
20
|
+
@payload=[(5339785585931699/2251799813685248)],
|
21
|
+
@attr=nil>
|
22
|
+
|
23
|
+
== REQUIREMENTS:
|
24
|
+
|
25
|
+
* R
|
26
|
+
* Rserve
|
27
|
+
|
28
|
+
== INSTALL:
|
29
|
+
|
30
|
+
sudo gem install rserve-client
|
31
|
+
|
32
|
+
== LICENSE:
|
33
|
+
|
34
|
+
REngine - Java interface to R
|
35
|
+
Copyright (C) 2004,5,6,7 Simon Urbanek
|
36
|
+
Copyrigth (C) 2010 Claudio Bustos (Ruby version)
|
37
|
+
|
38
|
+
This library is free software; you can redistribute it and/or
|
39
|
+
modify it under the terms of the GNU Lesser General Public
|
40
|
+
License as published by the Free Software Foundation; either
|
41
|
+
version 2.1 of the License, or (at your option) any later version.
|
42
|
+
|
43
|
+
This library is distributed in the hope that it will be useful,
|
44
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
45
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
46
|
+
Lesser General Public License for more details.
|
47
|
+
|
48
|
+
You should have received a copy of the GNU Lesser General Public
|
49
|
+
License along with this library; if not, write to the Free Software
|
50
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
$:.unshift(File.dirname(__FILE__)+"/lib")
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require 'rserve'
|
6
|
+
Hoe.plugin :git
|
7
|
+
Hoe.spec 'rserve-client' do
|
8
|
+
self.testlib=:rspec
|
9
|
+
self.version=Rserve::VERSION
|
10
|
+
self.rubyforge_name = 'ruby-statsample' # if different than 'rserve'
|
11
|
+
self.developer('Claudio Bustos', 'clbustos_AT_gmail.com')
|
12
|
+
end
|
13
|
+
|
14
|
+
# vim: syntax=ruby
|
data/lib/rserve.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
module Rserve
|
2
|
+
class Connection < Rserve::Engine
|
3
|
+
include Rserve::Protocol
|
4
|
+
ServerNotInstalled=Class.new(Exception)
|
5
|
+
IncorrectServer=Class.new(Exception)
|
6
|
+
IncorrectServerVersion=Class.new(Exception)
|
7
|
+
IncorrectProtocol=Class.new(Exception)
|
8
|
+
NotConnected=Class.new(Exception)
|
9
|
+
EvalError=Class.new(Exception)
|
10
|
+
attr_reader :protocol
|
11
|
+
attr_reader :last_error
|
12
|
+
attr_reader :connected
|
13
|
+
attr_reader :auth_req
|
14
|
+
attr_reader :auth_type
|
15
|
+
attr_reader :key
|
16
|
+
attr_reader :rt
|
17
|
+
attr_reader :s
|
18
|
+
attr_reader :port
|
19
|
+
attr_writer :transfer_charset
|
20
|
+
attr_reader :rsrv_version
|
21
|
+
AT_plain=0
|
22
|
+
AT_crypt=1
|
23
|
+
|
24
|
+
def host
|
25
|
+
@hostname
|
26
|
+
end
|
27
|
+
def initialize(opts=Hash.new)
|
28
|
+
@auth_req=false
|
29
|
+
@transfer_charset="UTF-8"
|
30
|
+
@auth_type=AT_plain
|
31
|
+
@hostname="127.0.0.1"
|
32
|
+
@port_number=6311
|
33
|
+
@tries=0
|
34
|
+
@max_tries=5
|
35
|
+
@connected=false
|
36
|
+
begin
|
37
|
+
#puts "Tryin to connect..."
|
38
|
+
connect
|
39
|
+
rescue Errno::ECONNREFUSED
|
40
|
+
if @tries<@max_tries
|
41
|
+
#puts "Init RServe"
|
42
|
+
if system "R CMD Rserve"
|
43
|
+
#puts "Ok"
|
44
|
+
retry
|
45
|
+
else
|
46
|
+
raise ServerNotInstalled, "Rserve not installed"
|
47
|
+
end
|
48
|
+
else
|
49
|
+
raise
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
def is
|
55
|
+
@s
|
56
|
+
end
|
57
|
+
def os
|
58
|
+
@s
|
59
|
+
end
|
60
|
+
def connect
|
61
|
+
close if @connected
|
62
|
+
@s = TCPSocket::new(@hostname, @port_number)
|
63
|
+
@rt=Rserve::Talk.new(@s)
|
64
|
+
#puts "Connected"
|
65
|
+
# Accept first input
|
66
|
+
input=@s.recv(32).unpack("a4a4a4a20")
|
67
|
+
raise IncorrectServer,"Handshake failed: Rsrv signature expected, but received #{input[0]}" unless input[0]=="Rsrv"
|
68
|
+
@rsrv_version=input[1].to_i
|
69
|
+
raise IncorrectServerVersion, "Handshake failed: The server uses more recent protocol than this client." if @rsrv_version>103
|
70
|
+
@protocol=input[2]
|
71
|
+
raise IncorrectProtocol, "Handshake failed: unsupported transfer protocol #{@protocol}, I talk only QAP1." if @protocol!="QAP1"
|
72
|
+
@extra=input[4]
|
73
|
+
@connected=true
|
74
|
+
@last_error="OK"
|
75
|
+
|
76
|
+
end
|
77
|
+
def connected?
|
78
|
+
@connected
|
79
|
+
end
|
80
|
+
def close
|
81
|
+
@s.shutdown if !@s.nil? and !@s.closed?
|
82
|
+
@connected=false
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
def get_server_version
|
86
|
+
@rsrv_version
|
87
|
+
end
|
88
|
+
|
89
|
+
# evaluates the given command, but does not fetch the result (useful for assignment operations)
|
90
|
+
# * @param cmd command/expression string */
|
91
|
+
def void_eval(cmd)
|
92
|
+
raise NotConnected if !connected? or rt.nil?
|
93
|
+
rp=rt.request(:cmd=>Rserve::Protocol::CMD_voidEval, :cont=>cmd+"\n")
|
94
|
+
if !rp.nil? and rp.ok?
|
95
|
+
true
|
96
|
+
else
|
97
|
+
raise EvalError, "voidEval failed: #{rp.to_s}"
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# evaluates the given command and retrieves the result
|
104
|
+
# * @param cmd command/expression string
|
105
|
+
# * @return R-xpression or <code>null</code> if an error occured */
|
106
|
+
def eval(cmd)
|
107
|
+
raise NotConnected if !connected? or rt.nil?
|
108
|
+
rp=rt.request(:cmd=>Rserve::Protocol::CMD_eval, :cont=>cmd+"\n")
|
109
|
+
if !rp.nil? and rp.ok?
|
110
|
+
parse_eval_response(rp)
|
111
|
+
else
|
112
|
+
raise EvalError, "voidEval failed: #{rp.to_s}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
def parse_eval_response(rp)
|
116
|
+
rxo=0
|
117
|
+
pc=rp.cont
|
118
|
+
if (rsrv_version>100) # /* since 0101 eval responds correctly by using DT_SEXP type/len header which is 4 bytes long */
|
119
|
+
rxo=4
|
120
|
+
# we should check parameter type (should be DT_SEXP) and fail if it's not
|
121
|
+
if (pc[0]!=Rserve::Protocol::DT_SEXP && pc[0]!=(Rserve::Protocol::DT_SEXP|Rserve::Protocol::DT_LARGE))
|
122
|
+
raise "Error while processing eval output: SEXP (type "+Rserve::Protocol::DT_SEXP+") expected but found result type "+pc[0].to_s+"."
|
123
|
+
end
|
124
|
+
if (pc[0]==(Rserve::Protocol::DT_SEXP|Rserve::Protocol::DT_LARGE))
|
125
|
+
rxo=8; # large data need skip of 8 bytes
|
126
|
+
end
|
127
|
+
# warning: we are not checking or using the length - we assume that only the one SEXP is returned. This is true for the current CMD_eval implementation, but may not be in the future. */
|
128
|
+
end
|
129
|
+
if pc.length>rxo
|
130
|
+
rx=REXPFactory.new;
|
131
|
+
rx.parse_REXP(pc, rxo);
|
132
|
+
return rx.get_REXP();
|
133
|
+
else
|
134
|
+
return nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Rserve
|
2
|
+
class Engine
|
3
|
+
def parse(text,resolve);end
|
4
|
+
def evaluate(what, where, resolve); end;
|
5
|
+
def assign(symbol, value, env=nil);end;
|
6
|
+
def get(symbol, env, resolve);end;
|
7
|
+
def resolve_reference(ref);end;
|
8
|
+
def create_reference(value);end;
|
9
|
+
def finalize_reference(ref);end;
|
10
|
+
def get_parent_enviroment(env,resolve);end;
|
11
|
+
def new_enviroment(parent,resolve);end;
|
12
|
+
def parse_and_eval(text,where=nil,resolve=true)
|
13
|
+
p=parse(text,false)
|
14
|
+
evaluate(p,where,resolve)
|
15
|
+
end
|
16
|
+
def close;
|
17
|
+
false
|
18
|
+
end
|
19
|
+
def supports_references?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
def supports_enviroments?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
def supports_REPL?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
def suuports_locking?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
def try_lock
|
32
|
+
0
|
33
|
+
end
|
34
|
+
def lock
|
35
|
+
0
|
36
|
+
end
|
37
|
+
def unlock;end;
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Rserve
|
2
|
+
class Packet
|
3
|
+
attr_reader :cont
|
4
|
+
attr_reader :cmd
|
5
|
+
def initialize(cmd, cont)
|
6
|
+
raise "cont [#{cont.class} - #{cont.to_s}] should respond to :length" if !cont.nil? and !cont.respond_to? :length
|
7
|
+
@cmd=cmd
|
8
|
+
@cont=cont
|
9
|
+
end
|
10
|
+
def cont_len
|
11
|
+
@cont.nil? ? 0 : @cont.length
|
12
|
+
end
|
13
|
+
def ok?
|
14
|
+
@cmd&15==1
|
15
|
+
end
|
16
|
+
def error?
|
17
|
+
@cmd&15==2
|
18
|
+
end
|
19
|
+
def stat
|
20
|
+
(@cmd>>24)&127
|
21
|
+
end
|
22
|
+
def to_s
|
23
|
+
if error?
|
24
|
+
status="status=error - #{stat}"
|
25
|
+
else
|
26
|
+
status="status=ok"
|
27
|
+
end
|
28
|
+
"Packet[cmd=#{@cmd},len="+((cont.nil?)?"<nil>":(""+cont.length.to_s))+", con='"+(cont.nil? ? "<nil>" : cont.pack("C*"))+"', status=#{status}]"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module Rserve
|
2
|
+
#
|
3
|
+
# This module encapsulates methods and constants related to QAP1 protocol used by Rserv. Follows almost exactly the interface on RTalk class
|
4
|
+
# on Java version, except for use of undescores instead of CamelCase
|
5
|
+
# Implementation could differ if a cleaner/faster ruby version is available
|
6
|
+
#
|
7
|
+
# Policy: No other class should know about the internal of protocol!
|
8
|
+
# See Rtalk class on Java version.
|
9
|
+
module Protocol
|
10
|
+
# Defines from Rsrv.h
|
11
|
+
CMD_RESP=0x010000 # all responses have this flag set
|
12
|
+
RESP_OK=(CMD_RESP|0x0001) # command succeeded; returned parameters depend on the command issued
|
13
|
+
RESP_ERR=(CMD_RESP|0x0002) # command failed, check stats code attached string may describe the error
|
14
|
+
|
15
|
+
ERR_auth_failed=0x41 # auth.failed or auth.requested but no login came. in case of authentification failure due to name/pwd mismatch, server may send CMD_accessDenied instead
|
16
|
+
ERR_conn_broken=0x42 # connection closed or broken packet killed it */
|
17
|
+
ERR_inv_cmd=0x43 # unsupported/invalid command */
|
18
|
+
ERR_inv_par=0x44 # some parameters are invalid */
|
19
|
+
ERR_Rerror=0x45 # R-error occured, usually followed by connection shutdown */
|
20
|
+
ERR_IOerror=0x46 # I/O error */
|
21
|
+
ERR_notOpen=0x47 # attempt to perform fileRead/Write on closed file */
|
22
|
+
ERR_accessDenied=0x48 # this answer is also valid on CMD_login; otherwise it's sent if the server deosn;t allow the user to issue the specified command. (e.g. some server admins may block file I/O operations for some users)
|
23
|
+
ERR_unsupportedCmd=0x49 # unsupported command */
|
24
|
+
ERR_unknownCmd=0x4a # unknown command - the difference between unsupported and unknown is that unsupported commands are known to the server but for some reasons (e.g. platform dependent) it's not supported. unknown commands are simply not recognized by the server at all. */
|
25
|
+
ERR_data_overflow=0x4b # incoming packet is too big. currently there is a limit as of the size of an incoming packet. */
|
26
|
+
ERR_object_too_big=0x4c # the requested object is too big to be transported in that way. If received after CMD_eval then the evaluation itself was successful. optional parameter is the size of the object
|
27
|
+
ERR_out_of_mem=0x4d # out of memory. the connection is usually closed after this error was sent
|
28
|
+
ERR_ctrl_closed=0x4e # control pipe to the master process is closed or broken
|
29
|
+
ERR_session_busy=0x50 # session is still busy */
|
30
|
+
ERR_detach_failed=0x51 # unable to detach seesion (cannot determine peer IP or problems creating a listening socket for resume) */
|
31
|
+
|
32
|
+
|
33
|
+
CMD_login=0x001 # "name\npwd" : - */
|
34
|
+
CMD_voidEval=0x002 # string : - */
|
35
|
+
CMD_eval=0x003 # string : encoded SEXP */
|
36
|
+
CMD_shutdown=0x004 # [admin-pwd] : - */
|
37
|
+
|
38
|
+
#/* file I/O routines. server may answe */
|
39
|
+
CMD_openFile=0x010 # fn : - */
|
40
|
+
CMD_createFile=0x011 # fn : - */
|
41
|
+
CMD_closeFile=0x012 # - : - */
|
42
|
+
CMD_readFile=0x013 # [int size] : data... ; if size not present,
|
43
|
+
#server is free to choose any value - usually
|
44
|
+
#it uses the size of its static buffer */
|
45
|
+
CMD_writeFile=0x014 # data : - */
|
46
|
+
CMD_removeFile=0x015 # fn : - */
|
47
|
+
|
48
|
+
# /* object manipulation */
|
49
|
+
CMD_setSEXP=0x020 # string(name), REXP : - */
|
50
|
+
CMD_assignSEXP=0x021 # string(name), REXP : - ; same as setSEXP except that the name is parsed */
|
51
|
+
|
52
|
+
# /* session management (since 0.4-0) */
|
53
|
+
CMD_detachSession=0x030 # : session key */
|
54
|
+
CMD_detachedVoidEval=0x031 # string : session key; doesn't */
|
55
|
+
CMD_attachSession=0x032 # session key : - */
|
56
|
+
|
57
|
+
# control commands (since 0.6-0) - passed on to the master process */
|
58
|
+
# Note: currently all control commands are asychronous, i.e. RESP_OK
|
59
|
+
# indicates that the command was enqueued in the master pipe, but there
|
60
|
+
# is no guarantee that it will be processed. Moreover non-forked
|
61
|
+
# connections (e.g. the default debug setup) don't process any
|
62
|
+
# control commands until the current client connection is closed so
|
63
|
+
# the connection issuing the control command will never see its
|
64
|
+
# result.
|
65
|
+
CMD_ctrl=0x40 # -- not a command - just a constant -- */
|
66
|
+
CMD_ctrlEval=0x42 # string : - */
|
67
|
+
CMD_ctrlSource=0x45 # string : - */
|
68
|
+
CMD_ctrlShutdown=0x44 # - : - */
|
69
|
+
|
70
|
+
# /* 'internal' commands (since 0.1-9) */
|
71
|
+
CMD_setBufferSize=0x081 # [int sendBufSize] this commad allow clients to request bigger buffer sizes if large data is to be transported from Rserve to the client. (incoming buffer is resized automatically) */
|
72
|
+
CMD_setEncoding=0x082 # string (one of "native","latin1","utf8") : -; since 0.5-3 */
|
73
|
+
|
74
|
+
# /* special commands - the payload of packages with this mask does not contain defined parameters */
|
75
|
+
|
76
|
+
CMD_SPECIAL_MASK=0xf0
|
77
|
+
|
78
|
+
CMD_serEval=0xf5 # serialized eval - the packets are raw serialized data without data header */
|
79
|
+
CMD_serAssign=0xf6 # serialized assign - serialized list with [[1]]=name, [[2]]=value */
|
80
|
+
CMD_serEEval=0xf7 # serialized expression eval - like serEval with one additional evaluation round */
|
81
|
+
|
82
|
+
# data types for the transport protocol (QAP1)do NOT confuse with XT_.. values.
|
83
|
+
|
84
|
+
DT_INT=1 # int */
|
85
|
+
DT_CHAR=2 # char */
|
86
|
+
DT_DOUBLE=3 # double */
|
87
|
+
DT_STRING=4 # 0 terminted string */
|
88
|
+
DT_BYTESTREAM=5 # stream of bytes (unlike DT_STRING may contain 0) */
|
89
|
+
DT_SEXP=10 # encoded SEXP */
|
90
|
+
DT_ARRAY=11 # array of objects (i.e. first 4 bytes specify how many subsequent objects are part of the array; 0 is legitimate) */
|
91
|
+
DT_LARGE=64 # new in 0102: if this flag is set then the length of the object is coded as 56-bit integer enlarging the header by 4 bytes */
|
92
|
+
|
93
|
+
# writes bit-wise int to a byte buffer at specified position in Intel-endian form
|
94
|
+
# Internal: byte buffer will be the result of unpack("CCCC") an integer.
|
95
|
+
# @param v value to be written
|
96
|
+
# @param buf buffer
|
97
|
+
# @param o offset in the buffer to start at. An int takes always 4 bytes */
|
98
|
+
def set_int(v, buf, o)
|
99
|
+
buf[o]=(v&255);o+=1
|
100
|
+
buf[o]=((v&0xff00)>>8); o+=1
|
101
|
+
buf[o]=((v&0xff0000)>>16); o+=1
|
102
|
+
buf[o]=((v&0xff000000)>>24);
|
103
|
+
end
|
104
|
+
|
105
|
+
# writes cmd/resp/type byte + 3/7 bytes len into a byte buffer at specified offset.
|
106
|
+
# @param ty type/cmd/resp byte
|
107
|
+
# @param len length
|
108
|
+
# @param buf buffer
|
109
|
+
# @param o offset
|
110
|
+
# @return offset in buf just after the header. Please note that since Rserve 0.3 the header can be either 4 or 8 bytes long, depending on the len parameter.
|
111
|
+
def set_hdr(ty, len, buf, o)
|
112
|
+
buf[o]=((ty&255)|((len>0xfffff0) ? DT_LARGE : 0)); o+=1;
|
113
|
+
buf[o]=(len&255); o+=1;
|
114
|
+
buf[o]=((len&0xff00)>>8); o+=1;
|
115
|
+
buf[o]=((len&0xff0000)>>16); o+=1;
|
116
|
+
if (len>0xfffff0) # for large data we need to set the next 4 bytes as well
|
117
|
+
buf[o]=((len&0xff000000)>>24); o+=1;
|
118
|
+
buf[o]=0; o+=1; # since len is int, we get 32-bits only
|
119
|
+
buf[o]=0; o+=1;
|
120
|
+
buf[o]=0; o+=1;
|
121
|
+
end
|
122
|
+
o
|
123
|
+
end
|
124
|
+
# creates a new header according to the type and length of the parameter
|
125
|
+
# @param ty type/cmd/resp byte
|
126
|
+
# @param len length
|
127
|
+
def new_hdr(ty, len)
|
128
|
+
hdr=Array.new( (len>0xfffff0)?8:4)
|
129
|
+
set_hdr(ty,len,hdr,0);
|
130
|
+
hdr
|
131
|
+
end
|
132
|
+
#
|
133
|
+
# converts bit-wise stored int in Intel-endian form into ruby int
|
134
|
+
#
|
135
|
+
# @param buf buffer containg the representation
|
136
|
+
# @param o offset where to start (4 bytes will be used)
|
137
|
+
# @return the int value. no bounds checking is done so you need to
|
138
|
+
# make sure that the buffer is big enough
|
139
|
+
|
140
|
+
def get_int(buf, o)
|
141
|
+
return buf.slice(o,4).pack("C*").unpack("I")[0]
|
142
|
+
#return ((buf[o]&255)|((buf[o+1]&255)<<8)|((buf[o+2]&255)<<16)|((buf[o+3]&255)<<24));
|
143
|
+
end
|
144
|
+
|
145
|
+
# converts bit-wise stored length from a header. "long" format is supported up to 32-bit
|
146
|
+
# @param buf buffer
|
147
|
+
# @param o offset of the header (length is at o+1)
|
148
|
+
# @return length */
|
149
|
+
def get_len(buf, o)
|
150
|
+
# // "long" format; still - we support 32-bit only
|
151
|
+
if ((buf[o]&64)>0)
|
152
|
+
(buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16)|((buf[o+4]&255)<<24)
|
153
|
+
else
|
154
|
+
(buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# converts bit-wise Intel-endian format into long
|
159
|
+
# @param buf buffer
|
160
|
+
# @param o offset (8 bytes will be used)
|
161
|
+
# @return long value */
|
162
|
+
def get_long(buf, o)
|
163
|
+
low=(get_int(buf,o))&0xffffffff;
|
164
|
+
hi=(get_int(buf,o+4))&0xffffffff;
|
165
|
+
hi<<=32; hi|=low;
|
166
|
+
hi
|
167
|
+
end
|
168
|
+
def longBitsToDouble(bits)
|
169
|
+
s = ((bits >> 63) == 0) ? 1 : -1;
|
170
|
+
e = ((bits >> 52) & 0x7ff)
|
171
|
+
m = (e == 0) ?
|
172
|
+
(bits & 0xfffffffffffff) << 1 :
|
173
|
+
(bits & 0xfffffffffffff) | 0x10000000000000;
|
174
|
+
s*m*2**(e-1075)
|
175
|
+
end
|
176
|
+
def set_long(l, buf, o)
|
177
|
+
set_int((l&0xffffffff),buf,o)
|
178
|
+
set_int((l>>32),buf,o+4)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
require 'rserve/protocol/rexpfactory'
|