Forum > Networking and Web Programming
Help: connecting to google map service using lNet
(1/1)
Leledumbo:
I'm trying to connect to a google map service, but the app hangs in infinite loop. GoogleMapConnector.Connecting is never set to false despite of the TimeOut property I set in the constructor.
--- Code: ---unit wmmain;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, HTTPDefs, websession, fpHTTP,
fpWeb, lHTTP;
type
{ TMainWebModule }
TMainWebModule = class(TFPWebModule)
procedure TFPWebActions0Request(Sender: TObject; ARequest: TRequest;
AResponse: TResponse; var Handled: Boolean);
procedure TFPWebActions1Request(Sender: TObject; ARequest: TRequest;
AResponse: TResponse; var Handled: Boolean);
procedure DataModuleCreate(Sender: TObject);
procedure DataModuleDestroy(Sender: TObject);
function GoogleMapConnectorOnInput(ASocket: TLHTTPClientSocket; ABuffer: pchar; ASize: integer): integer;
procedure GoogleMapConnectorOnDoneInput(ASocket: TLHTTPClientSocket);
private
{ private declarations }
GoogleMapConnector: TLHTTPClient;
ResponseBuf: String;
public
{ public declarations }
end;
var
MainWebModule: TMainWebModule;
implementation
{$R *.lfm}
const
QueryStr = 'restoran';
GoogleAPIKey = 'ABQIAAAAR16qAFe_aeUB7PXwb4ENZxRHYi30yMAYkyoiSwporea1yo0xLRTg3lf_7VNbntYiWxJvDo5nIAW_SA';
{ TMainWebModule }
procedure TMainWebModule.TFPWebActions0Request(Sender: TObject;
ARequest: TRequest; AResponse: TResponse; var Handled: Boolean);
begin
AResponse.Content := '<p>Hello, World 1!</p>';
Handled := true;
end;
procedure TMainWebModule.TFPWebActions1Request(Sender: TObject;
ARequest: TRequest; AResponse: TResponse; var Handled: Boolean);
var
StatusStr: String;
begin
ResponseBuf := '';
if GoogleMapConnector.Connect then begin
while GoogleMapConnector.Connecting do Sleep(100);
AResponse.Content := 'Respon:' +ResponseBuf;
end else begin
Str(GoogleMapConnector.Response.Status,StatusStr);
AResponse.Content := Format('HTTP %s: %s',
[StatusStr,GoogleMapConnector.Response.Reason]);
end;
Handled := true;
end;
procedure TMainWebModule.DataModuleCreate(Sender: TObject);
begin
GoogleMapConnector := TLHTTPClient.Create(Self);
with GoogleMapConnector do begin
Timeout := 10;
Host := 'http://maps.google.com';
Port := 80;
URI := Format('maps/geo?q=%s&output=json&oe=utf8&sensor=false' +
'&key=%s',[QueryStr,GoogleAPIKey]);
OnInput := @Self.GoogleMapConnectorOnInput;
OnDoneInput := @Self.GoogleMapConnectorOnDoneInput;
end;
end;
procedure TMainWebModule.DataModuleDestroy(Sender: TObject);
begin
GoogleMapConnector.Free;
end;
function TMainWebModule.GoogleMapConnectorOnInput(ASocket: TLHTTPClientSocket;
ABuffer: pchar; ASize: integer): integer;
var
TempBuf: String;
begin
SetString(TempBuf,ABuffer,ASize);
ResponseBuf := ResponseBuf + TempBuf;
end;
procedure TMainWebModule.GoogleMapConnectorOnDoneInput(
ASocket: TLHTTPClientSocket);
begin
GoogleMapConnector.Disconnect;
end;
initialization
RegisterHTTPModule('main', TMainWebModule);
end.
--- End code ---
Btw, I'm behind a proxy. Do I need to set up anything?
Platform: i386-win32
Leledumbo:
Solved with Synapse
JD:
I'm glad to know that you got it to work. But I'm of the opinion that Lazarus/FreePascal could do with small sample applications in the following areas
a) Web applications using modern API's - Google, Skype, Amazon, IMDB etc
b) Multitier database applications on LANs, WANs or the Internet
c) Graphics applications
d) Applications interacting with Java, Android, .NET etc
e) Applications showcasing Lazarus/FreePascal's reporting capabilities
In my opinion, these are the things necessary to convince corporate decision makers that Lazarus/FreePascal is not a hobbyist' toy.
To many of us are reinventing the wheel again & again because Lazarus/FreePascal does not have these "gotcha" sample apps. :D
Dibo:
1. lNET works on non-blocking mode. I'm not familiar in messages loop, but I think your loop block lNET callback message in Application main loop. Maybe Application.ProcessMessages solve this problem:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TMainWebModule.TFPWebActions1Request(Sender: TObject; ARequest: TRequest; AResponse: TResponse; var Handled: Boolean);var StatusStr: String;begin ResponseBuf := ''; if GoogleMapConnector.Connect then begin while GoogleMapConnector.Connecting do begin Sleep(100); Application.ProcessMessages; end; AResponse.Content := 'Respon:' +ResponseBuf; end else begin Str(GoogleMapConnector.Response.Status,StatusStr); AResponse.Content := Format('HTTP %s: %s', [StatusStr,GoogleMapConnector.Response.Reason]); end; Handled := true;end;
But I'm not Application.ProcessMessages fan. If you want use non-blocking sockets, you should change your TFPWebModule mechanism logic to non-blocking too. For example - changing TFPWebActions1Request procedure to Event property and call this event in GoogleMapConnectorOnDoneInput
2. I don't know which version of lNET you are using, but Host property was very sensitive for link format (like slash on end of link). In demo, they using DecomposeURL function, which return Host without "http://" prefix (maybe this is your problem). But be careful with this function. I see you are using params in link. DecomposeURL cut this params. So I written own DecomposeURL which include params in link:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---uses URIParser; function TMyLHttpClient.MyDecomposeURL(const URL: string; out Host, URI, Params: string; out Port: Word): Boolean;var uri_rec: TURI;begin Result := True; uri_rec := ParseURI(URL, 'http', 80); Host := uri_rec.Host; URI := uri_rec.Path + uri_rec.Document; Params := uri_rec.Params; Port := uri_rec.Port;end;
Edit:
3. Maybe problem is in response code status. LHTTPClient is fine, but to much "restricted". Each HTTP response code must be implemented in source of LHTTPClient (se lhttp unit and HTTPStatusCodes const). If google return uknown status, lHTTPClient hangs forever (OnDoneInput is never called, no errors etc.). In mantis bugtracker is my patch wich add some new codes, but not accepted yet.
Leledumbo:
--- Quote ---Graphics applications
--- End quote ---
There are some in the application gallery (and many more out there)
--- Quote ---Applications interacting with Java, Android, .NET etc
--- End quote ---
Except for Java, the other has entry in the wiki. I've tried JNI.pas bindings, but it seems outdated and I can't make it to work with current Oracle JDK.
--- Quote ---Applications showcasing Lazarus/FreePascal's reporting capabilities
--- End quote ---
I remember a MRP application in the gallery.
--- Quote ---lNET works on non-blocking mode
--- End quote ---
Yeah, I know that because I previously used it to create a chat application with many connections involved and they run without waiting each other.
--- Quote ---But I'm not Application.ProcessMessages fan. If you want use non-blocking sockets, you should change your TFPWebModule mechanism logic to non-blocking too
--- End quote ---
That seems a little inconvenient %)
--- Quote ---I don't know which version of lNET you are using
--- End quote ---
0.6.4
--- Quote ---DecomposeURL cut this params. So I written own DecomposeURL which include params in link
--- End quote ---
I haven't tried to print each host, port and uri from DecomposeURL myself. But if it really cuts that, well... that's disappointing.
--- Quote ---Maybe problem is in response code status. LHTTPClient is fine, but to much "restricted". Each HTTP response code must be implemented in source of LHTTPClient (se lhttp unit and HTTPStatusCodes const). If google return uknown status, lHTTPClient hangs forever (OnDoneInput is never called, no errors etc.). In mantis bugtracker is my patch wich add some new codes, but not accepted yet.
--- End quote ---
Actually, that's not it. My biggest problem is that I NEVER call SendRequest and in the waiting loop I NEVER call CallAction. After that, I believe it works. But since I have to pass through a proxy, it still fails. That's why I moved to Synapse. Plus, the code is much shorter now. A lesson learned: not every problem can be solved with component based approach easily.
Navigation
[0] Message Index