root/hydranode/hncore/imp_mldonkey/imp_mldonkey.cpp

Revision 3011, 10.4 kB (checked in by madcat, 2 years ago)

Only attempts to import supported (donkey) downloads.

Line 
1 /*
2  *  Copyright (C) 2006 Alo Sarv <madcat_@users.sourceforge.net>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include <boost/algorithm/string/replace.hpp>
20 #include <boost/algorithm/string/trim.hpp>
21 #include <boost/algorithm/string/split.hpp>
22 #include <boost/algorithm/string/predicate.hpp>
23 #include <boost/filesystem/path.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <boost/spirit.hpp>
26 #include <boost/spirit/actor.hpp>
27 #include <hnbase/hash.h>
28 #include <hnbase/range.h>
29 #include <hnbase/rangelist.h>
30 #include <hncore/metadata.h>
31 #include <hncore/partdata.h>
32 #include <hncore/sharedfile.h>
33 #include <hncore/fileslist.h>
34 #include <hncore/modules.h>
35 #include <iostream>
36 #include <fstream>
37 #include <vector>
38 #include <map>
39 #include <set>
40
41 struct FileInfo {
42         std::string m_network;
43         uint64_t    m_size;
44         uint8_t     m_priority;
45         std::string m_state;
46         std::string m_fileName;
47         uint32_t    m_age;
48         bool        m_primary;
49         std::string m_swarmer;
50         uint32_t    m_mTime;
51         std::string m_chunks;
52         uint64_t    m_downloaded;
53         std::string m_tempName;
54         std::vector<uint32_t>        m_chunksAge;
55         RangeList64                  m_completed;
56         RangeList64                  m_verified;
57         ED2KHashSet                  m_hashSet;
58         std::vector<std::string>     m_chunkHashes;
59         std::vector<std::string>     m_fileNames;
60         FileInfo();
61         friend std::ostream& operator<<(std::ostream &o, const FileInfo &i);
62 };
63
64 FileInfo::FileInfo() : m_size(), m_priority(), m_age(), m_primary(), m_mTime(),
65 m_downloaded() {}
66
67 std::ostream& operator<<(std::ostream &o, const FileInfo &i) {
68         o << "  Network:    " << i.m_network    << std::endl;
69         o << "  Size:       " << i.m_size       << std::endl;
70         o << "  Priority:   " << i.m_priority   << std::endl;
71         o << "  State:      " << i.m_state      << std::endl;
72         o << "  FileName:   " << i.m_fileName   << std::endl;
73         o << "  Age:        " << i.m_age        << std::endl;
74         o << "  Primary:    " << i.m_primary    << std::endl;
75         o << "  Swarmer:    " << i.m_swarmer    << std::endl;
76         o << "  ModTime:    " << i.m_mTime      << std::endl;
77         o << "  Chunks:     " << i.m_chunks     << std::endl;
78         o << "  Downloaded: " << i.m_downloaded << std::endl;
79         o << "  TempName:   " << i.m_tempName   << std::endl;
80         return o;
81 }
82
83 class Imp_MlDonkey : public ModuleBase {
84         DECLARE_MODULE(Imp_MlDonkey, "imp_mldonkey");
85 public:
86         virtual bool onInit();
87         virtual int onExit();
88 private:
89         void import(boost::filesystem::path from);
90 };
91
92 IMPLEMENT_MODULE(Imp_MlDonkey);
93
94 bool Imp_MlDonkey::onInit() {
95         FilesList::instance().import.connect(
96                 boost::bind(&Imp_MlDonkey::import, this, _1)
97         );
98         return true;
99 }
100
101 int Imp_MlDonkey::onExit() {
102         return 0;
103 }
104
105 void Imp_MlDonkey::import(boost::filesystem::path from) {
106         using namespace boost::algorithm;
107         using namespace boost::spirit;
108
109         std::ifstream ifs(
110                 (from / "files.ini").native_directory_string().c_str(),
111                 std::ios::in
112         );
113         std::string tmp;
114         bool inFiles(false), inFile(false);
115         std::string fileData;
116         std::vector<std::string> files;
117
118         // First round of processing - locate the 'files' section, and separate
119         // each file into separate string.
120         while (getline(ifs, tmp)) {
121                 trim(tmp);
122                 if (!inFiles && tmp == "files = [") {
123                         inFiles = true;
124                 } else if (inFiles && !inFile && tmp.find("{") == 0) {
125                         inFile = true;
126                         fileData += tmp.substr(1) + "\n";
127                 } else if (inFiles && inFile && tmp == "};") {
128                         files.push_back(fileData);
129                         fileData.clear();
130                         inFile = false;
131                 } else if (inFiles && inFile && tmp == "};]") {
132                         files.push_back(fileData);
133                         fileData.clear();
134                         inFile = false;
135                         inFiles = false;                       
136                 } else if (inFiles && inFile) {
137                         fileData += tmp + "\n";
138                 }
139         }
140         std::cerr << "Found " << files.size() << " temp files." << std::endl;
141
142         // Second round of processing - for each file, read all the keys
143         // (note that some keys may cross multiple lines), first copy then into
144         // key/val map of fileKeys, and near the end of section, construct
145         // FileInfo object and assign proper keys to proper variables (casting
146         // as needed).
147         std::vector<FileInfo> importList;
148         for (size_t i = 0; i < files.size(); ++i) {
149                 std::map<std::string, std::string> fileKeys;
150                 std::vector<std::string> lines;
151                 split(lines, files[i], is_any_of("\n"));
152                 std::string blockData;
153                 std::string curKey, curValue;
154                 bool inBlock(false);
155                 for (size_t j = 0; j < lines.size(); ++j) {
156                         if (!lines[j].size()) {
157                                 continue;
158                         }
159                         if (!inBlock && iends_with(lines[j], "[")) {
160                                 std::vector<std::string> keyVal;
161                                 split(keyVal, lines[j], is_any_of("="));
162                                 if (!keyVal.size()) {
163                                         std::cerr << "Parse failure on line '";
164                                         std::cerr << lines[j];
165                                         std::cerr << "' (expected '=' token)";
166                                         std::cerr << std::endl;
167                                 }
168                                 curKey = keyVal[0];
169                                 boost::algorithm::trim(curKey);
170                                 inBlock = true;
171                         } else if (inBlock && iends_with(lines[j], "]")) {
172                                 inBlock = false;
173                                 blockData += lines[j].substr(
174                                         0, lines[j].size() - 1
175                                 );
176                                 fileKeys[curKey] = blockData;
177                                 blockData.clear();
178                         } else if (inBlock) {
179                                 blockData += lines[j];
180                         } else {
181                                 std::vector<std::string> keyVal;
182                                 split(keyVal, lines[j], is_any_of("="));
183                                 if (keyVal.size() != 2) {
184                                         std::cerr << "Parse failure on line '";
185                                         std::cerr << lines[j];
186                                         std::cerr << "' (expected '=' token)";
187                                         std::cerr << std::endl;
188                                 } else {
189                                         curKey = keyVal[0];
190                                         curValue = keyVal[1];
191                                         trim(curKey);
192                                         trim(curValue);
193                                         fileKeys[curKey] = curValue;
194                                 }
195                         }
196                 }
197                 FileInfo f;
198                 f.m_network = fileKeys["file_network"];
199                 try {
200                         f.m_size = boost::lexical_cast<uint64_t>(
201                                 fileKeys["file_size"]
202                         );
203                 } catch (...) {
204                         std::cerr << "Failed to cast " << fileKeys["file_size"];
205                         std::cerr << "to integer (file_size key).\n";
206                 }
207                 try {
208                         f.m_priority = boost::lexical_cast<uint8_t>(
209                                 fileKeys["file_priority"]
210                         );
211                 } catch (...) {
212                         std::cerr << "Failed to cast ";
213                         std::cerr << fileKeys["file_priority"];
214                         std::cerr << "to integer (file_priority key).\n";
215                 }
216                 f.m_state = fileKeys["file_state"];
217                 f.m_fileName = fileKeys["file_filename"];
218                 // filenames are sometimes quoted
219                 trim_if(f.m_fileName, is_any_of("\""));
220                 try {
221                         f.m_age = boost::lexical_cast<uint32_t>(
222                                 fileKeys["file_age"]
223                         );
224                 } catch (...) {
225                         std::cerr << "Failed to cast " << fileKeys["file_age"];
226                         std::cerr << "to integer (file_age key).\n";
227                 }
228                 f.m_primary = fileKeys["file_primary"] == "true" ? true : false;
229                 f.m_swarmer = fileKeys["file_swarmer"];
230                 trim_if(f.m_swarmer, is_any_of("\""));
231                 try {
232                         if (iends_with(fileKeys["file_mtime"], ".")) {
233                                 fileKeys["file_mtime"] = fileKeys["file_mtime"]
234                                 .substr(0, fileKeys["file_mtime"].size() - 1);
235                         }
236                         f.m_mTime = boost::lexical_cast<uint32_t>(
237                                 fileKeys["file_mtime"]
238                         );
239                 } catch (...) {
240                         std::cerr << "Failed to cast ";
241                         std::cerr << fileKeys["file_mtime"];
242                         std::cerr << "to integer (file_mtime key).\n";
243                 }
244                 f.m_chunks = fileKeys["file_chunks"];
245                 try {
246                         f.m_downloaded = boost::lexical_cast<uint32_t>(
247                                 fileKeys["file_downloaded"]
248                         );
249                 } catch (...) {
250                         std::cerr << "Failed to cast ";
251                         std::cerr << fileKeys["file_downloaded"];
252                         std::cerr << "to integer (file_downloaded key).\n";
253                 }
254                 std::string tmp = fileKeys["file_md4"];
255                 trim_if(tmp, is_any_of("\""));
256                 f.m_hashSet.setFileHash(Utils::encode(tmp));
257                 f.m_tempName = fileKeys["file_diskname"];
258
259                 // makes parsing easier
260                 fileKeys["file_present_chunks"] += ";";
261
262                 std::vector<uint64_t> begins, ends;
263                 parse_info<> ret = parse(
264                         fileKeys["file_present_chunks"].c_str(),
265                         *('(' >> uint_p[push_back_a(begins)] >> ','
266                           >> uint_p[push_back_a(ends)] >> ')' >> ';'),
267                         space_p
268                 );
269                 if (ret.full) {
270                         for (size_t i = 0; i < begins.size(); ++i) {
271                                 f.m_completed.merge(begins[i], ends[i]);
272                         }
273                 } else if (fileKeys["file_present_chunks"].size() > 3) {
274                         std::cerr << "Parse failure (file_present_chunks key)";
275                         std::cerr << std::endl;
276                         std::cerr << fileKeys["file_present_chunks"];
277                         std::cerr << std::endl;
278                 }
279
280                 std::vector<std::string> chunkHashes;
281                 split(chunkHashes, fileKeys["file_md4s"], is_any_of(";"));
282                 for (size_t i = 0; i < chunkHashes.size(); ++i) {
283                         trim_if(chunkHashes[i], is_any_of("\""));
284                         if (!chunkHashes[i].size()) {
285                                 continue;
286                         }
287                         f.m_hashSet.addChunkHash(Utils::encode(chunkHashes[i]));
288                 }
289
290                 replace_all(f.m_swarmer, "\\\\", "\\");
291                 replace_all(f.m_chunks, "\"", "");
292
293                 for (size_t i = 0; i < f.m_chunks.size(); ++i) {
294                         if (f.m_chunks[i] == 3) {
295                                 uint64_t begin = i * (9500 * 1024);
296                                 uint64_t end = i + 1 * (9500 * 1024) - 1;
297                                 if (end > f.m_size - 1) {
298                                         end = f.m_size - 1;
299                                 }
300                                 f.m_verified.merge(begin, end);
301                         }
302                 }
303
304                 // only donkey downloads supported currently
305                 if (f.m_network == "Donkey") {
306                         importList.push_back(f);
307                 }
308         }
309
310         using namespace boost::filesystem;
311
312         for (size_t i = 0; i < importList.size(); ++i) {
313                 try {
314                         std::cerr << "#" << i << ": ";
315                         std::cerr << importList[i].m_fileName << std::endl;
316                         std::cerr << "Size: " << importList[i].m_size
317                                 << std::endl;
318
319                         replace_all(importList[i].m_swarmer, "\\", "/");
320
321                         MetaData *md = new MetaData(importList[i].m_size);
322                         md->addHashSet(
323                                 new ED2KHashSet(importList[i].m_hashSet)
324                         );
325                         md->addFileName(importList[i].m_fileName);
326
327                         PartData *pd = new PartData(
328                                 from / path(importList[i].m_swarmer, native),
329                                 md, importList[i].m_completed,
330                                 importList[i].m_verified
331                         );
332
333                         SharedFile *sf = new SharedFile(pd, md);
334
335                         FilesList::instance().push(sf);
336                 } catch (std::exception &e) {
337                         logError(e.what());
338                 }
339                 FilesList::instance().addTempDir(
340                         (from / path(importList[i].m_swarmer, native))
341                         .branch_path().string(), false
342                 );
343         }
344 }
Note: See TracBrowser for help on using the browser.