Recent

Author Topic: Help: connecting to google map service using lNet  (Read 9696 times)

Leledumbo

  • Hero Member
  • *****
  • Posts: 8717
  • Programming + Glam Metal + Tae Kwon Do = Me
Help: connecting to google map service using lNet
« on: December 17, 2010, 11:15:39 am »
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: [Select]
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.
Btw, I'm behind a proxy. Do I need to set up anything?
Platform: i386-win32

Leledumbo

  • Hero Member
  • *****
  • Posts: 8717
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Help: connecting to google map service using lNet
« Reply #1 on: December 17, 2010, 01:59:37 pm »
Solved with Synapse

JD

  • Hero Member
  • *****
  • Posts: 1847
Re: Help: connecting to google map service using lNet
« Reply #2 on: December 17, 2010, 02:32:35 pm »
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
« Last Edit: December 17, 2010, 02:34:31 pm by JD »
Windows (10) - Lazarus 2.1/FPC 3.2 (svn 64160 built using fpcupdeluxe),
Linux Mint - Lazarus 2.1/FPC 3.2 (svn 64380 built using fpcupdeluxe),
Delphi

Indy 10.6 series; mORMot; Zeos 7.3; SQLite, Firebird, PostgreSQL & MariaDB; VirtualTreeView 5.5.3 R1

Dibo

  • Hero Member
  • *****
  • Posts: 1048
Re: Help: connecting to google map service using lNet
« Reply #3 on: December 17, 2010, 02:33:06 pm »
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  [Select][+][-]
  1. procedure TMainWebModule.TFPWebActions1Request(Sender: TObject;
  2.   ARequest: TRequest; AResponse: TResponse; var Handled: Boolean);
  3. var
  4.   StatusStr: String;
  5. begin
  6.   ResponseBuf := '';
  7.   if GoogleMapConnector.Connect then begin
  8.     while GoogleMapConnector.Connecting do
  9.     begin
  10.       Sleep(100);
  11.       Application.ProcessMessages;
  12.     end;
  13.     AResponse.Content := 'Respon:' +ResponseBuf;
  14.   end else begin
  15.     Str(GoogleMapConnector.Response.Status,StatusStr);
  16.     AResponse.Content := Format('HTTP %s: %s',
  17.       [StatusStr,GoogleMapConnector.Response.Reason]);
  18.   end;
  19.   Handled := true;
  20. 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  [Select][+][-]
  1. uses URIParser;
  2.  
  3. function TMyLHttpClient.MyDecomposeURL(const URL: string; out Host, URI,
  4.   Params: string; out Port: Word): Boolean;
  5. var
  6.   uri_rec: TURI;
  7. begin
  8.   Result := True;
  9.   uri_rec := ParseURI(URL, 'http', 80);
  10.   Host := uri_rec.Host;
  11.   URI := uri_rec.Path + uri_rec.Document;
  12.   Params := uri_rec.Params;
  13.   Port := uri_rec.Port;
  14. end;  
  15.  

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.
« Last Edit: December 17, 2010, 02:43:23 pm by Dibo »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8717
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Help: connecting to google map service using lNet
« Reply #4 on: December 18, 2010, 04:58:59 pm »
Quote
Graphics applications
There are some in the application gallery (and many more out there)
Quote
Applications interacting with Java, Android, .NET etc
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
I remember a MRP application in the gallery.
Quote
lNET works on non-blocking mode
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
That seems a little inconvenient %)
Quote
I don't know which version of lNET you are using
0.6.4
Quote
DecomposeURL cut this params. So I written own DecomposeURL which include params in link
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.
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.
« Last Edit: December 18, 2010, 05:02:29 pm by Leledumbo »

 

TinyPortal © 2005-2018