Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to use streaming api
Forum Update on Monday, May 27th 2025

How to use streaming api

Scheduled Pinned Locked Moved Solved General and Desktop
3 Posts 2 Posters 1.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Offline
    W Offline
    wabisuke2718
    wrote on last edited by
    #1

    I am now making Mastodon client application.
    However, I do not know how to use Mastodon's streaming api from Qt.
    I wrote following code.
    And manager->get(req) in MainWindow::MainWindow() seems to be connected to server.
    But I do not know how to acquire data asynchronously.

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QLabel>
    #include <QFrame>
    
    #include <QNetworkAccessManager>
    #include <QNetworkReply>
    
    #include <QJsonObject>
    #include <QJsonDocument>
    #include <QJsonParseError>
    #include <QJsonArray>
    
    #include <vector>
    
    #include "IconWidget.h"
    #include <QHBoxLayout>
    
    #include "defineconstants.h"
    
    #include <QUrlQuery>
    #include <QSystemTrayIcon>
    
    #include <QTextCodec>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        manager = new QNetworkAccessManager(this);
        connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
    
        ui->menuStartLocalTimeline->setEnabled(false);
        ui->menuStopLocalTimeline->setEnabled(true);
        //Temporarily comment out
        //mLocalTimelineTimer = startTimer(LOCAL_TIMELINE_UPDATE_INTERVAL);
    
        connect(ui->menuStartLocalTimeline, SIGNAL(triggered(bool)), this, SLOT(startLocalTimelineTimer()));
        connect(ui->menuStopLocalTimeline, SIGNAL(triggered(bool)), this, SLOT(stopLocalTimelineTimer()));
    
        //Temporarily comment out
        //manager->get(QNetworkRequest(QUrl("https://mstdn.jp/api/v1/timelines/public?local=\"true\"")));
    
        trayIcon = new QSystemTrayIcon(this);
    
        QFile file("your_usercred.txt");
        if (!file.open(QIODevice::ReadOnly)) {
            if (DEBUG_MODE) {
                qDebug() << "file could not open.";
            }
        }
        QTextStream in(&file);
        mAccessToken = in.readLine();
    
        //QString urlStr = "https://streaming.mstdn.jp/api/v1/streaming/public?access_token" + mAccessToken + "&stream=public";
        QString urlStr = "https://streaming.mstdn.jp/api/v1/streaming/public";
        QNetworkRequest req(urlStr);
        QString headerText = "Bearer " + mAccessToken;
        req.setRawHeader("Authorization", headerText.toUtf8());
        manager->get(req);
    
        qDebug() << QSslSocket::supportsSsl();
    }
    
    void MainWindow::timerEvent(QTimerEvent *e)
    {
        if (e->timerId() == mLocalTimelineTimer) {
            manager->get(QNetworkRequest(QUrl("https://mstdn.jp/api/v1/timelines/public?local=\"true\"")));
        }
    }
    
    void MainWindow::startLocalTimelineTimer()
    {
        mLocalTimelineTimer = startTimer(LOCAL_TIMELINE_UPDATE_INTERVAL);
        ui->menuStartLocalTimeline->setEnabled(false);
        ui->menuStopLocalTimeline->setEnabled(true);
    }
    
    void MainWindow::stopLocalTimelineTimer()
    {
        killTimer(mLocalTimelineTimer);
        ui->menuStartLocalTimeline->setEnabled(true);
        ui->menuStopLocalTimeline->setEnabled(false);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_pushButton_2_clicked()
    {
        manager->get(QNetworkRequest(QUrl("https://mstdn.jp/api/v1/timelines/public?local=\"true\"")));
    }
    
    void MainWindow::replyFinished(QNetworkReply *reply)
    {
        if (DEBUG_MODE) {
            qDebug() << "MainWindow::replyFinished() called.";
            qDebug() << "url" << reply->url();
            qDebug() << reply->errorString();
        }
    
        if (reply->url().toString() == "https://mstdn.jp/api/v1/statuses") {
            return;
        }
    
        if (reply->error() == QNetworkReply::NoError) {
            QByteArray byteArray = reply->readAll();
            //ui->textEdit->setPlainText(byteArray);
    
            QJsonParseError error;
            QJsonDocument jsonDocument = QJsonDocument::fromJson(byteArray, &error);
            qDebug() << error.errorString();
    
            /*
            qDebug() << "Is Object? " << jsonDocument.isObject();
            qDebug() << "Is Array? " << jsonDocument.isArray();
            */
    
            QJsonArray jsonArray = jsonDocument.array();
            //qDebug() << jsonArray.size();
            QStringList keys = jsonArray[0].toObject().keys();
            qDebug() << keys;
            foreach (QString key, keys) {
                qDebug() << "key =" << key;
                QString value = jsonArray[0].toObject().value(key).toString();
                qDebug() << "value =" << value;
            }
    
            //std::vector<QHBoxLayout*> tootLayouts;
            static QVBoxLayout *timelineLayout = new QVBoxLayout();
            //for (int i=0; i<jsonArray.size(); i++) {
            for (int i=jsonArray.size()-1; i>=0; i--) {
                if (i == 0) {
                    QString *title = new QString("タイトルは長いんだよー");
                    trayIcon->show();
                    trayIcon->showMessage(*title, jsonArray[i].toObject().value("content").toString());
                }
    
                QFrame *tootFrame = new QFrame();
                tootFrame->setObjectName("tootFrame");
                tootFrame->setStyleSheet("#tootFrame { border: 1px solid; background-color: white; }");
                //tootFrame->maximumWidth = ui->scrollAreaWidgetContents->width();
                //tootFrame->setMaximumWidth(ui->scrollAreaWidgetContents->width());
                QHBoxLayout *tootLayout = new QHBoxLayout();
    
                QVBoxLayout *tootContentsLayout = new QVBoxLayout();
                QLabel *name = new QLabel(jsonArray[i].toObject().value("account").toObject().value("display_name").toString(), this);
    
                QString tootHtml = jsonArray[i].toObject().value("content").toString();
                QRegExp br("<br />");
                tootHtml.replace(br, "\n");
                //QRegExp tag("<[^>]*>");
                //tootHtml.remove(tag);
                QLabel *toot = new QLabel(tootHtml);
                toot->setWordWrap(true);
                toot->setTextFormat(Qt::PlainText);
    
                QUrl *iconUrl = new QUrl(jsonArray[i].toObject().value("account").toObject().value("avatar").toString());
                //QUrl *iconUrl = new QUrl("https://media.mstdn.jp/images/accounts/avatars/000/006/953/original/b0a6986188b3fdf7.png");
                IconWidget *iconWidget = new IconWidget(iconUrl, nullptr);
                tootLayout->addWidget(iconWidget);
    
                tootContentsLayout->addWidget(name);
                tootContentsLayout->addWidget(toot);
                tootLayout->addLayout(tootContentsLayout);
                tootFrame->setLayout(tootLayout);
    
                //timelineLayout->addLayout(tootLayout);
                //timelineLayout->addWidget(tootFrame);
                timelineLayout->insertWidget(0, tootFrame);
            }
            //ui->tootList->setLayout(timelineLayout);
            //ui->scrollAreaWidgetContents->setLayout(timelineLayout);
            ui->localTimelineContents->setLayout(timelineLayout);
        }
    }
    
    void MainWindow::on_tootButton_clicked()
    {
        QUrlQuery params;
        QNetworkRequest req(QUrl("https://mstdn.jp/api/v1/statuses"));
    
        /*
        QFile file("your_usercred.txt");
        if (!file.open(QIODevice::ReadOnly)) {
            if (DEBUG_MODE) {
                qDebug() << "file could not open.";
            }
        }
        QTextStream in(&file);
        QString usercred = in.readLine();
        */
        QString usercred = mAccessToken;
    
        QString header_text = "Bearer " + usercred;
        req.setRawHeader("Authorization", header_text.toUtf8());
        params.addQueryItem("visibility", "");
        params.addQueryItem("status", ui->tootText->toPlainText());
    
        manager->post(req, params.toString(QUrl::FullyEncoded).toUtf8());
    }
    
    jsulmJ 1 Reply Last reply
    0
    • W wabisuke2718

      I am now making Mastodon client application.
      However, I do not know how to use Mastodon's streaming api from Qt.
      I wrote following code.
      And manager->get(req) in MainWindow::MainWindow() seems to be connected to server.
      But I do not know how to acquire data asynchronously.

      #include "mainwindow.h"
      #include "ui_mainwindow.h"
      
      #include <QLabel>
      #include <QFrame>
      
      #include <QNetworkAccessManager>
      #include <QNetworkReply>
      
      #include <QJsonObject>
      #include <QJsonDocument>
      #include <QJsonParseError>
      #include <QJsonArray>
      
      #include <vector>
      
      #include "IconWidget.h"
      #include <QHBoxLayout>
      
      #include "defineconstants.h"
      
      #include <QUrlQuery>
      #include <QSystemTrayIcon>
      
      #include <QTextCodec>
      
      MainWindow::MainWindow(QWidget *parent) :
          QMainWindow(parent),
          ui(new Ui::MainWindow)
      {
          ui->setupUi(this);
      
          manager = new QNetworkAccessManager(this);
          connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
      
          ui->menuStartLocalTimeline->setEnabled(false);
          ui->menuStopLocalTimeline->setEnabled(true);
          //Temporarily comment out
          //mLocalTimelineTimer = startTimer(LOCAL_TIMELINE_UPDATE_INTERVAL);
      
          connect(ui->menuStartLocalTimeline, SIGNAL(triggered(bool)), this, SLOT(startLocalTimelineTimer()));
          connect(ui->menuStopLocalTimeline, SIGNAL(triggered(bool)), this, SLOT(stopLocalTimelineTimer()));
      
          //Temporarily comment out
          //manager->get(QNetworkRequest(QUrl("https://mstdn.jp/api/v1/timelines/public?local=\"true\"")));
      
          trayIcon = new QSystemTrayIcon(this);
      
          QFile file("your_usercred.txt");
          if (!file.open(QIODevice::ReadOnly)) {
              if (DEBUG_MODE) {
                  qDebug() << "file could not open.";
              }
          }
          QTextStream in(&file);
          mAccessToken = in.readLine();
      
          //QString urlStr = "https://streaming.mstdn.jp/api/v1/streaming/public?access_token" + mAccessToken + "&stream=public";
          QString urlStr = "https://streaming.mstdn.jp/api/v1/streaming/public";
          QNetworkRequest req(urlStr);
          QString headerText = "Bearer " + mAccessToken;
          req.setRawHeader("Authorization", headerText.toUtf8());
          manager->get(req);
      
          qDebug() << QSslSocket::supportsSsl();
      }
      
      void MainWindow::timerEvent(QTimerEvent *e)
      {
          if (e->timerId() == mLocalTimelineTimer) {
              manager->get(QNetworkRequest(QUrl("https://mstdn.jp/api/v1/timelines/public?local=\"true\"")));
          }
      }
      
      void MainWindow::startLocalTimelineTimer()
      {
          mLocalTimelineTimer = startTimer(LOCAL_TIMELINE_UPDATE_INTERVAL);
          ui->menuStartLocalTimeline->setEnabled(false);
          ui->menuStopLocalTimeline->setEnabled(true);
      }
      
      void MainWindow::stopLocalTimelineTimer()
      {
          killTimer(mLocalTimelineTimer);
          ui->menuStartLocalTimeline->setEnabled(true);
          ui->menuStopLocalTimeline->setEnabled(false);
      }
      
      MainWindow::~MainWindow()
      {
          delete ui;
      }
      
      void MainWindow::on_pushButton_2_clicked()
      {
          manager->get(QNetworkRequest(QUrl("https://mstdn.jp/api/v1/timelines/public?local=\"true\"")));
      }
      
      void MainWindow::replyFinished(QNetworkReply *reply)
      {
          if (DEBUG_MODE) {
              qDebug() << "MainWindow::replyFinished() called.";
              qDebug() << "url" << reply->url();
              qDebug() << reply->errorString();
          }
      
          if (reply->url().toString() == "https://mstdn.jp/api/v1/statuses") {
              return;
          }
      
          if (reply->error() == QNetworkReply::NoError) {
              QByteArray byteArray = reply->readAll();
              //ui->textEdit->setPlainText(byteArray);
      
              QJsonParseError error;
              QJsonDocument jsonDocument = QJsonDocument::fromJson(byteArray, &error);
              qDebug() << error.errorString();
      
              /*
              qDebug() << "Is Object? " << jsonDocument.isObject();
              qDebug() << "Is Array? " << jsonDocument.isArray();
              */
      
              QJsonArray jsonArray = jsonDocument.array();
              //qDebug() << jsonArray.size();
              QStringList keys = jsonArray[0].toObject().keys();
              qDebug() << keys;
              foreach (QString key, keys) {
                  qDebug() << "key =" << key;
                  QString value = jsonArray[0].toObject().value(key).toString();
                  qDebug() << "value =" << value;
              }
      
              //std::vector<QHBoxLayout*> tootLayouts;
              static QVBoxLayout *timelineLayout = new QVBoxLayout();
              //for (int i=0; i<jsonArray.size(); i++) {
              for (int i=jsonArray.size()-1; i>=0; i--) {
                  if (i == 0) {
                      QString *title = new QString("タイトルは長いんだよー");
                      trayIcon->show();
                      trayIcon->showMessage(*title, jsonArray[i].toObject().value("content").toString());
                  }
      
                  QFrame *tootFrame = new QFrame();
                  tootFrame->setObjectName("tootFrame");
                  tootFrame->setStyleSheet("#tootFrame { border: 1px solid; background-color: white; }");
                  //tootFrame->maximumWidth = ui->scrollAreaWidgetContents->width();
                  //tootFrame->setMaximumWidth(ui->scrollAreaWidgetContents->width());
                  QHBoxLayout *tootLayout = new QHBoxLayout();
      
                  QVBoxLayout *tootContentsLayout = new QVBoxLayout();
                  QLabel *name = new QLabel(jsonArray[i].toObject().value("account").toObject().value("display_name").toString(), this);
      
                  QString tootHtml = jsonArray[i].toObject().value("content").toString();
                  QRegExp br("<br />");
                  tootHtml.replace(br, "\n");
                  //QRegExp tag("<[^>]*>");
                  //tootHtml.remove(tag);
                  QLabel *toot = new QLabel(tootHtml);
                  toot->setWordWrap(true);
                  toot->setTextFormat(Qt::PlainText);
      
                  QUrl *iconUrl = new QUrl(jsonArray[i].toObject().value("account").toObject().value("avatar").toString());
                  //QUrl *iconUrl = new QUrl("https://media.mstdn.jp/images/accounts/avatars/000/006/953/original/b0a6986188b3fdf7.png");
                  IconWidget *iconWidget = new IconWidget(iconUrl, nullptr);
                  tootLayout->addWidget(iconWidget);
      
                  tootContentsLayout->addWidget(name);
                  tootContentsLayout->addWidget(toot);
                  tootLayout->addLayout(tootContentsLayout);
                  tootFrame->setLayout(tootLayout);
      
                  //timelineLayout->addLayout(tootLayout);
                  //timelineLayout->addWidget(tootFrame);
                  timelineLayout->insertWidget(0, tootFrame);
              }
              //ui->tootList->setLayout(timelineLayout);
              //ui->scrollAreaWidgetContents->setLayout(timelineLayout);
              ui->localTimelineContents->setLayout(timelineLayout);
          }
      }
      
      void MainWindow::on_tootButton_clicked()
      {
          QUrlQuery params;
          QNetworkRequest req(QUrl("https://mstdn.jp/api/v1/statuses"));
      
          /*
          QFile file("your_usercred.txt");
          if (!file.open(QIODevice::ReadOnly)) {
              if (DEBUG_MODE) {
                  qDebug() << "file could not open.";
              }
          }
          QTextStream in(&file);
          QString usercred = in.readLine();
          */
          QString usercred = mAccessToken;
      
          QString header_text = "Bearer " + usercred;
          req.setRawHeader("Authorization", header_text.toUtf8());
          params.addQueryItem("visibility", "");
          params.addQueryItem("status", ui->tootText->toPlainText());
      
          manager->post(req, params.toString(QUrl::FullyEncoded).toUtf8());
      }
      
      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @wabisuke2718 Please take a look at documentation: http://doc.qt.io/qt-5/qnetworkaccessmanager.html
      You will find there this example:

      QNetworkRequest request;
      request.setUrl(QUrl("http://qt-project.org"));
      request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
      
      QNetworkReply *reply = manager->get(request);
      connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
      connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
              this, SLOT(slotError(QNetworkReply::NetworkError)));
      connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
              this, SLOT(slotSslErrors(QList<QSslError>)));
      

      So, to get the data asynchronously you connect a slot to QNetworkReply::readyRead() signal and in that signal you can get the data currently available using readAll(). Keep in mind that you most probably will not get all the data at once but in chunks - that means your slot will be called several times.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • W Offline
        W Offline
        wabisuke2718
        wrote on last edited by
        #3

        I solved this problem.
        I should have used QWebSocket.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved