Jump to content

UniGUI + UniAlerter(UniDac)


Kenneth

Recommended Posts

Всем привет!

Может кто сталкивался. Решил использовать UniDac вместо FireDac, вроде все хорошо работает, но единственное, не работает UniAlerter, вроде ивентсы указал, авторегистер = тру, посылаю сообщение, тишина. И главное на десктопном приложении все работает как надо, а вот в uniGui не хочет. 

И еще после закрытия сервера выводит ошибку

image.png.d12148fdf8a8e68e333860b7835ecbe0.png

Видать все таки приходят сообщения, но не обрабатываются. Если сообщений не посылать, то этой ошибки нет.

P.S. Сервер Firebird 3.0

Link to comment
Share on other sites

Уважаемый @x11 вы только заголовки читаете? Что значит ничего общего не имеет? Все что нужно я написал в вопросе и думаю там все понятно описано о моей проблеме.

Link to comment
Share on other sites

10 hours ago, Kenneth said:

вы только заголовки читаете?

 

Я просто не понимаю, почему DevArt UniAlerter  должен работать в приложении uniGUI в браузере?

DevArt UniAlerter - это VCL. А VCL - это не uniGUI.

 

Если я не прав, поясните, пожалуйста.

Возможно, что сообщения от DevArt UniAlerter можно как-то перехватывать и показывать сообщения средствами uniGUI?

Link to comment
Share on other sites

А что ему мешает не работать? FireDac работает, FibPlus работает, так почему бы UniDacу не рабоать?

DevArt UniAlerter - это не VCL, это один из компонентов для работы с базами данных. Если слышали что-нибудь про линейку компонентов FireDac, которая присутствует в комплекте с IDE дельфи, то это такой же аналог.  В FireDac есть TFDEventsAlerter, так вот он работает с UniGui, но uniAlerter не реагирует. Хотя если делаю все тоже самое в обычном десктопном приложении он отзывается. 

Я не претендую на то чтобы разработчики UniGui занимались этим вопросом, но тем не менее, может кто то сталкивался с таким и мог бы подсказать, что не так с этим Алертом?

Link to comment
Share on other sites

Да и надо понимать что использование алертов практически автоматом подразумевает начало использования вебсокетов :) Хотя на форуме есть очень приличный и что самое приятное рабочий код работы с вебсокетами. У меня на нем сделано автообновление датасетов у клиентов.

Link to comment
Share on other sites

Есть опасения, что алертер выполняется в отдельном потоке, потому, там могут быть неприятности, посмотрите код, и попытайтесь переписать так чтобы выполнять в том же потоке.

Я помню делал алертер, независящий от библиотеки

З.ы. zilav, спасибо, что меня помните.

Link to comment
Share on other sites

@zilav, @stas спасибо вам за советы, не могли бы еще скинуть ссылку на рабочий код работы с вебсокетами? Поиск по форуму не дал результатов :(

У меня тоже стоит задача обновлять датасеты.

Link to comment
Share on other sites

Сразу примерно расскажу как сделано у меня. В основе лежит эхо-сервис с броадкаст рассылкой сообщений. Само сообщение представляет собой посути json, в котором указано что и как обновилось в системе. Клиент ловит такое сообщение и уже сам решает как он хочет отреагировать на это сообщение. 

Link to comment
Share on other sites

@zilav спасибо. Но почему так сложно, это по сути придется дополнительный сервис поднимать ради этого, ведь сам компонент уже предполагает в себе все эти функции. Все это конечно можно сделать, но как то усложняет систему, тогда мне было бы проще взять тот же компонент с FIBов или FireDac и уже его прикрутить. У них то это все работает. Хотя не проверял на сколько стабильно, может действительно где то в недрах есть проблемы. Но в любом случае, неужели нет возможности использовать стандартный компонент(UniAlerter)? 

Хотелось бы услышать мнение насколько это оправдано создавать для этого отдельный сервис, а не возиться с настройками UniAlerter или ему подобных компонентов?

Link to comment
Share on other sites

Тут вообще зависит от тебя, данные кто обновляет, посути ты, ну так и что тебе мешает уведомить остальных пользователей что ты что-то поменял без каких-то алертов? unidac ходил в исходниках, посмотри что у него там внутри. Да скорее всего придется посидеть с отладчиком.

Просто чем хороши вебсокеты это тем что с помощью них ты вообще можешь организовать полноценную связь между клиентами не используя БД. Хочешь чат встроить в программу, пожалуйста, надо сообщение от одного пользователя другому послать, не вопрос, надо уведомить всех о том что я что-то меняю и им возможно есть смысл обновить информацию на экране, да на здоровье. Спектр применения весьма широк.

Link to comment
Share on other sites

Кеннет, я вообще, не понимаю, что Вас пугает?

Дополнительный сервис , как предложил zilav,  убирает у Вас привязку к бд, это ли не плюс.

Далее, я не видел исходников унидака, но более чем уверен, что проблема с потоками.

У Вас есть два варианта, переписать унидак на внепотоковый вариант, или использовать вебсокеты.

Спасибо.

Link to comment
Share on other sites

помимо убирания привязки к БД получаем и плюсы, уведомления не только о событиях в БД а вообще любые, ну и уведомления идут в практически моментально что тоже весьма приятно

Плюс если очень хочется то можно вообще воткнуть единый websocket сервер на все свои проекты, только в сообщения надо будет добавить какой-нибудь ID программы и версии, ну а дальше уже в унигуи проекте разрулить твоему приложению сообщение адресовано или нет

Link to comment
Share on other sites

@stas, @zilav спасибо что уделили время и так подробно ответили. Я все понял, моя проблема, что немного узко мыслил. Мне то всего лишь надо было обновлять датасеты, раньше это делалось в пару действий, а тут как то внутренне не принималось, что еще что то нужно делать. Ну раз уж такие возможности открываются, думаю нужно освоить и это. Помню еще в 2008 через сокеты имел дело с примером чата внутри сети. 

Всем Спасибо.

Link to comment
Share on other sites

  • 1 month later...

@stas спасибо за пример. Но сейчас столкнулся с одной проблемой. Клиенты могут отправлять друг другу сообщения со своих сессий, здесь проблем нет, но вот никак не могу отправить сообщение с СерверМодуля. Если кидаю компонент TUniWebSocket на СерверМодуль, то при запуске вылетает с ошибкой. Каким образом можно отправить сообщение именно с СерверМодуля, у меня основные изменения с базой происходят именно здесь.

П.С. Все разобрался:

UniServerModule.BroadCast(nil, 'Сообщение');

 

Link to comment
Share on other sites

  • 2 weeks later...

Всем доброго дня! Вот решил в своем проекте вебсокеты использовать, и возникли еще вопросы. Я получаю информацию об изменении таблицы в ServerModule, и там же пытаюсь сообщить всем (взято с примера):

procedure TUniServerModule.BroadCast(AContext: TIdContext; AMsg: String);
var
  AC: TIdContext;
  L:TList;
  i:integer;
begin
  L:=Srv.Contexts.LockList;
  try
  for i := 0 to L.Count - 1 do
  begin
    AC := L[i];
    SendSocketMessage(AC,AMsg);
  end;
  finally
   Srv.Contexts.UnlockList;
  end;
end;

Но проблема в том, что он всем сокетам подряд отправляет. А мне нужно только тем у кого открыта сессия в данный момент. Можно ли как то через TIdContext узнать висит ли на нем активная сессия или нет? Или как то добраться до сессии. Если нет сиссий, то я бы не отправлял на него сообщение.

Link to comment
Share on other sites

Все вопрос решен! Разобрался. 

Если кто из знатоков читает, прошу еще совета или подсказки. Можно ли обычное десктопное приложение привязать к числу получающих уведомление от СерверМодуля? Кидал на форму TUniWebSocket и прописывал адрес url, ставлю актив, все как в вэб приложении, но ничего не происходит, он не коннектится к серверу. Есть ли какие у кого мысли по этому поводу. Задача стоит получать уведомления с сервера на десктопном VCL приложении.

Link to comment
Share on other sites

  • 2 years later...

Если кому-то актуально. Fix по UniDac Alerter (для Postgres):

В модуль PgClassesUni.pas 

в часть uses добавляем модуль: 

unit PgClassesUni;
interface
uses
  system.generics.collections,

Находим класс TPgSQLNotificationsHandler(PgClassesUni.pas):

 

  TPgSQLNotificationsHandler = class

  private

    FBaseConnection: TPgSQLConnection;

    FConnection: TPgSQLConnection;

    FEvents: array of TEventInfo;

    FThread: TPgSQLNotificationsThread;

    FMainTH: TThread; /// добавляем строчку

В этом-же классе процедуру: 

DoOnNotification 

Переносим на уровень public (декларативная часть)

Ниже описываем класс потока: 

TMaintThread = class(TThread)
  strict private
    FQueue: TQueue<TPgSQLNotification>;
    FObj: TPgSQLNotificationsHandler;
  public
    procedure Execute; override;
    property Queue: TQueue<TPgSQLNotification> read FQueue write FQueue;
    property Obj: TPgSQLNotificationsHandler read FObj write FObj;
  end;

В тело Execute пишем: 

{ TMaintThread }

procedure TMaintThread.Execute;
var
  li: integer;
  le: TPgSQLNotification;
begin
  FreeOnTerminate := True;
  while not Terminated do
  begin
    sleep(100);
    if Assigned(FQueue) and Assigned(Obj) then
    begin
      for li := FQueue.Count - 1 downto 0 do
      begin
        le := FQueue.extract;
        Obj.DoOnNotification(le.PID, le.Name, le.Message);
        le.free;
        le:=nil;
      end;
    end;
  end;
    if Assigned(FQueue) then
      FreeAndNil(FQueue);
  Obj := nil;
end;

В Destroy добавляем :

if assigned(FMainTH) then 
 FreeAndNil(FMainTH); 

 

Находим в этом же модуле процедуру: 

procedure TPgSQLNotificationsHandler.ProcessNotification(const Name: string;

  const PID: integer; const Message: string);

Заменяем: 

    Notif := TPgSQLNotification.Create;
    Notif.PID := PID;
    Notif.Name := Name;
    Notif.Message := Message;
{$IFDEF MSWINDOWS}
    PostMessage(hUtilWindow, WM_NOTIFICATION, wParam(GCHandle),
      lParam(AllocGCHandle(Notif)));
{$ELSE}
    try
      FLastNotification := Notif;
      FThread.Synchronize(DoNotification);
    finally
      FLastNotification := nil;
      Notif.Free;
    end;
{$ENDIF}

На вот это: 

    FLastNotification := TPgSQLNotification.Create;
    FLastNotification.PID := PID;
    FLastNotification.Name := name;
    FLastNotification.Message := Message;
    if not Assigned(FMainTH) then
    begin
      FMainTH := TMaintThread.Create(True);
      TMaintThread(FMainTH).Obj := Self;
    end;
    if not Assigned(TMaintThread(FMainTH).Queue) then
      TMaintThread(FMainTH).Queue := TQueue<TPgSQLNotification>.Create;

    TMaintThread(FMainTH).Queue.Enqueue(FLastNotification);
    FLastNotification := nil;

    if not FMainTH.Started then
      FMainTH.Start;

 

Наслаждаемся - все работает.

Причиной ошибки является вызов метода Synchronyze который фризит unigui сервер (ошибка возникает),  этот метод нужен на случай если придёт большое кол-во сообщений (Synchronize - будет дожидаться основной отработки). В фиксе все сообщения отработают по очереди. 

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...