Show live user storage quota in the member file browser
This commit is contained in:
1 parent
359a327ec4
commit
4fdecb697b
2 files changed
+62
No files matched your search
@@ -20,6 +20,9 @@
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
#include <QLocale>
|
||||
#include <limits>
|
||||
#include <cstring>
|
||||
extern "C" {
|
||||
#include "member_files/member_files.h"
|
||||
@@ -29,6 +32,10 @@ extern "C" {
|
||||
}
|
||||
|
||||
static QString text(const char* value) { return QCoreApplication::translate("ChatGui", value); }
|
||||
static QString quotaSize(quint64 bytes) {
|
||||
return bytes <= (quint64)std::numeric_limits<qint64>::max() ? QLocale().formattedDataSize((qint64)bytes, 2) :
|
||||
text("%1 bytes").arg(QLocale().toString(bytes));
|
||||
}
|
||||
static quint64 requestId() { quint64 id; do { id = QRandomGenerator::global()->generate64(); } while (!id); return id; }
|
||||
static bool copyPath(char* out, const QString& value) {
|
||||
QByteArray bytes = value.toUtf8();
|
||||
@@ -43,6 +50,10 @@ MemberFileBrowser::MemberFileBrowser(DbManager* db, QWidget* parent) : QDialog(p
|
||||
m_servers = new QComboBox(this); m_owners = new QComboBox(this);
|
||||
selectors->addWidget(new QLabel(text("Media server:"), this)); selectors->addWidget(m_servers, 1);
|
||||
selectors->addWidget(new QLabel(text("Member:"), this)); selectors->addWidget(m_owners, 1); layout->addLayout(selectors);
|
||||
m_quota = new QLabel(text("Select a member to see storage quota"), this);
|
||||
m_quota->setObjectName("memberFilesQuota"); layout->addWidget(m_quota);
|
||||
auto* quotaTimer = new QTimer(this); quotaTimer->setInterval(2000);
|
||||
connect(quotaTimer, &QTimer::timeout, this, [this]() { if (isVisible()) requestQuota(); }); quotaTimer->start();
|
||||
auto* navigation = new QHBoxLayout;
|
||||
auto* up = new QPushButton(text("Up"), this); auto* reload = new QPushButton(text("Refresh"), this);
|
||||
m_location = new QLineEdit(this); m_location->setPlaceholderText(text("Path inside the member directory"));
|
||||
@@ -91,6 +102,7 @@ MemberFileBrowser::MemberFileBrowser(DbManager* db, QWidget* parent) : QDialog(p
|
||||
|
||||
MemberFileBrowser::~MemberFileBrowser() {
|
||||
cancel(); cancelRequest(m_listId);
|
||||
cancelRequest(m_quotaId);
|
||||
for (auto id : m_actions.keys()) cancelRequest(id);
|
||||
}
|
||||
|
||||
@@ -162,11 +174,25 @@ void MemberFileBrowser::cancelRequest(quint64 id) {
|
||||
q->inst = gui_bridge_get_inst(); q->id = id; gui_bridge_post_uasync_fn(member_files_gui_cancel, q);
|
||||
}
|
||||
|
||||
void MemberFileBrowser::requestQuota() {
|
||||
if (m_quotaId || !owner() || !server() || !gui_bridge_is_uasync_ready()) return;
|
||||
mf_message q{}; q.command = MF_QUOTA; q.owner = owner();
|
||||
if (post(q)) m_quotaId = q.request_id;
|
||||
else {
|
||||
m_quota->setText(text("Quota unavailable"));
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "member_files: GUI quota request failed owner=%llu", (unsigned long long)owner());
|
||||
}
|
||||
}
|
||||
|
||||
void MemberFileBrowser::refresh() {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "member_files: GUI refresh old_id=%llu group=%llx server=%llx owner=%llx path=%s",
|
||||
(unsigned long long)m_listId, (unsigned long long)m_group, (unsigned long long)server(), (unsigned long long)owner(), qPrintable(m_path));
|
||||
cancelRequest(m_listId); m_listId = 0; m_entries->clear(); m_location->setText(m_path); updateActions();
|
||||
cancelRequest(m_quotaId); m_quotaId = 0; m_refreshGeneration++;
|
||||
m_quota->setToolTip(QString());
|
||||
m_quota->setText(owner() ? text("Loading quota…") : text("Select a member to see storage quota"));
|
||||
if (!server()) { m_status->setText(text("No media server in this group")); return; }
|
||||
requestQuota();
|
||||
mf_message q{}; q.command = MF_LIST; q.owner = owner();
|
||||
if (!copyPath(q.path, m_path) || !post(q)) { m_status->setText(text("Unable to request directory")); return; }
|
||||
m_listId = q.request_id; m_entries->setSortingEnabled(false); m_status->setText(text("Loading directory…"));
|
||||
@@ -200,9 +226,41 @@ void MemberFileBrowser::onResponse(const uint8_t* data, int length) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "member_files: GUI response id=%llu list_id=%llu cmd=%s status=%s bytes=%u owner=%llx/%llx path=%s",
|
||||
(unsigned long long)r.request_id, (unsigned long long)m_listId, mf_command_text(r.command), mf_status_text(r.status), r.data_len,
|
||||
(unsigned long long)r.owner, (unsigned long long)owner(), r.path);
|
||||
if (r.command == MF_QUOTA) {
|
||||
if (r.request_id != m_quotaId || r.owner != owner()) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "member_files: GUI stale quota response id=%llu", (unsigned long long)r.request_id);
|
||||
return;
|
||||
}
|
||||
m_quotaId = 0;
|
||||
if (r.status) {
|
||||
m_quota->setText(r.status == MF_BUSY ? text("Loading quota…") : text("Quota unavailable"));
|
||||
m_quota->setToolTip(QString::fromUtf8(mf_status_text(r.status)));
|
||||
if (r.status != MF_BUSY) DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "member_files: GUI quota failed status=%s", mf_status_text(r.status));
|
||||
return;
|
||||
}
|
||||
if (r.data_len != MF_QUOTA_BYTES || !mf_get64(r.data + 8)) {
|
||||
m_quota->setText(text("Quota unavailable"));
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "member_files: GUI malformed quota response bytes=%u", r.data_len);
|
||||
return;
|
||||
}
|
||||
quint64 used = mf_get64(r.data), limit = mf_get64(r.data + 8), reserved = mf_get64(r.data + 16);
|
||||
QString label = text("Storage: %1 used / %2 total").arg(quotaSize(used), quotaSize(limit));
|
||||
if (reserved) label += text(" · Reserved for uploads: %1").arg(quotaSize(reserved));
|
||||
m_quota->setText(label);
|
||||
m_quota->setToolTip(text("Used: %1 bytes\nLimit: %2 bytes\nReserved: %3 bytes").arg(used).arg(limit).arg(reserved));
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "member_files: GUI quota owner=%llu used=%llu limit=%llu reserved=%llu",
|
||||
(unsigned long long)owner(), (unsigned long long)used, (unsigned long long)limit, (unsigned long long)reserved);
|
||||
return;
|
||||
}
|
||||
if (r.request_id == m_listId && r.owner == owner() && QString::fromUtf8(r.path) == m_path) {
|
||||
if (r.status) {
|
||||
m_listId = 0;
|
||||
if (r.status == MF_BUSY) {
|
||||
quint64 generation = m_refreshGeneration;
|
||||
m_status->setText(text("Loading directory…"));
|
||||
QTimer::singleShot(1000, this, [this, generation]() { if (generation == m_refreshGeneration) refresh(); });
|
||||
return;
|
||||
}
|
||||
if (r.status == MF_STALE && m_staleRetries++ < 1) { refresh(); return; }
|
||||
m_entries->clear(); m_status->setText(QString::fromUtf8(mf_status_text(r.status))); return;
|
||||
}
|
||||
@@ -300,6 +358,7 @@ void MemberFileBrowser::onTransfer(const uint8_t* data, int length) {
|
||||
if (m_group == m_transferGroup && server() == m_transferServer) refresh();
|
||||
}
|
||||
m_openAfter = false;
|
||||
if (!m_quotaId) requestQuota();
|
||||
}
|
||||
|
||||
void MemberFileBrowser::mutate(uint8_t command) {
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
void onTransfer(const uint8_t* data, int length);
|
||||
private:
|
||||
void refresh();
|
||||
void requestQuota();
|
||||
void navigate(const QString& path);
|
||||
void enter(QTreeWidgetItem* item);
|
||||
void updateActions();
|
||||
@@ -42,6 +43,7 @@ private:
|
||||
void cancelRequest(quint64 id);
|
||||
DbManager* m_db;
|
||||
quint64 m_group = 0, m_listId = 0, m_transferId = 0;
|
||||
quint64 m_quotaId = 0, m_refreshGeneration = 0;
|
||||
quint64 m_transferGroup = 0, m_transferServer = 0;
|
||||
QString m_path, m_local;
|
||||
bool m_openAfter = false;
|
||||
@@ -53,5 +55,6 @@ private:
|
||||
QTreeWidget* m_entries;
|
||||
QPushButton *m_upload, *m_download, *m_mkdir, *m_rename, *m_remove, *m_cancel;
|
||||
QLabel* m_status;
|
||||
QLabel* m_quota;
|
||||
QProgressBar* m_progress;
|
||||
};
|
||||
Reference in new issue
Block a user