unit sock_ls;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Sockets,
blcksock,
fpjson, jsonparser,
strutils;
type
TPassMessage = procedure(AMsg: string) of object;
type
TQSockListen = class(TThread)
private
_PassMessage: TPassMessage;
_MainSocket: word;
_IAddr: TINetSockAddr; //internet address, needs Sockets unit
_ASocket: integer;
_RequestBody: string;
procedure Connect;
procedure sockRead;
procedure sockWrite();
function Rfc822DateTime(t: TDateTime): string;
protected
procedure Execute; override;
procedure TriggerMessage(AMsg: string);
public
constructor Create(APort: cardinal; AIP: string); reintroduce;
destructor Destroy(); override;
property OnPassMessage: TPassMessage read _PassMessage write _PassMessage;
end;
implementation
const
packet_size = 10485760;
constructor TQSockListen.Create(APort: cardinal; AIP: string);
begin
inherited Create(False);
self.FreeOnTerminate := True;
_MainSocket := fpsocket(AF_INET, SOCK_STREAM, 0);
_IAddr.sin_family := AF_INET;
_IAddr.sin_port := htons(APort);
_IAddr.sin_addr.s_addr := longword(StrToNetAddr(AIP));
fpbind(_MainSocket, @_IAddr, SizeOf(_IAddr));
fplisten(_MainSocket, 1);
end;
procedure TQSockListen.Execute;
begin
while not Terminated do
begin
Connect;
sockRead;
sockWrite;
{closing socket}
if _ASocket > 0 then
begin
CloseSocket(_ASocket);
end;
end;
end;
procedure TQSockListen.Connect;
var
sAddrSize: longint;
begin
try
sAddrSize := SizeOf(_IAddr);
_ASocket := fpaccept(_MainSocket, @_IAddr, @sAddrSize);
except
on E: Exception do
TriggerMessage('TQSocket.Connect: Error ' + E.Message);
end;
end;
procedure TQSockListen.sockRead;
var
buf: string;
c: integer;
j: TJSONData;
json: string;
begin
try
setLength(buf, packet_size);
c := fprecv(_ASocket, PChar(buf), packet_size, 0);
setLength(buf, c);
_RequestBody := buf;
writeln(_RequestBody);
writeln('--------- end: ' + FormatDateTime('hh:nn:ss.zzz', Now()) + '----------');
TriggerMessage('TQSocket.sRead: request body length: ' + IntToStr(Length(_RequestBody)) + sLineBreak + 'start|' + sLineBreak + _RequestBody + sLineBreak + '|end');
try
{verify body has left bracket}
if AnsiContainsStr(_RequestBody, '{') then
begin
json := Copy(_RequestBody, Pos('{', _RequestBody), Length(_RequestBody));
j := GetJSON(json);
TriggerMessage('JSON parsed : ' + json);
end;
except
on E: Exception do
begin
writeln('JSON conversion failed');
TriggerMessage('position of {: ' + IntToStr(Pos('{', _RequestBody)));
TriggerMessage('JSON conversion failed with error: ' + E.Message);
end;
end;
FreeAndNil(j);
except
on E: Exception do
TriggerMessage('TQSocket.sRead: Error ' + E.Message);
end;
end;
procedure TQSockListen.sockWrite();
var
resp: string;
begin
try
resp := 'HTTP/1.0 200' + CRLF;
fpsend(_ASocket, PChar(resp), Length(resp), 0);
resp := 'Content-type: Text/Html' + CRLF;
fpsend(_ASocket, PChar(resp), Length(resp), 0);
resp := 'Content-length: 0' + CRLF;
fpsend(_ASocket, PChar(resp), Length(resp), 0);
resp := 'Connection: close' + CRLF;
fpsend(_ASocket, PChar(resp), Length(resp), 0);
resp := 'Date: ' + Rfc822DateTime(now) + CRLF;
fpsend(_ASocket, PChar(resp), Length(resp), 0);
resp := 'Server: Lazarus Synapse' + CRLF;
fpsend(_ASocket, PChar(resp), Length(resp), 0);
resp := '' + CRLF;
fpsend(_ASocket, PChar(resp), Length(resp), 0);
except
on E: Exception do
TriggerMessage('TQSocket.sWrite: Error ' + E.Message);
end;
end;
procedure TQSockListen.TriggerMessage(AMsg: string);
begin
if Assigned(_PassMessage) then
_PassMessage(AMsg);
end;
function TQSockListen.Rfc822DateTime(t: TDateTime): string;
var
wYear, wMonth, wDay: word;
const
MyDayNames: array[1..7] of ansistring = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
MyMonthNames: array[1..12] of ansistring = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
begin
DecodeDate(t, wYear, wMonth, wDay);
Result := Format('%s, %d %s %s %s', [MyDayNames[DayOfWeek(t)], wDay, MyMonthNames[wMonth], FormatDateTime('yyyy hh":"nn":"ss', t), '+0200']);
end;
destructor TQSockListen.Destroy();
begin
inherited Destroy;
end;
end.