portal-ruby 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +34 -0
- data/Rakefile +115 -0
- data/ext/extconf.rb +13 -0
- data/ext/portalext.c +1098 -0
- data/ext/portalext.h +114 -0
- data/lib/portal.rb +47 -0
- data/test/setup.rb +68 -0
- data/test/test_all.rb +10 -0
- data/test/test_connect.rb +28 -0
- data/test/test_console.rb +46 -0
- data/test/test_leaks.rb +37 -0
- data/test/test_portalext.rb +173 -0
- metadata +62 -0
data/README
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Portal-Ruby: Ruby bindings for Portal's Infranet
|
2
|
+
by Ray Capozzi
|
3
|
+
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
portal-ruby enables Ruby programs to communicate with Portal's Infranet.
|
8
|
+
|
9
|
+
You can view http://portal-ruby.rubyforge.org for more information.
|
10
|
+
|
11
|
+
|
12
|
+
== SYNOPSIS:
|
13
|
+
|
14
|
+
require 'portal'
|
15
|
+
|
16
|
+
portal = Portal::Connection.new
|
17
|
+
portal.loopback
|
18
|
+
portal.xop(:PCM_OP_CUST_DELETE_ACCT,:PIN_FLD_POID => "0.0.0.1 /account 11")
|
19
|
+
|
20
|
+
This creates a connection to Portal using a pin.conf and deletes an account.
|
21
|
+
|
22
|
+
|
23
|
+
== REQUIREMENTS:
|
24
|
+
|
25
|
+
You need portal.[so|dll] to run.
|
26
|
+
|
27
|
+
|
28
|
+
== INSTALL
|
29
|
+
|
30
|
+
You need include files to build.
|
31
|
+
Under non-win32, the setup.rb should be enough. I'm still trying to understand
|
32
|
+
how one explains configuring VS. Perhaps I'll release win32 builds.
|
33
|
+
|
34
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'fileutils'
|
7
|
+
require 'rubyforge'
|
8
|
+
|
9
|
+
include FileUtils
|
10
|
+
|
11
|
+
PKG_NAME = "portal-ruby"
|
12
|
+
SVN_HOME = "file:///c:/svn/local/portal-ruby"
|
13
|
+
RELEASE_DIR = "release"
|
14
|
+
|
15
|
+
def get_version
|
16
|
+
ENV['version'] or "0.0.1"
|
17
|
+
# ENV['version'] or abort "Must supply VERSION=x.y.z"
|
18
|
+
end
|
19
|
+
|
20
|
+
rdoc_template = ENV['template'] || "allison.rb"
|
21
|
+
#rdoc_template = "jamis.rb"
|
22
|
+
|
23
|
+
# Define the files to get doc-ed
|
24
|
+
Rake::RDocTask.new do |rdoc|
|
25
|
+
rdoc.template = rdoc_template
|
26
|
+
rdoc.rdoc_dir = "doc/rdoc"
|
27
|
+
rdoc.options << '--line-numbers' << "--tab-width=2" << "--quiet"
|
28
|
+
rdoc.options << "--inline-source" if rdoc_template =~ /allison/
|
29
|
+
rdoc.rdoc_files.add(['README', 'lib/**/*.rb', 'doc/**/*.rdoc', 'ext/portalext.c'])
|
30
|
+
end
|
31
|
+
|
32
|
+
task :package => [:clean,:compile,:test,:rerdoc]
|
33
|
+
|
34
|
+
desc "Create the static web pages"
|
35
|
+
task :webgen do
|
36
|
+
sh %{pushd doc/site; webgen; popd }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Remote Site Section
|
40
|
+
|
41
|
+
desc "Push static files"
|
42
|
+
#task :site_webgen => [:webgen] do
|
43
|
+
task :site_webgen do
|
44
|
+
sh %{rsync -e 'ssh -1' -azv doc/site/output/* rubyforge.org:/var/www/gforge-projects/portal-ruby/}
|
45
|
+
end
|
46
|
+
|
47
|
+
task :site_rdoc do
|
48
|
+
sh %{ rsync -e 'ssh -1' -azv doc/rdoc/* rubyforge.org:/var/www/gforge-projects/portal-ruby/rdoc/ }
|
49
|
+
end
|
50
|
+
|
51
|
+
gem_spec = Gem::Specification.new do |spec|
|
52
|
+
test_files = Dir.glob("test/**/*.rb") - Dir.glob("test/**/*local*")
|
53
|
+
|
54
|
+
spec.name = PKG_NAME
|
55
|
+
spec.version = get_version
|
56
|
+
spec.summary = "Binding for Portal's Infranet and Oracle Telco Billing"
|
57
|
+
spec.description = spec.summary
|
58
|
+
spec.platform = Gem::Platform::RUBY
|
59
|
+
spec.has_rdoc = true
|
60
|
+
spec.extra_rdoc_files = [ "README" ]
|
61
|
+
spec.test_files = test_files
|
62
|
+
|
63
|
+
all_files = %w(README Rakefile) +
|
64
|
+
# Dir.glob("doc/rdoc/**/*") +
|
65
|
+
test_files +
|
66
|
+
Dir.glob("ext/**/*.{h,c,rb}") +
|
67
|
+
Dir.glob("{lib}/**/*.rb")
|
68
|
+
spec.files = all_files.to_a.delete_if {|f| f.include?('.svn')}
|
69
|
+
|
70
|
+
spec.require_path = "lib"
|
71
|
+
spec.extensions = FileList["ext/**/extconf.rb"].to_a
|
72
|
+
|
73
|
+
spec.required_ruby_version = '>= 1.8.5'
|
74
|
+
|
75
|
+
if RUBY_PLATFORM =~ /mswin/
|
76
|
+
# spec.files += ['Release/portalext.so']
|
77
|
+
spec.extensions.clear
|
78
|
+
spec.platform = Gem::Platform::WIN32
|
79
|
+
end
|
80
|
+
|
81
|
+
spec.author = "Raymond Capozzi"
|
82
|
+
spec.email = "rcapozzi+ruby@gmail.com"
|
83
|
+
spec.homepage = "portal-ruby.rubyforge.com"
|
84
|
+
spec.rubyforge_project = "portal-ruby"
|
85
|
+
end
|
86
|
+
|
87
|
+
Rake::GemPackageTask.new(gem_spec) do |pkg|
|
88
|
+
pkg.gem_spec = gem_spec
|
89
|
+
#pkg.need_tar = true if RUBY_PLATFORM !~ /mswin/
|
90
|
+
end
|
91
|
+
|
92
|
+
desc "Release from source control"
|
93
|
+
task :export do
|
94
|
+
rm_rf RELEASE_DIR
|
95
|
+
sh %{ svn export #{SVN_HOME} #{RELEASE_DIR} }
|
96
|
+
puts "Now cd #{RELEASE_DIR} && rake gem version=x.y.z"
|
97
|
+
end
|
98
|
+
|
99
|
+
desc "Release this turd to rubyforge"
|
100
|
+
task :release => [:gem] do |t|
|
101
|
+
rf = RubyForge.new
|
102
|
+
puts "Logging in"
|
103
|
+
rf.login
|
104
|
+
|
105
|
+
c = rf.userconfig
|
106
|
+
c["release_notes"] = description if description
|
107
|
+
c["release_changes"] = changes if changes
|
108
|
+
c["preformatted"] = true
|
109
|
+
|
110
|
+
files = ["#{pkg}.gem"].compact
|
111
|
+
|
112
|
+
puts "Releasing #{name} v. #{version}"
|
113
|
+
rf.add_release rubyforge_name, name, version, *files
|
114
|
+
|
115
|
+
end
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
# Create a Makefile for building this extension
|
4
|
+
#
|
5
|
+
# export PINSDK=$CVSTOP/portal
|
6
|
+
# ruby ./extconf.rb --with-portal-lib=$PINSDK/lib --with-portal-include=$PINSDK/include
|
7
|
+
|
8
|
+
sdk = ENV["PINSDK"] || "/usr/local/portal"
|
9
|
+
dir_config("portal", sdk)
|
10
|
+
if have_header( "pcm.h" ) and
|
11
|
+
have_library( "portal", "pin_log_flist" )
|
12
|
+
create_makefile( "portalext" )
|
13
|
+
end
|
data/ext/portalext.c
ADDED
@@ -0,0 +1,1098 @@
|
|
1
|
+
/* -*- indent-tabs-mode: nil -*- */
|
2
|
+
/*
|
3
|
+
* portalext.c
|
4
|
+
*
|
5
|
+
* $Author: rcapozzi $
|
6
|
+
* $Date: $
|
7
|
+
*
|
8
|
+
* Copyright (C) 2006-2007 Raymond Capozzi
|
9
|
+
*/
|
10
|
+
|
11
|
+
#if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
|
12
|
+
#define WIN32_LEAN_AND_MEAN
|
13
|
+
#include <windows.h>
|
14
|
+
#endif
|
15
|
+
|
16
|
+
#include <string.h>
|
17
|
+
#include "portalext.h"
|
18
|
+
#include "pbo_decimal.h"
|
19
|
+
#include "st.h"
|
20
|
+
#include "ruby.h"
|
21
|
+
#include "util.h"
|
22
|
+
|
23
|
+
/* Prototype */
|
24
|
+
static pin_flist_t * portal_hash_to_flist(VALUE hash);
|
25
|
+
static VALUE portal_to_flist_array_i(VALUE pair, VALUE data);
|
26
|
+
static int portal_to_flist_i(VALUE key, VALUE val, ConvertData *cd);
|
27
|
+
|
28
|
+
/* Class visible values */
|
29
|
+
VALUE mPortal, cContext, ePortalError;
|
30
|
+
|
31
|
+
/* Ids and constants */
|
32
|
+
static ID id_call;
|
33
|
+
static ID id_inspect;
|
34
|
+
static ID id_to_f;
|
35
|
+
static ID id_to_i;
|
36
|
+
static ID id_to_s;
|
37
|
+
static ID id_to_sym;
|
38
|
+
static ID id_xop;
|
39
|
+
|
40
|
+
/*
|
41
|
+
* Free the
|
42
|
+
* Called by ruby as part of the initialization.
|
43
|
+
*/
|
44
|
+
void
|
45
|
+
pdata_free(pd)
|
46
|
+
PortalData *pd;
|
47
|
+
{
|
48
|
+
TRACE("Freeing");
|
49
|
+
PDataClearErr(pd);
|
50
|
+
if (pd->ctxp != NULL){
|
51
|
+
PCM_CONTEXT_CLOSE(pd->ctxp,0,&pd->ebuf);
|
52
|
+
}
|
53
|
+
PIN_FLIST_DESTROY_EX(&(pd->in_flistp), NULL);
|
54
|
+
PIN_FLIST_DESTROY_EX(&(pd->out_flistp), NULL);
|
55
|
+
}
|
56
|
+
|
57
|
+
void
|
58
|
+
cdata_free(cd)
|
59
|
+
ConvertData *cd;
|
60
|
+
{
|
61
|
+
PIN_FLIST_DESTROY_EX(&(cd->flistp), NULL);
|
62
|
+
}
|
63
|
+
|
64
|
+
/*
|
65
|
+
* call-seq:
|
66
|
+
* Connection.new -> a naked object
|
67
|
+
*
|
68
|
+
* Allocate the C data structure that follows this instance around.
|
69
|
+
* Called by ruby as part of the initialization.
|
70
|
+
* We return a brand new Ruby object.
|
71
|
+
*/
|
72
|
+
static VALUE portal_alloc _((VALUE));
|
73
|
+
static VALUE
|
74
|
+
portal_alloc(klass)
|
75
|
+
VALUE klass;
|
76
|
+
{
|
77
|
+
VALUE obj;
|
78
|
+
PortalData *pd = NULL;
|
79
|
+
PDataWrap(klass,obj,pd);
|
80
|
+
TRACE_INSPECT("Allocated",obj);
|
81
|
+
return obj;
|
82
|
+
}
|
83
|
+
|
84
|
+
/*
|
85
|
+
* call-seq:
|
86
|
+
* inspectx -> String of debug info
|
87
|
+
*
|
88
|
+
* Connection.inspectx -> Dumps the associated C structs
|
89
|
+
*/
|
90
|
+
static VALUE
|
91
|
+
portal_inspect(self)
|
92
|
+
VALUE self;
|
93
|
+
{
|
94
|
+
char *cname = rb_obj_classname(self);
|
95
|
+
size_t len;
|
96
|
+
VALUE str;
|
97
|
+
unsigned long id = rb_obj_id(self);
|
98
|
+
char *format = "#<%s:0X%lx owner_id=0x%lx>";
|
99
|
+
|
100
|
+
PortalData *pd;
|
101
|
+
PDataGet(self,pd);
|
102
|
+
TRACE("Inspecting");
|
103
|
+
|
104
|
+
len = strlen(cname)+6+16;
|
105
|
+
// len = strlen(format);
|
106
|
+
str = rb_str_new(0, len); /* 6:tags 16:addr */
|
107
|
+
snprintf(RSTRING(str)->ptr, len+1, "#<%s:0X%lx>", cname, self);
|
108
|
+
RSTRING(str)->len = strlen(RSTRING(str)->ptr);
|
109
|
+
if (OBJ_TAINTED(self)) OBJ_TAINT(str);
|
110
|
+
|
111
|
+
return str;
|
112
|
+
|
113
|
+
}
|
114
|
+
|
115
|
+
/*
|
116
|
+
* Cast something into a string.
|
117
|
+
*/
|
118
|
+
#if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
|
119
|
+
static __inline VALUE
|
120
|
+
#else
|
121
|
+
static VALUE
|
122
|
+
#endif
|
123
|
+
portal_to_s(obj)
|
124
|
+
VALUE obj;
|
125
|
+
{
|
126
|
+
return rb_obj_as_string(obj);
|
127
|
+
return rb_funcall(obj, id_to_s, 0, 0);
|
128
|
+
}
|
129
|
+
|
130
|
+
/*
|
131
|
+
* Cast a String or Symbol into a char *.
|
132
|
+
*/
|
133
|
+
#if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
|
134
|
+
static __inline char*
|
135
|
+
#else
|
136
|
+
static char*
|
137
|
+
#endif
|
138
|
+
portal_to_char(str)
|
139
|
+
VALUE str;
|
140
|
+
{
|
141
|
+
VALUE tmp;
|
142
|
+
if (TYPE(str) == T_STRING){
|
143
|
+
return StringValuePtr(str);
|
144
|
+
}
|
145
|
+
tmp = rb_funcall(str, id_to_s, 0, 0);
|
146
|
+
return StringValuePtr(tmp);
|
147
|
+
}
|
148
|
+
|
149
|
+
/*
|
150
|
+
* The Portal field number for a string.
|
151
|
+
*/
|
152
|
+
static VALUE
|
153
|
+
portal_field_num(obj,str)
|
154
|
+
VALUE obj, str;
|
155
|
+
{
|
156
|
+
pin_fld_num_t fld_num = 0;
|
157
|
+
VALUE value;
|
158
|
+
|
159
|
+
if (TYPE(str) == T_STRING){
|
160
|
+
fld_num = PIN_FIELD_OF_NAME(StringValuePtr(str));
|
161
|
+
} else {
|
162
|
+
value = portal_to_s(str);
|
163
|
+
fld_num = PIN_FIELD_OF_NAME(portal_to_char(value));
|
164
|
+
}
|
165
|
+
|
166
|
+
if (!fld_num){
|
167
|
+
rb_raise(ePortalError, "Cannot find field number for %s", StringValuePtr(str));
|
168
|
+
}
|
169
|
+
return INT2FIX(PIN_GET_NUM_FROM_FLD(fld_num));
|
170
|
+
}
|
171
|
+
|
172
|
+
/*
|
173
|
+
* Returns the name for a given field number.
|
174
|
+
*/
|
175
|
+
static VALUE
|
176
|
+
portal_field_name(self,num)
|
177
|
+
VALUE self, num;
|
178
|
+
{
|
179
|
+
VALUE tmp = Qundef;
|
180
|
+
VALUE name = Qundef;
|
181
|
+
const char *fld_name = NULL;
|
182
|
+
|
183
|
+
tmp = rb_funcall(num, id_to_i, 0, 0);
|
184
|
+
|
185
|
+
fld_name = pin_name_of_field(FIX2INT(tmp));
|
186
|
+
name = rb_str_new2(fld_name);
|
187
|
+
return name;
|
188
|
+
}
|
189
|
+
|
190
|
+
/*
|
191
|
+
* The Portal field type.
|
192
|
+
*/
|
193
|
+
static VALUE
|
194
|
+
portal_field_type(obj, value)
|
195
|
+
VALUE obj, value;
|
196
|
+
{
|
197
|
+
int i = 0;
|
198
|
+
i = PIN_FIELD_OF_NAME(portal_to_char(value));
|
199
|
+
i = PIN_GET_TYPE_FROM_FLD(i);
|
200
|
+
if (!i){
|
201
|
+
rb_raise(ePortalError, "Cannot get type for %s",portal_to_char(value));
|
202
|
+
}
|
203
|
+
return INT2FIX(i);
|
204
|
+
}
|
205
|
+
|
206
|
+
/*
|
207
|
+
* TODO: Make robust enough to handle /account 1.
|
208
|
+
* Perhaps add: sscanf(portal_to_char(val),"0.0.0.%lld %s %lld",&poid_db,buf,&poid_id0);
|
209
|
+
*/
|
210
|
+
static poid_t *
|
211
|
+
portal_poid_from_string(string,ebufp)
|
212
|
+
char * string;
|
213
|
+
pin_errbuf_t *ebufp;
|
214
|
+
{
|
215
|
+
// int64 poid_id0,poid_db;
|
216
|
+
// static char buf[64];
|
217
|
+
poid_t *pdp;
|
218
|
+
#if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
|
219
|
+
pdp = strlen(string) == 0 ? NULL : PIN_POID_FROM_STR(string,NULL,ebufp);
|
220
|
+
#else
|
221
|
+
pdp = strnlen(string,2) == 0 ? NULL : PIN_POID_FROM_STR(string,NULL,ebufp);
|
222
|
+
#endif
|
223
|
+
return pdp;
|
224
|
+
}
|
225
|
+
|
226
|
+
/*
|
227
|
+
* call-seq:
|
228
|
+
* portal_to_flist(hash) => Portal FList
|
229
|
+
* An error is kept in a local ebuf untill the end.
|
230
|
+
*/
|
231
|
+
static int
|
232
|
+
portal_to_flist_i(VALUE key,VALUE val,ConvertData *cd)
|
233
|
+
{
|
234
|
+
pin_errbuf_t ebuf;
|
235
|
+
pin_fld_num_t fld_num = 0;
|
236
|
+
pin_flist_t *ary_flistp, *save_flistp;
|
237
|
+
int fld_type = 0;
|
238
|
+
int int_value = 0;
|
239
|
+
double big_value = 0.0;
|
240
|
+
char *fld_name = NULL, *tmp_str = NULL;
|
241
|
+
pin_decimal_t *pbo = NULL;
|
242
|
+
poid_t *pdp = NULL;
|
243
|
+
|
244
|
+
if (key == Qundef) {
|
245
|
+
return ST_CONTINUE;
|
246
|
+
}
|
247
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
248
|
+
|
249
|
+
fld_name = portal_to_char(key);
|
250
|
+
fld_num = PIN_FIELD_OF_NAME(fld_name);
|
251
|
+
if (!fld_num) {
|
252
|
+
rb_raise(ePortalError, "Cannot find field number for %s", fld_name);
|
253
|
+
}
|
254
|
+
|
255
|
+
fld_type = PIN_GET_TYPE_FROM_FLD(fld_num);
|
256
|
+
if (!fld_type){
|
257
|
+
rb_raise(ePortalError, "Cannot get type for %s", fld_name);
|
258
|
+
}
|
259
|
+
|
260
|
+
#ifdef _DEBUG
|
261
|
+
tmp_str = TYPE(val) ? "Hash" : portal_to_char(val);
|
262
|
+
if (rb_gv_get("$DEBUG"))
|
263
|
+
fprintf(stderr," hash2flist name=%s num=%ld type=%ld val=%s\n", fld_name, fld_num, fld_type, tmp_str);
|
264
|
+
#endif
|
265
|
+
|
266
|
+
switch(fld_type){
|
267
|
+
case PIN_FLDT_STR:
|
268
|
+
PIN_FLIST_FLD_SET(cd->flistp, fld_num, (void *) portal_to_char(val), &ebuf);
|
269
|
+
break;
|
270
|
+
|
271
|
+
case PIN_FLDT_INT:
|
272
|
+
case PIN_FLDT_UINT:
|
273
|
+
case PIN_FLDT_ENUM:
|
274
|
+
case PIN_FLDT_TSTAMP:
|
275
|
+
int_value = TO_INT(val);
|
276
|
+
PIN_FLIST_FLD_SET(cd->flistp, fld_num, (void *)&int_value, &ebuf);
|
277
|
+
break;
|
278
|
+
|
279
|
+
case PIN_FLDT_NUM:
|
280
|
+
case PIN_FLDT_DECIMAL:
|
281
|
+
big_value = TO_BIG(val);
|
282
|
+
pbo = pbo_decimal_from_double(big_value,&ebuf);
|
283
|
+
PIN_FLIST_FLD_SET(cd->flistp, fld_num, (void *)pbo, &ebuf);
|
284
|
+
|
285
|
+
if (! pbo_decimal_is_null(pbo,&ebuf)) {
|
286
|
+
pbo_decimal_destroy(&pbo);
|
287
|
+
}
|
288
|
+
break;
|
289
|
+
|
290
|
+
case PIN_FLDT_POID:
|
291
|
+
/* Parse 0.0.0.1 /account 1234 1 */
|
292
|
+
pdp = portal_poid_from_string(portal_to_char(val), &ebuf);
|
293
|
+
PIN_FLIST_FLD_PUT(cd->flistp, fld_num, (void *)pdp, &ebuf);
|
294
|
+
break;
|
295
|
+
|
296
|
+
case PIN_FLDT_ARRAY:
|
297
|
+
case PIN_FLDT_SUBSTRUCT:
|
298
|
+
Check_Type(val,T_HASH);
|
299
|
+
cd->fld_num = fld_num;
|
300
|
+
save_flistp = cd->flistp;
|
301
|
+
rb_iterate(rb_each, val, portal_to_flist_array_i,(VALUE)cd);
|
302
|
+
(cd)->flistp = save_flistp;
|
303
|
+
(cd)->fld_num = fld_num;
|
304
|
+
ebuf = *cd->ebufp;
|
305
|
+
break;
|
306
|
+
|
307
|
+
case PIN_FLDT_OBJ:
|
308
|
+
case PIN_FLDT_BINSTR:
|
309
|
+
case PIN_FLDT_ERR:
|
310
|
+
default:
|
311
|
+
rb_raise(ePortalError, "Type %ld not supported for %s", fld_type, fld_name);
|
312
|
+
break;
|
313
|
+
} /* End switch */
|
314
|
+
|
315
|
+
if (PIN_ERR_IS_ERR(&ebuf)) {
|
316
|
+
PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "Hash to flist conversion error", &ebuf);
|
317
|
+
rb_raise(ePortalError, "Cannot convert %s", fld_name);
|
318
|
+
}
|
319
|
+
|
320
|
+
return ST_CONTINUE;
|
321
|
+
}
|
322
|
+
|
323
|
+
/*
|
324
|
+
* Interates through a nested Hash to create a nested flist.
|
325
|
+
* The hash keys must respond to to_i, as that value becomes the REC ID in the array.
|
326
|
+
*
|
327
|
+
* === Example:
|
328
|
+
*
|
329
|
+
* hash = {
|
330
|
+
* "PIN_FLD_NAME" => "Foo",
|
331
|
+
* :PIN_FLD_ARGS => {
|
332
|
+
* 1 => { :PIN_FLD_NAME => "Name 0" },
|
333
|
+
* 2 => {
|
334
|
+
* :PIN_FLD_NAME => "Name 1",
|
335
|
+
* :PIN_FLD_CREATED_T => 1,
|
336
|
+
* },
|
337
|
+
* 3 => {
|
338
|
+
* :PIN_FLD_NAME => "Value 2",
|
339
|
+
* :PIN_FLD_CREATED_T => 2,
|
340
|
+
* },
|
341
|
+
* },
|
342
|
+
* }
|
343
|
+
* PIN_ELEMID_ANY is denoted using a "*" as the key.
|
344
|
+
*/
|
345
|
+
static VALUE
|
346
|
+
portal_to_flist_array_i(pair,data)
|
347
|
+
VALUE pair, data;
|
348
|
+
{
|
349
|
+
ConvertData *cd = (ConvertData *)data;
|
350
|
+
VALUE key, val;
|
351
|
+
pin_flist_t *ary_flistp, *save_flistp;
|
352
|
+
int rec_id = 0;
|
353
|
+
VALUE tmp_obj;
|
354
|
+
pin_fld_num_t fld_num;
|
355
|
+
|
356
|
+
//CDataGet(data,cd);
|
357
|
+
Check_Type(pair,T_ARRAY);
|
358
|
+
key = rb_ary_entry(pair, 0);
|
359
|
+
val = rb_ary_entry(pair, 1);
|
360
|
+
fld_num = cd->fld_num;
|
361
|
+
|
362
|
+
if (TYPE(key) == T_FIXNUM) {
|
363
|
+
rec_id = FIX2INT(key);
|
364
|
+
} else {
|
365
|
+
if (TYPE(key) == T_STRING && RSTRING(key)->ptr[0] == '*'){
|
366
|
+
rec_id = PIN_ELEMID_ANY;
|
367
|
+
} else {
|
368
|
+
tmp_obj = rb_funcall(key, id_to_i, 0, 0);
|
369
|
+
rec_id = FIX2INT(tmp_obj);
|
370
|
+
}
|
371
|
+
}
|
372
|
+
|
373
|
+
save_flistp = cd->flistp;
|
374
|
+
ary_flistp = PIN_FLIST_ELEM_ADD(cd->flistp, fld_num, rec_id, cd->ebufp);
|
375
|
+
|
376
|
+
cd->flistp = ary_flistp;
|
377
|
+
rb_hash_foreach(val, portal_to_flist_i,cd);
|
378
|
+
cd->flistp = save_flistp;
|
379
|
+
return ST_CONTINUE;
|
380
|
+
}
|
381
|
+
|
382
|
+
/*
|
383
|
+
* Convert a Ruby hash into a Portal flist
|
384
|
+
*/
|
385
|
+
static pin_flist_t *
|
386
|
+
portal_hash_to_flist(hash)
|
387
|
+
VALUE hash;
|
388
|
+
{
|
389
|
+
pin_errbuf_t ebuf;
|
390
|
+
ConvertData cdata;
|
391
|
+
|
392
|
+
cdata.flistp = NULL;
|
393
|
+
cdata.ebufp = &ebuf;
|
394
|
+
|
395
|
+
// TODO: rb_thread_critical = Qtrue;
|
396
|
+
Check_Type(hash,T_HASH);
|
397
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
398
|
+
cdata.flistp = PIN_FLIST_CREATE(&ebuf);
|
399
|
+
|
400
|
+
/* Iterate through the hash converting each key/val pair into
|
401
|
+
* their Portal equivilent.
|
402
|
+
* Not using rb_iterate(rb_each, hash, portal_to_flist_i, hash);
|
403
|
+
* because the receiver gets an array of [key,val] which you have to noodle.
|
404
|
+
*
|
405
|
+
* Using rb_hash_foreach(hash, inter_i, struct);
|
406
|
+
* Calls inter_i for each key/val pair in the hash.
|
407
|
+
* iter_i has prototype inter_i(key,val,struct).
|
408
|
+
* key and val are obvious. struct is some data structure
|
409
|
+
* that you use to maintain state between calls to the inter.
|
410
|
+
*/
|
411
|
+
rb_hash_foreach(hash, portal_to_flist_i,&cdata);
|
412
|
+
|
413
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
414
|
+
return cdata.flistp;
|
415
|
+
}
|
416
|
+
|
417
|
+
/*
|
418
|
+
* Converts Portal Poid to Ruby String. Returns a Ruby String.
|
419
|
+
*/
|
420
|
+
static VALUE
|
421
|
+
portal_poid_to_val(pdp)
|
422
|
+
poid_t *pdp;
|
423
|
+
{
|
424
|
+
pin_errbuf_t ebuf;
|
425
|
+
int buf_size = PCM_MAX_POID_TYPE + 48;
|
426
|
+
char buf[PCM_MAX_POID_TYPE + 48];
|
427
|
+
char *bufp = NULL;
|
428
|
+
memset(buf,0,sizeof(buf));
|
429
|
+
bufp = buf;
|
430
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
431
|
+
PIN_POID_TO_STR((poid_t *)pdp, &bufp, &buf_size, &ebuf);
|
432
|
+
return rb_str_new2(bufp);
|
433
|
+
}
|
434
|
+
|
435
|
+
/*
|
436
|
+
* Convert an Flist into a hash.
|
437
|
+
*/
|
438
|
+
static VALUE
|
439
|
+
portal_flist_to_hash(flistp)
|
440
|
+
pin_flist_t *flistp;
|
441
|
+
{
|
442
|
+
pin_fld_num_t fld_num = 0;
|
443
|
+
int buf_size = PCM_MAX_POID_TYPE + 48;
|
444
|
+
char buf[PCM_MAX_POID_TYPE + 48];
|
445
|
+
char *bufp = NULL;
|
446
|
+
const char *fld_name = NULL;
|
447
|
+
void *field_val = NULL;
|
448
|
+
int rec_id = 0;
|
449
|
+
int fld_type = 0;
|
450
|
+
pin_cookie_t cookie = NULL;
|
451
|
+
pin_cookie_t ary_cookie = NULL;
|
452
|
+
double dbl = 0.00;
|
453
|
+
VALUE subhash = Qundef;
|
454
|
+
pin_errbuf_t ebuf;
|
455
|
+
ConvertData cdata;
|
456
|
+
VALUE hash = Qundef, key = Qundef, val = Qundef;
|
457
|
+
|
458
|
+
cdata.flistp = NULL;
|
459
|
+
cdata.ebufp = &ebuf;
|
460
|
+
|
461
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
462
|
+
cdata.flistp = PIN_FLIST_CREATE(&ebuf);
|
463
|
+
|
464
|
+
memset(buf,0,sizeof(buf));
|
465
|
+
bufp = buf;
|
466
|
+
hash = rb_hash_new();
|
467
|
+
|
468
|
+
while ((field_val = pin_flist_any_get_next(flistp, &fld_num, &rec_id, NULL, &cookie, &ebuf)) != NULL) {
|
469
|
+
fld_name = pin_name_of_field(fld_num);
|
470
|
+
key = rb_str_new2(fld_name);
|
471
|
+
fld_type = PIN_GET_TYPE_FROM_FLD(fld_num);
|
472
|
+
switch(fld_type) {
|
473
|
+
case PIN_FLDT_STR:
|
474
|
+
val = rb_str_new2(field_val);
|
475
|
+
break;
|
476
|
+
|
477
|
+
case PIN_FLDT_INT:
|
478
|
+
case PIN_FLDT_UINT:
|
479
|
+
case PIN_FLDT_ENUM:
|
480
|
+
case PIN_FLDT_TSTAMP:
|
481
|
+
val = INT2NUM(*(int*)field_val);
|
482
|
+
break;
|
483
|
+
|
484
|
+
case PIN_FLDT_NUM:
|
485
|
+
case PIN_FLDT_DECIMAL:
|
486
|
+
dbl = pbo_decimal_to_double((pin_decimal_t *)field_val, &ebuf);
|
487
|
+
val = rb_float_new(dbl);
|
488
|
+
break;
|
489
|
+
|
490
|
+
case PIN_FLDT_POID:
|
491
|
+
buf_size = sizeof(buf); // b/c this changes it and memset(buf,0,sizeof(buf));
|
492
|
+
PIN_POID_TO_STR((poid_t *)field_val, &bufp, &buf_size, &ebuf);
|
493
|
+
val = rb_str_new2(bufp);
|
494
|
+
break;
|
495
|
+
|
496
|
+
case PIN_FLDT_ARRAY:
|
497
|
+
subhash = rb_hash_aref(hash, key);
|
498
|
+
if (TYPE(subhash) != T_HASH){
|
499
|
+
subhash = rb_hash_new();
|
500
|
+
rb_hash_aset(hash,key,subhash);
|
501
|
+
}
|
502
|
+
|
503
|
+
val = portal_flist_to_hash((pin_flist_t *) field_val);
|
504
|
+
rb_hash_aset(subhash,INT2FIX(rec_id),val);
|
505
|
+
|
506
|
+
goto SKIP_SET;
|
507
|
+
break;
|
508
|
+
|
509
|
+
case PIN_FLDT_SUBSTRUCT:
|
510
|
+
/*
|
511
|
+
val = portal_flist_to_hash((pin_flist_t *) field_val);
|
512
|
+
rb_hash_aset(hash,key,subhash);
|
513
|
+
goto SKIP_SET;
|
514
|
+
*/
|
515
|
+
/* A copy/paste of the Array code. Lets see if it works. */
|
516
|
+
subhash = rb_hash_aref(hash, key);
|
517
|
+
if (TYPE(subhash) != T_HASH){
|
518
|
+
subhash = rb_hash_new();
|
519
|
+
rb_hash_aset(hash,key,subhash);
|
520
|
+
}
|
521
|
+
|
522
|
+
val = portal_flist_to_hash((pin_flist_t *) field_val);
|
523
|
+
rb_hash_aset(subhash,INT2FIX(rec_id),val);
|
524
|
+
|
525
|
+
goto SKIP_SET;
|
526
|
+
break;
|
527
|
+
|
528
|
+
case PIN_FLDT_BINSTR:
|
529
|
+
case PIN_FLDT_ERR:
|
530
|
+
case PIN_FLDT_OBJ:
|
531
|
+
default:
|
532
|
+
fprintf(stderr," flist2hash name=%s num=%ld type=%ld\n", portal_to_char(key), fld_num, fld_type);
|
533
|
+
break;
|
534
|
+
}
|
535
|
+
|
536
|
+
if (PIN_ERR_IS_ERR(&ebuf)){
|
537
|
+
PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "Flist to hash conversion error", &ebuf);
|
538
|
+
rb_raise(ePortalError, "Error converting flist to hash key=%s type=%ld", portal_to_char(key),fld_type);
|
539
|
+
}
|
540
|
+
|
541
|
+
if (val != Qundef){
|
542
|
+
rb_hash_aset(hash, key, val);
|
543
|
+
#ifdef _DEBUG
|
544
|
+
if (rb_gv_get("$DEBUG"))
|
545
|
+
fprintf(stderr," flist2hash name=%s num=%ld type=%ld val=%s\n", portal_to_char(key), fld_num, fld_type, portal_to_char(val));
|
546
|
+
#endif
|
547
|
+
val = Qundef;
|
548
|
+
}
|
549
|
+
|
550
|
+
SKIP_SET:
|
551
|
+
;
|
552
|
+
}
|
553
|
+
|
554
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
555
|
+
|
556
|
+
Check_Type(hash,T_HASH);
|
557
|
+
return hash;
|
558
|
+
}
|
559
|
+
|
560
|
+
/*
|
561
|
+
* Test function for the from flist to hash conversion.
|
562
|
+
*/
|
563
|
+
#ifdef _DEBUG
|
564
|
+
static VALUE
|
565
|
+
portal_test_flist_to_hash(self,hash)
|
566
|
+
VALUE self, hash;
|
567
|
+
{
|
568
|
+
VALUE result;
|
569
|
+
pin_flist_t *flistp;
|
570
|
+
pin_errbuf_t ebuf;
|
571
|
+
//char *flist_str = NULL;
|
572
|
+
//int flist_len = NULL;
|
573
|
+
|
574
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
575
|
+
PIN_ERR_LOG_MSG(PIN_ERR_LEVEL_DEBUG, "Converting hash to flist");
|
576
|
+
flistp = portal_hash_to_flist(hash);
|
577
|
+
PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "portal_test_flist_to_hash flist", flistp);
|
578
|
+
result = portal_flist_to_hash(flistp);
|
579
|
+
|
580
|
+
//flist_str = NULL;
|
581
|
+
//PIN_FLIST_TO_STR(flistp, &flist_str, &flist_len, &ebuf);
|
582
|
+
PIN_FLIST_DESTROY_EX(&flistp,NULL);
|
583
|
+
|
584
|
+
return result;
|
585
|
+
}
|
586
|
+
#endif
|
587
|
+
|
588
|
+
/*
|
589
|
+
* Test function for the from flist to hash conversion.
|
590
|
+
*/
|
591
|
+
static VALUE
|
592
|
+
portal_hash_to_flist_string(self,hash)
|
593
|
+
VALUE self, hash;
|
594
|
+
{
|
595
|
+
VALUE result;
|
596
|
+
pin_flist_t *flistp;
|
597
|
+
pin_errbuf_t ebuf;
|
598
|
+
#if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
|
599
|
+
/* For some reason, windows does like other people giving us heap. */
|
600
|
+
int flist_len = 1000000;
|
601
|
+
char *flist_str = malloc(flist_len);
|
602
|
+
#else
|
603
|
+
int flist_len = NULL;
|
604
|
+
char *flist_str = NULL;
|
605
|
+
#endif
|
606
|
+
|
607
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
608
|
+
flistp = portal_hash_to_flist(hash);
|
609
|
+
PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "portal_hash_to_flist_string return", flistp);
|
610
|
+
PIN_FLIST_TO_STR(flistp, &flist_str, &flist_len, &ebuf);
|
611
|
+
PIN_FLIST_DESTROY_EX(&flistp,NULL);
|
612
|
+
result = rb_str_new2(flist_str);
|
613
|
+
free(flist_str);
|
614
|
+
return result;
|
615
|
+
}
|
616
|
+
|
617
|
+
/*
|
618
|
+
* Document-method: set_program_name
|
619
|
+
*
|
620
|
+
* call-seq:
|
621
|
+
* Portal.set_program_name(name) -> true
|
622
|
+
*
|
623
|
+
* Set the program name for the Portal log file.
|
624
|
+
*/
|
625
|
+
static VALUE
|
626
|
+
portal_set_program_name(self,name)
|
627
|
+
VALUE self, name;
|
628
|
+
{
|
629
|
+
PIN_ERR_SET_PROGRAM(portal_to_char(name));
|
630
|
+
return Qtrue;
|
631
|
+
}
|
632
|
+
|
633
|
+
/*
|
634
|
+
* Document-method: set_log_level
|
635
|
+
*
|
636
|
+
* call-seq:
|
637
|
+
* Portal.set_log_level(level) -> true
|
638
|
+
* example:
|
639
|
+
* Portal.set_log_level(:warn)
|
640
|
+
* Portal.set_log_level(2)
|
641
|
+
*
|
642
|
+
* Set the error level for the log file using symbols, strings, or ints.
|
643
|
+
*/
|
644
|
+
static VALUE
|
645
|
+
portal_set_log_level(self,level)
|
646
|
+
VALUE self, level;
|
647
|
+
{
|
648
|
+
int lev = 0;
|
649
|
+
char *cp = NULL;
|
650
|
+
|
651
|
+
if (TYPE(level) == T_STRING || TYPE(level) == T_SYMBOL) {
|
652
|
+
cp = portal_to_char(level);
|
653
|
+
if (!strcmpi(cp,"error")){
|
654
|
+
lev = PIN_ERR_LEVEL_ERROR;
|
655
|
+
} else if (!strcmpi(cp,"warn")) {
|
656
|
+
lev = PIN_ERR_LEVEL_WARNING;
|
657
|
+
} else if (!strcmpi(cp,"debug")) {
|
658
|
+
lev = PIN_ERR_LEVEL_DEBUG;
|
659
|
+
} else {
|
660
|
+
rb_raise(ePortalError, "Error level %s not supported", cp);
|
661
|
+
}
|
662
|
+
} else {
|
663
|
+
lev = NUM2INT(level);
|
664
|
+
if (lev > PIN_ERR_LEVEL_DEBUG){
|
665
|
+
rb_raise(ePortalError, "Error level %s not supported", cp);
|
666
|
+
}
|
667
|
+
}
|
668
|
+
PIN_ERR_SET_LEVEL(lev);
|
669
|
+
return Qtrue;
|
670
|
+
}
|
671
|
+
|
672
|
+
#define PORTAL_CHECK_ERROR(level,msg,flistp,ebufp) \
|
673
|
+
if (PIN_ERR_IS_ERR(ebufp)){ \
|
674
|
+
PIN_ERR_LOG_FLIST(level,msg,flistp); \
|
675
|
+
rb_raise(ePortalError, "Ebuf error: %s", msg); \
|
676
|
+
}
|
677
|
+
|
678
|
+
/*
|
679
|
+
* call-seq:
|
680
|
+
* xop(opcode,request) -> Hash
|
681
|
+
* xop(opcode,request,args) -> Hash
|
682
|
+
*
|
683
|
+
* Perform a Portal opcode by converting a hash into a flist.
|
684
|
+
*
|
685
|
+
* === Options:
|
686
|
+
* The options hash takes the following keys:
|
687
|
+
* :return | :flist_string | Converts the results flist into an flist_to_str like testnap
|
688
|
+
* :flags
|
689
|
+
*
|
690
|
+
* === Example:
|
691
|
+
* ph.xop(:PCM_OP_READ_OBJ,{:PIN_FLD_POID=>"0.0.0.1 /account 1"},:return => :flist_string)
|
692
|
+
*/
|
693
|
+
static VALUE
|
694
|
+
portal_xop(argc, argv, self)
|
695
|
+
int argc;
|
696
|
+
VALUE *argv;
|
697
|
+
VALUE self;
|
698
|
+
{
|
699
|
+
VALUE sym_flist_string = Qundef, sym_return = Qundef, sym_response = Qundef;
|
700
|
+
|
701
|
+
VALUE response, tmp;
|
702
|
+
VALUE opcode, request, args;
|
703
|
+
|
704
|
+
pin_errbuf_t ebuf;
|
705
|
+
pin_flist_t *in_flistp = NULL;
|
706
|
+
pin_flist_t *out_flistp = NULL;
|
707
|
+
pin_opcode_t op;
|
708
|
+
PortalData *pd;
|
709
|
+
#if defined WINDOWS || defined _WIN32 || defined HAVE_WINDOWS_H
|
710
|
+
/* For some reason, windows does like other people giving us heap. */
|
711
|
+
int flist_len = 1000000;
|
712
|
+
char *flist_str = malloc(flist_len);
|
713
|
+
#else
|
714
|
+
int flist_len = NULL;
|
715
|
+
char *flist_str = NULL;
|
716
|
+
#endif
|
717
|
+
int return_string = 0;
|
718
|
+
|
719
|
+
rb_scan_args(argc, argv, "21", &opcode, &request, &args);
|
720
|
+
|
721
|
+
TRACE_INSPECT("opcode:",opcode);
|
722
|
+
TRACE_INSPECT("Request",request);
|
723
|
+
TRACE_INSPECT("Args",args);
|
724
|
+
|
725
|
+
if (TYPE(sym_flist_string) == T_UNDEF){
|
726
|
+
sym_flist_string = ID2SYM(rb_intern("flist_string"));
|
727
|
+
sym_return = ID2SYM(rb_intern("return"));
|
728
|
+
sym_response = ID2SYM(rb_intern("response"));
|
729
|
+
}
|
730
|
+
|
731
|
+
if (TYPE(args) == T_HASH){
|
732
|
+
tmp = rb_hash_aref(args, sym_return);
|
733
|
+
if (TYPE(tmp) == T_SYMBOL && tmp == sym_flist_string){
|
734
|
+
return_string = 1;
|
735
|
+
}
|
736
|
+
}
|
737
|
+
|
738
|
+
switch (TYPE(opcode)) {
|
739
|
+
case T_FIXNUM:
|
740
|
+
case T_BIGNUM:
|
741
|
+
op = NUM2INT(opcode);
|
742
|
+
break;
|
743
|
+
case T_STRING:
|
744
|
+
op = pcm_opname_to_opcode(portal_to_char(opcode));
|
745
|
+
default:
|
746
|
+
rb_raise(ePortalError, "Invalid opcode");
|
747
|
+
break;
|
748
|
+
} /* End switch */
|
749
|
+
|
750
|
+
TRACE_FUNC("xop","Opcode",pcm_opcode_to_opname(op));
|
751
|
+
in_flistp = portal_hash_to_flist(request);
|
752
|
+
PDataGet(self,pd);
|
753
|
+
PIN_ERR_CLEAR_ERR(&ebuf);
|
754
|
+
PCM_OP(pd->ctxp, op, 0, in_flistp, &out_flistp, &ebuf);
|
755
|
+
pd->ops++;
|
756
|
+
/*
|
757
|
+
* cm_proxy returns PIN_ERR_STREAM_EOF when not allowed.
|
758
|
+
*/
|
759
|
+
// PORTAL_CHECK_ERROR(PIN_ERR_LEVEL_ERROR,"Bad operation",out_flistp,&ebuf);
|
760
|
+
if(PIN_ERR_IS_ERR(&ebuf)){
|
761
|
+
pd->errors++;
|
762
|
+
TRACE("Ebuf has error");
|
763
|
+
PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "xop error", &ebuf);
|
764
|
+
PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_ERROR, "input flist", in_flistp);
|
765
|
+
PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_ERROR, "return flist", out_flistp);
|
766
|
+
rb_raise(ePortalError, "Ebuf Error");
|
767
|
+
} else if (rb_gv_get("$DEBUG")) {
|
768
|
+
PIN_ERR_LOG_MSG(PIN_ERR_LEVEL_DEBUG, "xop input/output");
|
769
|
+
PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "input flist", in_flistp);
|
770
|
+
PIN_ERR_LOG_FLIST(PIN_ERR_LEVEL_DEBUG, "return flist", out_flistp);
|
771
|
+
} else {
|
772
|
+
TRACE("xop success");
|
773
|
+
}
|
774
|
+
|
775
|
+
if (return_string){
|
776
|
+
PIN_FLIST_TO_STR(out_flistp, &flist_str, &flist_len, &ebuf);
|
777
|
+
//rb_str_new(flist_str,flist_len);
|
778
|
+
response = rb_hash_new();
|
779
|
+
rb_hash_aset(response,sym_flist_string,rb_str_new(flist_str,flist_len));
|
780
|
+
rb_hash_aset(response,sym_response,portal_flist_to_hash(out_flistp));
|
781
|
+
free(flist_str);
|
782
|
+
} else {
|
783
|
+
response = portal_flist_to_hash(out_flistp);
|
784
|
+
}
|
785
|
+
TRACE_INSPECT("Response",response);
|
786
|
+
PIN_FLIST_DESTROY_EX(&in_flistp, NULL);
|
787
|
+
PIN_FLIST_DESTROY_EX(&out_flistp, NULL);
|
788
|
+
TRACE("xop returning");
|
789
|
+
return response;
|
790
|
+
}
|
791
|
+
|
792
|
+
/*
|
793
|
+
* call-seq:
|
794
|
+
* loopback -> Hash
|
795
|
+
*
|
796
|
+
* Calls PCM_OP_TEST_LOOPBACK to probe the CM connection.
|
797
|
+
* A bad test will raise an exception.
|
798
|
+
* portal.loopback
|
799
|
+
*/
|
800
|
+
static VALUE
|
801
|
+
portal_loopback(self)
|
802
|
+
VALUE self;
|
803
|
+
{
|
804
|
+
static VALUE poid_obj = NULL;
|
805
|
+
VALUE hash;
|
806
|
+
TRACE("Running loopback");
|
807
|
+
if (poid_obj == NULL){
|
808
|
+
poid_obj = rb_str_new2("0.0.0.1 /account 1 0")
|
809
|
+
}
|
810
|
+
hash = rb_hash_new();
|
811
|
+
rb_hash_aset(hash,rb_str_new2("PIN_FLD_POID"),poid_obj);
|
812
|
+
return rb_funcall(self, id_xop, 3, rb_str_new2("PCM_OP_TEST_LOOPBACK"), hash, Qnil);
|
813
|
+
}
|
814
|
+
|
815
|
+
/*
|
816
|
+
* call-seq:
|
817
|
+
* session -> String
|
818
|
+
*
|
819
|
+
* Returns the session associated to the current context.
|
820
|
+
* Returns nil if not connected.
|
821
|
+
*/
|
822
|
+
static VALUE
|
823
|
+
portal_get_session(self)
|
824
|
+
{
|
825
|
+
PortalData *pd;
|
826
|
+
PDataGet(self,pd);
|
827
|
+
if (pd->ctxp == NULL)
|
828
|
+
return Qnil;
|
829
|
+
return portal_poid_to_val(pcm_get_session(pd->ctxp));
|
830
|
+
}
|
831
|
+
|
832
|
+
/*
|
833
|
+
* call-seq:
|
834
|
+
* userid -> String
|
835
|
+
*
|
836
|
+
* Returns the user poid associated to the current context.
|
837
|
+
* Returns nil if not connected.
|
838
|
+
*/
|
839
|
+
static VALUE
|
840
|
+
portal_get_userid(self)
|
841
|
+
{
|
842
|
+
PortalData *pd;
|
843
|
+
TRACE("start");
|
844
|
+
PDataGet(self,pd);
|
845
|
+
if (pd->ctxp == NULL)
|
846
|
+
return Qnil;
|
847
|
+
return portal_poid_to_val(pcm_get_userid(pd->ctxp));
|
848
|
+
}
|
849
|
+
|
850
|
+
/*
|
851
|
+
* call-seq:
|
852
|
+
* robj(opcode,poid) -> Hash
|
853
|
+
* robj(opcode,poid,args) -> Hash
|
854
|
+
*
|
855
|
+
* Read an object. Returns the entire object.
|
856
|
+
*
|
857
|
+
* === Examples
|
858
|
+
*
|
859
|
+
* portal.robj :PIN_FLD_POID => "0.0.0.1 /account 1"
|
860
|
+
* portal.robj "0.0.0.1 /account 1"
|
861
|
+
* portal.robj "0.0.0.1 /account 1", :return => :flist_string
|
862
|
+
*/
|
863
|
+
static VALUE
|
864
|
+
portal_robj(argc, argv, obj)
|
865
|
+
int argc;
|
866
|
+
VALUE *argv;
|
867
|
+
VALUE obj;
|
868
|
+
{
|
869
|
+
VALUE read_obj = NULL;
|
870
|
+
VALUE request, args, hash;
|
871
|
+
rb_scan_args(argc, argv, "11", &request, &args);
|
872
|
+
|
873
|
+
if (TYPE(request) == T_HASH) {
|
874
|
+
hash = request;
|
875
|
+
} else if (TYPE(request) == T_STRING) {
|
876
|
+
hash = rb_hash_new();
|
877
|
+
rb_hash_aset(hash,rb_str_new2("PIN_FLD_POID"),request);
|
878
|
+
} else {
|
879
|
+
rb_raise(ePortalError, "Expected Hash or String.");
|
880
|
+
}
|
881
|
+
|
882
|
+
if (read_obj == NULL){
|
883
|
+
read_obj = rb_str_new2("PCM_OP_READ_OBJ");
|
884
|
+
}
|
885
|
+
|
886
|
+
return rb_funcall(obj, id_xop, 3, read_obj, hash, args);
|
887
|
+
}
|
888
|
+
|
889
|
+
/*
|
890
|
+
* call-seq:
|
891
|
+
* connect()
|
892
|
+
* connect(hash)
|
893
|
+
* connect(string)
|
894
|
+
*
|
895
|
+
* Create a connection to Portal in one of several ways based on the arg.
|
896
|
+
* If nil, then the pin.conf in the current directory is used.
|
897
|
+
* If hash, use those details.
|
898
|
+
* If string, then that is the location for our pin.conf
|
899
|
+
*
|
900
|
+
* Connect using a pin.conf
|
901
|
+
* Portal::Connection.new.connect("/usr/local/portal/sys/test")
|
902
|
+
*
|
903
|
+
* You can supply the connection information in the request.
|
904
|
+
* This method avoids the need for a pin.conf.
|
905
|
+
* Note that this is a cm_proxy login type, so the password is not needed.
|
906
|
+
* request = {
|
907
|
+
* :PIN_FLD_POID => "0.0.0.1 /service/pcm_client 1",
|
908
|
+
* :PIN_FLD_TYPE => 0,
|
909
|
+
* :PIN_FLD_CM_PTR => {
|
910
|
+
* 0 => { :PIN_FLD_CM_PTR => "ip portal01.prod.example.com 11960"}
|
911
|
+
* 1 => { :PIN_FLD_CM_PTR => "ip portal02.prod.example.com 11960"}
|
912
|
+
* }
|
913
|
+
* Portal::Connection.new.connect(request)
|
914
|
+
*/
|
915
|
+
static VALUE
|
916
|
+
portal_connect(self,obj)
|
917
|
+
VALUE self, obj;
|
918
|
+
{
|
919
|
+
PortalData *pd;
|
920
|
+
pcm_context_t *ctxp = NULL;
|
921
|
+
int64 database;// = 0;
|
922
|
+
static char * cwd = NULL;
|
923
|
+
pin_flist_t *in_flistp = NULL;
|
924
|
+
|
925
|
+
TRACE("Connecting");
|
926
|
+
PDataGet(self,pd);
|
927
|
+
PDataClearErr(pd);
|
928
|
+
|
929
|
+
if (TYPE(obj) == T_NIL ) {
|
930
|
+
PCM_CONNECT(&ctxp,&database,&pd->ebuf);
|
931
|
+
} else if (TYPE(obj) == T_HASH ) {
|
932
|
+
TRACE_INSPECT("Hash of args",obj);
|
933
|
+
in_flistp = portal_hash_to_flist(obj);
|
934
|
+
PCM_CONTEXT_OPEN(&ctxp,in_flistp,&pd->ebuf);
|
935
|
+
PIN_FLIST_DESTROY_EX(&in_flistp, NULL);
|
936
|
+
} else if (TYPE(obj) == T_STRING ) {
|
937
|
+
|
938
|
+
// Only do this once. getwd is not thread smart.
|
939
|
+
if (cwd == NULL ) {
|
940
|
+
cwd = ruby_getcwd();
|
941
|
+
if (cwd == NULL) {
|
942
|
+
rb_raise(ePortalError, "getcwd failed.");
|
943
|
+
}
|
944
|
+
}
|
945
|
+
|
946
|
+
/* Move to that directory */
|
947
|
+
if (chdir(portal_to_char(obj)) < 0) {
|
948
|
+
rb_raise(ePortalError, "Cannot cd to %s",portal_to_char(obj));
|
949
|
+
}
|
950
|
+
|
951
|
+
PCM_CONNECT(&ctxp,&database,&pd->ebuf);
|
952
|
+
|
953
|
+
/* Return to the original directory */
|
954
|
+
if (chdir(cwd) < 0) {
|
955
|
+
rb_raise(ePortalError, "Cannot cd to original dir %s",cwd);
|
956
|
+
}
|
957
|
+
|
958
|
+
} else {
|
959
|
+
rb_raise(ePortalError, "Unable to connect with supplied args.");
|
960
|
+
}
|
961
|
+
|
962
|
+
if (PIN_ERR_IS_ERR(&pd->ebuf)) {
|
963
|
+
TRACE("Bad Connect");
|
964
|
+
pd->ctxp = NULL;
|
965
|
+
if (pd->ebuf.pin_err == PIN_ERR_BAD_LOGIN_RESULT){
|
966
|
+
rb_raise(ePortalError, "Bad login result.");
|
967
|
+
}
|
968
|
+
rb_raise(ePortalError, "Cannot connect.");
|
969
|
+
}
|
970
|
+
TRACE("Connected");
|
971
|
+
pd->ctxp = ctxp;
|
972
|
+
return self;
|
973
|
+
}
|
974
|
+
|
975
|
+
/*
|
976
|
+
* call-seq:
|
977
|
+
* connected? -> true or false
|
978
|
+
*
|
979
|
+
* Returns true is we are connected to Portal. This does not probe the connection.
|
980
|
+
* Use +loopback+ to ping the CM.
|
981
|
+
* ph.connect unless ph.connected?
|
982
|
+
*/
|
983
|
+
static VALUE
|
984
|
+
portal_connected(self)
|
985
|
+
VALUE self;
|
986
|
+
{
|
987
|
+
VALUE result = Qundef;
|
988
|
+
PortalData *pd;
|
989
|
+
PDataGet(self,pd);
|
990
|
+
result = pd->ctxp == NULL ? Qfalse : Qtrue;
|
991
|
+
return result;
|
992
|
+
}
|
993
|
+
|
994
|
+
/*
|
995
|
+
* call-seq:
|
996
|
+
* disconnect
|
997
|
+
*
|
998
|
+
* Disconnect from Portal. This is important to avoid mem leaks.
|
999
|
+
* ph.disconnect() rescue nil
|
1000
|
+
*/
|
1001
|
+
static VALUE
|
1002
|
+
portal_disconnect(self)
|
1003
|
+
VALUE self;
|
1004
|
+
{
|
1005
|
+
PortalData *pd;
|
1006
|
+
PDataGet(self,pd);
|
1007
|
+
TRACE("Disconnecting");
|
1008
|
+
PCM_CONTEXT_CLOSE(pd->ctxp,0,&pd->ebuf);
|
1009
|
+
pd->ctxp = NULL;
|
1010
|
+
TRACE("Disconnected");
|
1011
|
+
return self;
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
static VALUE
|
1015
|
+
portal_initialize(VALUE self)
|
1016
|
+
{
|
1017
|
+
if (rb_gv_get("$DEBUG")){
|
1018
|
+
PIN_ERR_SET_LEVEL(PIN_ERR_LEVEL_DEBUG);
|
1019
|
+
fprintf(stderr,"Portal logging set to debug\n");
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
return self;
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
/*
|
1026
|
+
* Document-class: Portal::Connection
|
1027
|
+
*
|
1028
|
+
* A single connection to Portal. Create a connection to execute opcodes.
|
1029
|
+
* Send Hash that mimics the input FList. The response is a Hash.
|
1030
|
+
* Errors usually result in an exception getting raised.
|
1031
|
+
*
|
1032
|
+
* The connection has the following attributes:
|
1033
|
+
*
|
1034
|
+
* ctxp:: The Portal context for this current connection.
|
1035
|
+
* program_name:: The program name. By default, it is the same name as the Ruby script.
|
1036
|
+
* log_level:: The logging done through the Portal logging interface.
|
1037
|
+
*
|
1038
|
+
*/
|
1039
|
+
|
1040
|
+
/*
|
1041
|
+
* Document-class: Portal::Error
|
1042
|
+
*
|
1043
|
+
* In general, this exception is raise when the ebuf contains errors.
|
1044
|
+
*/
|
1045
|
+
|
1046
|
+
/*
|
1047
|
+
* Document-module: Portal
|
1048
|
+
*
|
1049
|
+
* Helper functions for manipulating and converting data between Ruby and Flist.
|
1050
|
+
*/
|
1051
|
+
void
|
1052
|
+
Init_portalext(void)
|
1053
|
+
{
|
1054
|
+
/* Initialize global IDs */
|
1055
|
+
id_call = rb_intern("call");
|
1056
|
+
id_inspect = rb_intern("inspect");
|
1057
|
+
id_to_f = rb_intern("to_f");
|
1058
|
+
id_to_i = rb_intern("to_i");
|
1059
|
+
id_to_s = rb_intern("to_s");
|
1060
|
+
id_xop = rb_intern("xop");
|
1061
|
+
|
1062
|
+
mPortal = rb_define_module ("Portal");
|
1063
|
+
|
1064
|
+
ePortalError = rb_define_class_under(mPortal, "Error", rb_eStandardError);
|
1065
|
+
|
1066
|
+
PIN_ERR_SET_PROGRAM(portal_to_char(rb_gv_get("$PROGRAM_NAME")));
|
1067
|
+
|
1068
|
+
/*
|
1069
|
+
* Module Portal
|
1070
|
+
*/
|
1071
|
+
rb_define_module_function(mPortal,"field_num", portal_field_num,1);
|
1072
|
+
rb_define_module_function(mPortal,"field_type", portal_field_type,1);
|
1073
|
+
rb_define_module_function(mPortal,"field_name", portal_field_name,1);
|
1074
|
+
rb_define_module_function(mPortal,"set_program_name", portal_set_program_name,1);
|
1075
|
+
rb_define_module_function(mPortal,"set_log_level", portal_set_log_level,1);
|
1076
|
+
rb_define_module_function(mPortal,"hash_to_flist_string", portal_hash_to_flist_string,1);
|
1077
|
+
|
1078
|
+
#ifdef _DEBUG
|
1079
|
+
rb_define_module_function(mPortal,"test_flist_to_hash", portal_test_flist_to_hash,1);
|
1080
|
+
#endif
|
1081
|
+
|
1082
|
+
/*
|
1083
|
+
* Portal::Connection
|
1084
|
+
*/
|
1085
|
+
cContext = rb_define_class_under(mPortal,"Connection", rb_cObject);
|
1086
|
+
rb_define_alloc_func(cContext, portal_alloc);
|
1087
|
+
rb_define_method(cContext, "initialize", portal_initialize, 0);
|
1088
|
+
rb_define_method(cContext, "connect", portal_connect, 1);
|
1089
|
+
rb_define_method(cContext, "connected?", portal_connected, 0);
|
1090
|
+
rb_define_method(cContext, "disconnect", portal_disconnect, 1);
|
1091
|
+
rb_define_method(cContext, "loopback", portal_loopback, 0);
|
1092
|
+
rb_define_method(cContext, "session", portal_get_session, 0);
|
1093
|
+
rb_define_method(cContext, "userid", portal_get_userid, 0);
|
1094
|
+
rb_define_method(cContext, "inspectx", portal_inspect, 0);
|
1095
|
+
rb_define_method(cContext, "robj", portal_robj, -1);
|
1096
|
+
rb_define_method(cContext, "xop", portal_xop, -1);
|
1097
|
+
|
1098
|
+
}
|