unit LogServer;

interface
  uses Windows, Classes;

  type TOnMessageCallback = function(
    context : Pointer;
    msg : PAnsiChar;
    msg_len : NativeUInt;
    reply : PAnsiChar;
    reply_buf_len : NativeUInt) : NativeUInt stdcall;

  function on_message_callback(
    context : Pointer;
    msg : PAnsiChar;
    msg_len : NativeUInt;
    reply : PAnsiChar;
    reply_buf_len : NativeUInt) : NativeUInt stdcall;

  type TLogServer = class
  private
    var _dll : THandle;
    var _create_log_server : function(cb : TOnMessageCallback; context : Pointer; port : Integer; enable_v6 : Byte) : Pointer stdcall;
    var _destroy_log_server : procedure(obj : Pointer) stdcall;
    var _server : Pointer;
  public
    constructor Create;
    destructor Destroy; override;

    function Start(port:Integer; enable_v6: Boolean) : Boolean;
    procedure Stop();

    var OnMessage: procedure(msg : PAnsiChar; msg_len : NativeUInt; reply : PAnsiChar; var reply_len : NativeUInt) of object;
  end;

implementation

constructor TLogServer.Create;
begin
  _server := nil;

  _dll := LoadLibrary(
    {$IFDEF WIN32} 'x86\LogServerNative.dll' {$ENDIF}
    {$IFDEF WIN64} 'x64\LogServerNative.dll' {$ENDIF});

  if _dll <> 0 then
  begin
    @_create_log_server := GetProcAddress(_dll, 'create_log_server');
    @_destroy_log_server := GetProcAddress(_dll, 'stop_log_server');
  end;
end;

destructor TLogServer.Destroy;
begin
  if _dll <> 0 then
  begin
    FreeLibrary(_dll);
    _dll := 0;
  end;
end;

function TLogServer.Start(port: Integer; enable_v6: Boolean) : Boolean;
  var v6 : Byte;
begin
  if not assigned(_create_log_server) or not assigned(@_destroy_log_server) then
  begin
    start := false;
    exit;
  end;

  stop;

  if enable_v6 then v6 := 1 else v6 := 0;

  _server := _create_log_server(on_message_callback, self, port, v6);
  if _server = nil then
  begin
    start := false;
    exit;
  end;

  start := true;
end;

procedure TLogServer.Stop();
begin
  if _server <> nil then
  begin
    _destroy_log_server(_server);
    _server := nil;
  end;
end;

function on_message_callback(
  context : Pointer;
  msg : PAnsiChar;
  msg_len : NativeUInt;
  reply : PAnsiChar;
  reply_buf_len : NativeUInt) : NativeUInt stdcall;
  var res : NativeUInt;
begin
  res := reply_buf_len;
  TThread.Synchronize(TThread.CurrentThread, procedure begin
    TLogServer(context).OnMessage(msg, msg_len, reply, res);
  end);
  on_message_callback := res;
end;

end.
