Please tell me how to use Mastodon streaming api with qt



  • Please tell me how to use Mastodon streaming api with qt.
    I wrote this code but doesn't work and is likely to be wrong.
    Please please tell me

    WebSocket.cpp

    #include "WebSocket.h"
    #include <QDebug>
    #include <QAbstractSocket>
    
    
    WebSocket::WebSocket(const QUrl &url, QString accessToken, bool debug, QObject *parent) :
        QObject(parent),
        m_url(url),
        mAccessToken(accessToken),
        m_debug(debug)
    {
        if (m_debug) {
            qDebug() << "WebSocket server:" << url;
        }
    
        connect(&m_webSocket, &QWebSocket::connected, this, &WebSocket::onConnected);
        connect(&m_webSocket, &QWebSocket::disconnected, this, &WebSocket::closed);
    
        connect(&m_webSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onWebSocketError(QAbstractSocket::SocketError)));
    
        //m_webSocket.open(QUrl(url));
    
        //QNetworkRequest req(url);
        QString header_text = "Bearer " + mAccessToken;
        //req.setRawHeader("Authorization", header_text.toUtf8());
    
        QString urlStr = url.toString() + "?access_token=" + header_text + "&stream=public";
        QNetworkRequest req(urlStr);
    
        m_webSocket.open(req);
    }
    
    void WebSocket::onWebSocketError(QAbstractSocket::SocketError error)
    {
        qDebug() << error;
    }
    
    void WebSocket::onConnected()
    {
        if (m_debug) {
            qDebug() << "WebSocket connected";
        }
        connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &WebSocket::onTextMessageReceived);
        //m_webSocket.sendTextMessage(QStringLiteral("Hello, world!"));
    }
    
    void WebSocket::onTextMessageReceived(QString message)
    {
        if (m_debug) {
            qDebug() << "Message received:" << message;
        }
        m_webSocket.close();
    }
    
    

    mainwindow.cpp

    #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>
    
    #include "WebSocket.h"
    
    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);
        //★一時的に無効化
        //mLocalTimelineTimer = startTimer(LOCAL_TIMELINE_UPDATE_INTERVAL);
    
        connect(ui->menuStartLocalTimeline, SIGNAL(triggered(bool)), this, SLOT(startLocalTimelineTimer()));
        connect(ui->menuStopLocalTimeline, SIGNAL(triggered(bool)), this, SLOT(stopLocalTimelineTimer()));
    
        //★一時的に無効化
        //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();
    
        //★ストリーミングAPIテスト
        /*
        //QEventLoop eventLoop;
        connect(manager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
        QNetworkRequest req(QUrl("https://streaming.mstdn.jp/api/v1/streaming/public"));
        QString header_text = "Bearer " + mAccessToken;
        req.setRawHeader("Authorization", header_text.toUtf8());
        req.setRawHeader("Connection", "Keep-Alive");
        manager->get(req);
        //eventLoop.exec();
        */
    
        //mWebSocketForTimeline = new WebSocket(QUrl(QStringLiteral("ws://streaming.mstdn.jp/api/v1/streaming/public")), mAccessToken, true);
        mWebSocketForTimeline = new WebSocket(QUrl(QStringLiteral("ws://streaming.mstdn.jp/api/v1/streaming")), mAccessToken, true);
    }
    
    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"));
    
        QString header_text = "Bearer " + mAccessToken;
        qDebug() << "AAA" << header_text;
        req.setRawHeader("Authorization", header_text.toUtf8());
        params.addQueryItem("visibility", "");
        params.addQueryItem("status", ui->tootText->toPlainText());
    
        manager->post(req, params.toString(QUrl::FullyEncoded).toUtf8());
    }
    
    


  • From code it looks alright. There are three slots u have written. Can u tell me which slot is getting executed ?



  • I added mainwindow.cpp source code to first comment.
    And when I execute the program, the following error occurs.
    So onWebSocketError slot is executed.
    And onConnected slot is not executed.

    qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_client_method
    qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_client_method
    qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_server_method
    qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_server_method
    qt.network.ssl: QSslSocket: cannot resolve SSL_select_next_proto
    qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
    qt.network.ssl: QSslSocket: cannot resolve SSL_get0_next_proto_negotiated
    qt.network.ssl: QSslSocket: cannot resolve SSL_set_alpn_protos
    qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_alpn_select_cb
    qt.network.ssl: QSslSocket: cannot resolve SSL_get0_alpn_selected
    WebSocket server: QUrl("ws://streaming.mstdn.jp/api/v1/streaming")
    QAbstractSocket::ConnectionRefusedError
    QAbstractSocket::ConnectionRefusedError
    QAbstractSocket::ConnectionRefusedError
    QAbstractSocket::ConnectionRefusedError
    QAbstractSocket::ConnectionRefusedError
    QAbstractSocket::ConnectionRefusedError
    QAbstractSocket::ConnectionRefusedError
    QAbstractSocket::ConnectionRefusedError



  • Is it windows box ? Looks ssl libraries are not found in path. Can u check it ?



  • I tried QSslSocket::supportsSsl() and result was true.
    (windows)


  • Moderators

    @wabisuke2718 These error messages say that you SSL functions cannot be resolved. That means: either there is no openSSL library or the version of that library does not provide these functions.

    qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_client_method
    qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_client_method
    qt.network.ssl: QSslSocket: cannot resolve TLSv1_1_server_method
    qt.network.ssl: QSslSocket: cannot resolve TLSv1_2_server_method
    qt.network.ssl: QSslSocket: cannot resolve SSL_select_next_proto
    qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb
    qt.network.ssl: QSslSocket: cannot resolve SSL_get0_next_proto_negotiated
    qt.network.ssl: QSslSocket: cannot resolve SSL_set_alpn_protos
    qt.network.ssl: QSslSocket: cannot resolve SSL_CTX_set_alpn_select_cb
    qt.network.ssl: QSslSocket: cannot resolve SSL_get0_alpn_selected
    


  • How can I tell if there is no openSSL library or not providing a function?
    I added "qDebug() << QSslSocket::sslLibraryBuildVersionString();" to my source code.
    And result is "OpenSSL 1.0.2h 3 May 2016".

    Would you please let me know if there are documents on procedures to make the appropriate version of openSSL available with Qt?


  • Lifetime Qt Champion

    Hi,

    This information tells you which version of OpenSSL was used to build the backend. Qt doesn't distribute OpenSSL because there are several countries that have restrictions regarding application using encryption.

    What OS are you running your application on ?


Log in to reply