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

Go to full version