fpc/utils/fppkg/pkglnet.pp
2017-06-18 21:54:42 +00:00

185 lines
4.3 KiB
ObjectPascal

{$mode objfpc}
{$h+}
unit pkglnet;
interface
uses
SysUtils, Classes,
uriparser,
lnet, lftp, lhttp, pkgdownload,pkgoptions, fprepos;
Type
{ TLNetDownloader }
TLNetDownloader = Class(TBaseDownloader)
private
FQuit: Boolean;
FFTP: TLFTPClient;
FHTTP: TLHTTPClient;
FOutStream: TStream;
URI: TURI;
protected
// callbacks
function OnHttpClientInput(ASocket: TLHTTPClientSocket; ABuffer: pchar;
ASize: Integer): Integer;
procedure OnLNetDisconnect(aSocket: TLSocket);
procedure OnHttpDoneInput(aSocket: TLHTTPClientSocket);
procedure OnLNetError(const msg: string; aSocket: TLSocket);
procedure OnFTPControl(aSocket: TLSocket);
procedure OnFTPReceive(aSocket: TLSocket);
procedure OnFTPSuccess(aSocket: TLSocket; const aStatus: TLFTPStatus);
procedure OnFTPFailure(aSocket: TLSocket; const aStatus: TLFTPStatus);
// overrides
function FTPDownload(Const URL : String; Dest : TStream): Boolean; override;
function HTTPDownload(Const URL: String; Dest: TStream): Boolean; override;
public
constructor Create(AOwner : TComponent); override;
end;
implementation
uses
pkgglobals,
pkgmessages;
{ TLNetDownloader }
function TLNetDownloader.OnHttpClientInput(ASocket: TLHTTPClientSocket;
ABuffer: pchar; ASize: Integer): Integer;
begin
Result:=FOutStream.Write(aBuffer[0], aSize);
end;
procedure TLNetDownloader.OnLNetDisconnect(aSocket: TLSocket);
begin
FQuit:=True;
end;
procedure TLNetDownloader.OnHttpDoneInput(aSocket: TLHTTPClientSocket);
begin
ASocket.Disconnect;
FQuit:=True;
end;
procedure TLNetDownloader.OnLNetError(const msg: string; aSocket: TLSocket);
begin
Error(msg);
FQuit:=True;
end;
procedure TLNetDownloader.OnFTPControl(aSocket: TLSocket);
var
s: string;
begin
FFTP.GetMessage(s); // have to empty OS buffer, write the info if you wish to debug
end;
procedure TLNetDownloader.OnFTPReceive(aSocket: TLSocket);
const
BUF_SIZE = 65536; // standard OS recv buffer size
var
Buf: array[1..BUF_SIZE] of Byte;
begin
FOutStream.Write(Buf[1], FFTP.GetData(Buf[1], BUF_SIZE));
end;
procedure TLNetDownloader.OnFTPSuccess(aSocket: TLSocket;
const aStatus: TLFTPStatus);
begin
FFTP.Disconnect;
FQuit:=True;
end;
procedure TLNetDownloader.OnFTPFailure(aSocket: TLSocket;
const aStatus: TLFTPStatus);
begin
FFTP.Disconnect;
Error(SErrDownloadFailed,['FTP',EncodeURI(URI),'']);
FQuit:=True;
end;
function TLNetDownloader.FTPDownload(Const URL: String; Dest: TStream): Boolean;
begin
Result := False;
FOutStream:=Dest;
Try
{ parse URL }
URI:=ParseURI(URL);
if URI.Port = 0 then
URI.Port := 21;
FFTP.Connect(URI.Host, URI.Port);
while not FFTP.Connected and not FQuit do
FFTP.CallAction;
if not FQuit then begin
Result := FFTP.Authenticate(URI.Username, URI.Password);
if Result then
Result := FFTP.ChangeDirectory(URI.Path);
if Result then
Result := FFTP.Retrieve(URI.Document);
while not FQuit do
FFTP.CallAction;
end;
finally
FOutStream:=nil;
end;
end;
function TLNetDownloader.HTTPDownload(Const URL: String; Dest: TStream): Boolean;
begin
Result := False;
FOutStream:=Dest;
Try
{ parse aURL }
URI := ParseURI(URL);
if URI.Port = 0 then
URI.Port := 80;
FHTTP.Host := URI.Host;
FHTTP.Method := hmGet;
FHTTP.Port := URI.Port;
FHTTP.URI := URI.Path + URI.Document;
FHTTP.SendRequest;
FQuit:=False;
while not FQuit do
FHTTP.CallAction;
if FHTTP.Response.Status<>HSOK then
Error(SErrDownloadFailed,['HTTP',EncodeURI(URI),FHTTP.Response.Reason])
else
Result := True;
Finally
FOutStream:=nil; // to be sure
end;
end;
constructor TLNetDownloader.Create(AOwner: TComponent);
begin
inherited;
FFTP:=TLFTPClient.Create(Self);
FFTP.Timeout:=1000;
FFTP.StatusSet:=[fsRetr]; // watch for success/failure of retreives only
FFTP.OnError:=@OnLNetError;
FFTP.OnControl:=@OnFTPControl;
FFTP.OnReceive:=@OnFTPReceive;
FFTP.OnSuccess:=@OnFTPSuccess;
FFTP.OnFailure:=@OnFTPFailure;
FHTTP:=TLHTTPClient.Create(Self);
FHTTP.Timeout := 1000; // go by 1s times if nothing happens
FHTTP.OnDisconnect := @OnLNetDisconnect;
FHTTP.OnDoneInput := @OnHttpDoneInput;
FHTTP.OnError := @OnLNetError;
FHTTP.OnInput := @OnHttpClientInput;
end;
initialization
RegisterDownloader('lnet',TLNetDownloader);
end.