unit uHCMQTTSender;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VCL.TMSFNCTypes, VCL.TMSFNCUtils,
  VCL.TMSFNCGraphics, VCL.TMSFNCGraphicsTypes, AdvStyleIF, AdvAppStyler,
  VCL.TMSFNCCustomControl, VCL.TMSFNCStatusBar, VCL.TMSFNCPageControl,
  VCL.TMSFNCTabSet, TMS.MQTT.Global, TMS.MQTT.Logging, TMS.MQTT.Client,
  VCL.TMSFNCPanel, Vcl.StdCtrls, VCL.TMSFNCEdit, VCL.TMSFNCButton, Vcl.ExtCtrls,
  DCPrc4, DCPsha256, Inifiles, uHCDefines;

type
  TfrmHCMQTTSender = class(TForm)
    sb1: TTMSFNCStatusBar;
    pc1: TTMSFNCPageControl;
    pgDLLInit: TTMSFNCPageControlContainer;
    pgLog: TTMSFNCPageControlContainer;
    MQTTClient: TTMSMQTTClient;
    MQTTLogger: TTMSMQTTLogger;
    pnlDLLInit: TTMSFNCPanel;
    memMessages: TMemo;
    TMSFNCPanel2: TTMSFNCPanel;
    memMQTTLog: TMemo;
    pgSettings: TTMSFNCPageControlContainer;
    TMSFNCPanel3: TTMSFNCPanel;
    edMQTTUsername: TTMSFNCEdit;
    Label1: TLabel;
    Label2: TLabel;
    edMQTTPassword: TTMSFNCEdit;
    btMQTTCredSave: TTMSFNCButton;
    tmConnect: TTimer;
    btnConnect: TButton;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure MQTTLoggerLog(Sender: TObject; ALevel: TTMSMQTTLogLevel;
      AMessage: string);
    procedure FormDestroy(Sender: TObject);
    procedure MQTTClientConnectedStatusChanged(ASender: TObject;
      const AConnected: Boolean; AStatus: TTMSMQTTConnectionStatus);
    procedure FormActivate(Sender: TObject);
    procedure btMQTTCredSaveClick(Sender: TObject);
    procedure tmConnectTimer(Sender: TObject);
    procedure btnConnectClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    lIniHC: TIniFile;
    lMQTTOkayToLog: Boolean;
    lMessageQueue: TStringList;
    procedure WMCopyData(var Msg : TWMCopyData) ; message WM_COPYDATA;
  public
    { Public declarations }
    gCntMsg_GameTime: NativeUInt;
    function EncodeString(const pString: String): String;
    function DecodeString(const pString: String): String;
  end;

var
  frmHCMQTTSender: TfrmHCMQTTSender;
  gSendMessageMsg: DWORD = 0;

implementation

{$R *.dfm}

uses ulazharpooneventsmqttglobals;

procedure TfrmHCMQTTSender.btMQTTCredSaveClick(Sender: TObject);
begin
   MQTTClient.Credentials.Username := edMQTTUsername.Text;
   MQTTClient.Credentials.Password := edMQTTPassword.Text;

   lIniHC.WriteString('ExportDLL_lazHarpoonEventsMQTT', 'MQTT_Username',
    MQTTClient.Credentials.Username);
   lIniHC.WriteString('ExportDLL_lazHarpoonEventsMQTT', 'MQTT_Password',
    EncodeString(MQTTClient.Credentials.Password));
end;

procedure TfrmHCMQTTSender.FormActivate(Sender: TObject);
begin
  lMQTTOkayToLog := True;
  tmConnect.Enabled := True;
end;

procedure TfrmHCMQTTSender.FormCreate(Sender: TObject);
begin
  lMQTTOkayToLog := False;
  lMessageQueue := TStringList.Create;

  lIniHC := TIniFile.Create(ExtractFilePath(Application.ExeName) + '..\..\'
   + HCINIFILENAME);

  //MQTTClient := TTMSMQTTClient.Create(nil);
  MQTTClient.Credentials.Username :=
   lIniHC.ReadString('ExportDLL_lazHarpoonEventsMQTT', 'MQTT_Username', '');
  MQTTClient.Credentials.Password:=
   DecodeString(lIniHC.ReadString('ExportDLL_lazHarpoonEventsMQTT', 'MQTT_Password', ''));
  MQTTClient.BrokerHostName:='mqtt.harpgamer.com';
  MQTTClient.BrokerPort:=8883;
  //MQTTClient.BrokerHostName:='192.168.77.175';
  //MQTTClient.BrokerPort:=1883;
  MQTTClient.UseSSL:=True;
  MQTTClient.KeepAliveSettings.AutoReconnect:=True;

  edMQTTUsername.Text := MQTTClient.Credentials.Username;
  edMQTTPassword.Text := MQTTClient.Credentials.Password;

end;

procedure TfrmHCMQTTSender.FormDestroy(Sender: TObject);
begin
  MQTTClient.Disconnect;
  lMessageQueue.Free;
  lIniHC.Free;
end;

procedure TfrmHCMQTTSender.MQTTClientConnectedStatusChanged(ASender: TObject;
  const AConnected: Boolean; AStatus: TTMSMQTTConnectionStatus);
begin
  if sb1 <> nil then
  begin
  if AConnected then
    sb1.Panels.Items[0].Text := 'MQTT Connected'
  else
    sb1.Panels.Items[0].Text := 'MQTT Not Connected';
  end;
end;

procedure TfrmHCMQTTSender.MQTTLoggerLog(Sender: TObject;
  ALevel: TTMSMQTTLogLevel; AMessage: string);
begin
  if ((memMQTTLog <> nil) AND (lMQTTOkayToLog)) then
  begin
    memMQTTLog.Lines.Insert(0, FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz ', Now()) + AMessage);
  end;
end;

procedure TfrmHCMQTTSender.tmConnectTimer(Sender: TObject);
begin
  if ((MQTTClient.Credentials.Password <> '') AND (NOT MQTTClient.IsConnected)) then
  begin
    tmConnect.Enabled := False;
    //lMQTTConnectFromTimer := True;
    MQTTClient.Connect(True);
  end;
end;

procedure TfrmHCMQTTSender.WMCopyData(var Msg: TWMCopyData);
var
  lMessage: THCMessage;
  lMessageMS: TMemoryStream;
  lStringStream: TStringStream;
  lCntMessage: String;
  //lStringBytes: TBytes;
begin
  if ((gSendMessageMsg <> 0) AND (Msg.CopyDataStruct.dwData = gSendMessageMsg)) then
  begin
  lMessageMS := TMemoryStream.Create;
  lMessageMS.Write(Msg.CopyDataStruct.lpData^, Msg.CopyDataStruct.cbData);
//  FreeMem(Msg.CopyDataStruct.lpData);
  lMessageMS.Position := 0; // ALE 20200918 back to start for reading
  lMessageMS.ReadBuffer(lMessage.topicLen, SizeOf(lMessage.topicLen));
  lMessageMS.ReadBuffer(lMessage.msgLen, SizeOf(lMessage.msgLen));
  lStringStream := TStringStream.Create('', TEncoding.Unicode);
  lStringStream.CopyFrom(lMessageMS, lMessage.topicLen * SizeOf(Char));
  lMessage.topic := lStringStream.DataString;
  lStringStream.Clear;
  lStringStream.CopyFrom(lMessageMS, lMessage.msgLen * SizeOf(Char));
  lMessageMS.Free;
  lMessage.msg := lStringStream.DataString;
  lStringStream.Free;
  msg.Result := 2006;
  lMessageQueue.AddPair(lMessage.topic, lMessage.msg);
  if MQTTClient.IsConnected then
  begin
    while lMessageQueue.Count > 0 do
    begin
      MQTTClient.Publish(lMessageQueue.Names[0], lMessageQueue.ValueFromIndex[0], qosAtLeastOnce);
      lMessageQueue.Delete(0);
      //MQTTClient.Publish(lMessage.topic, lMessage.msg, qosAtLeastOnce);
      Inc(gCntMsg_GameTime);
      lCntMessage := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz ', Now())
       + 'Messages Sent: ' + IntToStr(gCntMsg_GameTime);
      if (memMessages.Lines.Count = 0) then
        memMessages.Lines.Add(lCntMessage)
      else
        memMessages.Lines[0] := lCntMessage;
      //memMessages.Lines.Insert(0, lMessage.topic + ' ' + lMessage.msg);
    end;
  end;
  end
  else
  begin
    inherited;
  end;
end;

function TfrmHCMQTTSender.EncodeString(const pString: String): String;
var
  Cipher: TDCP_rc4;
begin
  Cipher:= TDCP_rc4.Create(Self);
  Cipher.InitStr(MAGIC_DATA, TDCP_sha256);         // initialize the cipher with a hash of the passphrase
  Result:= Cipher.EncryptString(pString);
  Cipher.Burn;
  Cipher.Free;
end;

procedure TfrmHCMQTTSender.btnConnectClick(Sender: TObject);
begin
  MQTTClient.Connect(True);
end;

procedure TfrmHCMQTTSender.Button1Click(Sender: TObject);
begin
  MQTTClient.Disconnect;
end;

function TfrmHCMQTTSender.DecodeString(const pString: String): String;
var
  Cipher: TDCP_rc4;
begin
  if (pString <> '') then
  begin
    Cipher:= TDCP_rc4.Create(Self);
    Cipher.InitStr(MAGIC_DATA, TDCP_sha256);         // initialize the cipher with a hash of the passphrase
    Result:= Cipher.DecryptString(pString);
    Cipher.Burn;
    Cipher.Free;
  end
  else
    Result:='';
end;


initialization
  gSendMessageMsg := RegisterWindowMessage('HCMQTTMessage');
end.
