summaryrefslogtreecommitdiffstats
path: root/logic/updater/DownloadUpdateTask.h
blob: 6fb745abf68c42aa22e43b289f2dfe15e38758dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* Copyright 2013 MultiMC Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include "logic/tasks/Task.h"
#include "logic/net/NetJob.h"

/*!
 * The DownloadUpdateTask is a task that takes a given version ID and repository URL,
 * downloads that version's files from the repository, and prepares to install them.
 */
class DownloadUpdateTask : public Task
{
	Q_OBJECT

public:
	explicit DownloadUpdateTask(QString repoUrl, int versionId, QObject* parent=0);
	
protected:
	// TODO: We should probably put these data structures into a separate header...

	/*!
	 * Struct that describes an entry in a VersionFileEntry's `Sources` list.
	 */
	struct FileSource
	{
		FileSource(QString type, QString url, QString compression="")
		{
			this->type = type;
			this->url = url;
			this->compressionType = compression;
		}

		QString type;
		QString url;
		QString compressionType;
	};

	typedef QList<FileSource> FileSourceList;

	/*!
	 * Structure that describes an entry in a GoUpdate version's `Files` list.
	 */
	struct VersionFileEntry
	{
		QString path;
		bool isExecutable;
		FileSourceList sources;
		QString md5;
	};

	typedef QList<VersionFileEntry> VersionFileList;


	/*!
	 * Structure that describes an operation to perform when installing updates.
	 */
	struct UpdateOperation
	{
		static UpdateOperation CopyOp(QString fsource, QString fdest) { return UpdateOperation{OP_COPY, fsource, fdest, 644}; }
		static UpdateOperation MoveOp(QString fsource, QString fdest) { return UpdateOperation{OP_MOVE, fsource, fdest, 644}; }
		static UpdateOperation DeleteOp(QString file) { return UpdateOperation{OP_DELETE, file, "", 644}; }
		static UpdateOperation ChmodOp(QString file, int fmode) { return UpdateOperation{OP_CHMOD, file, "", fmode}; }

		//! Specifies the type of operation that this is.
		enum Type
		{
			OP_COPY,
			OP_DELETE,
			OP_MOVE,
			OP_CHMOD,
		} type;

		//! The source file. If this is a DELETE or CHMOD operation, this is the file that will be modified.
		QString source;

		//! The destination file. If this is a DELETE or CHMOD operation, this field will be ignored.
		QString dest;

		//! The mode to change the source file to. Ignored if this isn't a CHMOD operation.
		int mode;

		// Yeah yeah, polymorphism blah blah inheritance, blah blah object oriented. I'm lazy, OK?
	};

	typedef QList<UpdateOperation> UpdateOperationList;

	/*!
	 * Used for arguments to parseVersionInfo and friends to specify which version info file to parse.
	 */
	enum VersionInfoFileEnum { NEW_VERSION, CURRENT_VERSION };


	//! Entry point for tasks.
	virtual void executeTask();

	/*!
	 * Attempts to find the version ID and repository URL for the current version.
	 * The function will look up the repository URL in the UpdateChecker's channel list.
	 * If the repository URL can't be found, this function will return false.
	 */
	virtual void findCurrentVersionInfo();

	/*!
	 * Downloads the version info files from the repository.
	 * The files for both the current build, and the build that we're updating to need to be downloaded.
	 * If the current version's info file can't be found, MultiMC will not delete files that 
	 * were removed between versions. It will still replace files that have changed, however.
	 * Note that although the repository URL for the current version is not given to the update task,
	 * the task will attempt to look it up in the UpdateChecker's channel list.
	 * If an error occurs here, the function will call emitFailed and return false.
	 */
	virtual void loadVersionInfo();

	/*!
	 * This function is called when version information is finished downloading.
	 * This handles parsing the JSON downloaded by the version info network job and then calls processFileLists.
	 * Note that this function will sometimes be called even if the version info download emits failed. If
	 * we couldn't download the current version's info file, we can still update. This will be called even if the 
	 * current version's info file fails to download, as long as the new version's info file succeeded.
	 */
	virtual void parseDownloadedVersionInfo();

	/*!
	 * Loads the file list from the given version info JSON object into the given list.
	 */
	virtual void parseVersionInfo(VersionInfoFileEnum vfile, VersionFileList* list);

	/*!
	 * Takes a list of file entries for the current version's files and the new version's files
	 * and populates the downloadList and operationList with information about how to download and install the update.
	 */
	virtual void processFileLists();

	VersionFileList m_downloadList;
	UpdateOperationList m_operationList;

	VersionFileList m_nVersionFileList;
	VersionFileList m_cVersionFileList;

	//! Network job for downloading version info files.
	NetJobPtr m_vinfoNetJob;
	
	//! Network job for downloading update files.
	NetJobPtr m_filesNetJob;

	// Version ID and repo URL for the new version.
	int m_nVersionId;
	QString m_nRepoUrl;

	// Version ID and repo URL for the currently installed version.
	int m_cVersionId;
	QString m_cRepoUrl;

	/*!
	 * Temporary directory to store update files in.
	 * This will be set to not auto delete. Task will fail if this fails to be created.
	 */
	QTemporaryDir m_updateFilesDir;

protected slots:
	void vinfoDownloadFinished();
	void vinfoDownloadFailed();

	void fileDownloadFinished();
	void fileDownloadFailed();
	void fileDownloadProgressChanged(qint64 current, qint64 total);
};