feat: 初始代码

AM初始代码,迁移自gitlabwh

Log:
Task: https://pms.uniontech.com/task-view-108539.html
Influence:
Change-Id: I6096f97e5d68d13796ff5dc51d9858c0f40264a0
This commit is contained in:
tanfeng
2022-03-30 17:56:27 +08:00
parent 9414feb1f7
commit 0b22bb3adf
54 changed files with 3607 additions and 0 deletions

View File

@ -0,0 +1,55 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 REQUIRED COMPONENTS Core DBus Concurrent)
qt5_add_dbus_adaptor(ADAPTER_SOURCES
../../DBus/org.desktopspec.ApplicationManager.xml
impl/application_manager.h
ApplicationManager)
qt5_add_dbus_adaptor(ADAPTER_SOURCES
../../DBus/org.desktopspec.Application.xml
impl/application.h
Application)
qt5_add_dbus_adaptor(ADAPTER_SOURCES
../../DBus/org.desktopspec.ApplicationInstance.xml
impl/application_instance.h
ApplicationInstance)
add_definitions(-DUSE_QT)
set(SRCS ${PROJECT_BINARY_DIR}/src/define.h)
set(SRCS
./main.cpp
./impl/application_manager.h
./impl/application_manager.cpp
./impl/application.h
./impl/application.cpp
./impl/application_instance.h
./impl/application_instance.cpp
../modules/applicationhelper/helper.h
../modules/tools/desktop_deconstruction.hpp
../modules/socket/server.h
../modules/socket/server.cpp
../modules/methods/basic.h
../modules/methods/task.hpp
../modules/methods/instance.hpp
../modules/methods/quit.hpp
../modules/methods/registe.hpp
)
add_executable(deepin-application-manager
${SRCS}
${ADAPTER_SOURCES}
)
target_link_libraries(deepin-application-manager
Qt5::Core
Qt5::DBus
Qt5::Concurrent
)
install(TARGETS deepin-application-manager DESTINATION bin)

View File

@ -0,0 +1,168 @@
#include "application.h"
#include <QCryptographicHash>
#include <QDebug>
#include <QSettings>
#include <QThread>
#include <algorithm>
#include "../modules/applicationhelper/helper.h"
#include "../modules/tools/desktop_deconstruction.hpp"
#include "application_instance.h"
class ApplicationPrivate {
Application *q_ptr = nullptr;
Q_DECLARE_PUBLIC(Application);
QList<QSharedPointer<ApplicationInstance>> instances;
QSharedPointer<modules::ApplicationHelper::Helper> helper;
QString m_prefix;
Application::Type m_type;
public:
ApplicationPrivate(Application *parent) : q_ptr(parent) {}
~ApplicationPrivate() {}
QStringList categories() const
{
return helper->categories();
}
QString icon() const
{
return helper->icon();
}
QString id() const
{
return helper->id();
}
QStringList mimetypes() const
{
return helper->mimetypes();
}
QString comment(const QString &locale) const
{
return helper->comment(locale);
}
QString name(const QString &name) const
{
return helper->name(name);
}
};
Application::Application(const QString &prefix, Type type, QSharedPointer<modules::ApplicationHelper::Helper> helper) : QObject(nullptr), dd_ptr(new ApplicationPrivate(this))
{
Q_D(Application);
d->helper = helper;
d->m_type = type;
d->m_prefix = prefix;
}
Application::~Application() {}
QStringList Application::categories() const
{
Q_D(const Application);
return d->categories();
}
QString Application::icon() const
{
Q_D(const Application);
return d->icon();
}
QString Application::id() const
{
Q_D(const Application);
const QString id{ d->id() };
return QString("/%1/%2/%3").arg(d->m_prefix).arg(d->m_type == Application::Type::System ? "system" : "user").arg(id);
}
QList<QDBusObjectPath> Application::instances() const
{
Q_D(const Application);
QList<QDBusObjectPath> result;
for (const auto &ins : d->instances) {
result << ins->path();
}
return result;
}
QStringList Application::mimetypes() const
{
Q_D(const Application);
return d->mimetypes();
}
QString Application::Comment(const QString &locale)
{
Q_D(const Application);
return d->comment(locale);
}
QString Application::Name(const QString &locale)
{
Q_D(const Application);
return d->name(locale);
}
QDBusObjectPath Application::path() const
{
return QDBusObjectPath(QString("/org/desktopspec/Application/%1").arg(QString(QCryptographicHash::hash(id().toUtf8(), QCryptographicHash::Md5).toHex())));
}
Application::Type Application::type() const
{
Q_D(const Application);
return d->m_type;
}
QString Application::filePath() const
{
Q_D(const Application);
return d->helper->desktop();
}
QSharedPointer<ApplicationInstance> Application::createInstance()
{
Q_D(Application);
d->instances << QSharedPointer<ApplicationInstance>(new ApplicationInstance(this, d->helper));
connect(d->instances.last().get(), &ApplicationInstance::taskFinished, this, [=] {
for (auto it = d->instances.begin(); it != d->instances.end(); ++it) {
if ((*it).data() == sender()) {
d->instances.erase(it);
return;
}
}
qWarning() << "The instance should not be found!";
});
return d->instances.last();
}
QString Application::prefix() const
{
Q_D(const Application);
return d->m_prefix;
}

View File

@ -0,0 +1,60 @@
#ifndef A216803F_06DD_4F40_8FD1_5BAED85905BE
#define A216803F_06DD_4F40_8FD1_5BAED85905BE
#include <QSharedPointer>
#include <QObject>
#include <QDBusObjectPath>
namespace modules {
namespace ApplicationHelper {
class Helper;
}
}
class ApplicationPrivate;
class ApplicationInstance;
class Application : public QObject {
Q_OBJECT
QScopedPointer<ApplicationPrivate> dd_ptr;
Q_DECLARE_PRIVATE_D(qGetPtrHelper(dd_ptr), Application)
public:
enum class Type {
System,
User,
};
Application(const QString& prefix, Type type, QSharedPointer<modules::ApplicationHelper::Helper> helper);
~Application() override;
public: // PROPERTIES
Q_PROPERTY(QStringList categories READ categories)
QStringList categories() const;
Q_PROPERTY(QString icon READ icon)
QString icon() const;
Q_PROPERTY(QString id READ id)
QString id() const;
Q_PROPERTY(QList<QDBusObjectPath> instances READ instances)
QList<QDBusObjectPath> instances() const;
Q_PROPERTY(QStringList mimetypes READ mimetypes)
QStringList mimetypes() const;
QDBusObjectPath path() const;
QString prefix() const;
Type type() const;
QString filePath() const;
QSharedPointer<ApplicationInstance> createInstance();
public Q_SLOTS: // METHODS
QString Comment(const QString &locale);
QString Name(const QString &locale);
};
#endif /* A216803F_06DD_4F40_8FD1_5BAED85905BE */

View File

@ -0,0 +1,169 @@
#include "application_instance.h"
#include <qdatetime.h>
#include <QCryptographicHash>
#include <QDateTime>
#include <QProcess>
#include <QTimer>
#include <QUuid>
#include <QtConcurrent/QtConcurrent>
#include "../../modules/applicationhelper/helper.h"
#include "application.h"
#include "applicationinstanceadaptor.h"
#ifdef DEFINE_LOADER_PATH
#include "../../src/define.h"
#endif
class ApplicationInstancePrivate {
ApplicationInstance* q_ptr = nullptr;
Q_DECLARE_PUBLIC(ApplicationInstance);
Application* application;
ApplicationInstanceAdaptor* adapter;
QString m_path;
QSharedPointer<modules::ApplicationHelper::Helper> helper;
QDateTime startupTime;
QString m_id;
public:
ApplicationInstancePrivate(ApplicationInstance* parent) : q_ptr(parent)
{
startupTime = QDateTime::currentDateTime();
m_id = QString(QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Md5).toHex());
m_path = QString("/org/desktopspec/ApplicationInstance/%1").arg(m_id);
adapter = new ApplicationInstanceAdaptor(q_ptr);
}
~ApplicationInstancePrivate()
{
// disconnect dbus
QDBusConnection::sessionBus().unregisterObject(m_path);
}
void run()
{
#ifdef DEFINE_LOADER_PATH
const QString task_hash{ QString("DAM_TASK_HASH=%1").arg(m_id) };
const QString task_type{ "DAM_TASK_TYPE=freedesktop " };
QProcess* p = new QProcess(q_ptr);
p->connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), p, [=] {
qInfo().noquote() << p->readAllStandardOutput();
qWarning().noquote() << p->readAllStandardError();
});
p->connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), q_ptr, &ApplicationInstance::taskFinished);
p->connect(p, &QProcess::readyReadStandardOutput, p, [=] { qInfo() << p->readAllStandardOutput(); });
p->connect(p, &QProcess::readyReadStandardError, p, [=] { qWarning() << p->readAllStandardError(); });
p->setProgram(LOADER_PATH);
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("DAM_TASK_HASH", m_id);
env.insert("DAM_TASK_TYPE", "freedesktop");
p->setEnvironment(env.toStringList());
p->start();
p->waitForStarted();
if (p->state() == QProcess::ProcessState::NotRunning) {
emit q_ptr->taskFinished(p->exitCode());
}
#else
QDBusInterface systemd("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager");
QDBusReply<void> reply = systemd.call("StartUnit", QString("org.deskspec.application.instance@%1.service").arg(m_id), "replace-irreversibly");
if (!reply.isValid()) {
qInfo() << reply.error();
q_ptr->deleteLater();
}
#endif
}
void _exit()
{
#ifdef LOADER_PATH
#else
QDBusInterface systemd("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager");
qInfo() << systemd.call("StopUnit", QString("org.deskspec.application.instance@%1.service").arg(m_id), "replace-irreversibly");
#endif
}
void _kill() {}
};
ApplicationInstance::ApplicationInstance(Application* parent, QSharedPointer<modules::ApplicationHelper::Helper> helper) : QObject(nullptr), dd_ptr(new ApplicationInstancePrivate(this))
{
Q_D(ApplicationInstance);
d->application = parent;
d->helper = helper;
QTimer::singleShot(0, this, [=] {
QDBusConnection::sessionBus().registerObject(d->m_path, "org.desktopspec.ApplicationInstance", this);
d->run();
});
}
ApplicationInstance::~ApplicationInstance()
{
Q_D(ApplicationInstance);
qDebug() << "instance quit " << d->helper->desktop();
}
QDBusObjectPath ApplicationInstance::id() const
{
Q_D(const ApplicationInstance);
return d->application->path();
}
QString ApplicationInstance::hash() const
{
Q_D(const ApplicationInstance);
return d->m_id;
}
quint64 ApplicationInstance::startuptime() const
{
Q_D(const ApplicationInstance);
return d->startupTime.toSecsSinceEpoch();
}
QDBusObjectPath ApplicationInstance::path() const
{
Q_D(const ApplicationInstance);
return QDBusObjectPath(d->m_path);
}
Methods::Task ApplicationInstance::taskInfo() const
{
Q_D(const ApplicationInstance);
Methods::Task task;
task.id = d->m_id.toStdString();
task.runId = d->application->id().toStdString();
task.date = QString::number(startuptime()).toStdString();
// TODO: debug to display environment
task.environments.insert({ "DISPLAY", ":0" });
auto sysEnv = QProcessEnvironment::systemEnvironment();
for (const auto& key : sysEnv.keys()) {
task.environments.insert({ key.toStdString(), sysEnv.value(key).toStdString() });
}
return task;
}
void ApplicationInstance::Exit()
{
Q_D(ApplicationInstance);
return d->_exit();
}
void ApplicationInstance::Kill()
{
Q_D(ApplicationInstance);
return d->_kill();
}

View File

@ -0,0 +1,44 @@
#ifndef D6D05668_8A58_43AA_91C5_C6278643A1AF
#define D6D05668_8A58_43AA_91C5_C6278643A1AF
#include <QDBusObjectPath>
#include <QObject>
#include "../../modules/methods/task.hpp"
namespace modules {
namespace ApplicationHelper {
class Helper;
}
} // namespace modules
class Application;
class ApplicationInstancePrivate;
class ApplicationInstance : public QObject {
Q_OBJECT
QScopedPointer<ApplicationInstancePrivate> dd_ptr;
Q_DECLARE_PRIVATE_D(qGetPtrHelper(dd_ptr), ApplicationInstance)
public:
ApplicationInstance(Application* parent, QSharedPointer<modules::ApplicationHelper::Helper> helper);
~ApplicationInstance() override;
public: // PROPERTIES
Q_PROPERTY(QDBusObjectPath id READ id)
QDBusObjectPath id() const;
Q_PROPERTY(quint64 startuptime READ startuptime)
quint64 startuptime() const;
QDBusObjectPath path() const;
QString hash() const;
Methods::Task taskInfo() const;
Q_SIGNALS:
void taskFinished(int exitCode) const;
public Q_SLOTS: // METHODS
void Exit();
void Kill();
};
#endif /* D6D05668_8A58_43AA_91C5_C6278643A1AF */

View File

@ -0,0 +1,195 @@
#include "application_manager.h"
#include <unistd.h>
#include <iostream>
#include <map>
#include <mutex>
#include <nlohmann/json.hpp>
#include <thread>
#include "../../modules/methods/basic.h"
#include "../../modules/methods/instance.hpp"
#include "../../modules/methods/quit.hpp"
#include "../../modules/methods/registe.hpp"
#include "../../modules/methods/task.hpp"
#include "../../modules/socket/server.h"
#include "application.h"
#include "application_instance.h"
#include "applicationinstanceadaptor.h"
class ApplicationManagerPrivate : public QObject {
Q_OBJECT
ApplicationManager *q_ptr = nullptr;
Q_DECLARE_PUBLIC(ApplicationManager);
QList<QSharedPointer<Application>> applications;
Socket::Server server;
std::multimap<std::string, QSharedPointer<ApplicationInstance>> tasks;
public:
ApplicationManagerPrivate(ApplicationManager *parent) : QObject(parent), q_ptr(parent)
{
const QString socketPath{ QString("/run/user/%1/deepin-application-manager.socket").arg(getuid()) };
connect(&server, &Socket::Server::onReadyRead, this, &ApplicationManagerPrivate::recvClientData, Qt::QueuedConnection);
server.listen(socketPath.toStdString());
}
~ApplicationManagerPrivate() {}
private:
void recvClientData(int socket, const std::vector<char> &data)
{
std::string tmp;
for (char c : data) {
tmp += c;
}
using namespace nlohmann;
if (json::parse(tmp).is_null()) {
server.close(socket);
return;
}
Methods::Basic basic = json::parse(tmp);
do {
if (basic.type == "instance") {
Methods::Instance instance = nlohmann::json::parse(tmp);
auto find = tasks.find(instance.hash);
if (find != tasks.end()) {
nlohmann::json result = find->second->taskInfo();
write(socket, result.dump());
tasks.erase(find);
break;
}
}
if (basic.type == "quit") {
Methods::Quit quit = json::parse(tmp);
server.close(socket);
std::cout << "client quit" << std::endl;
break;
}
if (basic.type == "registe") {
Methods::Registe registe = nlohmann::json::parse(tmp);
Methods::Registe result;
result.state = false;
//std::lock_guard<std::mutex> lock(task_mutex);
for (auto it = tasks.begin(); it != tasks.end(); ++it) {
result.state = true;
result.hash = it->first;
}
write(socket, json(result).dump());
std::cout << "registe a new client" << std::endl;
break;
}
write(socket, json().dump());
} while (false);
}
void write(int socket, const std::vector<char> &data)
{
std::vector<char> tmp = data;
tmp.push_back('\0');
server.write(socket, tmp);
}
void write(int socket, const std::string &data)
{
std::vector<char> result;
std::copy(data.cbegin(), data.cend(), std::back_inserter(result));
return write(socket, result);
}
void write(int socket, const char c)
{
return write(socket, std::vector<char>(c));
}
};
ApplicationManager::ApplicationManager(QObject *parent) : QObject(parent), dd_ptr(new ApplicationManagerPrivate(this)) {}
ApplicationManager::~ApplicationManager() {}
void ApplicationManager::addApplication(const QList<QSharedPointer<Application>> &list)
{
Q_D(ApplicationManager);
d->applications = list;
}
QDBusObjectPath ApplicationManager::GetId(int pid)
{
return {};
}
QDBusObjectPath ApplicationManager::GetInformation(const QString &id)
{
Q_D(ApplicationManager);
for (const QSharedPointer<Application> &app : d->applications) {
if (app->id() == id) {
return app->path();
}
}
return {};
}
QList<QDBusObjectPath> ApplicationManager::GetInstances(const QString &id)
{
Q_D(const ApplicationManager);
for (const auto &app : d->applications) {
if (app->id() == id) {
return app->instances();
}
}
return {};
}
QDBusObjectPath ApplicationManager::Run(const QString &id)
{
Q_D(ApplicationManager);
// 创建一个实例
for (const QSharedPointer<Application> &app : d->applications) {
if (app->id() == id) {
// 创建任务所需的数据,并记录到任务队列,等待 loader 消耗
QSharedPointer<ApplicationInstance> instance{ app->createInstance() };
const std::string hash{ instance->hash().toStdString() };
connect(instance.get(), &ApplicationInstance::taskFinished, this, [=] {
for (auto it = d->tasks.begin(); it != d->tasks.end(); ++it) {
if (it->first == hash) {
d->tasks.erase(it);
break;
}
}
});
d->tasks.insert(std::make_pair(hash, instance));
return instance->path();
}
}
return {};
}
QList<QDBusObjectPath> ApplicationManager::instances() const
{
Q_D(const ApplicationManager);
QList<QDBusObjectPath> result;
for (const auto &app : d->applications) {
result += app->instances();
}
return result;
}
QList<QDBusObjectPath> ApplicationManager::list() const
{
Q_D(const ApplicationManager);
QList<QDBusObjectPath> result;
for (const QSharedPointer<Application> &app : d->applications) {
result << app->path();
}
return result;
}
#include "application_manager.moc"

View File

@ -0,0 +1,43 @@
#ifndef A2862DC7_5DA3_4129_9796_671D88015BED
#define A2862DC7_5DA3_4129_9796_671D88015BED
#include <QObject>
#include <QDBusObjectPath>
#include <QList>
class Application;
class ApplicationInstance;
class ApplicationManagerPrivate;
class ApplicationManager : public QObject {
Q_OBJECT
Q_PROPERTY(QList<QDBusObjectPath> instances READ instances)
Q_PROPERTY(QList<QDBusObjectPath> list READ list)
QScopedPointer<ApplicationManagerPrivate> dd_ptr;
Q_DECLARE_PRIVATE_D(qGetPtrHelper(dd_ptr), ApplicationManager)
ApplicationManager(QObject *parent = nullptr);
public:
~ApplicationManager() override;
static ApplicationManager* Instance() {
static ApplicationManager manager;
return &manager;
}
void addApplication(const QList<QSharedPointer<Application>> &list);
signals:
void requestCreateInstance(const QSharedPointer<ApplicationInstance> instance);
public: // PROPERTIES
QList<QDBusObjectPath> instances() const;
QList<QDBusObjectPath> list() const;
public Q_SLOTS: // METHODS
QDBusObjectPath GetId(int pid);
QDBusObjectPath GetInformation(const QString &id);
QList<QDBusObjectPath> GetInstances(const QString &id);
QDBusObjectPath Run(const QString &id);
};
#endif /* A2862DC7_5DA3_4129_9796_671D88015BED */

81
src/service/main.cpp Normal file
View File

@ -0,0 +1,81 @@
#include <QCoreApplication>
#include "impl/application_manager.h"
#include "impl/application.h"
#include "applicationmanageradaptor.h"
#include "applicationadaptor.h"
#include "../modules/applicationhelper/helper.h"
#include <QDir>
#include <pwd.h>
QFileInfoList scan(const QString &path)
{
QDir dir(path);
dir.setFilter(QDir::Files);
dir.setNameFilters({ "*.desktop" });
return dir.entryInfoList();
}
// 扫描系统目录
// 扫描用户目录
QList<QSharedPointer<Application>> scanFiles()
{
QList<QSharedPointer<Application>> applications;
auto apps = scan("/usr/share/applications/");
for (const QFileInfo &info : apps) {
applications << QSharedPointer<Application>(new Application(
"freedesktop",
Application::Type::System,
QSharedPointer<modules::ApplicationHelper::Helper>(new modules::ApplicationHelper::Helper(info.filePath()))
));
}
struct passwd *user = getpwent();
while (user) {
auto userApps = scan(QString("%1/.local/share/applications/").arg(user->pw_dir));
for (const QFileInfo &info : userApps) {
applications << QSharedPointer<Application>(new Application(
"freedesktop",
Application::Type::System,
QSharedPointer<modules::ApplicationHelper::Helper>(new modules::ApplicationHelper::Helper(info.filePath()))
));
}
user = getpwent();
}
endpwent();
auto linglong = scan("/deepin/linglong/entries/share/applications/");
for (const QFileInfo &info : linglong) {
applications << QSharedPointer<Application>(new Application(
"linglong",
Application::Type::System,
QSharedPointer<modules::ApplicationHelper::Helper>(new modules::ApplicationHelper::Helper(info.filePath()))
));
}
return applications;
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
new ApplicationManagerAdaptor(ApplicationManager::Instance());
QDBusConnection::sessionBus().registerService("org.desktopspec.Application");
QDBusConnection::sessionBus().registerService("org.desktopspec.ApplicationManager");
QDBusConnection::sessionBus().registerObject("/org/desktopspec/ApplicationManager", "org.desktopspec.ApplicationManager", ApplicationManager::Instance());
QList<QSharedPointer<Application>> apps{ scanFiles() };
QList<QSharedPointer<ApplicationAdaptor>> appAdapters;
for (const QSharedPointer<Application> app : apps) {
QSharedPointer<ApplicationAdaptor> adapter = QSharedPointer<ApplicationAdaptor>(new ApplicationAdaptor(app.get()));
appAdapters << adapter;
QDBusConnection::sessionBus().registerObject(app->path().path(), "org.desktopspec.Application", app.get());
}
ApplicationManager::Instance()->addApplication(apps);
return app.exec();
}