version 0.1.11
[fms.git] / include / freenet / iindexrequester.h
1 #ifndef _iindexrequester_\r
2 #define _iindexrequester_\r
3 \r
4 #include "../idatabase.h"\r
5 #include "../ilogger.h"\r
6 #include "../datetime.h"\r
7 #include "../option.h"\r
8 #include "../stringfunctions.h"\r
9 #include "ifreenetregistrable.h"\r
10 #include "ifcpconnected.h"\r
11 #include "ifcpmessagehandler.h"\r
12 #include "iperiodicprocessor.h"\r
13 \r
14 #ifdef XMEM\r
15         #include <xmem.h>\r
16 #endif\r
17 \r
18 template <class IDTYPE>\r
19 class IIndexRequester:public IFreenetRegistrable,public IFCPConnected,public IFCPMessageHandler,public IPeriodicProcessor,public IDatabase,public ILogger\r
20 {\r
21 public:\r
22         IIndexRequester();\r
23         IIndexRequester(FCPv2 *fcp);\r
24         virtual ~IIndexRequester()              {}\r
25 \r
26         virtual void FCPConnected();\r
27         virtual void FCPDisconnected();\r
28         virtual const bool HandleMessage(FCPMessage &message);\r
29 \r
30         virtual void Process();\r
31 \r
32         virtual void RegisterWithThread(FreenetMasterThread *thread);\r
33 \r
34 protected:\r
35         void InitializeIIndexRequester();\r
36         virtual void Initialize()=0;            // initialize m_maxrequests and m_fcpuniquename\r
37         virtual void PopulateIDList()=0;\r
38         virtual void StartRequest(const IDTYPE &id)=0;\r
39         virtual const bool HandleAllData(FCPMessage &message)=0;\r
40         virtual const bool HandleGetFailed(FCPMessage &message)=0;\r
41         virtual void RemoveFromRequestList(const IDTYPE id);\r
42 \r
43         DateTime m_tempdate;\r
44         std::string m_messagebase;\r
45         std::map<IDTYPE,bool> m_ids;                    // map of all ids we know and whether we have requested file from them yet\r
46         std::vector<IDTYPE> m_requesting;               // list of ids we are currently requesting from\r
47 \r
48         // these MUST be populated by child class\r
49         long m_maxrequests;\r
50         std::string m_fcpuniquename;\r
51 \r
52 };\r
53 \r
54 template <class IDTYPE>\r
55 IIndexRequester<IDTYPE>::IIndexRequester()\r
56 {\r
57         InitializeIIndexRequester();\r
58 }\r
59 \r
60 template <class IDTYPE>\r
61 IIndexRequester<IDTYPE>::IIndexRequester(FCPv2 *fcp):IFCPConnected(fcp)\r
62 {\r
63         InitializeIIndexRequester();\r
64 }\r
65 \r
66 template <class IDTYPE>\r
67 void IIndexRequester<IDTYPE>::FCPConnected()\r
68 {\r
69         // make sure variables have been initialized by the derived class\r
70         if(m_maxrequests==-1)\r
71         {\r
72                 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IIndexRequester<IDTYPE>::FCPConnected maxrequests not initialized correctly!");\r
73         }\r
74         if(m_fcpuniquename=="")\r
75         {\r
76                 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IIndexRequester<IDTYPE>::FCPConnected fcpuniquename not initialized correctly!");\r
77         }\r
78         if(m_fcpuniquename.find("|")!=std::string::npos)\r
79         {\r
80                 m_log->WriteLog(LogFile::LOGLEVEL_ERROR,"IIndexRequester<IDTYPE>::FCPConnected fcpuniquename contains | character!  This is not a valid character!");\r
81         }\r
82 \r
83         m_requesting.clear();\r
84         PopulateIDList();\r
85 }\r
86 \r
87 template <class IDTYPE>\r
88 void IIndexRequester<IDTYPE>::FCPDisconnected()\r
89 {\r
90         \r
91 }\r
92 \r
93 template <class IDTYPE>\r
94 const bool IIndexRequester<IDTYPE>::HandleMessage(FCPMessage &message)\r
95 {\r
96 \r
97         if(message["Identifier"].find(m_fcpuniquename)==0)\r
98         {\r
99                 if(message.GetName()=="DataFound")\r
100                 {\r
101                         return true;\r
102                 }\r
103 \r
104                 if(message.GetName()=="AllData")\r
105                 {\r
106                         return HandleAllData(message);\r
107                 }\r
108 \r
109                 if(message.GetName()=="GetFailed")\r
110                 {\r
111                         return HandleGetFailed(message);\r
112                 }\r
113 \r
114                 if(message.GetName()=="IdentifierCollision")\r
115                 {\r
116                         // remove one of the ids from the requesting list\r
117                         IDTYPE id;\r
118                         std::vector<std::string> idparts;\r
119                         StringFunctions::Split(message["Identifier"],"|",idparts);\r
120                         StringFunctions::Convert(idparts[1],id);\r
121                         RemoveFromRequestList(id);\r
122                         return true;\r
123                 }\r
124         }\r
125 \r
126         return false;\r
127 }\r
128 \r
129 template <class IDTYPE>\r
130 void IIndexRequester<IDTYPE>::InitializeIIndexRequester()\r
131 {\r
132         m_maxrequests=-1;\r
133         m_fcpuniquename="";\r
134 \r
135         Option::Instance()->Get("MessageBase",m_messagebase);\r
136         m_tempdate.SetToGMTime();\r
137 }\r
138 \r
139 template <class IDTYPE>\r
140 void IIndexRequester<IDTYPE>::Process()\r
141 {\r
142         // max is the smaller of the config value or the total number of ids we will request from\r
143         typename std::map<IDTYPE,bool>::size_type max=m_maxrequests>m_ids.size() ? m_ids.size() : m_maxrequests;\r
144 \r
145         // try to keep up to max requests going\r
146         if(m_requesting.size()<max)\r
147         {\r
148                 typename std::map<IDTYPE,bool>::iterator i=m_ids.begin();\r
149 \r
150                 while(i!=m_ids.end() && (*i).second==true)\r
151                 {\r
152                         i++;\r
153                 }\r
154 \r
155                 if(i!=m_ids.end())\r
156                 {\r
157                         StartRequest((*i).first);\r
158                 }\r
159                 else\r
160                 {\r
161                         // we requested from all ids in the list, repopulate the list\r
162                         PopulateIDList();\r
163                 }\r
164         }\r
165         // special case - if there were 0 ids on the list when we started then we will never get a chance to repopulate the list\r
166         // this will recheck for ids every minute\r
167         DateTime now;\r
168         now.SetToGMTime();\r
169         if(m_ids.size()==0 && m_tempdate<(now-(1.0/1440.0)))\r
170         {\r
171                 PopulateIDList();\r
172                 m_tempdate=now;\r
173         }\r
174 \r
175 }\r
176 \r
177 template <class IDTYPE>\r
178 void IIndexRequester<IDTYPE>::RegisterWithThread(FreenetMasterThread *thread)\r
179 {\r
180         thread->RegisterFCPConnected(this);\r
181         thread->RegisterFCPMessageHandler(this);\r
182         thread->RegisterPeriodicProcessor(this);\r
183 }\r
184 \r
185 template <class IDTYPE>\r
186 void IIndexRequester<IDTYPE>::RemoveFromRequestList(const IDTYPE id)\r
187 {\r
188         typename std::vector<IDTYPE>::iterator i=m_requesting.begin();\r
189         while(i!=m_requesting.end() && (*i)!=id)\r
190         {\r
191                 i++;\r
192         }\r
193         if(i!=m_requesting.end())\r
194         {\r
195                 m_requesting.erase(i);\r
196         }\r
197 }\r
198 \r
199 #endif  // _iindexrequester_\r