From c84d114b3119f9ed933f6ad48833fb6d32eadfbf Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Wed, 27 Sep 2017 23:19:57 +0200 Subject: [PATCH] feat(package): defer apk / upk parsing --- inc/package.class.php | 153 ++++++++++++++---------- install/installer.class.php | 17 ++- install/mysql/plugin_flyvemdm_empty.sql | 22 ++-- install/upgrade/update_to_dev.php | 4 + setup.php | 4 +- 5 files changed, 122 insertions(+), 78 deletions(-) diff --git a/inc/package.class.php b/inc/package.class.php index f38c5681..cb61fcb3 100644 --- a/inc/package.class.php +++ b/inc/package.class.php @@ -232,29 +232,6 @@ public function prepareInputForAdd($input) { $this->createEntityDirectory(dirname($destination)); if (rename($uploadedFile, $destination)) { $fileExtension = pathinfo($destination, PATHINFO_EXTENSION); - $filename = pathinfo($destination, PATHINFO_FILENAME); - if ($fileExtension == 'apk') { - $apk = new \ApkParser\Parser($destination); - } else if ($fileExtension == 'upk') { - $upkParser = new PluginFlyvemdmUpkparser($destination); - $apk = $upkParser->getApkParser(); - if (!($apk instanceof \ApkParser\Parser)) { - Session::addMessageAfterRedirect(__('Could not parse the UPK file', 'flyvemdm')); - return false; - } - } - $manifest = $apk->getManifest(); - $iconResourceId = $manifest->getApplication()->getIcon(); - $labelResourceId = $manifest->getApplication()->getLabel(); - $iconResources = $apk->getResources($iconResourceId); - $apkLabel = $apk->getResources($labelResourceId); - $input['icon'] = base64_encode(stream_get_contents($apk->getStream($iconResources[0]))); - $input['name'] = $manifest->getPackageName(); - if ((!isset($input['alias'])) || (strlen($input['alias']) == 0)) { - $input['alias'] = $apkLabel[0]; // Get the first item - } - $input['version'] = $manifest->getVersionName(); - $input['version_code'] = $manifest->getVersionCode(); $input['filesize'] = fileSize($destination); $input['dl_filename'] = basename($uploadedFile); } else { @@ -317,48 +294,30 @@ public function prepareInputForUpdate($input) { } } - try { - $input['filename'] = $this->fields['entities_id'] . "/" . uniqid() . "_" . basename($uploadedFile); - $destination = FLYVEMDM_PACKAGE_PATH . "/" . $input['filename']; - $this->createEntityDirectory(dirname($destination)); - if (rename($uploadedFile, $destination)) { - if ($fileExtension == "apk") { - $apk = new \ApkParser\Parser($destination); - } else if ($fileExtension == "upk") { - $upkParser = new PluginFlyvemdmUpkparser($destination); - $apk = $upkParser->getApkParser(); - if (!($apk instanceof \ApkParser\Parser)) { - Session::addMessageAfterRedirect(__('Could not parse the UPK file', "flyvemdm")); - return false; + if (isset($uploadedFile)) { + try { + $input['filename'] = $this->fields['entities_id'] . "/" . uniqid() . "_" . basename($uploadedFile); + $destination = FLYVEMDM_PACKAGE_PATH . "/" . $input['filename']; + $this->createEntityDirectory(dirname($destination)); + if (rename($uploadedFile, $destination)) { + $input['filesize'] = fileSize($destination); + $input['dl_filename'] = basename($uploadedFile); + if ($filename != $this->fields['filename']) { + unlink(FLYVEMDM_PACKAGE_PATH . "/" . $this->fields['filename']); } + } else { + if (!is_writable(dirname($destination))) { + $destination = dirname($destination); + Toolbox::logInFile('php-errors', "Plugin Flyvemdm : Directory '$destination' is not writeable"); + } + Session::addMessageAfterRedirect(__('Unable to save the file', "flyvemdm")); + $input = false; } - $manifest = $apk->getManifest(); - $iconResourceId = $manifest->getApplication()->getIcon(); - $labelResourceId = $manifest->getApplication()->getLabel(); - $iconResources = $apk->getResources($iconResourceId); - $apkLabel = $apk->getResources($labelResourceId); - $input['icon'] = base64_encode(stream_get_contents($apk->getStream($iconResources[0]))); - $input['name'] = $manifest->getPackageName(); - $input['version'] = $manifest->getVersionName(); - $input['version_code'] = $manifest->getVersionCode(); - $input['filesize'] = fileSize($destination); - $input['dl_filename'] = basename($uploadedFile); - if ($filename != $this->fields['filename']) { - unlink(FLYVEMDM_PACKAGE_PATH . "/" . $this->fields['filename']); - } - } else { - if (!is_writable(dirname($destination))) { - $destination = dirname($destination); - Toolbox::logInFile('php-errors', "Plugin Flyvemdm : Directory '$destination' is not writeable"); - } - Session::addMessageAfterRedirect(__('Unable to save the file', "flyvemdm")); + } catch (Exception $e) { + // Ignore exceptions for now $input = false; } - } catch (Exception $e) { - // Ignore exceptions for now - $input = false; } - return $input; } @@ -581,6 +540,80 @@ protected function sendFile() { exit(0); } + /** + * Launch parsing of applciation files + * + * @see PluginFlyvemdmPackage::parseApplication() + * + * @param CronTask $crontask + * + * @return integer >0 means done, < 0 means not finished, 0 means nothing to do + */ + public static function cronParseApplication(CronTask $crontask) { + global $DB; + + $cronStatus = 0; + + $request = [ + 'FROM' => static::getTable(), + 'WHERE' => ['AND' => [ + 'parse_status' => 'pending', + ]], + 'LIMIT' => 10 + ]; + foreach ($DB->request($request) as $data) { + $package = new static(); + $package->getFromDB($data['id']); + if ($package->parseApplication()) { + $cronStatus++; + } + } + + return $cronStatus; + } + + /** + * Analyzes an application (APK or UPK) to collect metadata + * + * @return boolean true if success, false otherwise + */ + private function parseApplication() { + $destination = FLYVEMDM_PACKAGE_PATH . '/' . $this->fields['filename']; + $fileExtension = pathinfo($destination, PATHINFO_EXTENSION); + if ($fileExtension == 'apk') { + $apk = new \ApkParser\Parser($destination); + } else if ($fileExtension == 'upk') { + $upkParser = new PluginFlyvemdmUpkparser($destination); + $apk = $upkParser->getApkParser(); + if (!($apk instanceof \ApkParser\Parser)) { + $this->update([ + 'id' => $this->fields['id'], + 'parse_status' => 'failed' + ]); + return false; + } + } + $manifest = $apk->getManifest(); + $iconResourceId = $manifest->getApplication()->getIcon(); + $labelResourceId = $manifest->getApplication()->getLabel(); + $iconResources = $apk->getResources($iconResourceId); + $apkLabel = $apk->getResources($labelResourceId); + + $input = []; + $input['icon'] = base64_encode(stream_get_contents($apk->getStream($iconResources[0]))); + $input['name'] = $manifest->getPackageName(); + if ((!isset($input['alias'])) || (strlen($input['alias']) == 0)) { + $input['alias'] = $apkLabel[0]; // Get the first item + } + $input['version'] = $manifest->getVersionName(); + $input['version_code'] = $manifest->getVersionCode(); + + $input['id'] = $this->fields['id']; + $input['parse_status'] = 'parsed'; + $this->update($input); + return true; + } + /** * Deletes the packages related to the entity * @param CommonDBTM $item diff --git a/install/installer.class.php b/install/installer.class.php index 25f1f144..03c85a65 100644 --- a/install/installer.class.php +++ b/install/installer.class.php @@ -490,7 +490,6 @@ protected function upgrade($fromVersion) { * @param string $toVersion */ protected function upgradeOneStep($toVersion) { - $suffix = str_replace('.', '_', $toVersion); $includeFile = __DIR__ . "/upgrade/update_to_$suffix.php"; if (is_readable($includeFile) && is_file($includeFile)) { @@ -506,11 +505,17 @@ protected function upgradeOneStep($toVersion) { } protected function createJobs() { - CronTask::Register('PluginFlyvemdmMqttupdatequeue', 'UpdateTopics', MINUTE_TIMESTAMP, - array( - 'comment' => __('Update retained MQTT topics for fleet policies', 'flyvemdm'), - 'mode' => CronTask::MODE_EXTERNAL - )); + CronTask::Register(PluginFlyvemdmMqttupdatequeue::class, 'UpdateTopics', MINUTE_TIMESTAMP, + [ + 'comment' => __('Update retained MQTT topics for fleet policies', 'flyvemdm'), + 'mode' => CronTask::MODE_EXTERNAL + ]); + + CronTask::Register(PluginFlyvemdmPackage::class, 'ParseApplication', MINUTE_TIMESTAMP, + [ + 'comment' => __('Parse uploaded applications', 'flyvemdm'), + 'mode' => CronTask::MODE_EXTERNAL + ]); } /** diff --git a/install/mysql/plugin_flyvemdm_empty.sql b/install/mysql/plugin_flyvemdm_empty.sql index eac28fb2..b140899b 100644 --- a/install/mysql/plugin_flyvemdm_empty.sql +++ b/install/mysql/plugin_flyvemdm_empty.sql @@ -119,17 +119,17 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_flyvemdm_mqttusers` ( -- Export de la structure de table glpi-flyvemdm. glpi_plugin_flyvemdm_packages DROP TABLE IF EXISTS `glpi_plugin_flyvemdm_packages`; CREATE TABLE IF NOT EXISTS `glpi_plugin_flyvemdm_packages` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL DEFAULT '', - `alias` varchar(255) NOT NULL DEFAULT '', - `version` varchar(255) NOT NULL DEFAULT '', - `version_code` varchar(255) NOT NULL DEFAULT '', - `icon` text COLLATE utf8_unicode_ci NOT NULL, - `filename` varchar(255) NOT NULL DEFAULT '', - `filesize` int(11) NOT NULL DEFAULT '0', - `entities_id` int(11) NOT NULL DEFAULT '0', - `dl_filename` varchar(255) NOT NULL DEFAULT '', - `is_parsed` tinyint(1) NOT NULL DEFAULT '0', + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `alias` varchar(255) NOT NULL DEFAULT '', + `version` varchar(255) NOT NULL DEFAULT '', + `version_code` varchar(255) NOT NULL DEFAULT '', + `icon` text COLLATE utf8_unicode_ci NOT NULL, + `filename` varchar(255) NOT NULL DEFAULT '', + `filesize` int(11) NOT NULL DEFAULT '0', + `entities_id` int(11) NOT NULL DEFAULT '0', + `dl_filename` varchar(255) NOT NULL DEFAULT '', + `parse_status` enum('pending', 'parsed', 'failed') NOT NULL DEFAULT 'pending', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/install/upgrade/update_to_dev.php b/install/upgrade/update_to_dev.php index b32a231f..9d548426 100644 --- a/install/upgrade/update_to_dev.php +++ b/install/upgrade/update_to_dev.php @@ -102,4 +102,8 @@ function plugin_flyvemdm_update_to_dev(Migration $migration) { // All policies exist for Android $migration->addPostQuery("UPDATE `$table` SET `is_android_policy` = '1'"); + // update Applications table + $table = 'glpi_plugin_flyvemdm_packages'; + $migration->addField($table, 'parse_status', "enum('pending', 'parsed', 'failed')", ['after' => 'dl_filename', 'default' => 'pending']); + $migration->addPostQuery("UPDATE `$table` SET `parse_status` = 'parsed'"); } diff --git a/setup.php b/setup.php index 9bf4df9f..7db21020 100644 --- a/setup.php +++ b/setup.php @@ -82,7 +82,9 @@ function plugin_init_flyvemdm() { if ($plugin->isActivated('flyvemdm')) { require_once(__DIR__ . '/vendor/autoload.php'); - require_once(__DIR__ . '/lib/GlpiLocalesExtension.php'); + if (!class_exists('GlpiLocalesExtension')) { + require_once(__DIR__ . '/lib/GlpiLocalesExtension.php'); + } plugin_flyvemdm_registerClasses(); plugin_flyvemdm_addHooks();