File indexing completed on 2024-10-06 07:38:13
0001 // SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com> 0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0003 0004 #include "networkcontroller.h" 0005 0006 #include "abstractaccount.h" 0007 #include "accountmanager.h" 0008 #include "config.h" 0009 #include "tokodon_http_debug.h" 0010 0011 using namespace Qt::Literals::StringLiterals; 0012 0013 NetworkController::NetworkController(QObject *parent) 0014 : QObject(parent) 0015 { 0016 setApplicationProxy(); 0017 0018 connect(&AccountManager::instance(), &AccountManager::accountsReady, this, [=] { 0019 m_accountsReady = true; 0020 openLink(); 0021 0022 if (!m_storedComposedText.isEmpty()) { 0023 Q_EMIT openComposer(m_storedComposedText); 0024 m_storedComposedText.clear(); 0025 } 0026 }); 0027 m_accountsReady = AccountManager::instance().isReady(); 0028 } 0029 0030 NetworkController &NetworkController::instance() 0031 { 0032 static NetworkController _instance; 0033 return _instance; 0034 } 0035 0036 void NetworkController::setApplicationProxy() 0037 { 0038 Config *cfg = Config::self(); 0039 QNetworkProxy proxy; 0040 0041 // type match to ProxyType from config.kcfg 0042 switch (cfg->proxyType()) { 0043 case 1: // HTTP 0044 proxy.setType(QNetworkProxy::HttpProxy); 0045 proxy.setHostName(cfg->proxyHost()); 0046 proxy.setPort(cfg->proxyPort()); 0047 proxy.setUser(cfg->proxyUser()); 0048 proxy.setPassword(cfg->proxyPassword()); 0049 break; 0050 case 2: // SOCKS 5 0051 proxy.setType(QNetworkProxy::Socks5Proxy); 0052 proxy.setHostName(cfg->proxyHost()); 0053 proxy.setPort(cfg->proxyPort()); 0054 proxy.setUser(cfg->proxyUser()); 0055 proxy.setPassword(cfg->proxyPassword()); 0056 break; 0057 case 0: // System Default 0058 default: 0059 // do nothing 0060 break; 0061 } 0062 0063 QNetworkProxy::setApplicationProxy(proxy); 0064 0065 AccountManager::instance().reloadAccounts(); 0066 } 0067 0068 void NetworkController::openWebApLink(QString input) 0069 { 0070 QUrl url(input); 0071 // only web+ap (declared in app manifest) and https (explicitly not declared, can be used from command line) 0072 if (url.scheme() != QStringLiteral("web+ap") && url.scheme() != QStringLiteral("https")) { 0073 // FIXME maybe warn about unsupported links? 0074 return; 0075 } 0076 0077 m_requestedLink = std::move(url); 0078 0079 if (m_accountsReady) { 0080 openLink(); 0081 } 0082 } 0083 0084 void NetworkController::setAuthCode(QUrl authCode) 0085 { 0086 QUrlQuery query(authCode); 0087 0088 if (query.hasQueryItem(QStringLiteral("code"))) { 0089 Q_EMIT receivedAuthCode(query.queryItemValue(QStringLiteral("code"))); 0090 } 0091 } 0092 0093 void NetworkController::openLink() 0094 { 0095 if (m_requestedLink.isEmpty()) 0096 return; 0097 0098 auto account = AccountManager::instance().selectedAccount(); 0099 0100 if (m_requestedLink.scheme() == QStringLiteral("web+ap")) { 0101 if (m_requestedLink.userName() == QStringLiteral("tag")) { 0102 // TODO implement in a future MR 0103 m_requestedLink.clear(); 0104 return; 0105 } 0106 m_requestedLink.setScheme(QStringLiteral("https")); 0107 m_requestedLink.setUserInfo(QString()); 0108 } 0109 0110 const QUrl instanceUrl(account->instanceUri()); 0111 0112 // TODO: this assumes the post id is in the last path segment 0113 // Is this always true? Maybe there's some way to query it. 0114 if (instanceUrl.host() == m_requestedLink.host()) { 0115 QString path = m_requestedLink.path(); 0116 path.remove(0, path.lastIndexOf(QLatin1Char('/')) + 1); 0117 0118 Q_EMIT NetworkController::instance().openPost(path); 0119 return; 0120 } 0121 0122 requestRemoteObject(account, m_requestedLink.toString(), [=](QNetworkReply *reply) { 0123 const auto searchResult = QJsonDocument::fromJson(reply->readAll()).object(); 0124 0125 const auto statuses = searchResult[QStringLiteral("statuses")].toArray(); 0126 const auto accounts = searchResult[QStringLiteral("accounts")].toArray(); 0127 0128 if (statuses.isEmpty()) { 0129 qCDebug(TOKODON_HTTP) << "Failed to find any statuses!"; 0130 } else { 0131 const auto status = statuses[0].toObject(); 0132 0133 Q_EMIT NetworkController::instance().openPost(status["id"_L1].toString()); 0134 } 0135 0136 if (accounts.isEmpty()) { 0137 qCDebug(TOKODON_HTTP) << "Failed to find any accounts!"; 0138 } else { 0139 const auto account = accounts[0].toObject(); 0140 0141 Q_EMIT NetworkController::instance().openAccount(account["id"_L1].toString()); 0142 } 0143 0144 m_requestedLink.clear(); 0145 }); 0146 } 0147 0148 void NetworkController::startComposing(const QString &text) 0149 { 0150 if (m_accountsReady) { 0151 Q_EMIT openComposer(text); 0152 } else { 0153 m_storedComposedText = text; 0154 } 0155 } 0156 0157 void NetworkController::requestRemoteObject(AbstractAccount *account, const QString &remoteUrl, std::function<void(QNetworkReply *)> callback) 0158 { 0159 auto url = account->apiUrl(QStringLiteral("/api/v2/search")); 0160 url.setQuery({ 0161 {QStringLiteral("q"), remoteUrl}, 0162 {QStringLiteral("resolve"), QStringLiteral("true")}, 0163 {QStringLiteral("limit"), QStringLiteral("1")}, 0164 }); 0165 account->get(url, true, &AccountManager::instance(), std::move(callback)); 0166 } 0167 0168 bool NetworkController::pushNotificationsAvailable() const 0169 { 0170 return !endpoint.isEmpty(); 0171 } 0172 0173 #include "moc_networkcontroller.cpp"