1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2021 Andrew Lutsenko, anlutsenko at gmail dot com
5  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef PCM_TASK_MANAGER_H_
22 #define PCM_TASK_MANAGER_H_
23 
24 #include "dialogs/dialog_pcm_progress.h"
25 #include "pcm.h"
26 #include "pcm_data.h"
27 #include "sync_queue.h"
28 #include <atomic>
29 #include <condition_variable>
30 #include <functional>
31 #include <memory>
32 #include <mutex>
33 #include <nlohmann/json-schema.hpp>
34 #include <widgets/wx_progress_reporters.h>
35 #include <wx/string.h>
36 
37 
38 typedef std::function<void()> PCM_TASK;
39 
40 
41 /**
42  * @brief Helper class that handles package (un)installation
43  *
44  * Package state changes are first enqueued using DownloadAndInstall/Uninstall methods
45  * and then applied using RunQueue().
46  *
47  * RunQueue() is multithreaded for better experience.
48  */
49 class PCM_TASK_MANAGER
50 {
51 public:
PCM_TASK_MANAGER(std::shared_ptr<PLUGIN_CONTENT_MANAGER> pcm)52     PCM_TASK_MANAGER( std::shared_ptr<PLUGIN_CONTENT_MANAGER> pcm ) : m_pcm( pcm ){};
53 
54     /**
55      * @brief Enqueue package download and installation
56      *
57      * Enqueues a download task for a given package version.
58      *
59      * Download task fetches the package archive and if successful enqueues an installation task.
60      * Installation task verifies sha256 hash if specified, extracts the package, removes the
61      * downloaded archive and marks package as installed.
62      *
63      * Both tasks report their state independently to a progress dialog.
64      *
65      * @param aPackage package metadata
66      * @param aVersion version to be installed
67      * @param aRepositoryId id of the source repository
68      */
69     void DownloadAndInstall( const PCM_PACKAGE& aPackage, const wxString& aVersion,
70                              const wxString& aRepositoryId );
71 
72     /**
73      * @brief Enqueue package uninstallation
74      *
75      * Enqueues uninstallation task that removes all package files and marks package
76      * as uninstalled.
77      *
78      * @param aPackage package metadata
79      */
80     void Uninstall( const PCM_PACKAGE& aPackage );
81 
82     /**
83      * @brief Run queue of pending actions
84      *
85      * This method spawns 2 threads to concurrently run tasks in download and install
86      * queues until they are drained.
87      *
88      * Download queue feeds into install queue so the install thread keeps running until
89      * download thread indicated that it's finished AND all installs are processed.
90      *
91      * @param aParent parent dialog for progress window
92      */
93     void RunQueue( wxWindow* aParent );
94 
95     /**
96      * @brief Installs package from an archive file on disk
97      *
98      * Unlike DownloadAndInstall/Uninstall methods this one immediately extracts the package
99      * and marks it as installed.
100      *
101      * @param aParent parent dialog for progress window
102      * @param aFilePath path to the archive file
103      */
104     void InstallFromFile( wxWindow* aParent, const wxString& aFilePath );
105 
106 private:
107     /**
108      * @brief Download URL to a file
109      *
110      * @param aFilePath path to file
111      * @param aUrl URL to download
112      * @return int CURLE error code
113      */
114     int downloadFile( const wxString& aFilePath, const wxString& aUrl );
115 
116     /**
117      * @brief Extract package archive
118      *
119      * @param aFilePath path to the archive
120      * @param aPackageId id of the package
121      * @param isMultiThreaded MUST be set to true if the caller is not running in the main thread
122      * @return true if archive was extracted successfuly
123      */
124     bool extract( const wxString& aFilePath, const wxString& aPackageId, bool isMultiThreaded );
125 
126     /**
127      * @brief Delete all package files
128      *
129      * @param aPackageId id of the package
130      */
131     void deletePackageDirectories( const wxString& aPackageId );
132 
133     std::unique_ptr<DIALOG_PCM_PROGRESS>    m_reporter;
134     SYNC_QUEUE<PCM_TASK>                    m_download_queue;
135     SYNC_QUEUE<PCM_TASK>                    m_install_queue;
136     std::shared_ptr<PLUGIN_CONTENT_MANAGER> m_pcm;
137 };
138 
139 
140 #endif // PCM_TASK_MANAGER_H_
141