1 /*
2 clientmedia.h
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 */
5 
6 /*
7 This file is part of Freeminer.
8 
9 Freeminer is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Freeminer  is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Freeminer.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #ifndef CLIENTMEDIA_HEADER
24 #define CLIENTMEDIA_HEADER
25 
26 #include "irrlichttypes.h"
27 #include "filecache.h"
28 #include <ostream>
29 #include <map>
30 #include <set>
31 #include <vector>
32 
33 class Client;
34 struct HTTPFetchResult;
35 
36 #define MTHASHSET_FILE_SIGNATURE 0x4d544853 // 'MTHS'
37 #define MTHASHSET_FILE_NAME "index.mth"
38 
39 class ClientMediaDownloader
40 {
41 public:
42 	ClientMediaDownloader();
43 	~ClientMediaDownloader();
44 
getProgress()45 	float getProgress() const {
46 		if (m_uncached_count >= 1)
47 			return 1.0 * m_uncached_received_count /
48 				m_uncached_count;
49 		else
50 			return 0.0;
51 	}
52 
isStarted()53 	bool isStarted() const {
54 		return m_initial_step_done;
55 	}
56 
57 	// If this returns true, the downloader is done and can be deleted
isDone()58 	bool isDone() const {
59 		return m_initial_step_done &&
60 			m_uncached_received_count == m_uncached_count;
61 	}
62 
63 	// Add a file to the list of required file (but don't fetch it yet)
64 	void addFile(std::string name, std::string sha1);
65 
66 	// Add a remote server to the list; ignored if not built with cURL
67 	void addRemoteServer(std::string baseurl);
68 
69 	// Steps the media downloader:
70 	// - May load media into client by calling client->loadMedia()
71 	// - May check media cache for files
72 	// - May add files to media cache
73 	// - May start remote transfers by calling httpfetch_async
74 	// - May check for completion of current remote transfers
75 	// - May start conventional transfers by calling client->request_media()
76 	// - May inform server that all media has been loaded
77 	//   by calling client->received_media()
78 	// After step has been called once, don't call addFile/addRemoteServer.
79 	void step(Client *client);
80 
81 	// Must be called for each file received through TOCLIENT_MEDIA
82 	void conventionalTransferDone(
83 			const std::string &name,
84 			const std::string &data,
85 			Client *client);
86 
87 private:
88 	struct FileStatus {
89 		bool received;
90 		std::string sha1;
91 		s32 current_remote;
92 		std::vector<s32> available_remotes;
93 	};
94 
95 	struct RemoteServerStatus {
96 		std::string baseurl;
97 		s32 active_count;
98 		bool request_by_filename;
99 	};
100 
101 	void initialStep(Client *client);
102 	void remoteHashSetReceived(const HTTPFetchResult &fetch_result);
103 	void remoteMediaReceived(const HTTPFetchResult &fetch_result,
104 			Client *client);
105 	s32 selectRemoteServer(FileStatus *filestatus);
106 	void startRemoteMediaTransfers();
107 	void startConventionalTransfers(Client *client);
108 
109 	bool checkAndLoad(const std::string &name, const std::string &sha1,
110 			const std::string &data, bool is_from_cache,
111 			Client *client);
112 
113 	std::string serializeRequiredHashSet();
114 	static void deSerializeHashSet(const std::string &data,
115 			std::set<std::string> &result);
116 
117 	// Maps filename to file status
118 	std::map<std::string, FileStatus*> m_files;
119 
120 	// Array of remote media servers
121 	std::vector<RemoteServerStatus*> m_remotes;
122 
123 	// Filesystem-based media cache
124 	FileCache m_media_cache;
125 
126 	// Has an attempt been made to load media files from the file cache?
127 	// Have hash sets been requested from remote servers?
128 	bool m_initial_step_done;
129 
130 	// Total number of media files to load
131 	s32 m_uncached_count;
132 
133 	// Number of media files that have been received
134 	s32 m_uncached_received_count;
135 
136 	// Status of remote transfers
137 	unsigned long m_httpfetch_caller;
138 	unsigned long m_httpfetch_next_id;
139 	long m_httpfetch_timeout;
140 	s32 m_httpfetch_active;
141 	s32 m_httpfetch_active_limit;
142 	s32 m_outstanding_hash_sets;
143 	std::map<unsigned long, std::string> m_remote_file_transfers;
144 
145 	// All files up to this name have either been received from a
146 	// remote server or failed on all remote servers, so those files
147 	// don't need to be looked at again
148 	// (use m_files.upper_bound(m_name_bound) to get an iterator)
149 	std::string m_name_bound;
150 
151 };
152 
153 #endif // !CLIENTMEDIA_HEADER
154