I have a two-level Delphi application for Win32 with a lot of business logic implemented in the god object, which I want to transfer to a separate service. This separate service should be accessed by several TCP / IP telnet clients.
How can I make the transition the easiest?
Exactly, I would like to keep this simplicity: I want to define each function only once. For example, if I want to add a PIN entry function to my application, I just need to define
function Login(Username: string; PinCode: integer): boolean;
in any object on the server, then I can use it with clients without additional work.
In the worst case, I have to implement three functions instead of one. Firstly, the function object itself on the server, and secondly, the non-marshaller, which receives a text string from the network, unpacks it and checks for validity:
procedure HandleCommand(Cmd: string; Params: array of string);
begin
...
if SameText(Cmd, 'Login') then begin
CheckParamCount(Params, 2);
ServerObject.Login(
Params[0],
StrToInt(Params[1])
);
end;
end;
Thirdly, the marshaller, which, when calling the client, packs the parameters and sends them to the server:
function TServerConnection.Login(Username: string; PinCode: integer): boolean;
begin
Result := StrToBool(ServerCall('Login '+Escape(Username)+' '+IntToStr(PinCode)));
end;
Obviously, I do not want this.
Until now, I have managed to get rid of the non-partisan. Working with Delphi RTTI, I wrote a universal unmarshaller that looks for a published method by name, checks the parameters, and calls it.
So now I can just add the published method to the server object, and I can call it from telnet:
function Login(Username: string; PinCode: integer): boolean;
> login john_locke
Missing parameter 2 (PinCode: integer)!
? . , - , :
ServerConnection.Call('Login', [Username, Password]);
, , . , .
? , "GetFunctionList()" "GetFunctionPrototype (Name: string)" :
> GetFunctionList
Login
Logout
IsLoggedIn
> GetFunctionPrototype Login
function Login(Username: string; PinCode: integer): boolean;
, , , . : , , . !
- , :
procedure TServerConnection.GenericMarshaller(); assembler;
asm
end;
function TServerConnection.Login(Username: string; PinCode: integer): boolean; assembler;
asm
call GenericMarshaller
end;
, ( ), , -. , , , .
RPC, , IDL. Delphi IDL . OLE Delphi "safecall", . - -, EVERY SINGLE RPC:
function TServerWrapper.Login(Username: string; PinCode: integer): boolean;
begin
try
RealObject.Login(Username, Pincode);
except
on E: EOleException do
if IndicatesDisconnect(E) then
Disconnect;
Reconnect;
RealObject.Login(Username, Pincode);
end;
end;
.
, ? ? Delphi?