From 0b70897ce88aad88b5dfce38dd8676ed1ac14d79 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Fri, 25 Mar 2016 12:03:38 -0400 Subject: [PATCH] Add a new API call/system: sysadm/pkg. This system reads the pkg database directly and returns any relevant information about the pkgs requested. Note: The "repo" input is optional (defaults to "local"), and the "pkg_origins" will become optional here soon as well (going to make it default to listing all pkgs if the pkg_origins variable is missing/empty). REST Request: ------------------------------- PUT /sysadm/pkg { "pkg_origins" : [ "x11/lumina" ], "repo" : "local", "action" : "pkg_info" } WebSocket Request: ------------------------------- { "name" : "pkg", "namespace" : "sysadm", "args" : { "repo" : "local", "action" : "pkg_info", "pkg_origins" : [ "x11/lumina" ] }, "id" : "fooid" } Response: ------------------------------- { "args": { "pkg_info": { "x11/lumina": { "arch": "FreeBSD:11:amd64", "automatic": "0", "comment": "Lumina Desktop Environment", "dep_formula": "", "dependencies": [ "x11-toolkits/qt5-gui", "x11/qt5-x11extras", "x11-wm/fluxbox", "x11/libXdamage", "devel/qt5-linguist", "x11/numlockx", "devel/qt5-buildtools", "multimedia/qt5-multimedia", "graphics/qt5-svg", "x11/xbrightness", "x11/xorg", "devel/desktop-file-utils", "devel/qt5-concurrent", "x11/libX11", "net/qt5-network", "x11-themes/fluxbox-tenr-styles-pack", "x11-themes/kde4-icons-oxygen", "devel/qt5-core", "x11/xscreensaver", "multimedia/gstreamer1-plugins-core", "graphics/qt5-imageformats" ], "desc": "Lumina-DE is a lightweight, BSD licensed desktop environment,\ndesigned specifically for use on FreeBSD\n\nWWW: http://lumina-desktop.org", "files": [ "/usr/local/share/licenses/lumina-0.8.8_2,1/catalog.mk", "/usr/local/share/licenses/lumina-0.8.8_2,1/LICENSE", "/usr/local/share/licenses/lumina-0.8.8_2,1/BSD3CLAUSE", "/usr/local/bin/Lumina-DE", "/usr/local/bin/lumina-config", "/usr/local/bin/lumina-fileinfo", "/usr/local/bin/lumina-fm", "/usr/local/bin/lumina-info", "/usr/local/bin/lumina-open", "/usr/local/bin/lumina-screenshot", "/usr/local/bin/lumina-search", "/usr/local/bin/lumina-xconfig", "/usr/local/etc/luminaDesktop.conf.dist", "/usr/local/include/LuminaOS.h", "/usr/local/include/LuminaSingleApplication.h", "/usr/local/include/LuminaThemes.h", "/usr/local/include/LuminaUtils.h", "/usr/local/include/LuminaX11.h", "/usr/local/include/LuminaXDG.h", "/usr/local/lib/libLuminaUtils.so", "/usr/local/lib/libLuminaUtils.so.1", "/usr/local/lib/libLuminaUtils.so.1.0", "/usr/local/lib/libLuminaUtils.so.1.0.0", "/usr/local/share/Lumina-DE/Login.ogg", "/usr/local/share/Lumina-DE/Logout.ogg", "/usr/local/share/Lumina-DE/colors/Black.qss.colors", "/usr/local/share/Lumina-DE/colors/Blue-Light.qss.colors", "/usr/local/share/Lumina-DE/colors/Grey-Dark.qss.colors", "/usr/local/share/Lumina-DE/colors/Lumina-Glass.qss.colors", "/usr/local/share/Lumina-DE/colors/Lumina-Gold.qss.colors", "/usr/local/share/Lumina-DE/colors/Lumina-Green.qss.colors", "/usr/local/share/Lumina-DE/colors/Lumina-Purple.qss.colors", "/usr/local/share/Lumina-DE/colors/Lumina-Red.qss.colors", "/usr/local/share/Lumina-DE/colors/PCBSD10-Default.qss.colors", "/usr/local/share/Lumina-DE/colors/Solarized-Dark.qss.colors", "/usr/local/share/Lumina-DE/colors/Solarized-Light.qss.colors", "/usr/local/share/Lumina-DE/desktop-background.jpg", "/usr/local/share/Lumina-DE/fluxbox-init-rc", "/usr/local/share/Lumina-DE/fluxbox-keys", "/usr/local/share/Lumina-DE/luminaDesktop.conf", "/usr/local/share/Lumina-DE/quickplugins/quick-sample.qml", "/usr/local/share/Lumina-DE/themes/Lumina-default.qss.template", "/usr/local/share/Lumina-DE/themes/None.qss.template", "/usr/local/share/applications/lumina-fm.desktop", "/usr/local/share/applications/lumina-info.desktop", "/usr/local/share/applications/lumina-screenshot.desktop", "/usr/local/share/applications/lumina-search.desktop", "/usr/local/share/applications/lumina-support.desktop", "/usr/local/share/pixmaps/Insight-FileManager.png", "/usr/local/share/pixmaps/Lumina-DE.png", "/usr/local/share/wallpapers/Lumina-DE/Lumina_Wispy_gold.jpg", "/usr/local/share/wallpapers/Lumina-DE/Lumina_Wispy_green.jpg", "/usr/local/share/wallpapers/Lumina-DE/Lumina_Wispy_purple.jpg", "/usr/local/share/wallpapers/Lumina-DE/Lumina_Wispy_red.jpg", "/usr/local/share/xsessions/Lumina-DE.desktop" ], "flatsize": "12324767", "icon": "\\\"http://www.pcbsd.org/appcafe/icons/x11_lumina.png\\\"", "id": "2541", "licenselogic": "1", "licenses": [ "BSD3CLAUSE" ], "locked": "0", "maintainer": "kmoore@FreeBSD.org", "manifestdigest": "2$0$4ypg5zrco9upyuioczmo3uwbtdd5yart7xuit6fx3gjrn1k979qb", "message": "[{\"message\":\"The Lumina Desktop Environment has been installed!\\n\\nAn entry for for launching Lumina from a graphical login manager has already been added to the system, but if you with to start Lumina manually, you will need to do one of the following:\\n1) Put the line \\\"exec Lumina-DE\\\" at the end of your user's \\\"~/.xinitrc\\\" file before running startx\\n2) Wrap the Lumina binary call with an X initialization call: \\nExample: \\\"xinit ${PREFIX}/bin/Lumina-DE -- :0\\\"\\n\\nAlso note that the system-wide default settings for Lumina are contained in ${PREFIX}/etc/luminaDesktop.conf[.dist]. While it is possible to customize the desktop to the user's liking after logging in, you may want to adjust the default settings as necessary if there are multiple user accounts on this system.\"}]", "mtree_id": "", "name": "lumina", "options": { "MULTIMEDIA": "on", "PCBSD": "on" }, "origin": "x11/lumina", "pkg_format_version": "", "prefix": "/usr/local", "repo_type": "binary", "repository": "pcbsd-major", "screen1": "\\\"http://www.pcbsd.org/appcafe/screenshots/x11/lumina/screen1.png\\\"", "shlibs_provided": [ "libLuminaUtils.so.1" ], "shlibs_required": [ "libxcb.so.1", "libxcb-composite.so.0", "libxcb-damage.so.0", "libXdamage.so.1", "libxcb-util.so.1", "libGL.so.1", "libQt5Core.so.5", "libxcb-image.so.0", "libxcb-icccm.so.4", "libxcb-ewmh.so.2", "libQt5Gui.so.5", "libQt5Network.so.5", "libQt5Widgets.so.5", "libQt5Concurrent.so.5", "libQt5Multimedia.so.5", "libQt5MultimediaWidgets.so.5", "libQt5Svg.so.5", "libQt5X11Extras.so.5" ], "time": "1458334158", "version": "0.8.8_2,1", "www": "http://lumina-desktop.org" } } }, "id": "fooid", "name": "response", "namespace": "sysadm" } --- src/server/WebBackend.cpp | 35 ++++++++ src/server/WebSocket.h | 2 + src/server/library/library.pri | 6 +- src/server/library/sysadm-pkg.cpp | 139 ++++++++++++++++++++++++++++++ src/server/library/sysadm-pkg.h | 26 ++++++ src/server/server.pro | 2 +- 6 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 src/server/library/sysadm-pkg.cpp create mode 100644 src/server/library/sysadm-pkg.h diff --git a/src/server/WebBackend.cpp b/src/server/WebBackend.cpp index ed313bd..89c98af 100644 --- a/src/server/WebBackend.cpp +++ b/src/server/WebBackend.cpp @@ -18,6 +18,7 @@ #include "library/sysadm-systemmanager.h" #include "library/sysadm-update.h" #include "library/sysadm-zfs.h" +#include "library/sysadm-pkg.h" #include "syscache-client.h" @@ -67,10 +68,16 @@ RestOutputStruct::ExitCode WebSocket::AvailableSubsystems(bool allaccess, QJsonO out->insert("sysadm/iohyve", "read/write"); } + // - zfs if(QFile::exists("/sbin/zfs") && QFile::exists("/sbin/zpool")){ out->insert("sysadm/zfs", allaccess ? "read/write" : "read"); } + // - pkg + if(QFile::exists("/usr/local/sbin/pkg")){ + out->insert("sysadm/pkg", "read/write"); + } + // - Generic system information out->insert("sysadm/systemmanager","read/write"); @@ -123,6 +130,8 @@ RestOutputStruct::ExitCode WebSocket::EvaluateBackendRequest(const RestInputStru return EvaluateSysadmUpdateRequest(IN.args, out); }else if(namesp=="sysadm" && name=="zfs"){ return EvaluateSysadmZfsRequest(IN.args, out); + }else if(namesp=="sysadm" && name=="pkg"){ + return EvaluateSysadmPkgRequest(IN.args, out); }else{ return RestOutputStruct::BADREQUEST; } @@ -681,3 +690,29 @@ RestOutputStruct::ExitCode WebSocket::EvaluateSysadmZfsRequest(const QJsonValue return RestOutputStruct::OK; } + +// ==== SYSADM PKG API ==== +RestOutputStruct::ExitCode WebSocket::EvaluateSysadmPkgRequest(const QJsonValue in_args, QJsonObject *out){ + if(!in_args.isObject() || !in_args.toObject().contains("action") ){ return RestOutputStruct::BADREQUEST; } + //REQUIRED: "action" + QString act = in_args.toObject().value("action").toString(); + //OPTIONAL: "repo" (uses local repo database by default) + QString repo = "local"; + if(in_args.toObject().contains("repo")){ repo = in_args.toObject().value("repo").toString(); } + //OPTIONAL: "pkg_origins" (defaults to everything for listing functions) + QStringList pkgs; + if(in_args.toObject().contains("pkg_origins")){ + if(in_args.toObject().value("pkg_origins").isString()){ pkgs << in_args.toObject().value("pkg_origins").toString(); } + else if(in_args.toObject().value("pkg_origins").isArray()){ pkgs = JsonArrayToStringList(in_args.toObject().value("pkg_origins").toArray()); } + } + //Parse + if(act=="pkg_info"){ + QJsonObject info = sysadm::PKG::pkg_info(pkgs, repo); + if(!pkgs.isEmpty()){ out->insert("pkg_info",info); } + }else{ + //unknown action + return RestOutputStruct::BADREQUEST; + } + + return RestOutputStruct::OK; +} \ No newline at end of file diff --git a/src/server/WebSocket.h b/src/server/WebSocket.h index 0c149eb..d127ef8 100644 --- a/src/server/WebSocket.h +++ b/src/server/WebSocket.h @@ -70,6 +70,8 @@ private: RestOutputStruct::ExitCode EvaluateSysadmUpdateRequest(const QJsonValue in_args, QJsonObject *out); // -- sysadm ZFS API RestOutputStruct::ExitCode EvaluateSysadmZfsRequest(const QJsonValue in_args, QJsonObject *out); + // -- sysadm PKG API + RestOutputStruct::ExitCode EvaluateSysadmPkgRequest(const QJsonValue in_args, QJsonObject *out); private slots: void sendReply(QString msg); diff --git a/src/server/library/library.pri b/src/server/library/library.pri index 97e1da8..1b0fc54 100644 --- a/src/server/library/library.pri +++ b/src/server/library/library.pri @@ -13,7 +13,8 @@ HEADERS += $${PWD}/sysadm-global.h \ $${PWD}/sysadm-systemmanager.h\ $${PWD}/sysadm-update.h \ $${PWD}/sysadm-usermanager.h \ - $${PWD}/sysadm-zfs.h + $${PWD}/sysadm-zfs.h \ + $${PWD}/sysadm-pkg.h SOURCES += $${PWD}/NetDevice.cpp \ $${PWD}/sysadm-general.cpp \ @@ -27,5 +28,6 @@ SOURCES += $${PWD}/NetDevice.cpp \ $${PWD}/sysadm-systemmanager.cpp \ $${PWD}/sysadm-update.cpp \ $${PWD}/sysadm-usermanager.cpp \ - $${PWD}/sysadm-zfs.cpp + $${PWD}/sysadm-zfs.cpp \ + $${PWD}/sysadm-pkg.cpp diff --git a/src/server/library/sysadm-pkg.cpp b/src/server/library/sysadm-pkg.cpp new file mode 100644 index 0000000..5aa7882 --- /dev/null +++ b/src/server/library/sysadm-pkg.cpp @@ -0,0 +1,139 @@ +//=========================================== +// PC-BSD source code +// Copyright (c) 2015, PC-BSD Software/iXsystems +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "sysadm-general.h" +#include "sysadm-pkg.h" +#include "sysadm-global.h" +#include "globals.h" + +using namespace sysadm; + +// ================== +// INLINE FUNCTIONS +// ================== +//Get Option Name +inline QString option_from_id(QString id){ + QSqlQuery q("SELECT option FROM option WHERE option_id = '"+id+"'"); + while(q.next()){ + return q.value("option").toString(); + } + return ""; //nothing found +} +//Get Annotation (name/value - both use ID's) +inline QString anno_from_id(QString id){ + QSqlQuery q("SELECT annotation FROM annotation WHERE annotation_id = '"+id+"'"); + while(q.next()){ + return q.value("annotation").toString(); + } + return ""; //nothing found +} +//Get origin from package_id (for reverse lookups) +inline QStringList origins_from_package_ids(QStringList ids){ + QSqlQuery q("SELECT origin FROM packages WHERE id = '"+ids.join("' OR id = '")+"'"); + QStringList out; + while(q.next()){ out << q.value("origin").toString(); } + return out; +} +//Generic ID's -> Names function (known databases: users, groups, licenses, shlibs, categories ) +inline QStringList names_from_ids(QStringList ids, QString db){ + QSqlQuery q("SELECT name FROM "+db+" WHERE id = '"+ids.join("' OR id = '")+"'"); + QStringList out; + while(q.next()){ out << q.value("name").toString(); } + return out; +} + +// ================= +// MAIN FUNCTIONS +// ================= +QJsonObject PKG::pkg_info(QStringList origins, QString repo){ + QJsonObject retObj; + //Open the local database + QSqlDatabase DB = QSqlDatabase::addDatabase("QSQLITE"); + DB.setHostName("localhost"); + if(repo=="local"){ DB.setDatabaseName( "/var/db/pkg/local.sqlite"); } + else{ DB.setDatabaseName( "/var/db/pkg/repo-"+repo+".sqlite"); } + DB.setConnectOptions("QSQLITE_OPEN_READONLY=1"); + if( !DB.open() ){ return retObj; } //cannot open database + //Now do all the pkg info, one pkg origin at a time + QSqlQuery query("SELECT * FROM packages" +(origins.isEmpty() ? "" : " WHERE origin = '"+origins.join("' OR origin = '")+"'") ); + //int id = query.record().indexOf("origin"); + while(query.next()){ + QJsonObject info; + QString id = query.value("id").toString(); //need this pkg id for later + QString origin = query.value("origin").toString(); //need the origin for later + //General info + for(int i=0; i +#include "sysadm-global.h" +#include +#include +#include +#include +#include +namespace sysadm{ + +class PKG{ +public: + static QJsonObject pkg_info(QStringList origins, QString repo); +}; + +} //end of sysadm namespace + +#endif \ No newline at end of file diff --git a/src/server/server.pro b/src/server/server.pro index 34259a9..1fabc91 100644 --- a/src/server/server.pro +++ b/src/server/server.pro @@ -2,7 +2,7 @@ TEMPLATE = app LANGUAGE = C++ CONFIG += qt warn_off release -QT = core network websockets concurrent +QT = core network websockets concurrent sql HEADERS += globals.h globals-qt.h \ WebServer.h \