Implement Tairent::Main::TorrentManager::getClient() method.
[tairent.git] / src / main / torrentmanager.cpp
blob1af2053272732294d7166fc31ba214ff1d4542c7
1 /***************************************************************************
2 * *
3 * Copyright (C) 2006 David Brodsky *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation and appearing *
8 * in the file LICENSE.GPL included in the packaging of this file. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 * General Public License for more details. *
14 * *
15 ***************************************************************************/
17 #include <cstdlib>
18 #include <ctime>
19 #include <fstream>
21 #include <tairon/core/config.h>
22 #include <tairon/core/exceptions.h>
23 #include <tairon/core/log.h>
24 #include <tairon/core/tinyxml.h>
26 #include "torrentmanager.h"
28 #include "core/bencode.h"
29 #include "torrentclient.h"
31 #define TAIRENT_VERSION "0.1"
33 namespace Tairent
36 namespace Main
39 TorrentManager *TorrentManager::torrentManager = 0;
41 /* {{{ TorrentManager::TorrentManager() */
42 TorrentManager::TorrentManager()
44 if (torrentManager)
45 throw Tairon::Core::SingletonException("Cannot make another instance of Tairent::Main::TorrentManager");
47 makeClientID();
48 loadTorrents();
50 torrentManager = this;
52 /* }}} */
54 /* {{{ TorrentManager::~TorrentManager() */
55 TorrentManager::~TorrentManager()
57 torrentManager = 0;
59 /* }}} */
61 /* {{{ TorrentManager::destroy() */
62 void TorrentManager::destroy()
64 for (std::map<String, TorrentStruct *>::const_iterator it = torrents.begin(); it != torrents.end(); ++it) {
65 if (it->second->client)
66 delete it->second->client;
67 if (it->second->metaInfo)
68 delete it->second->metaInfo;
69 delete it->second;
71 torrents.clear();
73 /* }}} */
75 /* {{{ TorrentManager::getClient(const String &) */
76 TorrentClient *TorrentManager::getClient(const String &infoHash)
78 if (torrents.count(infoHash)) {
79 TorrentStruct *t = torrents[infoHash];
80 if (t->client)
81 return t->client;
83 // TODO: create client
86 return 0; // no client found
88 /* }}} */
90 /* {{{ TorrentManager::getClientID() */
91 const String &TorrentManager::getClientID()
93 return clientID;
95 /* }}} */
97 /* {{{ TorrentManager::hexToBin(char) */
98 char TorrentManager::hexToBin(char c)
100 if ((c >= '0') && (c <= '9'))
101 return c - '0';
102 return c - 'a' + 10;
104 /* }}} */
106 /* {{{ TorrentManager::hexToBin(const String &) */
107 String TorrentManager::hexToBin(const String &data)
109 String ret;
110 ret.resize(data.length() / 2);
112 unsigned int i = 0;
113 const char *d = data;
114 while (*d) {
115 ret[i++] = (hexToBin(*d) << 4) | (hexToBin(*(d + 1)));
116 d += 2;
119 return ret;
121 /* }}} */
123 /* {{{ TorrentManager::loadMetaInfo(const String &) */
124 Tairent::Core::BEncode *TorrentManager::loadMetaInfo(const String &filename)
126 std::ifstream f(filename, std::ios_base::in);
127 if (!f.is_open()) {
128 WARNING((const char *) String("Cannot load informations from " + filename));
129 return 0;
132 Tairent::Core::BEncode *ret = new Tairent::Core::BEncode();
133 try {
134 f >> (*ret);
135 } catch (const Tairent::Core::BEncodeException &e) {
136 WARNING((const char *) String("Cannot load metainfo from " + filename + ": " + (const String &) e));
137 delete ret;
138 return 0;
141 return ret;
143 /* }}} */
145 /* {{{ TorrentManager::loadTorrent(TiXmlNode *) */
146 void TorrentManager::loadTorrent(TiXmlNode *t)
148 TiXmlElement *element = t->ToElement();
149 const char *data = element->Attribute("file");
150 if (!data)
151 return;
153 INFO((const char *) String(String("Loading informations about ") + data));
155 TorrentStruct *torrent = new TorrentStruct;
156 torrent->client = 0;
158 torrent->torrentFile = data;
160 data = element->Attribute("complete");
161 if (data && (data[0] == '1'))
162 torrent->complete = true;
163 else
164 torrent->complete = false;
166 data = element->Attribute("hash");
167 if (data) {
168 torrent->metaInfo = 0;
169 torrents[hexToBin(data)] = torrent;
170 } else {
171 torrent->metaInfo = loadMetaInfo(torrent->torrentFile);
172 if (!torrent->metaInfo)
173 return;
174 String hash = (*torrent->metaInfo)["info"].computeSHA1();
175 torrents[hash] = torrent;
178 /* }}} */
180 /* {{{ TorrentManager::loadTorrents() */
181 void TorrentManager::loadTorrents()
183 TiXmlDocument document;
185 if (!document.LoadFile((*Tairon::Core::Config::self())["torrents-directory"] + "/torrents.xml"))
186 return;
188 TiXmlElement *root = document.RootElement();
189 if (!root)
190 return;
192 if (root->ValueStr() != "torrents") // invalid file
193 return;
195 for (TiXmlNode *node = root->FirstChild(); node; node = node->NextSibling()) {
196 if (node->Type() != TiXmlNode::ELEMENT)
197 continue;
198 if (node->ValueStr() == "torrent")
199 loadTorrent(node);
202 /* }}} */
204 /* {{{ TorrentManager::makeClientID() */
205 void TorrentManager::makeClientID()
207 srandom(time(0));
209 clientID = "TA-" TAIRENT_VERSION "-";
210 size_t len = clientID.length();
211 clientID.resize(20);
213 std::ifstream f("/dev/urandom", std::ios_base::in);
214 if (f.is_open()) {
215 for (size_t i = len; i < 20; ++i)
216 clientID[i] = (char) f.get();
217 f.close();
218 } else { // cannot open /dev/urandom? fall back to standard random
219 srandom(time(0));
220 for (size_t i = len; i < 20; ++i)
221 clientID[i] = random() % 256;
224 /* }}} */
226 /* {{{ TorrentManager::startTorrents() */
227 void TorrentManager::startTorrents()
229 for (std::map<String, TorrentStruct *>::const_iterator it = torrents.begin(); it != torrents.end(); ++it) {
230 TorrentStruct *t = it->second;
231 if (t->complete)
232 continue;
234 if (!t->metaInfo)
235 t->metaInfo = loadMetaInfo(t->torrentFile);
237 if (!t->metaInfo) { // metainfo loading failed
238 WARNING((const char *) String("Cannot start torrent " + t->torrentFile));
239 continue;
242 t->client = new TorrentClient(t, it->first);
245 /* }}} */
247 /* {{{ TorrentManager::stopTorrents() */
248 void TorrentManager::stopTorrents()
250 for (std::map<String, TorrentStruct *>::const_iterator it = torrents.begin(); it != torrents.end(); ++it)
251 it->second->client->stop();
253 /* }}} */
255 }; // namespace Main
257 }; // namespace Tairent
259 // vim: ai sw=4 ts=4 noet fdm=marker