QWebSocket potwierdzenie operacji

0

Jak to powinno zostać prawidłowo zrobione w koncepcji asynchronicznej ?

  1. Klient wysyła zapytanie od serwera np. "ustaw cenę pomidora na 6.70 PLN"
  2. serwer przetwarza zapytanie przez pewien czas
  3. serwer odpowiada np. "OK" albo "error: pomidorów brak"

metoda QWebSocket::sendTextMessage wysyła dane ale nie zwraca odpowiedzi z serwera,
odpowiedz serwera otrzymujemy za pomocą sygnału QWebSocket::textMessageReceived

Jak to połączyć razem tak aby zapytanie serwera i odpowiedz były blisko w kodzie np.

np. myWebsocket.callMetod(USTAW_CENE_POMIDORA, 6.70 ).(jakas_lambda ????);

1

A interesuje Cię jakiś konkretny sposób komunikacji? Bo jak chcesz RESTowo, to tutaj jest przykładowy lib do Qt.

0

była odpowiedz i znikła, to nie jest przypadek ;)

Generalnie to chodziło mi o czytelność kodu aby żądanie WebSocket i obsługa odpowiedzi były w tym samy bloku kodu

Co do samego problemu to np. proste rozwiązanie, do każdej transmisji klienta trzeba dodać unikany identyfikator, serwer w odpowiedzi odsyła ten sam numer, dodatkowo musimy

pisane z glowy i sporo uproszczeń

class ClientMetod
{
private:
 std::function<void()> m_onComplete;
 std::function<void()> m_onError;
public:
  int ID;

  ClientMetod& onComplete(const std::function<void()> &fu)
  {
      m_onComplete = fu;
      return *this;
  }
  ClientMetod& onError(const std::function<void()> &fu)
  {
      m_onError = fu;
      return *this;
  }
}

class MyWebsocket
{
  QWebSocket m_webSocket;
public:
  std::map<int, ClientMetod> clientCalls;
  int clientCallsID{0};
  ClientMetod &MyWebsocket.callMetod(....)


ClientMetod& callMetod(....)
{
  auto ID = clientCallsID++;
  auto call = clientCalls[ID];

  json["ID"] = ID;  // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TUTAJ dodaje ID do transmisji 

  m_webSocket.sendTextMessage(QString::fromStdString(json.dump())) 
  
  return call; 
}

void onTextMessageReceived(QString message)
{
  
  auto json = nlohmann::json::parse(message);

  if(json["ID"].is_number_integer())  // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TUTAJ testuj czy jest ID w transmisji 
  {
    int ID = json["ID"];
    if(clientCalls.find(ID) != clientCalls.end()
    {
       // jesli blad
       if(....)
       if(clientCalls[ID].m_onError)  clientCalls[ID].m_onError();

       // jesli OK
       if(...)
       if(clientCalls[ID].m_onComplete)  clientCalls[ID].m_onComplete();

       // kasuje z std::map bo nie potrzebne 
       clientCalls.erase(clientCalls.find(ID)) 
    }
  }
  else
  {
     // odpowiedzi ktore nie zawiara "ID" sa obsługiwane w alternatywny sposób (klasyczny)
  } 
}

i potem użycie:

MyWebsocket* myWebsocket = new MyWebsocket(...);

myWebsocket.callMetod(...)
   .onComplete([](...)
    {
      spdlog::info("wszytko OK")
    }
    .onError([](...)
    {
     spdlog::error("masz problem")
    }
0

Hmm powinieneś jedną warstwę wyżej trzymać połączenia, bo clienta po id jaki przysyła jsonem sprawdzasz, a można sprawdzać po prostu po tcp połączeniu.
Jak używasz wss, czyli szyfrowany websocket to możesz przy pierwszym połączeniu odebrać token i jeśli jest poprawny to zaakceptować połączenie, a jak nie to zerwać czyli zrobić takie uwierzytelnianie, żeby potwierdzić, że jest się tym samym zalogowanym użytkownikiem co na stronie, czyli po zalogowaniu na stronie do websocketa dodaje się ten token.

A każde połączenie i tak jest unikalne, to tworzysz sobie ConnectionManagera, tam trzymasz hash mapę/vector połączeń i każde zerwane potem usuwasz z tej listy.
Jak wyjątek pójdzie czy w jakiś inny sposób dowiesz się o zerwaniu połączenia to wykasowujesz z listy.

Jak chcesz do kogoś konkretnego odpisać to możesz przeszukać listę, jak odpowiadasz od razu to nic nie musisz robić bo masz jego połączenie przy odbiorze.
A jak chcesz zrobić broadcast do wszystkich to iterujesz po tej liście.

A potwierdzenie to możesz odesłać websocketem jakiś message, {"status":"200"} tylko takie coś jest problematyczne, bo wiadomości są async czyli jak przyjdzie to nie wiesz od czego przyszedł ten status, byś musiał jeszcze id taska dać, który jest wykonywany i to tak będzie źle wyglądało, zależy od aplikacji, bo jeśli tylko updatujesz widok to nie ma sensu odpisywać, że się odebrało, bo to i tak jest w sumie na tcp warstwie wykrywane jak wiadomość nie doszła.
W sumie zależy do czego to potrzebne.
Chyba, że klient coś zleca do zmiany, wtedy wysyłasz {"ops":"update", "price":"357} nic nie robisz więcej, serwer dostaje procesuje i odsyła ci np. {"ops":"update_widok": "id":"34", "price":"357"} wtedy masz pewność, że wszystko się poprawnie wykonało, bo serwer zwrócił zaaktualnioną wersję jakby się nie udało to by nie odesłał i widok też by się nie zmienił.
A jak ktoś dopiero będzie korzystał z usługi to mu z serwera zassie najświeższe informacje.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.