nwrfc 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -77,6 +77,17 @@ so that ["system2"] at the end points to whatever label you gave it in the YAML
77
77
 
78
78
  == Release Notes
79
79
 
80
+ === What's new in 0.0.2
81
+
82
+ * More comprehensive type support
83
+ * More table operations
84
+
85
+ === What's new in 0.0.1
86
+
87
+ * Fix loading sapnw library
88
+ * Fix UTF-8 conversion for Windows
89
+ * Enhanced type support
90
+
80
91
  === What's new in 0.0.0
81
92
 
82
93
  * Able to call functions
@@ -85,6 +96,6 @@ so that ["system2"] at the end points to whatever label you gave it in the YAML
85
96
 
86
97
  == Contributing
87
98
 
88
- Improvements to the source code are welcome. Email me at martin dot ceronio at infosize dot co dot za.
89
-
90
- Also let me know, please on which platforms you have tested the gem.
99
+ * Improvements to the source code are welcome
100
+ * Indicate on which platforms you have tested the gem
101
+ * Suggestions for improving the API / Hints for idiomatic Ruby
data/lib/nwrfc.rb CHANGED
@@ -7,6 +7,8 @@
7
7
 
8
8
  require File.dirname(__FILE__)+'/nwrfc/nwrfclib'
9
9
  require File.dirname(__FILE__)+'/nwrfc/datacontainer'
10
+ require File.dirname(__FILE__)+'/nwrfc/server'
11
+ require File.dirname(__FILE__)+'/nwrfc/nwerror'
10
12
 
11
13
  require 'date'
12
14
  require 'time'
@@ -38,9 +40,26 @@ module NWRFC
38
40
  [version.read_string_dn.uC, major.read_uint, minor.read_uint, patch.read_uint]
39
41
  end
40
42
 
43
+ # Take Hash of connection parameters and returns FFI pointer to an array
44
+ # for passing to connection
45
+ def NWRFC.make_conn_params(params) #https://github.com/ffi/ffi/wiki/Structs
46
+ par = FFI::MemoryPointer.new(NWRFCLib::RFCConnParam, params.length)
47
+ pars = params.length.times.collect do |i|
48
+ NWRFCLib::RFCConnParam.new(par + i * NWRFCLib::RFCConnParam.size)
49
+ end
50
+ tpar = params.to_a
51
+ params.length.times do |n|
52
+ pars[n][:name] = FFI::MemoryPointer.from_string(tpar[n][0].to_s.cU)
53
+ pars[n][:value] = FFI::MemoryPointer.from_string(tpar[n][1].to_s.cU)
54
+ end
55
+ par
56
+ end
57
+
41
58
  def NWRFC.check_error(error_handle)
42
- raise "Error code #{error_handle[:code]} group #{error_handle[:group]} message #{error_handle[:message].get_str}" \
59
+ raise NWError, error_handle \
43
60
  if error_handle[:code] > 0
61
+ #raise "Error code #{error_handle[:code]} group #{error_handle[:group]} message #{error_handle[:message].get_str}" \
62
+
44
63
  end
45
64
 
46
65
  # Represents a connection to a SAP system that can be used to invoke
@@ -54,11 +73,9 @@ module NWRFC
54
73
  def initialize(conn_params)
55
74
  conn_params.untaint #For params loaded from file, e.g.
56
75
  raise "Connection parameters must be a Hash" unless conn_params.instance_of? Hash
57
- #NWRFCLib.init
58
- @cparams = NWRFCLib.make_conn_params(conn_params)
76
+ @cparams = NWRFC.make_conn_params(conn_params)
59
77
  raise "Could not create valid pointer from parameters" unless @cparams.instance_of? FFI::MemoryPointer
60
- #@errp = FFI::MemoryPointer.new(NWRFCLib::RFCError)
61
- @error = NWRFCLib::RFCError.new #@errp
78
+ @error = NWRFCLib::RFCError.new
62
79
  @handle = NWRFCLib.open_connection(@cparams, conn_params.length, @error.to_ptr)
63
80
  NWRFC.check_error(@error)
64
81
  self
@@ -108,8 +125,15 @@ module NWRFC
108
125
  attr_accessor :handle
109
126
 
110
127
  # Create a parameter by setting parameter attributes
111
- def initialize(*args)
128
+ def initialize(*args)
129
+
112
130
  attr = args[0]
131
+
132
+ #TODO: For certain types, e.g. :RFCTYPE_BCD, a length specification is
133
+ # required, otherwise a segfault is the result later down the line.
134
+ # Find and implement all the types where this is required
135
+ raise "RFCTYPE_BCD requires a length" if attr[:type] == :RFCTYPE_BCD && !(attr[:length])
136
+
113
137
  @handle = NWRFCLib::RFCFuncParam.new
114
138
  @handle[:name] = attr[:name].cU if attr[:name]
115
139
  @handle[:direction] = NWRFCLib::RFC_DIRECTION[attr[:direction]] if attr[:direction]
@@ -133,8 +157,10 @@ module NWRFC
133
157
  # or by calling Connection#get_function. This only represents the description of the function;
134
158
  # to call a function, an instance of a function call must be obtained with #get_function_call
135
159
  class Function
136
- attr_reader :desc, :connection, :function_name
160
+ attr_reader :desc, :function_name
161
+ attr_accessor :connection
137
162
 
163
+ # TODO: Update doc to reflect different calling options
138
164
  # Get a function module instance; can also be obtained by calling Connection#get_function
139
165
  # Takes either: (connection, function_name) or (function_name)
140
166
  # When passed only `function_name`, creates a new function description locally, instead of
@@ -173,17 +199,47 @@ module NWRFC
173
199
  pcount.read_uint
174
200
  end
175
201
 
202
+ # Return the description of parameters associated with this Function
203
+ def parameters
204
+ parameter_count.times.inject({}) do |params, index|
205
+ param = NWRFCLib::RFCFuncParam.new
206
+ NWRFCLib.get_parameter_desc_by_index(@desc, index, param.to_ptr, @error.to_ptr)
207
+ params[param[:name].get_str] = {
208
+ :type => NWRFCLib::RFC_TYPE[param[:type]],
209
+ :direction => NWRFCLib::RFC_DIRECTION[param[:direction]],
210
+ :nucLength => param[:nucLength],
211
+ :ucLength => param[:ucLength],
212
+ :decimals => param[:decimals],
213
+ :typeDescHandle => param[:typeDescHandle],
214
+ :defaultValue => param[:defaultValue].get_str,
215
+ :parameterText => param[:parameterText].get_str,
216
+ :optional => param[:optional]
217
+ }
218
+ params
219
+ end
220
+ end
221
+
176
222
  end
177
223
 
224
+ # Represents a callable instance of a function
178
225
  class FunctionCall < DataContainer
179
226
  attr_reader :handle, :desc, :connection, :function
180
227
 
181
- def initialize(function)
228
+ # TODO: Update doc to reflect different calling options
229
+ # Call with either Function or Connection and Function Call instance (handle)
230
+ def initialize(*args)
231
+ raise("Must initialize function with 1 or 2 arguments") if args.size != 1 && args.size != 2
182
232
  @error = NWRFCLib::RFCError.new
183
- @function = function
184
- @connection = function.connection
185
- @handle = NWRFCLib.create_function(@function.desc, @error.to_ptr)
186
- @desc = function.desc
233
+ if args.size == 2
234
+ @handle = args[1]
235
+ @connection = args[0].connection
236
+ # TODO: Get function description from instance
237
+ else
238
+ @function = args[0] #function
239
+ @connection = args[0].connection
240
+ @handle = NWRFCLib.create_function(@function.desc, @error.to_ptr)
241
+ @desc = args[0].desc
242
+ end
187
243
  NWRFC.check_error(@error)
188
244
  end
189
245
 
@@ -198,7 +254,8 @@ module NWRFC
198
254
 
199
255
  include Enumerable
200
256
 
201
- def each(&block)
257
+ # Iterate over the rows in a table. Each row is yielded as a structure
258
+ def each(&block) #:yields row
202
259
  rc = NWRFCLib.move_to_first_row(@handle, @error)
203
260
  NWRFC.check_error(@error) if rc > 0
204
261
  size.times do |row|
@@ -210,6 +267,7 @@ module NWRFC
210
267
  end
211
268
  end
212
269
 
270
+ # Return the number of rows in the table
213
271
  def size
214
272
  rows = FFI::MemoryPointer.new(:uint)
215
273
  rc = NWRFCLib.get_row_count(@handle, rows, @error)
@@ -231,6 +289,20 @@ module NWRFC
231
289
  Structure.new(struct_handle)
232
290
  end
233
291
 
292
+ # Append a row (structure) to the table
293
+ def append(row)
294
+ raise "Must append a structure" unless row.class == NWRFC::Structure
295
+ rc = NWRFCLib.append_row(@handle, row.handle, @error)
296
+ NWRFC.check_error(@error) if rc > 0
297
+ end
298
+
299
+ # Add new (empty) row and return the structure handle
300
+ def new_row
301
+ s_handle = NWRFCLib.append_new_row(@handle, @error)
302
+ NWRFC.check_error(@error)
303
+ Structure.new(s_handle)
304
+ end
305
+
234
306
  end #class Table
235
307
 
236
308
  # Represents a structure. An instance is obtained internally by passing the
@@ -241,7 +313,7 @@ module NWRFC
241
313
  # Return a list (array) of symbols representing the names of the fields
242
314
  # of this structure
243
315
  #---
244
- # TODO: This is not working!
316
+ # FIXME: This is not working!
245
317
  def fields
246
318
  fc = FFI::MemoryPointer.new(:uint)
247
319
  rc = NWRFCLib.get_field_count(@handle, fc, @error)
@@ -12,157 +12,225 @@ module NWRFC
12
12
  NWRFC.check_error(@error)
13
13
  end
14
14
 
15
- # Return the member specified by string or symbol
15
+ #--
16
+ # VALUE RETRIEVAL
17
+ #++
18
+
19
+ # Get value from a data container (structure, function instance or table)
16
20
  def [](element)
17
21
  member = element.to_s.upcase
18
22
  metadata = member_metadata(element)
19
23
  case metadata[:type]
20
- when :RFCTYPE_CHAR
21
- # TODO: Try use :string parameter in get_chars
22
- return read_chars(metadata)
23
- when :RFCTYPE_DATE
24
- return Date.parse(read_chars(metadata))
24
+
25
+ when :RFCTYPE_CHAR
26
+ # TODO: Try use :string parameter in get_chars
27
+ return read_chars(metadata)
28
+
29
+ when :RFCTYPE_DATE
30
+ return Date.parse(read_chars(metadata))
25
31
  #return Date.new(date[0..3].to_i, date[4..5].to_i, date[6..7].to_i)
26
- when :RFCTYPE_BCD
27
- size = metadata[:ucLength]
28
- cb = FFI::MemoryPointer.new :char, size * 2
29
- rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, size * 2, @error.to_ptr)
30
- NWRFC.check_error(@error) if rc > 0
31
- cb.read_string(size).uC
32
- when :RFCTYPE_TIME
33
- # TODO: See whether we can optimize this
34
- timec = read_chars(metadata)
35
- return Time.parse("#{timec[0..1]}:#{timec[2..3]}:#{timec[4..5]}")
36
- when :RFCTYPE_BYTE
37
- return read_chars(metadata)
38
- when :RFCTYPE_TABLE
39
- new_handle = NWRFCLib::RFCDataContainer.new
40
- rc = NWRFCLib.get_table(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
41
- NWRFC.check_error(@error) if rc > 0
42
- # CAVEAT: Other calls using the handle require "handle" field
43
- # of the RFC_DATA_CONTAINER struct for some reason.
44
- new_handle = new_handle[:handle]
45
- value = Table.new(new_handle)
46
- when :RFCTYPE_NUM
47
- return read_chars(metadata).to_i
48
- when :RFCTYPE_FLOAT
49
- double = FFI::MemoryPointer.new :double
50
- rc = NWRFCLib.get_float(@handle, member.cU, double, @error)
51
- NWRFC.check_error(@error) if rc > 0
52
- return double.get_double(0)
53
- when :RFCTYPE_INT
54
- int = FFI::MemoryPointer.new :int
55
- rc = NWRFCLib.get_int(@handle, member.cU, int, @error)
56
- NWRFC.check_error(@error) if rc > 0
57
- return int.get_int(0)
58
- when :RFCTYPE_INT2
59
- short = FFI::MemoryPointer.new :short
60
- rc = NWRFCLib.get_int2(@handle, member.cU, short, @error)
61
- NWRFC.check_error(@error) if rc > 0
62
- return short.get_short(0)
63
- when :RFCTYPE_INT1
64
- int1 = FFI::MemoryPointer.new :uint8
65
- rc = NWRFCLib.get_int1(@handle, member.cU, int1, @error)
66
- NWRFC.check_error(@error) if rc > 0
67
- return int1.get_uint8(0)
68
- when :RFCTYPE_NULL
69
- raise "Unsupported type RFCTYPE_NULL" #You should never run into this
70
- when :RFCTYPE_STRUCTURE
71
- new_handle = NWRFCLib::RFCDataContainer.new
72
- rc = NWRFCLib.get_structure(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
73
- NWRFC.check_error(@error) if rc > 0
74
- new_handle = new_handle[:handle]
75
- value = Structure.new(new_handle)
76
- when :RFCTYPE_DECF16
77
- double = FFI::MemoryPointer.new :double
78
- rc = NWRFCLib.get_dec_f16(@handle, member.cU, double, @error)
79
- NWRFC.check_error(@error) if rc > 0
80
- return double.get_double(0)
81
- when :RFCTYPE_DECF34
82
- double = FFI::MemoryPointer.new :double, 2
83
- rc = NWRFCLib.get_dec_f34(@handle, member.cU, double, @error)
84
- NWRFC.check_error(@error) if rc > 0
85
- return double.get_double(0)
86
- when :RFCTYPE_XMLDATA
87
- raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
88
- when :RFCTYPE_STRING
89
- return read_string(metadata)
90
- when :RFCTYPE_XSTRING
91
- size = FFI::MemoryPointer.new(:uint)
92
- rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
93
- NWRFC.check_error(@error) if rc > 0
94
- buf_len = size.read_uint
95
- sbuf = FFI::MemoryPointer.new :uchar, buf_len
96
- rc = NWRFCLib.get_x_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
97
- NWRFC.check_error(@error) if rc > 0
98
- return sbuf.read_string(sbuf.size)
99
- else
100
- raise "Illegal member type #{metadata[:type]}"
32
+
33
+ when :RFCTYPE_BCD
34
+ size = metadata[:nucLength] + (metadata[:decimals] || 0)
35
+ buf = FFI::MemoryPointer.new(:uchar, size*2)
36
+ rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, buf, size, @error.to_ptr)
37
+ NWRFC.check_error(@error) if rc > 0
38
+ return buf.get_bytes(0, size*2).uC.to_f
39
+ #size = metadata[:ucLength]
40
+ #cb = FFI::MemoryPointer.new :char, size * 2
41
+ #rc = NWRFCLib.get_chars(@handle, metadata[:name].cU, cb, size * 2, @error.to_ptr)
42
+ #NWRFC.check_error(@error) if rc > 0
43
+ #cb.read_string(size).uC
44
+
45
+ when :RFCTYPE_TIME
46
+ # TODO: See whether we can optimize this
47
+ timec = read_chars(metadata)
48
+ return Time.parse("#{timec[0..1]}:#{timec[2..3]}:#{timec[4..5]}")
49
+
50
+ when :RFCTYPE_BYTE
51
+ size = metadata[:ucLength]
52
+ buf = FFI::MemoryPointer.new(:uchar, size)
53
+ rc = NWRFCLib.get_bytes(@handle, metadata[:name].cU, buf, size, @error.to_ptr)
54
+ NWRFC.check_error(@error) if rc > 0
55
+ return buf.get_bytes(0, size)
56
+
57
+ when :RFCTYPE_TABLE
58
+ # TODO Cache instances of table members and return those where available
59
+ new_handle = NWRFCLib::RFCDataContainer.new
60
+ rc = NWRFCLib.get_table(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
61
+ NWRFC.check_error(@error) if rc > 0
62
+ # CAVEAT: Other calls using the handle require "handle" field
63
+ # of the RFC_DATA_CONTAINER struct for some reason.
64
+ new_handle = new_handle[:handle]
65
+ return Table.new(new_handle)
66
+
67
+ when :RFCTYPE_NUM
68
+ return read_chars(metadata)
69
+
70
+ when :RFCTYPE_FLOAT
71
+ double = FFI::MemoryPointer.new :double
72
+ rc = NWRFCLib.get_float(@handle, member.cU, double, @error)
73
+ NWRFC.check_error(@error) if rc > 0
74
+ return double.get_double(0)
75
+
76
+ when :RFCTYPE_INT
77
+ int = FFI::MemoryPointer.new :int
78
+ rc = NWRFCLib.get_int(@handle, member.cU, int, @error)
79
+ NWRFC.check_error(@error) if rc > 0
80
+ return int.get_int(0)
81
+
82
+ when :RFCTYPE_INT2
83
+ short = FFI::MemoryPointer.new :short
84
+ rc = NWRFCLib.get_int2(@handle, member.cU, short, @error)
85
+ NWRFC.check_error(@error) if rc > 0
86
+ return short.get_short(0)
87
+
88
+ when :RFCTYPE_INT1
89
+ int1 = FFI::MemoryPointer.new :uint8
90
+ rc = NWRFCLib.get_int1(@handle, member.cU, int1, @error)
91
+ NWRFC.check_error(@error) if rc > 0
92
+ return int1.get_uint8(0)
93
+
94
+ when :RFCTYPE_NULL
95
+ raise "Unsupported type RFCTYPE_NULL" #You should never run into this
96
+
97
+ when :RFCTYPE_STRUCTURE
98
+ # TODO Cache instances of structure members and return those where available
99
+ new_handle = NWRFCLib::RFCDataContainer.new
100
+ rc = NWRFCLib.get_structure(@handle, member.cU, new_handle.to_ptr, @error.to_ptr)
101
+ NWRFC.check_error(@error) if rc > 0
102
+ new_handle = new_handle[:handle]
103
+ return Structure.new(new_handle)
104
+
105
+ when :RFCTYPE_DECF16
106
+ double = FFI::MemoryPointer.new :double
107
+ rc = NWRFCLib.get_dec_f16(@handle, member.cU, double, @error)
108
+ NWRFC.check_error(@error) if rc > 0
109
+ return double.get_double(0)
110
+
111
+ when :RFCTYPE_DECF34
112
+ double = FFI::MemoryPointer.new :double, 2
113
+ rc = NWRFCLib.get_dec_f34(@handle, member.cU, double, @error)
114
+ NWRFC.check_error(@error) if rc > 0
115
+ return double.get_double(0)
116
+
117
+ when :RFCTYPE_XMLDATA
118
+ raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
119
+
120
+ when :RFCTYPE_STRING
121
+ return read_string(metadata)
122
+
123
+ when :RFCTYPE_XSTRING
124
+ size = FFI::MemoryPointer.new(:uint)
125
+ rc = NWRFCLib.get_string_length(@handle, metadata[:name].cU, size, @error)
126
+ NWRFC.check_error(@error) if rc > 0
127
+ buf_len = size.read_uint
128
+ sbuf = FFI::MemoryPointer.new :uchar, buf_len
129
+ rc = NWRFCLib.get_x_string(@handle, metadata[:name].cU, sbuf, buf_len, size, @error)
130
+ NWRFC.check_error(@error) if rc > 0
131
+ return sbuf.read_string(sbuf.size)
132
+
133
+ else
134
+ raise "Illegal member type #{metadata[:type]}"
101
135
  end
102
- NWRFC.check_error(@error)
103
- value
136
+
104
137
  end
105
138
 
139
+ #--
140
+ # VALUE STORAGE
141
+ #++
142
+
143
+ # Set value on a data container (structure, function instance or table)
106
144
  def []=(element, value)
107
145
  member = element.to_s.upcase
108
146
  metadata = member_metadata(element)
109
147
  case metadata[:type]
110
- when :RFCTYPE_CHAR
111
- NWRFCLib.set_chars(@handle, member.cU, value.cU, value.length, @error.to_ptr)
112
- when :RFCTYPE_DATE
113
- value = value_to_date(value)
114
- NWRFCLib.set_date(@handle, member.cU, value.cU, @error.to_ptr)
115
- when :RFCTYPE_BCD
116
- when :RFCTYPE_TIME
117
- value = value_to_time(value)
118
- NWRFCLib.set_time(@handle, member.cU, value.cU, @error.to_ptr)
119
- when :RFCTYPE_BYTE
120
- when :RFCTYPE_TABLE
121
- when :RFCTYPE_NUM
122
- when :RFCTYPE_FLOAT
123
- NWRFCLib.set_float(@handle, member.cU, value.to_f, @error.to_ptr)
124
- #NWRFCLib.set_chars(@handle, member.cU, value.to_s.cU, value.to_s.length, @error.to_ptr)
125
- when :RFCTYPE_INT
126
- NWRFCLib.set_int(@handle, member.cU, value.to_i, @error.to_ptr)
127
- when :RFCTYPE_INT2
128
- NWRFCLib.set_int2(@handle, member.cU, value.to_i, @error.to_ptr)
129
- when :RFCTYPE_INT1
130
- NWRFCLib.set_int1(@handle, member.cU, value.to_i, @error.to_ptr)
131
- when :RFCTYPE_NULL
132
- raise "Unsupported type RFCTYPE_NULL" #You should never run into this
133
- when :RFCTYPE_STRUCTURE
134
- when :RFCTYPE_DECF16
135
- raise "#{@members[:type]}: decfloat16 not supported yet"
136
- double = NWRFCLib::RFC_DECF16.new #FFI::MemoryPointer.new :double
137
- double[:align] = value.to_f
138
- #double.put_double(0, value.to_f)
139
- #double = FFI::Pointer.new 4
140
- NWRFCLib.set_dec_f16(@handle, member.cU, double.pointer, @error)
141
- when :RFCTYPE_DECF34
142
- raise "#{@members[:type]}: decfloat34 not supported yet"
143
- # double = FFI::MemoryPointer.new :double, 2
144
- # double.put_double(0, value.to_f)
145
- double = NWRFCLib::RFC_DECF34.new #FFI::MemoryPointer.new :double
146
- double[:align] = value.to_f
147
- NWRFCLib.set_dec_f34(@handle, member.cU, double, @error)
148
- when :RFCTYPE_XMLDATA
149
- raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
150
- when :RFCTYPE_STRING
151
- when :RFCTYPE_XSTRING
152
- m = FFI::MemoryPointer.new value.size
153
- m.put_bytes 0, value
154
- NWRFCLib.set_x_string(@handle, member.cU, m, value.size, @error)
155
- else
156
- raise "Illegal member type #{@members[:type]}"
148
+
149
+ when :RFCTYPE_CHAR
150
+ value = value.to_s
151
+ NWRFCLib.set_chars(@handle, member.cU, value.cU, value.length, @error.to_ptr)
152
+
153
+ when :RFCTYPE_DATE
154
+ value = value_to_date(value)
155
+ NWRFCLib.set_date(@handle, member.cU, value.cU, @error.to_ptr)
156
+
157
+ when :RFCTYPE_BCD
158
+ stval = value.to_s.cU
159
+ m = FFI::MemoryPointer.from_string stval
160
+ NWRFCLib.set_string(@handle, member.cU, m, value.to_s.size, @error)
161
+
162
+ when :RFCTYPE_TIME
163
+ value = value_to_time(value)
164
+ NWRFCLib.set_time(@handle, member.cU, value.cU, @error.to_ptr)
165
+
166
+ when :RFCTYPE_BYTE
167
+ m = FFI::MemoryPointer.from_string value.to_s
168
+ NWRFCLib.set_bytes(@handle, member.cU, m, value.to_s.size, @error.to_ptr)
169
+
170
+ when :RFCTYPE_TABLE
171
+ raise "Value must be of type table" unless value.class == NWRFC::Table
172
+ NWRFCLib.set_table(@handle, member.cU, value.handle, @error)
173
+
174
+ when :RFCTYPE_NUM
175
+ value = value.to_s
176
+ NWRFCLib.set_num(@handle, member.cU, value.cU, value.length, @error.to_ptr)
177
+
178
+ when :RFCTYPE_FLOAT
179
+ NWRFCLib.set_float(@handle, member.cU, value.to_f, @error.to_ptr)
180
+
181
+ when :RFCTYPE_INT
182
+ NWRFCLib.set_int(@handle, member.cU, value.to_i, @error.to_ptr)
183
+
184
+ when :RFCTYPE_INT2
185
+ NWRFCLib.set_int2(@handle, member.cU, value.to_i, @error.to_ptr)
186
+
187
+ when :RFCTYPE_INT1
188
+ NWRFCLib.set_int1(@handle, member.cU, value.to_i, @error.to_ptr)
189
+
190
+ when :RFCTYPE_NULL
191
+ raise "Unsupported type RFCTYPE_NULL" #You should never run into this
192
+
193
+ when :RFCTYPE_STRUCTURE
194
+ raise "Value must be of type table" unless value.class == NWRFC::Structure
195
+ NWRFCLib.set_structure(@handle, member.cU, value.handle, @error)
196
+
197
+ when :RFCTYPE_DECF16
198
+ raise "#{@members[:type]}: decfloat16 not supported yet"
199
+ double = NWRFCLib::RFC_DECF16.new #FFI::MemoryPointer.new :double
200
+ double[:align] = value.to_f
201
+ #double.put_double(0, value.to_f)
202
+ #double = FFI::Pointer.new 4
203
+ NWRFCLib.set_dec_f16(@handle, member.cU, double.pointer, @error)
204
+
205
+ when :RFCTYPE_DECF34
206
+ raise "#{@members[:type]}: decfloat34 not supported yet"
207
+ # double = FFI::MemoryPointer.new :double, 2
208
+ # double.put_double(0, value.to_f)
209
+ double = NWRFCLib::RFC_DECF34.new #FFI::MemoryPointer.new :double
210
+ double[:align] = value.to_f
211
+ NWRFCLib.set_dec_f34(@handle, member.cU, double, @error)
212
+
213
+ when :RFCTYPE_XMLDATA
214
+ raise "Unsupported type RFCTYPE_XMLDATA (no longer used)" #You should never run into this
215
+
216
+ when :RFCTYPE_STRING
217
+ stval = value.cU
218
+ m = FFI::MemoryPointer.from_string stval
219
+ NWRFCLib.set_string(@handle, member.cU, m, value.size, @error)
220
+
221
+ when :RFCTYPE_XSTRING
222
+ m = FFI::MemoryPointer.new value.size
223
+ m.put_bytes 0, value
224
+ NWRFCLib.set_x_string(@handle, member.cU, m, value.size, @error)
225
+
226
+ else
227
+ raise "Illegal member type #{@members[:type]}"
157
228
  end
158
229
  NWRFC.check_error(@error)
159
230
  end
160
231
 
161
- def value_to_time(value)
162
- return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
163
- value.to_s
164
- end
165
-
232
+ # Return value as a SAP-formatted date ("YYYYMMDD"). Force value to fit into 8 chars by
233
+ # truncating or padding with spaces
166
234
  def value_to_date(value)
167
235
  return value.strftime(NW_DATE_FORMAT) if value.respond_to? :strftime
168
236
  # Force the resulting string into 8 characters otherwise
@@ -172,6 +240,8 @@ module NWRFC
172
240
  value
173
241
  end
174
242
 
243
+ # Return value as a SAP-formatted time ("HHMMSS"). Force value to fit into 6 chars by
244
+ # truncating or padding with spaces
175
245
  def value_to_time(value)
176
246
  return value.strftime(NW_TIME_FORMAT) if value.respond_to? :strftime
177
247
  # Force the resulting string into 6 characters otherwise
@@ -183,6 +253,7 @@ module NWRFC
183
253
 
184
254
  # Get the metadata of a member (function, structure or table)
185
255
  def member_metadata(member_name)
256
+ # TODO: Cache metadata definitions; will it be quicker than making a hash of metadata for a given member each time?
186
257
  member = member_name.to_s.upcase
187
258
  if self.class == NWRFC::FunctionCall
188
259
  fpar = NWRFCLib::RFCFuncParam.new
@@ -202,12 +273,12 @@ module NWRFC
202
273
  # and a type field
203
274
  def member_to_hash(member)
204
275
  {
205
- :name => member[:name].get_str,
206
- :type => NWRFCLib::RFC_TYPE[member[:type]],
207
- :nucLength => member[:nucLength],
208
- :ucLength => member[:ucLength],
209
- :decimals => member[:decimals],
210
- :typeDescHandle => member[:typeDescHandle]
276
+ :name => member[:name].get_str,
277
+ :type => NWRFCLib::RFC_TYPE[member[:type]],
278
+ :nucLength => member[:nucLength],
279
+ :ucLength => member[:ucLength],
280
+ :decimals => member[:decimals],
281
+ :typeDescHandle => member[:typeDescHandle]
211
282
  }
212
283
  end
213
284
 
@@ -0,0 +1,25 @@
1
+ module NWRFC
2
+
3
+ class NWError < Exception
4
+
5
+ attr_reader :code, :group, :message, :class, :type, :number
6
+
7
+ # Instantiate Error object with a handle to an FFI::MemoryPointer
8
+ # to an NWRFCLib::RFCError object. The error object is analyzed so that
9
+ # when the caller intercepts it with Rescue, all the error details are
10
+ # available
11
+ def initialize(error)
12
+ @code = NWRFCLib::RFC_RC[error[:code]]
13
+ @group = NWRFCLib::RFC_ERROR_GROUP[error[:group]]
14
+ @message = error[:message].get_str
15
+ @type = error[:abapMsgType].get_str
16
+ @number = error[:abapMsgNumber].get_str
17
+ end
18
+
19
+ def inspect
20
+ "#{@message} (code #{@code}, group #{@group}, type #{@type}, number #{@number})"
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -143,12 +143,16 @@ module NWRFCLib
143
143
  :RFCTYPE_INT2 , 9,
144
144
  :RFCTYPE_INT1 , 10,
145
145
  :RFCTYPE_NULL , 14,
146
+ :RFCTYPE_ABAPOBJECT, 16,
146
147
  :RFCTYPE_STRUCTURE , 17,
147
148
  :RFCTYPE_DECF16 , 23,
148
149
  :RFCTYPE_DECF34 , 24,
149
150
  :RFCTYPE_XMLDATA , 28,
150
151
  :RFCTYPE_STRING , 29,
151
- :RFCTYPE_XSTRING , 30
152
+ :RFCTYPE_XSTRING , 30,
153
+ :RFCTYPE_BOX, 31,
154
+ :RFCTYPE_GENERIC_BOX, 32,
155
+ :_RFCTYPE_max_value
152
156
  )
153
157
 
154
158
  # Connection parameter wrapper (struct RFC_CONNECTION_PARAMETER in sapnwrfc.h)
@@ -267,6 +271,10 @@ module NWRFCLib
267
271
  # yet used in our NWRFC library, so calling them may not work. For best results, consult sapnwrfc.h from
268
272
  # the SDK
269
273
  #############################################################################################################
274
+ # Callback for function server (function implementation)
275
+ callback :funcimpl, [:pointer, :pointer, :pointer], :int
276
+
277
+ # Function mappings
270
278
  [
271
279
  [:add_exception, :RfcAddException, [:pointer, :pointer, :pointer], :int],
272
280
  [:add_function_desc, :RfcAddFunctionDesc, [:pointer, :pointer, :pointer], :int],
@@ -343,7 +351,7 @@ module NWRFCLib
343
351
  [:insert_new_row, :RfcInsertNewRow, [:pointer, :pointer], :pointer],
344
352
  [:insert_row, :RfcInsertRow, [:pointer, :pointer, :pointer], :int],
345
353
  [:install_generic_server_function, :RfcInstallGenericServerFunction, [:pointer, :pointer, :pointer], :int],
346
- [:install_server_function, :RfcInstallServerFunction, [:pointer, :pointer, :pointer, :pointer], :int],
354
+ [:install_server_function, :RfcInstallServerFunction, [:pointer, :pointer, :funcimpl, :pointer], :int],
347
355
  [:install_transaction_handlers, :RfcInstallTransactionHandlers, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int],
348
356
  [:invoke, :RfcInvoke, [:pointer, :pointer, :pointer], :int],
349
357
  [:invoke_in_transaction, :RfcInvokeInTransaction, [:pointer, :pointer, :pointer], :int],
@@ -0,0 +1,36 @@
1
+ module NWRFC
2
+
3
+ # Implementation of a server to host RFC functions to be called from an ABAP system
4
+ # or from another RFC implementation
5
+ class Server
6
+
7
+ TIMEOUT = 200
8
+
9
+ # Register a server with the given gateway and program ID
10
+ def initialize(params)
11
+ raise "Rarameters must be a Hash" unless params.instance_of? Hash
12
+ @rparams = NWRFC.make_conn_params(params)
13
+ raise "Could not create valid pointer from parameters" unless @rparams.instance_of? FFI::MemoryPointer
14
+ @error = NWRFCLib::RFCError.new
15
+ @handle = NWRFCLib.register_server(@rparams, params.size, @error)
16
+ NWRFC.check_error(@error)
17
+ end
18
+
19
+ def serve(function, &block)
20
+ # Establish callback handler
21
+ callback = Proc.new do |connection, function_call, error|
22
+ fc =
23
+ debugger
24
+ yield(function_call)
25
+ end
26
+ rc = NWRFCLib.install_server_function(nil, function.desc, callback, @error)
27
+ NWRFC.check_error(@error) if rc > 0
28
+ # Server loop
29
+ while (rc==NWRFCLib::RFC_RC[:RFC_OK] || rc==NWRFCLib::RFC_RC[:RFC_RETRY] || rc==NWRFCLib::RFC_RC[:RFC_ABAP_EXCEPTION])
30
+ rc = NWRFCLib.listen_and_dispatch(@handle, TIMEOUT, @error)
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nwrfc
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Martin Ceronio
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-02-20 00:00:00 Z
18
+ date: 2012-02-22 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: SAP Netweaver RFC Library Wrapper using Ruby-FFI
@@ -30,10 +30,10 @@ files:
30
30
  - README.rdoc
31
31
  - Rakefile
32
32
  - lib/nwrfc.rb
33
+ - lib/nwrfc/server.rb
33
34
  - lib/nwrfc/datacontainer.rb
35
+ - lib/nwrfc/nwerror.rb
34
36
  - lib/nwrfc/nwrfclib.rb
35
- - lib/nwrfc/dev_rfc.trc
36
- - lib/dev_rfc.trc
37
37
  homepage: http://rubygems.org/gems/nwrfc
38
38
  licenses: []
39
39
 
data/lib/dev_rfc.trc DELETED
@@ -1,140 +0,0 @@
1
-
2
- **** Trace file opened at 2012-02-15, 13:50:29 SAST
3
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
4
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
5
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
6
-
7
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
8
-
9
- **** Trace file opened at 2012-02-15, 13:51:02 SAST
10
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
11
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
12
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
13
-
14
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
15
-
16
- **** Trace file opened at 2012-02-15, 14:07:53 SAST
17
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
18
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
19
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
20
-
21
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
22
-
23
- **** Trace file opened at 2012-02-15, 14:08:23 SAST
24
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
25
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
26
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
27
-
28
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
29
-
30
- **** Trace file opened at 2012-02-15, 14:09:49 SAST
31
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
32
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
33
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
34
-
35
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
36
-
37
- **** Trace file opened at 2012-02-15, 14:40:33 SAST
38
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb1
39
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
40
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
41
-
42
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
43
-
44
- **** Trace file opened at 2012-02-15, 14:42:34 SAST
45
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
46
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
47
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
48
-
49
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
50
-
51
- **** Trace file opened at 2012-02-15, 14:50:05 SAST
52
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
53
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
54
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
55
-
56
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
57
-
58
- **** Trace file opened at 2012-02-15, 15:19:16 SAST
59
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
60
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
61
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
62
-
63
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
64
-
65
- **** Trace file opened at 2012-02-15, 15:19:42 SAST
66
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
67
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
68
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
69
-
70
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
71
-
72
- **** Trace file opened at 2012-02-15, 15:20:37 SAST
73
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
74
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
75
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
76
-
77
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
78
-
79
- **** Trace file opened at 2012-02-15, 15:21:59 SAST
80
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
81
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
82
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
83
-
84
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
85
-
86
- **** Trace file opened at 2012-02-15, 15:23:05 SAST
87
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
88
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
89
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
90
-
91
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
92
-
93
- **** Trace file opened at 2012-02-15, 15:25:42 SAST
94
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
95
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
96
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
97
-
98
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
99
-
100
- **** Trace file opened at 2012-02-15, 15:26:25 SAST
101
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
102
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
103
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
104
-
105
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
106
-
107
- **** Trace file opened at 2012-02-15, 22:23:25 SAST
108
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
109
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
110
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
111
-
112
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
113
-
114
- **** Trace file opened at 2012-02-15, 22:23:59 SAST
115
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
116
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
117
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
118
-
119
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
120
-
121
- **** Trace file opened at 2012-02-15, 22:27:38 SAST
122
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
123
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
124
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
125
-
126
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
127
-
128
- **** Trace file opened at 2012-02-15, 22:28:08 SAST
129
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
130
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
131
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
132
-
133
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
134
-
135
- **** Trace file opened at 2012-02-17, 12:38:41 SAST
136
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib, Program: irb
137
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
138
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
139
-
140
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
@@ -1,28 +0,0 @@
1
-
2
- **** Trace file opened at 2012-02-17, 14:29:25 SAST
3
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
4
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
5
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
6
-
7
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
8
-
9
- **** Trace file opened at 2012-02-17, 14:35:20 SAST
10
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
11
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
12
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
13
-
14
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
15
-
16
- **** Trace file opened at 2012-02-17, 14:50:20 SAST
17
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
18
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
19
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
20
-
21
- ERROR pfuuid_init returns error -> UUIDs cannot be generated
22
-
23
- **** Trace file opened at 2012-02-17, 15:04:13 SAST
24
- RFC library: 720, Current working directory: /home/martin/Development/ruby/sapnwrfc/lib/nwrfc, Program: irb
25
- Hardware: Intel x86 with Linux i686, Operating_system: Linux 3.0.0-14-generic-pae, Kernel_release: 720 patchlevel 2
26
- Hostname: martin-laptop, IP address: 127.0.1.1, IP address_v6: 127.0.1.1
27
-
28
- ERROR pfuuid_init returns error -> UUIDs cannot be generated