Встала задача написания телеграм-бота для передачи в телеграм данных из БД Firebird; при этом программа должна работать на линуксовом сервере без графики. По понятным причинам я выбрал Lazarus, который хорошо дружит с Firebird через компоненты IBX (использую модификацию от Rik). Оптимальный вариант - это написание демона, но это я пока не осилил, поэтому хочу для начала сделать консольное приложение.
Однако добавление TDataModule в консольное приложение - это не так просто, как в LCL. Где бы почитать, как это делать правильно? Я перепробовал разные варианты, в том числе ручное создание компонентов, и всегда получаю при попытке соединения с БД непонятную ошибку: Failed to create win32 control, error: 1407 : Не удается найти класс окна. Как это получается - не пойму.
Добавлено спустя 7 минут 54 секунды:
Забыл написать, что пока пишу под виндой, чтобы отработать процесс. Потом буду открывать в линуксовом Лазаре.
Добавлено спустя 25 минут 46 секунд:
Немного деталей, как пытаюсь делать сейчас.
Основной код
- Код: Выделить всё
program docbotapp;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, Interfaces, SysUtils, ibexpress, CustApp, dbunit
{ you can add units after this };
type
{ DocBot }
DocBot = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
end;
{ DocBot }
procedure DocBot.DoRun;
begin
if DM.Start then
{ add your program here }
while not Terminated do DM.Loop;
// stop program loop
Terminate;
end;
constructor DocBot.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
DM:=TDM.Create(TheOwner);
end;
destructor DocBot.Destroy;
begin
DM.Free;
inherited Destroy;
end;
var
Application: DocBot;
begin
Application:=DocBot.Create(nil);
Application.Title:='Bot Application';
Application.Run;
Application.Free;
end.
Модуль данных:
- Код: Выделить всё
unit dbunit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, IBDatabase, IBSQL, tgsendertypes, tgtypes,
tgfclhttpclientbroker;
type
{ TDM }
TDM = class(TDataModule)
DB: TIBDatabase;
Qry: TIBSQL;
ReadTransaction: TIBTransaction;
procedure DataModuleCreate(Sender: TObject);
procedure DataModuleDestroy(Sender: TObject);
procedure BotReceiveMessage(ASender: TObject; AMessage: TTelegramMessageObj);
private
FBot: TTelegramSender;
public
function Start: Boolean;
procedure Loop;
end;
const
BOTTOKEN = 'MyToken';
ERRORMESSAGE = 'Ошибка: неверный запрос или нет соединения с базой данных.';
var
DM: TDM;
implementation
{$R *.lfm}
{ TDM }
procedure TDM.DataModuleCreate(Sender: TObject);
begin
DB:=TIBDatabase.Create(Self);
with DB
do begin
Connected:=False;
AllowStreamedConnected:=False;
DatabaseName:='localhost:E:\DB\MyDB.fdb';
{$IFDEF WINDOWS}
DB.LibraryName:='fbclient.dll';
{$ELSE}
DB.LibraryName:='libfbclient.so.2.5.9';
{$ENDIF}
Params.Text:='user_name=SYSDBA'+sLineBreak
+'password=masterke'+sLineBreak
//+'role='+DBConfig.role+sLineBreak
+'lc_ctype=UTF8'+sLineBreak;
DefaultTransaction:=Nil;
DefaultUpdTransaction:=Nil;
IdleTimer:=0;
TraceFlags:=[];
//Left:=49;
//Top:=30;
end;
ReadTransaction:=TIBTransaction.Create(Self);
with ReadTransaction
do begin
Active:=False;
DefaultDatabase:=DB;
Params.Text:='read'+sLineBreak+'read_committed'+sLineBreak
+'rec_version';
//Left:=136;
//Top:=30;
end;
DB.DefaultTransaction:=ReadTransaction;
DB.DefaultUpdTransaction:=ReadTransaction;
Qry:=TIBSQL.Create(Self);
with Qry
do begin
Database:=DB;
ParamCheck:=True;
Transaction:=ReadTransaction;
SelectOnBlock:=False;
//Left:=216;
//Top:=32;
end;
FBot:=TTelegramSender.Create (BOTTOKEN);
FBot.OnReceiveMessage:=@BotReceiveMessage;
end;
function TDM.Start: Boolean;
begin
Result:=True;
try
DB.Connected:=True; //на этой строке вылетает приведенная ошибка
ReadTransaction.StartTransaction;
except
on E: Exception
do begin
with TStringList.Create
do try
Add (E.Message);
SaveToFile ('error.log');
finally
Free;
end;
writeln (E.Message);
Result:=False;
Exit;
end;
end;
if not FBot.getMe then Result:=False;
end;
procedure TDM.Loop;
begin
FBot.getUpdatesEx(0, 10);
end;
procedure TDM.BotReceiveMessage(ASender: TObject; AMessage: TTelegramMessageObj);
var
AChatID: Int64;
SendingMessage, RcvMessage: String;
label SendStr;
begin
RcvMessage:=AMessage.Text;
AChatID:=AMessage.Chat.ID;
if (Length(RcvMessage)>50) or (Length(RcvMessage)=0)
then begin
SendingMessage:=ERRORMESSAGE;
goto SendStr;
end;
//...
SendingMessage:='Ответ: '+RcvMessage;
SendStr:
FBot.sendMessage(AChatID, SendingMessage);
end;
procedure TDM.DataModuleDestroy(Sender: TObject);
begin
DB.Connected:=False;
FBot.Free;
end;
end.