first commit

This commit is contained in:
2025-09-13 15:34:27 +02:00
commit d423636b03
18 changed files with 475 additions and 0 deletions

74
.gitignore vendored Normal file
View File

@@ -0,0 +1,74 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

3
backup.cpp Normal file
View File

@@ -0,0 +1,3 @@
#include "backup.h"
Backup::Backup() {}

10
backup.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef BACKUP_H
#define BACKUP_H
class Backup
{
public:
Backup();
};
#endif // BACKUP_H

71
client.cpp Normal file
View File

@@ -0,0 +1,71 @@
#include "client.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QUrl>
#include <QJsonDocument>
Client::Client(QString url, QString username, QString password) {
this->url = url;
this->username = username;
this->password = password;
}
void Client::version(std::function<void (Information)> callback, std::function<void (QString)> errorCallback)
{
QNetworkAccessManager manager;
QUrl url(this->url);
url = url.resolved(QUrl("/api/v1/version/"));
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, [&]() {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
QJsonDocument doc = QJsonDocument::fromJson(response);
Information info(doc.object());
callback(info);
} else {
errorCallback(reply->errorString());
}
reply->deleteLater();
});
}
void Client::hash(QString gameID, std::function<void(QString)> callback, std::function<void(QString)> errorCallback)
{
QNetworkAccessManager manager;
QUrl url(this->url);
url = url.resolved("/api/v1/games/"+gameID+"/metadata");
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, [&]() {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
QJsonDocument doc = QJsonDocument::fromJson(response);
callback(doc.object()["md5"].toString());
} else {
errorCallback(reply->errorString());
}
reply->deleteLater();
});
}
void Client::metadata(QString gameID, std::function<void(Metadata)> callback, std::function<void(QString)> errorCallback)
{
QNetworkAccessManager manager;
QUrl url(this->url);
url = url.resolved("/api/v1/games/"+gameID+"/metadata");
QNetworkRequest request(url);
QNetworkReply *reply = manager.get(request);
QObject::connect(reply, &QNetworkReply::finished, [&]() {
if (reply->error() == QNetworkReply::NoError) {
QByteArray response = reply->readAll();
QJsonDocument doc = QJsonDocument::fromJson(response);
Metadata m(doc.object());
callback(m);
} else {
errorCallback(reply->errorString());
}
reply->deleteLater();
});
}

35
client.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include "information.h"
#include "metadata.h"
#include "backup.h"
class Client
{
public:
Client(QString url, QString username, QString password);
bool exists(QString gameID, std::function<void(bool)> callback, std::function<void(QString)> errorCallback);
void version(std::function<void(Information)> callback, std::function<void(QString)> errorCallback);
void hash(QString gameID, std::function<void(QString)> callback, std::function<void(QString)> errorCallback);
void metadata(QString gameID, std::function<void(Metadata)> callback, std::function<void(QString)> errorCallback);
void pushSave(QString archivePath, Metadata game, std::function<void(Metadata)> callback, std::function<void(QString)> errorCallback);
void pushBackup(QString archivePath, Metadata game, std::function<void(Metadata)> callback, std::function<void(QString)> errorCallback);
void listArchives(QString gameID, std::function<void(QVector<QString>)> callback, std::function<void(QString)> errorCallback);
void archiveInfo(QString gameID, QString backupID, std::function<void(Backup)> callback, std::function<void(QString)> errorCallback);
void pull(QString gameID, QString archivePath, std::function<void(Metadata)> callback, std::function<void(QString)> errorCallback);
void pullBackup(QString gameID, QString backupID, QString archivePath, std::function<void(Metadata)> callback, std::function<void(QString)> errorCallback);
bool ping(std::function<void(Metadata)> callback, std::function<void(QString)> errorCallback);
void all(std::function<void(QVector<Metadata>)> callback, std::function<void(QString)> errorCallback);
QString baseURL();
private:
QString url;
QString username;
QString password;
};
#endif // CLIENT_H

35
cloudsave-gui.pro Normal file
View File

@@ -0,0 +1,35 @@
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
backup.cpp \
client.cpp \
information.cpp \
main.cpp \
mainwindow.cpp \
metadata.cpp
HEADERS += \
backup.h \
client.h \
information.h \
mainwindow.h \
metadata.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
resources.qrc

18
information.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include "information.h"
Information::Information(QString version, QString apiVersion, QString goVersion, QString osName, QString osArchitecture) {
this->_version = version;
this->_apiVersion = apiVersion;
this->_goVersion = goVersion;
this->_osName = osName;
this->_osArchitecture = osArchitecture;
}
Information::Information(QJsonObject obj)
{
this->_version = obj["version"].toString();
this->_apiVersion = obj["api_version"].toString();
this->_goVersion = obj["go_version"].toString();
this->_osName = obj["os_name"].toString();
this->_osArchitecture = obj["os_architecture"].toString();
}

21
information.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef INFORMATION_H
#define INFORMATION_H
#include <QString>
#include <QJsonObject>
class Information
{
public:
Information(QString version, QString apiVersion, QString goVersion, QString osName, QString osArchitecture);
Information(QJsonObject obj);
private:
QString _version;
QString _apiVersion;
QString _goVersion;
QString _osName;
QString _osArchitecture;
};
#endif // INFORMATION_H

11
main.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

14
mainwindow.cpp Normal file
View File

@@ -0,0 +1,14 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}

23
mainwindow.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

108
mainwindow.ui Normal file
View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1002</width>
<height>594</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>1002</width>
<height>594</height>
</size>
</property>
<property name="windowTitle">
<string>CloudSave</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="tableView"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>90</height>
</size>
</property>
<property name="windowTitle">
<string>toolBar</string>
</property>
<property name="movable">
<bool>false</bool>
</property>
<property name="iconSize">
<size>
<width>70</width>
<height>37</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionAdd"/>
<addaction name="separator"/>
<addaction name="actionScan"/>
<addaction name="actionSync"/>
</widget>
<action name="actionAdd">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icon/resources/plus-solid-full.svg</normaloff>:/icon/resources/plus-solid-full.svg</iconset>
</property>
<property name="text">
<string>Add</string>
</property>
</action>
<action name="actionScan">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icon/resources/magnifying-glass-solid-full.svg</normaloff>:/icon/resources/magnifying-glass-solid-full.svg</iconset>
</property>
<property name="text">
<string>Scan</string>
</property>
</action>
<action name="actionSync">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icon/resources/arrows-rotate-solid-full.svg</normaloff>:/icon/resources/arrows-rotate-solid-full.svg</iconset>
</property>
<property name="text">
<string>Sync</string>
</property>
</action>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections/>
</ui>

19
metadata.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include "metadata.h"
Metadata::Metadata(QString name) {
this->_name = name;
}
Metadata::Metadata(QJsonObject obj)
{
this->_id = obj["id"].toString();
this->_name = obj["name"].toString();
this->_version = obj["version"].toInt();
this->_date = QDateTime::fromString(obj["date"].toString());
this->_md5 = obj["md5"].toString();
}
QString Metadata::md5()
{
return this->_md5;
}

23
metadata.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef METADATA_H
#define METADATA_H
#include <QString>
#include <QJsonObject>
#include <QDateTime>
class Metadata
{
public:
Metadata(QString name);
Metadata(QJsonObject obj);
QString md5();
private:
QString _id;
QString _name;
uint64_t _version;
QDateTime _date;
QString _md5;
};
#endif // METADATA_H

7
resources.qrc Normal file
View File

@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/icon">
<file>resources/plus-solid-full.svg</file>
<file>resources/arrows-rotate-solid-full.svg</file>
<file>resources/magnifying-glass-solid-full.svg</file>
</qresource>
</RCC>

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.0.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M129.9 292.5C143.2 199.5 223.3 128 320 128C373 128 421 149.5 455.8 184.2C456 184.4 456.2 184.6 456.4 184.8L464 192L416.1 192C398.4 192 384.1 206.3 384.1 224C384.1 241.7 398.4 256 416.1 256L544.1 256C561.8 256 576.1 241.7 576.1 224L576.1 96C576.1 78.3 561.8 64 544.1 64C526.4 64 512.1 78.3 512.1 96L512.1 149.4L500.8 138.7C454.5 92.6 390.5 64 320 64C191 64 84.3 159.4 66.6 283.5C64.1 301 76.2 317.2 93.7 319.7C111.2 322.2 127.4 310 129.9 292.6zM573.4 356.5C575.9 339 563.7 322.8 546.3 320.3C528.9 317.8 512.6 330 510.1 347.4C496.8 440.4 416.7 511.9 320 511.9C267 511.9 219 490.4 184.2 455.7C184 455.5 183.8 455.3 183.6 455.1L176 447.9L223.9 447.9C241.6 447.9 255.9 433.6 255.9 415.9C255.9 398.2 241.6 383.9 223.9 383.9L96 384C87.5 384 79.3 387.4 73.3 393.5C67.3 399.6 63.9 407.7 64 416.3L65 543.3C65.1 561 79.6 575.2 97.3 575C115 574.8 129.2 560.4 129 542.7L128.6 491.2L139.3 501.3C185.6 547.4 249.5 576 320 576C449 576 555.7 480.6 573.4 356.5z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.0.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M480 272C480 317.9 465.1 360.3 440 394.7L566.6 521.4C579.1 533.9 579.1 554.2 566.6 566.7C554.1 579.2 533.8 579.2 521.3 566.7L394.7 440C360.3 465.1 317.9 480 272 480C157.1 480 64 386.9 64 272C64 157.1 157.1 64 272 64C386.9 64 480 157.1 480 272zM272 416C351.5 416 416 351.5 416 272C416 192.5 351.5 128 272 128C192.5 128 128 192.5 128 272C128 351.5 192.5 416 272 416z"/></svg>

After

Width:  |  Height:  |  Size: 595 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free 7.0.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M352 128C352 110.3 337.7 96 320 96C302.3 96 288 110.3 288 128L288 288L128 288C110.3 288 96 302.3 96 320C96 337.7 110.3 352 128 352L288 352L288 512C288 529.7 302.3 544 320 544C337.7 544 352 529.7 352 512L352 352L512 352C529.7 352 544 337.7 544 320C544 302.3 529.7 288 512 288L352 288L352 128z"/></svg>

After

Width:  |  Height:  |  Size: 522 B