Class: Rserve::Talk

Inherits:
Object
  • Object
show all
Includes:
Protocol
Defined in:
lib/rserve/talk.rb

Overview

Class which ‘talk’ to the server.

I separated the ‘abstract’ aspect of the protocol on Protocol module, for better testing

Constant Summary

Constants included from Protocol

Protocol::CMD_RESP, Protocol::CMD_SPECIAL_MASK, Protocol::CMD_assignSEXP, Protocol::CMD_attachSession, Protocol::CMD_closeFile, Protocol::CMD_createFile, Protocol::CMD_ctrl, Protocol::CMD_ctrlEval, Protocol::CMD_ctrlShutdown, Protocol::CMD_ctrlSource, Protocol::CMD_detachSession, Protocol::CMD_detachedVoidEval, Protocol::CMD_eval, Protocol::CMD_login, Protocol::CMD_openFile, Protocol::CMD_readFile, Protocol::CMD_removeFile, Protocol::CMD_serAssign, Protocol::CMD_serEEval, Protocol::CMD_serEval, Protocol::CMD_setBufferSize, Protocol::CMD_setEncoding, Protocol::CMD_setSEXP, Protocol::CMD_shutdown, Protocol::CMD_voidEval, Protocol::CMD_writeFile, Protocol::DT_ARRAY, Protocol::DT_BYTESTREAM, Protocol::DT_CHAR, Protocol::DT_DOUBLE, Protocol::DT_INT, Protocol::DT_LARGE, Protocol::DT_SEXP, Protocol::DT_STRING, Protocol::ERROR_DESCRIPTIONS, Protocol::ERR_IOerror, Protocol::ERR_Rerror, Protocol::ERR_accessDenied, Protocol::ERR_auth_failed, Protocol::ERR_conn_broken, Protocol::ERR_ctrl_closed, Protocol::ERR_data_overflow, Protocol::ERR_detach_failed, Protocol::ERR_inv_cmd, Protocol::ERR_inv_par, Protocol::ERR_notOpen, Protocol::ERR_object_too_big, Protocol::ERR_out_of_mem, Protocol::ERR_session_busy, Protocol::ERR_unknownCmd, Protocol::ERR_unsupportedCmd, Protocol::MAX_LONG_SIGNED, Protocol::MAX_LONG_UNSIGNED, Protocol::RESP_ERR, Protocol::RESP_OK

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Protocol

#doubleToRawLongBits, #get_int, #get_int_original, #get_len, #get_long, #get_long_original, #longBitsToDouble, #longBitsToDouble_old, #new_hdr, #set_hdr, #set_int, #set_long

Constructor Details

#initialize(io) ⇒ Talk

Returns a new instance of Talk.



10
11
12
# File 'lib/rserve/talk.rb', line 10

def initialize(io)
  @io=io
end

Instance Attribute Details

#ioObject (readonly)

Returns the value of attribute io.



9
10
11
# File 'lib/rserve/talk.rb', line 9

def io
  @io
end

Instance Method Details

#request(params = Hash.new) ⇒ Object

sends a request with attached prefix and parameters. All parameters should be enter on Hash Both :prefix and :cont can be nil. Effectively request(:cmd=>a,:prefix=>b,:cont=>nil) and request(:cmd=>a,:prefix=>nil,:cont=>b) are equivalent.

Parameters:

  • :cmd

    command - a special command of -1 prevents request from sending anything

  • :prefix
    • this content is sent before cont. It is provided to save memory copy operations where a small header precedes a large data chunk (usually prefix conatins the parameter header and cont contains the actual data).

  • :cont

    contents

  • :offset

    offset in cont where to start sending (if <0 then 0 is assumed, if >cont.length then no cont is sent)

  • :len

    number of bytes in cont to send (it is clipped to the length of cont if necessary)

Returns:

  • returned packet or null if something went wrong */

Raises:

  • (ArgumentError)


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/rserve/talk.rb', line 22

def request(params=Hash.new)

  cmd     = params.delete :cmd
  prefix  = params.delete :prefix
  cont    = params.delete :cont
  offset  = params.delete :offset
  len     = params.delete :len

  if cont.is_a? String
    cont=request_string(cont)
  elsif cont.is_a? Integer
    cont=request_int(cont)
  end
  raise ArgumentError, ":cont should be an Enumerable" if !cont.nil? and !cont.is_a? Enumerable
  if len.nil?
    len=(cont.nil?) ? 0 : cont.length
  end

  offset||=0


  if (!cont.nil?)
    raise ":cont shouldn't contain anything but Fixnum" if cont.any? {|v| !v.is_a? Fixnum}
    if (offset>=cont.length)
      cont=nil;len=0
    elsif (len>cont.length-offset)
      len=cont.length-offset
    end
  end
  offset=0 if offset<0
  len=0 if len<0
  contlen=(cont.nil?) ? 0 : len
  contlen+=prefix.length if (!prefix.nil? and prefix.length>0)

  hdr=Array.new(16)
  set_int(cmd,hdr,0)
  set_int(contlen,hdr,4);
  8.upto(15) {|i| hdr[i]=0}
  if (cmd!=-1)
    io.write(hdr.pack("C*"))
    if (!prefix.nil? && prefix.length>0)
      io.write(prefix.pack("C*"))
      puts "SEND PREFIX #{prefix}" if $DEBUG
    end
    if (!cont.nil? and cont.length>0)
      puts "SEND CONTENT #{cont.slice(offset, len)} (#{offset},#{len})" if $DEBUG
      io.write(cont.slice(offset, len).pack("C*"))
    end
  end
  puts "Expecting 16 bytes..." if $DEBUG
  ih=io.recv(16).unpack("C*")

  return nil if (ih.length!=16)

  puts "Answer: #{ih.to_s}" if $DEBUG

  rep=get_int(ih,0);

  rl =get_int(ih,4);

  if $DEBUG
    puts "rep: #{rep} #{rep.class} #{rep & 0x00FFFFFF}"
    puts "rl: #{rl} #{rl.class}"
  end

  if (rl>0)
    ct=Array.new();
    n=0;
    while (n<rl) do
      data=io.recv(rl-n).unpack("C*")
      ct+=data
      rd=data.length
      n+=rd;
    end

    return Packet.new(rep,ct);
  end

  return Packet.new(rep,nil);
end

#request_int(par) ⇒ Object



115
116
117
118
119
120
# File 'lib/rserve/talk.rb', line 115

def request_int(par)
  rq=Array.new(8)
  set_int(par,rq,4)
  set_hdr(DT_INT,4,rq,0)
  rq
end

#request_string(s) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/rserve/talk.rb', line 102

def request_string(s)
  b=s.unpack("C*")
  sl=b.length+1;
  sl=(sl&0xfffffc)+4 if ((sl&3)>0)  # make sure the length is divisible by 4
  rq=Array.new(sl+5)

  b.length.times {|i| rq[i+4]=b[i]}
  ((b.length)..sl).each {|i|
    rq[i+4]=0
  }
  set_hdr(DT_STRING,sl,rq,0)
  rq
end