mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-12-25 16:42:39 -06:00
citra_qt: Use the new verify backend; UI changes
Displayed username along with nickname (when they are not identical); Requested and displayed user's avatar; Made the dialog bigger for extended names. Added a few functions to web_backend (GetImage, GetPlain) to support getting data in multiple content-types. Added a no_avatar icon for users without avatars.
This commit is contained in:
parent
4906c8ce7b
commit
386bf5c861
18 changed files with 263 additions and 80 deletions
2
dist/license.md
vendored
2
dist/license.md
vendored
|
@ -11,6 +11,7 @@ qt_themes/default/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.
|
||||||
qt_themes/default/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/default/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
|
qt_themes/default/icons/48x48/no_avatar.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
|
qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
|
||||||
qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/qdarkstyle/icons/16x16/checked.png | Free for non-commercial use
|
qt_themes/qdarkstyle/icons/16x16/checked.png | Free for non-commercial use
|
||||||
|
@ -22,6 +23,7 @@ qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icon
|
||||||
qt_themes/qdarkstyle/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/qdarkstyle/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/qdarkstyle/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/qdarkstyle/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/qdarkstyle/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/qdarkstyle/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
|
qt_themes/qdarkstyle/icons/48x48/no_avatar.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/qdarkstyle/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
|
qt_themes/qdarkstyle/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
|
||||||
qt_themes/qdarkstyle/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/qdarkstyle/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
qt_themes/colorful/icons/16x16/connected.png | CC BY-ND 3.0 | https://icons8.com
|
qt_themes/colorful/icons/16x16/connected.png | CC BY-ND 3.0 | https://icons8.com
|
||||||
|
|
1
dist/qt_themes/colorful_dark/style.qrc
vendored
1
dist/qt_themes/colorful_dark/style.qrc
vendored
|
@ -7,6 +7,7 @@
|
||||||
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
|
||||||
|
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
|
||||||
<file alias="48x48/plus.png">../colorful/icons/48x48/plus.png</file>
|
<file alias="48x48/plus.png">../colorful/icons/48x48/plus.png</file>
|
||||||
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
|
||||||
<file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
|
<file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
|
||||||
|
|
2
dist/qt_themes/default/default.qrc
vendored
2
dist/qt_themes/default/default.qrc
vendored
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||||
|
|
||||||
|
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
|
||||||
|
|
||||||
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
||||||
|
|
||||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||||
|
|
BIN
dist/qt_themes/default/icons/48x48/no_avatar.png
vendored
Normal file
BIN
dist/qt_themes/default/icons/48x48/no_avatar.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 588 B |
BIN
dist/qt_themes/qdarkstyle/icons/48x48/no_avatar.png
vendored
Normal file
BIN
dist/qt_themes/qdarkstyle/icons/48x48/no_avatar.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 708 B |
1
dist/qt_themes/qdarkstyle/style.qrc
vendored
1
dist/qt_themes/qdarkstyle/style.qrc
vendored
|
@ -7,6 +7,7 @@
|
||||||
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||||
|
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
|
||||||
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
<file alias="48x48/plus.png">icons/48x48/plus.png</file>
|
||||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||||
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
<file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
|
||||||
|
|
|
@ -228,6 +228,10 @@ if (USE_DISCORD_PRESENCE)
|
||||||
target_compile_definitions(citra-qt PRIVATE -DUSE_DISCORD_PRESENCE)
|
target_compile_definitions(citra-qt PRIVATE -DUSE_DISCORD_PRESENCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_WEB_SERVICE)
|
||||||
|
target_compile_definitions(citra-qt PRIVATE -DENABLE_WEB_SERVICE)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
if(UNIX AND NOT APPLE)
|
||||||
install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <QUrl>
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "citra_qt/game_list_p.h"
|
#include "citra_qt/game_list_p.h"
|
||||||
#include "citra_qt/multiplayer/chat_room.h"
|
#include "citra_qt/multiplayer/chat_room.h"
|
||||||
|
@ -19,6 +21,9 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/announce_multiplayer_session.h"
|
#include "core/announce_multiplayer_session.h"
|
||||||
#include "ui_chat_room.h"
|
#include "ui_chat_room.h"
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
#include "web_service/web_backend.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class ChatMessage {
|
class ChatMessage {
|
||||||
public:
|
public:
|
||||||
|
@ -27,14 +32,21 @@ public:
|
||||||
QLocale locale;
|
QLocale locale;
|
||||||
timestamp = locale.toString(ts.isValid() ? ts : QTime::currentTime(), QLocale::ShortFormat);
|
timestamp = locale.toString(ts.isValid() ? ts : QTime::currentTime(), QLocale::ShortFormat);
|
||||||
nickname = QString::fromStdString(chat.nickname);
|
nickname = QString::fromStdString(chat.nickname);
|
||||||
|
username = QString::fromStdString(chat.username);
|
||||||
message = QString::fromStdString(chat.message);
|
message = QString::fromStdString(chat.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Format the message using the players color
|
/// Format the message using the players color
|
||||||
QString GetPlayerChatMessage(u16 player) const {
|
QString GetPlayerChatMessage(u16 player) const {
|
||||||
auto color = player_color[player % 16];
|
auto color = player_color[player % 16];
|
||||||
|
QString name;
|
||||||
|
if (username.isEmpty() || username == nickname) {
|
||||||
|
name = nickname;
|
||||||
|
} else {
|
||||||
|
name = QString("%1 (%2)").arg(nickname, username);
|
||||||
|
}
|
||||||
return QString("[%1] <font color='%2'><%3></font> %4")
|
return QString("[%1] <font color='%2'><%3></font> %4")
|
||||||
.arg(timestamp, color, nickname.toHtmlEscaped(), message.toHtmlEscaped());
|
.arg(timestamp, color, name.toHtmlEscaped(), message.toHtmlEscaped());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -44,6 +56,7 @@ private:
|
||||||
|
|
||||||
QString timestamp;
|
QString timestamp;
|
||||||
QString nickname;
|
QString nickname;
|
||||||
|
QString username;
|
||||||
QString message;
|
QString message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,22 +80,54 @@ private:
|
||||||
QString message;
|
QString message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PlayerListItem : public QStandardItem {
|
||||||
|
public:
|
||||||
|
static const int NicknameRole = Qt::UserRole + 1;
|
||||||
|
static const int UsernameRole = Qt::UserRole + 2;
|
||||||
|
static const int AvatarUrlRole = Qt::UserRole + 3;
|
||||||
|
static const int GameNameRole = Qt::UserRole + 4;
|
||||||
|
|
||||||
|
PlayerListItem() = default;
|
||||||
|
explicit PlayerListItem(const std::string& nickname, const std::string& username,
|
||||||
|
const std::string& avatar_url, const std::string& game_name) {
|
||||||
|
setEditable(false);
|
||||||
|
setData(QString::fromStdString(nickname), NicknameRole);
|
||||||
|
setData(QString::fromStdString(username), UsernameRole);
|
||||||
|
setData(QString::fromStdString(avatar_url), AvatarUrlRole);
|
||||||
|
if (game_name.empty()) {
|
||||||
|
setData(QObject::tr("Not playing a game"), GameNameRole);
|
||||||
|
} else {
|
||||||
|
setData(QString::fromStdString(game_name), GameNameRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant data(int role) const override {
|
||||||
|
if (role != Qt::DisplayRole) {
|
||||||
|
return QStandardItem::data(role);
|
||||||
|
}
|
||||||
|
QString name;
|
||||||
|
const QString nickname = data(NicknameRole).toString();
|
||||||
|
const QString username = data(UsernameRole).toString();
|
||||||
|
if (username.isEmpty() || username == nickname) {
|
||||||
|
name = nickname;
|
||||||
|
} else {
|
||||||
|
name = QString("%1 (%2)").arg(nickname, username);
|
||||||
|
}
|
||||||
|
return QString("%1\n %2").arg(name, data(GameNameRole).toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ChatRoom>()) {
|
ChatRoom::ChatRoom(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ChatRoom>()) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
// set the item_model for player_view
|
// set the item_model for player_view
|
||||||
enum {
|
|
||||||
COLUMN_NAME,
|
|
||||||
COLUMN_GAME,
|
|
||||||
COLUMN_COUNT, // Number of columns
|
|
||||||
};
|
|
||||||
|
|
||||||
player_list = new QStandardItemModel(ui->player_view);
|
player_list = new QStandardItemModel(ui->player_view);
|
||||||
ui->player_view->setModel(player_list);
|
ui->player_view->setModel(player_list);
|
||||||
ui->player_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
ui->player_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
player_list->insertColumns(0, COLUMN_COUNT);
|
// set a header to make it look better though there is only one column
|
||||||
player_list->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
|
player_list->insertColumns(0, 1);
|
||||||
player_list->setHeaderData(COLUMN_GAME, Qt::Horizontal, tr("Game"));
|
player_list->setHeaderData(0, Qt::Horizontal, tr("Members"));
|
||||||
|
|
||||||
ui->chat_history->document()->setMaximumBlockCount(max_chat_lines);
|
ui->chat_history->document()->setMaximumBlockCount(max_chat_lines);
|
||||||
|
|
||||||
|
@ -157,7 +202,8 @@ void ChatRoom::OnChatReceive(const Network::ChatEntry& chat) {
|
||||||
auto members = room->GetMemberInformation();
|
auto members = room->GetMemberInformation();
|
||||||
auto it = std::find_if(members.begin(), members.end(),
|
auto it = std::find_if(members.begin(), members.end(),
|
||||||
[&chat](const Network::RoomMember::MemberInformation& member) {
|
[&chat](const Network::RoomMember::MemberInformation& member) {
|
||||||
return member.nickname == chat.nickname;
|
return member.nickname == chat.nickname &&
|
||||||
|
member.username == chat.username;
|
||||||
});
|
});
|
||||||
if (it == members.end()) {
|
if (it == members.end()) {
|
||||||
LOG_INFO(Network, "Chat message received from unknown player. Ignoring it.");
|
LOG_INFO(Network, "Chat message received from unknown player. Ignoring it.");
|
||||||
|
@ -184,12 +230,14 @@ void ChatRoom::OnSendChat() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto nick = room->GetNickname();
|
auto nick = room->GetNickname();
|
||||||
Network::ChatEntry chat{nick, message};
|
auto username = room->GetUsername();
|
||||||
|
Network::ChatEntry chat{nick, username, message};
|
||||||
|
|
||||||
auto members = room->GetMemberInformation();
|
auto members = room->GetMemberInformation();
|
||||||
auto it = std::find_if(members.begin(), members.end(),
|
auto it = std::find_if(members.begin(), members.end(),
|
||||||
[&chat](const Network::RoomMember::MemberInformation& member) {
|
[&chat](const Network::RoomMember::MemberInformation& member) {
|
||||||
return member.nickname == chat.nickname;
|
return member.nickname == chat.nickname &&
|
||||||
|
member.username == chat.username;
|
||||||
});
|
});
|
||||||
if (it == members.end()) {
|
if (it == members.end()) {
|
||||||
LOG_INFO(Network, "Cannot find self in the player list when sending a message.");
|
LOG_INFO(Network, "Cannot find self in the player list when sending a message.");
|
||||||
|
@ -202,20 +250,64 @@ void ChatRoom::OnSendChat() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatRoom::UpdateIconDisplay() {
|
||||||
|
for (int row = 0; row < player_list->invisibleRootItem()->rowCount(); ++row) {
|
||||||
|
QStandardItem* item = player_list->invisibleRootItem()->child(row);
|
||||||
|
const std::string avatar_url =
|
||||||
|
item->data(PlayerListItem::AvatarUrlRole).toString().toStdString();
|
||||||
|
if (icon_cache.count(avatar_url)) {
|
||||||
|
item->setData(icon_cache.at(avatar_url), Qt::DecorationRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list) {
|
void ChatRoom::SetPlayerList(const Network::RoomMember::MemberList& member_list) {
|
||||||
// TODO(B3N30): Remember which row is selected
|
// TODO(B3N30): Remember which row is selected
|
||||||
player_list->removeRows(0, player_list->rowCount());
|
player_list->removeRows(0, player_list->rowCount());
|
||||||
for (const auto& member : member_list) {
|
for (const auto& member : member_list) {
|
||||||
if (member.nickname.empty())
|
if (member.nickname.empty())
|
||||||
continue;
|
continue;
|
||||||
QList<QStandardItem*> l;
|
QStandardItem* name_item = new PlayerListItem(member.nickname, member.username,
|
||||||
std::vector<std::string> elements = {member.nickname, member.game_info.name};
|
member.avatar_url, member.game_info.name);
|
||||||
for (const auto& item : elements) {
|
|
||||||
QStandardItem* child = new QStandardItem(QString::fromStdString(item));
|
if (!icon_cache.count(member.avatar_url)) {
|
||||||
child->setEditable(false);
|
// Emplace a default question mark icon as avatar
|
||||||
l.append(child);
|
icon_cache.emplace(member.avatar_url, QIcon::fromTheme("no_avatar").pixmap(48));
|
||||||
|
if (!member.avatar_url.empty()) {
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
// Start a request to get the member's avatar
|
||||||
|
const QUrl url(QString::fromStdString(member.avatar_url));
|
||||||
|
QFuture<std::string> future = QtConcurrent::run([url] {
|
||||||
|
WebService::Client client(
|
||||||
|
QString("%1://%2").arg(url.scheme(), url.host()).toStdString(), "", "");
|
||||||
|
auto result = client.GetImage(url.path().toStdString(), true);
|
||||||
|
if (result.returned_data.empty()) {
|
||||||
|
LOG_ERROR(WebService, "Failed to get avatar");
|
||||||
}
|
}
|
||||||
player_list->invisibleRootItem()->appendRow(l);
|
return result.returned_data;
|
||||||
|
});
|
||||||
|
auto* future_watcher = new QFutureWatcher<std::string>(this);
|
||||||
|
connect(future_watcher, &QFutureWatcher<std::string>::finished, this,
|
||||||
|
[this, future_watcher, avatar_url = member.avatar_url] {
|
||||||
|
const std::string result = future_watcher->result();
|
||||||
|
if (result.empty())
|
||||||
|
return;
|
||||||
|
QPixmap pixmap;
|
||||||
|
if (!pixmap.loadFromData(reinterpret_cast<const u8*>(result.data()),
|
||||||
|
result.size()))
|
||||||
|
return;
|
||||||
|
icon_cache[avatar_url] = pixmap.scaled(48, 48, Qt::IgnoreAspectRatio,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
// Update all the displayed icons with the new icon_cache
|
||||||
|
UpdateIconDisplay();
|
||||||
|
});
|
||||||
|
future_watcher->setFuture(future);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name_item->setData(icon_cache.at(member.avatar_url), Qt::DecorationRole);
|
||||||
|
|
||||||
|
player_list->invisibleRootItem()->appendRow(name_item);
|
||||||
}
|
}
|
||||||
// TODO(B3N30): Restore row selection
|
// TODO(B3N30): Restore row selection
|
||||||
}
|
}
|
||||||
|
@ -230,7 +322,8 @@ void ChatRoom::PopupContextMenu(const QPoint& menu_location) {
|
||||||
if (!item.isValid())
|
if (!item.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string nickname = player_list->item(item.row())->text().toStdString();
|
std::string nickname =
|
||||||
|
player_list->item(item.row())->data(PlayerListItem::NicknameRole).toString().toStdString();
|
||||||
if (auto room = Network::GetRoomMember().lock()) {
|
if (auto room = Network::GetRoomMember().lock()) {
|
||||||
// You can't block yourself
|
// You can't block yourself
|
||||||
if (nickname == room->GetNickname())
|
if (nickname == room->GetNickname())
|
||||||
|
|
|
@ -52,9 +52,12 @@ private:
|
||||||
static constexpr u32 max_chat_lines = 1000;
|
static constexpr u32 max_chat_lines = 1000;
|
||||||
void AppendChatMessage(const QString&);
|
void AppendChatMessage(const QString&);
|
||||||
bool ValidateMessage(const std::string&);
|
bool ValidateMessage(const std::string&);
|
||||||
|
void UpdateIconDisplay();
|
||||||
|
|
||||||
QStandardItemModel* player_list;
|
QStandardItemModel* player_list;
|
||||||
std::unique_ptr<Ui::ChatRoom> ui;
|
std::unique_ptr<Ui::ChatRoom> ui;
|
||||||
std::unordered_set<std::string> block_list;
|
std::unordered_set<std::string> block_list;
|
||||||
|
std::unordered_map<std::string, QPixmap> icon_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Network::ChatEntry);
|
Q_DECLARE_METATYPE(Network::ChatEntry);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>607</width>
|
<width>807</width>
|
||||||
<height>432</height>
|
<height>432</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>607</width>
|
<width>807</width>
|
||||||
<height>432</height>
|
<height>432</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "ui_host_room.h"
|
#include "ui_host_room.h"
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
#include "web_service/verify_user_jwt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
|
HostRoomWindow::HostRoomWindow(QWidget* parent, QStandardItemModel* list,
|
||||||
std::shared_ptr<Core::AnnounceMultiplayerSession> session)
|
std::shared_ptr<Core::AnnounceMultiplayerSession> session)
|
||||||
|
@ -79,6 +82,21 @@ void HostRoomWindow::RetranslateUi() {
|
||||||
ui->retranslateUi(this);
|
ui->retranslateUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Network::VerifyUser::Backend> HostRoomWindow::CreateVerifyBackend(
|
||||||
|
bool use_validation) const {
|
||||||
|
std::unique_ptr<Network::VerifyUser::Backend> verify_backend;
|
||||||
|
if (use_validation) {
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
verify_backend = std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url);
|
||||||
|
#else
|
||||||
|
verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
|
||||||
|
}
|
||||||
|
return verify_backend;
|
||||||
|
}
|
||||||
|
|
||||||
void HostRoomWindow::Host() {
|
void HostRoomWindow::Host() {
|
||||||
if (!ui->username->hasAcceptableInput()) {
|
if (!ui->username->hasAcceptableInput()) {
|
||||||
NetworkMessage::ShowError(NetworkMessage::USERNAME_NOT_VALID);
|
NetworkMessage::ShowError(NetworkMessage::USERNAME_NOT_VALID);
|
||||||
|
@ -108,11 +126,12 @@ void HostRoomWindow::Host() {
|
||||||
auto game_id = ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong();
|
auto game_id = ui->game_list->currentData(GameListItemPath::ProgramIdRole).toLongLong();
|
||||||
auto port = ui->port->isModified() ? ui->port->text().toInt() : Network::DefaultRoomPort;
|
auto port = ui->port->isModified() ? ui->port->text().toInt() : Network::DefaultRoomPort;
|
||||||
auto password = ui->password->text().toStdString();
|
auto password = ui->password->text().toStdString();
|
||||||
|
const bool is_public = ui->host_type->currentIndex() == 0;
|
||||||
if (auto room = Network::GetRoom().lock()) {
|
if (auto room = Network::GetRoom().lock()) {
|
||||||
bool created =
|
bool created = room->Create(ui->room_name->text().toStdString(),
|
||||||
room->Create(ui->room_name->text().toStdString(),
|
ui->room_description->toPlainText().toStdString(), "", port,
|
||||||
ui->room_description->toPlainText().toStdString(), "", port, password,
|
password, ui->max_player->value(), game_name.toStdString(),
|
||||||
ui->max_player->value(), game_name.toStdString(), game_id);
|
game_id, CreateVerifyBackend(is_public));
|
||||||
if (!created) {
|
if (!created) {
|
||||||
NetworkMessage::ShowError(NetworkMessage::COULD_NOT_CREATE_ROOM);
|
NetworkMessage::ShowError(NetworkMessage::COULD_NOT_CREATE_ROOM);
|
||||||
LOG_ERROR(Network, "Could not create room!");
|
LOG_ERROR(Network, "Could not create room!");
|
||||||
|
@ -120,9 +139,34 @@ void HostRoomWindow::Host() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Start the announce session if they chose Public
|
||||||
|
if (is_public) {
|
||||||
|
if (auto session = announce_multiplayer_session.lock()) {
|
||||||
|
// Register the room first to ensure verify_UID is present when we connect
|
||||||
|
session->Register();
|
||||||
|
session->Start();
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Network, "Starting announce session failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string token;
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
if (is_public) {
|
||||||
|
WebService::Client client(Settings::values.web_api_url, Settings::values.citra_username,
|
||||||
|
Settings::values.citra_token);
|
||||||
|
if (auto room = Network::GetRoom().lock()) {
|
||||||
|
token = client.GetExternalJWT(room->GetVerifyUID()).returned_data;
|
||||||
|
}
|
||||||
|
if (token.empty()) {
|
||||||
|
LOG_ERROR(WebService, "Could not get external JWT, verification may fail");
|
||||||
|
} else {
|
||||||
|
LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
member->Join(ui->username->text().toStdString(),
|
member->Join(ui->username->text().toStdString(),
|
||||||
Service::CFG::GetConsoleIdHash(Core::System::GetInstance()), "127.0.0.1", port,
|
Service::CFG::GetConsoleIdHash(Core::System::GetInstance()), "127.0.0.1", port,
|
||||||
0, Network::NoPreferredMac, password);
|
0, Network::NoPreferredMac, password, token);
|
||||||
|
|
||||||
// Store settings
|
// Store settings
|
||||||
UISettings::values.room_nickname = ui->username->text();
|
UISettings::values.room_nickname = ui->username->text();
|
||||||
|
@ -137,25 +181,9 @@ void HostRoomWindow::Host() {
|
||||||
: QString::number(Network::DefaultRoomPort);
|
: QString::number(Network::DefaultRoomPort);
|
||||||
UISettings::values.room_description = ui->room_description->toPlainText();
|
UISettings::values.room_description = ui->room_description->toPlainText();
|
||||||
Settings::Apply();
|
Settings::Apply();
|
||||||
OnConnection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HostRoomWindow::OnConnection() {
|
|
||||||
ui->host->setEnabled(true);
|
ui->host->setEnabled(true);
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
|
||||||
if (room_member->GetState() == Network::RoomMember::State::Joining) {
|
|
||||||
// Start the announce session if they chose Public
|
|
||||||
if (ui->host_type->currentIndex() == 0) {
|
|
||||||
if (auto session = announce_multiplayer_session.lock()) {
|
|
||||||
session->Start();
|
|
||||||
} else {
|
|
||||||
LOG_ERROR(Network, "Starting announce session failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ComboBoxProxyModel::data(const QModelIndex& idx, int role) const {
|
QVariant ComboBoxProxyModel::data(const QModelIndex& idx, int role) const {
|
||||||
|
|
|
@ -26,6 +26,10 @@ class ComboBoxProxyModel;
|
||||||
|
|
||||||
class ChatMessage;
|
class ChatMessage;
|
||||||
|
|
||||||
|
namespace Network::VerifyUser {
|
||||||
|
class Backend;
|
||||||
|
};
|
||||||
|
|
||||||
class HostRoomWindow : public QDialog {
|
class HostRoomWindow : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -36,15 +40,9 @@ public:
|
||||||
|
|
||||||
void RetranslateUi();
|
void RetranslateUi();
|
||||||
|
|
||||||
private slots:
|
|
||||||
/**
|
|
||||||
* Handler for connection status changes. Launches the chat window if successful or
|
|
||||||
* displays an error
|
|
||||||
*/
|
|
||||||
void OnConnection();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Host();
|
void Host();
|
||||||
|
std::unique_ptr<Network::VerifyUser::Backend> CreateVerifyBackend(bool use_validation) const;
|
||||||
|
|
||||||
std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
|
std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
|
||||||
QStandardItemModel* game_list;
|
QStandardItemModel* game_list;
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
#include "web_service/web_backend.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
|
Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
|
||||||
std::shared_ptr<Core::AnnounceMultiplayerSession> session)
|
std::shared_ptr<Core::AnnounceMultiplayerSession> session)
|
||||||
|
@ -136,12 +139,27 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
|
||||||
const std::string ip =
|
const std::string ip =
|
||||||
proxy->data(connection_index, LobbyItemHost::HostIPRole).toString().toStdString();
|
proxy->data(connection_index, LobbyItemHost::HostIPRole).toString().toStdString();
|
||||||
int port = proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
|
int port = proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt();
|
||||||
|
const std::string verify_UID =
|
||||||
|
proxy->data(connection_index, LobbyItemHost::HostVerifyUIDRole).toString().toStdString();
|
||||||
|
|
||||||
// attempt to connect in a different thread
|
// attempt to connect in a different thread
|
||||||
QFuture<void> f = QtConcurrent::run([nickname, ip, port, password] {
|
QFuture<void> f = QtConcurrent::run([nickname, ip, port, password, verify_UID] {
|
||||||
|
std::string token;
|
||||||
|
#ifdef ENABLE_WEB_SERVICE
|
||||||
|
if (!Settings::values.citra_username.empty() && !Settings::values.citra_token.empty()) {
|
||||||
|
WebService::Client client(Settings::values.web_api_url, Settings::values.citra_username,
|
||||||
|
Settings::values.citra_token);
|
||||||
|
token = client.GetExternalJWT(verify_UID).returned_data;
|
||||||
|
if (token.empty()) {
|
||||||
|
LOG_ERROR(WebService, "Could not get external JWT, verification may fail");
|
||||||
|
} else {
|
||||||
|
LOG_INFO(WebService, "Successfully requested external JWT: size={}", token.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
room_member->Join(nickname, Service::CFG::GetConsoleIdHash(Core::System::GetInstance()),
|
room_member->Join(nickname, Service::CFG::GetConsoleIdHash(Core::System::GetInstance()),
|
||||||
ip.c_str(), port, 0, Network::NoPreferredMac, password);
|
ip.c_str(), port, 0, Network::NoPreferredMac, password, token);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
watcher->setFuture(f);
|
watcher->setFuture(f);
|
||||||
|
@ -193,7 +211,8 @@ void Lobby::OnRefreshLobby() {
|
||||||
QList<QVariant> members;
|
QList<QVariant> members;
|
||||||
for (auto member : room.members) {
|
for (auto member : room.members) {
|
||||||
QVariant var;
|
QVariant var;
|
||||||
var.setValue(LobbyMember{QString::fromStdString(member.name), member.game_id,
|
var.setValue(LobbyMember{QString::fromStdString(member.username),
|
||||||
|
QString::fromStdString(member.nickname), member.game_id,
|
||||||
QString::fromStdString(member.game_name)});
|
QString::fromStdString(member.game_name)});
|
||||||
members.append(var);
|
members.append(var);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +224,7 @@ void Lobby::OnRefreshLobby() {
|
||||||
new LobbyItemGame(room.preferred_game_id, QString::fromStdString(room.preferred_game),
|
new LobbyItemGame(room.preferred_game_id, QString::fromStdString(room.preferred_game),
|
||||||
smdh_icon),
|
smdh_icon),
|
||||||
new LobbyItemHost(QString::fromStdString(room.owner), QString::fromStdString(room.ip),
|
new LobbyItemHost(QString::fromStdString(room.owner), QString::fromStdString(room.ip),
|
||||||
room.port),
|
room.port, QString::fromStdString(room.verify_UID)),
|
||||||
new LobbyItemMemberList(members, room.max_player),
|
new LobbyItemMemberList(members, room.max_player),
|
||||||
});
|
});
|
||||||
model->appendRow(row);
|
model->appendRow(row);
|
||||||
|
|
|
@ -120,12 +120,14 @@ public:
|
||||||
static const int HostUsernameRole = Qt::UserRole + 1;
|
static const int HostUsernameRole = Qt::UserRole + 1;
|
||||||
static const int HostIPRole = Qt::UserRole + 2;
|
static const int HostIPRole = Qt::UserRole + 2;
|
||||||
static const int HostPortRole = Qt::UserRole + 3;
|
static const int HostPortRole = Qt::UserRole + 3;
|
||||||
|
static const int HostVerifyUIDRole = Qt::UserRole + 4;
|
||||||
|
|
||||||
LobbyItemHost() = default;
|
LobbyItemHost() = default;
|
||||||
explicit LobbyItemHost(QString username, QString ip, u16 port) {
|
explicit LobbyItemHost(QString username, QString ip, u16 port, QString verify_UID) {
|
||||||
setData(username, HostUsernameRole);
|
setData(username, HostUsernameRole);
|
||||||
setData(ip, HostIPRole);
|
setData(ip, HostIPRole);
|
||||||
setData(port, HostPortRole);
|
setData(port, HostPortRole);
|
||||||
|
setData(verify_UID, HostVerifyUIDRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant data(int role) const override {
|
QVariant data(int role) const override {
|
||||||
|
@ -146,12 +148,17 @@ class LobbyMember {
|
||||||
public:
|
public:
|
||||||
LobbyMember() = default;
|
LobbyMember() = default;
|
||||||
LobbyMember(const LobbyMember& other) = default;
|
LobbyMember(const LobbyMember& other) = default;
|
||||||
explicit LobbyMember(QString username, u64 title_id, QString game_name)
|
explicit LobbyMember(QString username, QString nickname, u64 title_id, QString game_name)
|
||||||
: username(std::move(username)), title_id(title_id), game_name(std::move(game_name)) {}
|
: username(std::move(username)), nickname(std::move(nickname)), title_id(title_id),
|
||||||
|
game_name(std::move(game_name)) {}
|
||||||
~LobbyMember() = default;
|
~LobbyMember() = default;
|
||||||
|
|
||||||
QString GetUsername() const {
|
QString GetName() const {
|
||||||
return username;
|
if (username.isEmpty() || username == nickname) {
|
||||||
|
return nickname;
|
||||||
|
} else {
|
||||||
|
return QString("%1 (%2)").arg(nickname, username);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
u64 GetTitleId() const {
|
u64 GetTitleId() const {
|
||||||
return title_id;
|
return title_id;
|
||||||
|
@ -162,6 +169,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString username;
|
QString username;
|
||||||
|
QString nickname;
|
||||||
u64 title_id;
|
u64 title_id;
|
||||||
QString game_name;
|
QString game_name;
|
||||||
};
|
};
|
||||||
|
@ -220,10 +228,9 @@ public:
|
||||||
out += '\n';
|
out += '\n';
|
||||||
const auto& m = member.value<LobbyMember>();
|
const auto& m = member.value<LobbyMember>();
|
||||||
if (m.GetGameName().isEmpty()) {
|
if (m.GetGameName().isEmpty()) {
|
||||||
out += QString(QObject::tr("%1 is not playing a game")).arg(m.GetUsername());
|
out += QString(QObject::tr("%1 is not playing a game")).arg(m.GetName());
|
||||||
} else {
|
} else {
|
||||||
out +=
|
out += QString(QObject::tr("%1 is playing %2")).arg(m.GetName(), m.GetGameName());
|
||||||
QString(QObject::tr("%1 is playing %2")).arg(m.GetUsername(), m.GetGameName());
|
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ static std::string public_key;
|
||||||
std::string GetPublicKey(const std::string& host) {
|
std::string GetPublicKey(const std::string& host) {
|
||||||
if (public_key.empty()) {
|
if (public_key.empty()) {
|
||||||
Client client(host, "", ""); // no need for credentials here
|
Client client(host, "", ""); // no need for credentials here
|
||||||
public_key = client.GetJson("/jwt/external/key.pem", true).returned_data;
|
public_key = client.GetPlain("/jwt/external/key.pem", true).returned_data;
|
||||||
if (public_key.empty()) {
|
if (public_key.empty()) {
|
||||||
LOG_ERROR(WebService, "Could not fetch external JWT public key, verification may fail");
|
LOG_ERROR(WebService, "Could not fetch external JWT public key, verification may fail");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -33,8 +33,9 @@ struct Client::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A generic function handles POST, GET and DELETE request together
|
/// A generic function handles POST, GET and DELETE request together
|
||||||
Common::WebResult GenericJson(const std::string& method, const std::string& path,
|
Common::WebResult GenericRequest(const std::string& method, const std::string& path,
|
||||||
const std::string& data, bool allow_anonymous) {
|
const std::string& data, bool allow_anonymous,
|
||||||
|
const std::string& accept) {
|
||||||
if (jwt.empty()) {
|
if (jwt.empty()) {
|
||||||
UpdateJWT();
|
UpdateJWT();
|
||||||
}
|
}
|
||||||
|
@ -45,11 +46,11 @@ struct Client::Impl {
|
||||||
"Credentials needed"};
|
"Credentials needed"};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = GenericJson(method, path, data, jwt);
|
auto result = GenericRequest(method, path, data, accept, jwt);
|
||||||
if (result.result_string == "401") {
|
if (result.result_string == "401") {
|
||||||
// Try again with new JWT
|
// Try again with new JWT
|
||||||
UpdateJWT();
|
UpdateJWT();
|
||||||
result = GenericJson(method, path, data, jwt);
|
result = GenericRequest(method, path, data, accept, jwt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -61,9 +62,10 @@ struct Client::Impl {
|
||||||
* username + token is used if jwt is empty but username and token are
|
* username + token is used if jwt is empty but username and token are
|
||||||
* not empty anonymous if all of jwt, username and token are empty
|
* not empty anonymous if all of jwt, username and token are empty
|
||||||
*/
|
*/
|
||||||
Common::WebResult GenericJson(const std::string& method, const std::string& path,
|
Common::WebResult GenericRequest(const std::string& method, const std::string& path,
|
||||||
const std::string& data, const std::string& jwt = "",
|
const std::string& data, const std::string& accept,
|
||||||
const std::string& username = "", const std::string& token = "") {
|
const std::string& jwt = "", const std::string& username = "",
|
||||||
|
const std::string& token = "") {
|
||||||
if (cli == nullptr) {
|
if (cli == nullptr) {
|
||||||
auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
|
auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);
|
||||||
int port;
|
int port;
|
||||||
|
@ -134,9 +136,7 @@ struct Client::Impl {
|
||||||
return Common::WebResult{Common::WebResult::Code::WrongContent, ""};
|
return Common::WebResult{Common::WebResult::Code::WrongContent, ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (content_type->second.find("application/json") == std::string::npos &&
|
if (content_type->second.find(accept) == std::string::npos) {
|
||||||
content_type->second.find("text/html; charset=utf-8") == std::string::npos &&
|
|
||||||
content_type->second.find("text/plain; charset=utf-8") == std::string::npos) {
|
|
||||||
LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,
|
LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,
|
||||||
content_type->second);
|
content_type->second);
|
||||||
return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content"};
|
return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content"};
|
||||||
|
@ -150,7 +150,7 @@ struct Client::Impl {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = GenericJson("POST", "/jwt/internal", "", "", username, token);
|
auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token);
|
||||||
if (result.result_code != Common::WebResult::Code::Success) {
|
if (result.result_code != Common::WebResult::Code::Success) {
|
||||||
LOG_ERROR(WebService, "UpdateJWT failed");
|
LOG_ERROR(WebService, "UpdateJWT failed");
|
||||||
} else {
|
} else {
|
||||||
|
@ -183,20 +183,29 @@ Client::~Client() = default;
|
||||||
|
|
||||||
Common::WebResult Client::PostJson(const std::string& path, const std::string& data,
|
Common::WebResult Client::PostJson(const std::string& path, const std::string& data,
|
||||||
bool allow_anonymous) {
|
bool allow_anonymous) {
|
||||||
return impl->GenericJson("POST", path, data, allow_anonymous);
|
return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {
|
Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {
|
||||||
return impl->GenericJson("GET", path, "", allow_anonymous);
|
return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json");
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data,
|
Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data,
|
||||||
bool allow_anonymous) {
|
bool allow_anonymous) {
|
||||||
return impl->GenericJson("DELETE", path, data, allow_anonymous);
|
return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json");
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) {
|
||||||
|
return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain");
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::WebResult Client::GetImage(const std::string& path, bool allow_anonymous) {
|
||||||
|
return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png");
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::WebResult Client::GetExternalJWT(const std::string& audience) {
|
Common::WebResult Client::GetExternalJWT(const std::string& audience) {
|
||||||
return PostJson(fmt::format("/jwt/external/{}", audience), "", false);
|
return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false,
|
||||||
|
"text/html");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace WebService
|
} // namespace WebService
|
||||||
|
|
|
@ -46,6 +46,22 @@ public:
|
||||||
Common::WebResult DeleteJson(const std::string& path, const std::string& data,
|
Common::WebResult DeleteJson(const std::string& path, const std::string& data,
|
||||||
bool allow_anonymous);
|
bool allow_anonymous);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a plain string from the specified path.
|
||||||
|
* @param path the URL segment after the host address.
|
||||||
|
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
|
||||||
|
* @return the result of the request.
|
||||||
|
*/
|
||||||
|
Common::WebResult GetPlain(const std::string& path, bool allow_anonymous);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an PNG image from the specified path.
|
||||||
|
* @param path the URL segment after the host address.
|
||||||
|
* @param allow_anonymous If true, allow anonymous unauthenticated requests.
|
||||||
|
* @return the result of the request.
|
||||||
|
*/
|
||||||
|
Common::WebResult GetImage(const std::string& path, bool allow_anonymous);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests an external JWT for the specific audience provided.
|
* Requests an external JWT for the specific audience provided.
|
||||||
* @param audience the audience of the JWT requested.
|
* @param audience the audience of the JWT requested.
|
||||||
|
|
Loading…
Reference in a new issue