source: cprs/branches/foia-cprs/CPRS-Lib/ORNet.pas@ 459

Last change on this file since 459 was 459, checked in by Kevin Toppenberg, 16 years ago

Adding foia-cprs branch

File size: 16.4 KB
Line 
1unit ORNet;
2
3interface
4
5uses SysUtils, Windows, Classes, Forms, Controls, ORFn, TRPCB, RPCConf1, Dialogs; //, SharedRPCBroker;
6
7procedure SetBrokerServer(const AName: string; APort: Integer; WantDebug: Boolean);
8function AuthorizedOption(const OptionName: string): Boolean;
9function ConnectToServer(const OptionName: string): Boolean;
10function MRef(glvn: string): string;
11procedure CallV(const RPCName: string; const AParam: array of const);
12function sCallV(const RPCName: string; const AParam: array of const): string;
13procedure tCallV(ReturnData: TStrings; const RPCName: string; const AParam: array of const);
14function UpdateContext(NewContext: string): boolean;
15function IsBaseContext: boolean;
16procedure CallBrokerInContext;
17procedure CallBroker;
18function RetainedRPCCount: Integer;
19procedure SetRetainedRPCMax(Value: Integer);
20function GetRPCMax: integer;
21procedure LoadRPCData(Dest: TStrings; ID: Integer);
22function DottedIPStr: string;
23procedure CallRPCWhenIdle(CallProc: TORIdleCallProc; Msg: String);
24
25procedure EnsureBroker;
26
27(*
28function pCallV(const RPCName: string; const AParam: array of const): PChar;
29procedure wCallV(AControl: TControl; const RPCName: string; const AParam: array of const);
30procedure WrapWP(Buf: pChar);
31*)
32
33var
34 //RPCBrokerV: TSharedRPCBroker; // an RPC Broker object - used by all calls
35 RPCBrokerV: TRPCBroker;
36 RPCLastCall: string;
37
38implementation
39
40uses Winsock;
41
42const
43 // *** these are constants from RPCBErr.pas, will broker document them????
44 XWB_M_REJECT = 20000 + 2; // M error
45 XWB_BadSignOn = 20000 + 4; // SignOn 'Error' (happens when cancel pressed)
46
47var
48 uCallList: TList;
49 uMaxCalls: Integer;
50 uShowRPCs: Boolean;
51 uBaseContext: string = '';
52 uCurrentContext: string = '';
53
54{ private procedures and functions ---------------------------------------------------------- }
55
56procedure EnsureBroker;
57{ ensures that a broker object has been created - creates & initializes it if necessary }
58begin
59 if RPCBrokerV = nil then
60 begin
61 //RPCBrokerV := TSharedRPCBroker.Create(Application);
62 RPCBrokerV := TRPCBroker.Create(Application);
63 with RPCBrokerV do
64 begin
65 KernelLogIn := True;
66 Login.Mode := lmAppHandle;
67 ClearParameters := True;
68 ClearResults := True;
69 DebugMode := False;
70 end;
71 end;
72end;
73
74procedure SetList(AStringList: TStrings; ParamIndex: Integer);
75{ places TStrings into RPCBrokerV.Mult[n], where n is a 1-based (not 0-based) index }
76var
77 i: Integer;
78begin
79 with RPCBrokerV.Param[ParamIndex] do
80 begin
81 PType := list;
82 with AStringList do for i := 0 to Count - 1 do Mult[IntToStr(i+1)] := Strings[i];
83 end;
84end;
85
86procedure SetParams(const RPCName: string; const AParam: array of const);
87{ takes the params (array of const) passed to xCallV and sets them into RPCBrokerV.Param[i] }
88const
89 BoolChar: array[boolean] of char = ('0', '1');
90var
91 i: integer;
92 TmpExt: Extended;
93begin
94 RPCLastCall := RPCName + ' (SetParam begin)';
95 if Length(RPCName) = 0 then raise Exception.Create('No RPC Name');
96 EnsureBroker;
97 with RPCBrokerV do
98 begin
99 ClearParameters := True;
100 RemoteProcedure := RPCName;
101 for i := 0 to High(AParam) do with AParam[i] do
102 begin
103 Param[i].PType := literal;
104 case VType of
105 vtInteger: Param[i].Value := IntToStr(VInteger);
106 vtBoolean: Param[i].Value := BoolChar[VBoolean];
107 vtChar: if VChar = #0 then
108 Param[i].Value := ''
109 else
110 Param[i].Value := VChar;
111 //vtExtended: Param[i].Value := FloatToStr(VExtended^);
112 vtExtended: begin
113 TmpExt := VExtended^;
114 if(abs(TmpExt) < 0.0000000000001) then TmpExt := 0;
115 Param[i].Value := FloatToStr(TmpExt);
116 end;
117 vtString: with Param[i] do
118 begin
119 Value := VString^;
120 if (Length(Value) > 0) and (Value[1] = #1) then
121 begin
122 Value := Copy(Value, 2, Length(Value));
123 PType := reference;
124 end;
125 end;
126 vtPChar: Param[i].Value := StrPas(VPChar);
127 vtPointer: if VPointer = nil
128 then ClearParameters := True {Param[i].PType := null}
129 else raise Exception.Create('Pointer type must be nil.');
130 vtObject: if VObject is TStrings then SetList(TStrings(VObject), i);
131 vtAnsiString: with Param[i] do
132 begin
133 Value := string(VAnsiString);
134 if (Length(Value) > 0) and (Value[1] = #1) then
135 begin
136 Value := Copy(Value, 2, Length(Value));
137 PType := reference;
138 end;
139 end;
140 vtInt64: Param[i].Value := IntToStr(VInt64^);
141 else raise Exception.Create('Unable to pass parameter type to Broker.');
142 end; {case}
143 end; {for}
144 end; {with}
145 RPCLastCall := RPCName + ' (SetParam end)';
146end;
147
148{ public procedures and functions ----------------------------------------------------------- }
149
150function UpdateContext(NewContext: string): boolean;
151begin
152 if NewContext = uCurrentContext then
153 Result := TRUE
154 else
155 begin
156 Result := RPCBrokerV.CreateContext(NewContext);
157 if Result then
158 uCurrentContext := NewContext
159 else
160 if (NewContext <> uBaseContext) and RPCBrokerV.CreateContext(uBaseContext) then
161 uCurrentContext := uBaseContext
162 else
163 uCurrentContext := '';
164 end;
165end;
166
167function IsBaseContext: boolean;
168begin
169 Result := ((uCurrentContext = uBaseContext) or (uCurrentContext = ''));
170end;
171
172procedure CallBrokerInContext;
173var
174 AStringList: TStringList;
175 i, j: Integer;
176 x, y: string;
177begin
178 RPCLastCall := RPCBrokerV.RemoteProcedure + ' (CallBroker begin)';
179 if uShowRPCs then StatusText(RPCBrokerV.RemoteProcedure);
180 with RPCBrokerV do if not Connected then // happens if broker connection is lost
181 begin
182 ClearResults := True;
183 Exit;
184 end;
185 if uCallList.Count = uMaxCalls then
186 begin
187 AStringList := uCallList.Items[0];
188 AStringList.Free;
189 uCallList.Delete(0);
190 end;
191 AStringList := TStringList.Create;
192 AStringList.Add(RPCBrokerV.RemoteProcedure);
193 if uCurrentContext <> uBaseContext then
194 AStringList.Add('Context: ' + uCurrentContext);
195 AStringList.Add(' ');
196 AStringList.Add('Params ------------------------------------------------------------------');
197 with RPCBrokerV do for i := 0 to Param.Count - 1 do
198 begin
199 case Param[i].PType of
200 //global: x := 'global';
201 list: x := 'list';
202 literal: x := 'literal';
203 //null: x := 'null';
204 reference: x := 'reference';
205 undefined: x := 'undefined';
206 //wordproc: x := 'wordproc';
207 end;
208 AStringList.Add(x + #9 + Param[i].Value);
209 if Param[i].PType = list then
210 begin
211 for j := 0 to Param[i].Mult.Count - 1 do
212 begin
213 x := Param[i].Mult.Subscript(j);
214 y := Param[i].Mult[x];
215 AStringList.Add(#9 + '(' + x + ')=' + y);
216 end;
217 end;
218 end; {with...for}
219 //RPCBrokerV.Call;
220 try
221 RPCBrokerV.Call;
222 except
223 // The broker erroneously sets connected to false if there is any error (including an
224 // error on the M side). It should only set connection to false if there is no connection.
225 on E:EBrokerError do
226 begin
227 if E.Code = XWB_M_REJECT then
228 begin
229 x := 'An error occurred on the server.' + CRLF + CRLF + E.Action;
230 Application.MessageBox(PChar(x), 'Server Error', MB_OK);
231 end
232 else raise;
233 (*
234 case E.Code of
235 XWB_M_REJECT: begin
236 x := 'An error occurred on the server.' + CRLF + CRLF + E.Action;
237 Application.MessageBox(PChar(x), 'Server Error', MB_OK);
238 end;
239 else begin
240 x := 'An error occurred with the network connection.' + CRLF +
241 'Action was: ' + E.Action + CRLF + 'Code was: ' + E.Mnemonic +
242 CRLF + CRLF + 'Application cannot continue.';
243 Application.MessageBox(PChar(x), 'Network Error', MB_OK);
244 end;
245 end;
246 *)
247 // make optional later...
248 if not RPCBrokerV.Connected then Application.Terminate;
249 end;
250 end;
251 AStringList.Add(' ');
252 AStringList.Add('Results -----------------------------------------------------------------');
253 AStringList.AddStrings(RPCBrokerV.Results);
254 uCallList.Add(AStringList);
255 if uShowRPCs then StatusText('');
256 RPCLastCall := RPCBrokerV.RemoteProcedure + ' (completed)';
257end;
258
259procedure CallBroker;
260begin
261 UpdateContext(uBaseContext);
262 CallBrokerInContext;
263end;
264
265procedure SetBrokerServer(const AName: string; APort: Integer; WantDebug: Boolean);
266{ makes the initial connection to a server }
267begin
268 EnsureBroker;
269 with RPCBrokerV do
270 begin
271 Server := AName;
272 if APort > 0 then ListenerPort := APort;
273 DebugMode := WantDebug;
274 Connected := True;
275 end;
276end;
277
278function AuthorizedOption(const OptionName: string): Boolean;
279{ checks to see if the user is authorized to use this application }
280begin
281 EnsureBroker;
282 Result := RPCBrokerV.CreateContext(OptionName);
283 if Result then
284 begin
285 if (uBaseContext = '') then
286 uBaseContext := OptionName;
287 uCurrentContext := OptionName;
288 end;
289end;
290
291function ConnectToServer(const OptionName: string): Boolean;
292{ establish initial connection to server using optional command line parameters and check that
293 this application (option) is allowed for this user }
294var
295 WantDebug: Boolean;
296 AServer, APort, x: string;
297 i, ModalResult: Integer;
298begin
299 Result := False;
300 WantDebug := False;
301 AServer := '';
302 APort := '';
303 for i := 1 to ParamCount do // params may be: S[ERVER]=hostname P[ORT]=port DEBUG
304 begin
305 if UpperCase(ParamStr(i)) = 'DEBUG' then WantDebug := True;
306 if UpperCase(ParamStr(i)) = 'SHOWRPCS' then uShowRPCs := True;
307 x := UpperCase(Piece(ParamStr(i), '=', 1));
308 if (x = 'S') or (x = 'SERVER') then AServer := Piece(ParamStr(i), '=', 2);
309 if (x = 'P') or (x = 'PORT') then APort := Piece(ParamStr(i), '=', 2);
310 end;
311 if (AServer = '') or (APort = '') then
312 begin
313 ModalResult := GetServerInfo(AServer, APort);
314 if ModalResult = mrCancel then Exit;
315 end;
316 // use try..except to work around errors in the Broker SignOn screen
317 try
318 SetBrokerServer(AServer, StrToIntDef(APort, 9200), WantDebug);
319 Result := AuthorizedOption(OptionName);
320 if Result then Result := RPCBrokerV.Connected;
321 RPCBrokerV.RPCTimeLimit := 300;
322 except
323 on E:EBrokerError do
324 begin
325 if E.Code <> XWB_BadSignOn then InfoBox(E.Message, 'Error', MB_OK or MB_ICONERROR);
326 Result := False;
327 end;
328 end;
329end;
330
331function MRef(glvn: string): string;
332{ prepends ASCII 1 to string, allows SetParams to interpret as an M reference }
333begin
334 Result := #1 + glvn;
335end;
336
337procedure CallV(const RPCName: string; const AParam: array of const);
338{ calls the broker leaving results in results property which must be read by caller }
339var
340 SavedCursor: TCursor;
341begin
342 SavedCursor := Screen.Cursor;
343 Screen.Cursor := crHourGlass;
344 SetParams(RPCName, AParam);
345 CallBroker; //RPCBrokerV.Call;
346 Screen.Cursor := SavedCursor;
347end;
348
349function sCallV(const RPCName: string; const AParam: array of const): string;
350{ calls the broker and returns a scalar value. }
351var
352 SavedCursor: TCursor;
353begin
354 SavedCursor := Screen.Cursor;
355 Screen.Cursor := crHourGlass;
356 SetParams(RPCName, AParam);
357 CallBroker; //RPCBrokerV.Call;
358 if RPCBrokerV.Results.Count > 0 then Result := RPCBrokerV.Results[0] else Result := '';
359 Screen.Cursor := SavedCursor;
360end;
361
362procedure tCallV(ReturnData: TStrings; const RPCName: string; const AParam: array of const);
363{ calls the broker and returns TStrings data }
364var
365 SavedCursor: TCursor;
366begin
367 if ReturnData = nil then raise Exception.Create('TString not created');
368 SavedCursor := Screen.Cursor;
369 Screen.Cursor := crHourGlass;
370 SetParams(RPCName, AParam);
371 CallBroker; //RPCBrokerV.Call;
372 ReturnData.Assign(RPCBrokerV.Results);
373 Screen.Cursor := SavedCursor;
374end;
375
376(* uncomment if these are needed -
377
378function pCallV(const RPCName: string; const AParam: array of const): PChar;
379{ Calls the Broker. Result is a PChar containing raw Broker data. }
380{ -- Caller must dispose the string that is returned -- }
381var
382 SavedCursor: TCursor;
383begin
384 SavedCursor := Screen.Cursor;
385 Screen.Cursor := crHourGlass;
386 SetParams(RPCName, AParam);
387 RPCBrokerV.Call;
388 pCallV := StrNew(RPCBrokerV.Results.GetText);
389 Screen.Cursor := SavedCursor;
390end;
391
392procedure wCallV(AControl: TControl; const RPCName: string; const AParam: array of const);
393{ Calls the Broker. Places data into control (wrapped). }
394var
395 BufPtr: PChar;
396begin
397 BufPtr := pCallV(RPCName, AParam);
398 WrapWP(BufPtr);
399 AControl.SetTextBuf(BufPtr);
400 StrDispose(BufPtr);
401end;
402
403procedure WrapWP(Buf: pChar);
404{ Iterates through Buf and wraps text in the same way that FM wraps text. }
405var
406 PSub: PChar;
407begin
408 PSub := StrScan(Buf, #13);
409 while PSub <> nil do
410 begin
411 if Ord(PSub[2]) > 32 then
412 begin
413 StrMove(PSub, PSub + SizeOf(Char), StrLen(PSub));
414 PSub[0] := #32;
415 end
416 else repeat Inc(PSub, SizeOf(Char)) until (Ord(PSub[0]) > 32) or (PSub = StrEnd(PSub));
417 PSub := StrScan(PSub, #13);
418 end;
419end;
420
421*)
422
423function RetainedRPCCount: Integer;
424begin
425 Result := uCallList.Count;
426end;
427
428procedure SetRetainedRPCMax(Value: Integer);
429begin
430 if Value > 0 then uMaxCalls := Value;
431end;
432
433function GetRPCMax: integer;
434begin
435 Result := uMaxCalls;
436end;
437
438procedure LoadRPCData(Dest: TStrings; ID: Integer);
439begin
440 if (ID > -1) and (ID < uCallList.Count) then Dest.Assign(TStringList(uCallList.Items[ID]));
441end;
442
443function DottedIPStr: string;
444{ return the IP address of the local machine as a string in dotted form: nnn.nnn.nnn.nnn }
445const
446 WINSOCK1_1 = $0101; // minimum required version of WinSock
447 SUCCESS = 0; // value returned by WinSock functions if no error
448var
449 //WSAData: TWSAData; // structure to hold startup information
450 HostEnt: PHostEnt; // pointer to Host Info structure (see WinSock 1.1, page 60)
451 IPAddr: PInAddr; // pointer to IP address in network order (4 bytes)
452 LocalName: array[0..255] of Char; // buffer for the name of the client machine
453begin
454 Result := 'No IP Address';
455 // ensure the Winsock DLL has been loaded (should be if there is a broker connection)
456 //if WSAStartup(WINSOCK1_1, WSAData) <> SUCCESS then Exit;
457 //try
458 // get the name of the client machine
459 if gethostname(LocalName, SizeOf(LocalName) - 1) <> SUCCESS then Exit;
460 // get information about the client machine (contained in a record of type THostEnt)
461 HostEnt := gethostbyname(LocalName);
462 if HostEnt = nil then Exit;
463 // get a pointer to the four bytes that contain the IP address
464 // Dereference HostEnt to get the THostEnt record. In turn, dereference the h_addr_list
465 // field to get a pointer to the IP address. The pointer to the IP address is type PChar,
466 // so it needs to be typecast as PInAddr in order to make the call to inet_ntoa.
467 IPAddr := PInAddr(HostEnt^.h_addr_list^);
468 // Dereference IPAddr (which is a PChar typecast as PInAddr) to get the 4 bytes that need
469 // to be passed to inet_ntoa. A string with the IP address in dotted format is returned.
470 Result := inet_ntoa(IPAddr^);
471 //finally
472 // causes the reference counter in Winsock (set by WSAStartup, above) to be decremented
473 //WSACleanup;
474 //end;
475end;
476
477procedure RPCIdleCallDone(Msg: string);
478begin
479 RPCBrokerV.ClearResults := True;
480end;
481
482procedure CallRPCWhenIdle(CallProc: TORIdleCallProc; Msg: String);
483begin
484 CallWhenIdleNotifyWhenDone(CallProc, RPCIdleCallDone, Msg);
485end;
486
487initialization
488 RPCBrokerV := nil;
489 RPCLastCall := 'No RPCs called';
490 uCallList := TList.Create;
491 uMaxCalls := 10;
492 uShowRPCs := False;
493
494finalization
495 while uCallList.Count > 0 do
496 begin
497 TStringList(uCallList.Items[0]).Free;
498 uCallList.Delete(0);
499 end;
500 uCallList.Free;
501
502end.
Note: See TracBrowser for help on using the repository browser.