]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_httpd_stats.cpp
Add call to protocol interface to get useful info on the server map. Return a std...
[user/henk/code/inspircd.git] / src / modules / m_httpd_stats.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "httpd.h"
16 #include "protocol.h"
17
18 /* $ModDesc: Provides statistics over HTTP via m_httpd.so */
19 /* $ModDep: httpd.h */
20
21 typedef std::map<irc::string,int> StatsHash;
22 typedef StatsHash::iterator StatsIter;
23
24 typedef std::vector<std::pair<int,irc::string> > SortedList;
25 typedef SortedList::iterator SortedIter;
26
27 static StatsHash* sh = new StatsHash();
28 static SortedList* so = new SortedList();
29
30 class ModuleHttpStats : public Module
31 {
32         
33         std::string stylesheet;
34         bool changed;
35
36  public:
37
38         void ReadConfig()
39         {
40                 ConfigReader c(ServerInstance);
41                 this->stylesheet = c.ReadValue("httpstats", "stylesheet", 0);
42         }
43
44         ModuleHttpStats(InspIRCd* Me) : Module(Me)
45         {
46                 ReadConfig();
47                 this->changed = true;
48                 Implementation eventlist[] = { I_OnEvent, I_OnRequest, I_OnChannelDelete, I_OnUserJoin, I_OnUserPart, I_OnUserQuit };
49                 ServerInstance->Modules->Attach(eventlist, this, 6);
50         }
51
52         void InsertOrder(irc::string channel, int count)
53         {
54                 /* This function figures out where in the sorted list to put an item from the hash */
55                 SortedIter a;
56                 for (a = so->begin(); a != so->end(); a++)
57                 {
58                         /* Found an item equal to or less than, we insert our item before it */
59                         if (a->first <= count)
60                         {
61                                 so->insert(a,std::pair<int,irc::string>(count,channel));
62                                 return;
63                         }
64                 }
65                 /* There are no items in the list yet, insert something at the beginning */
66                 so->insert(so->begin(), std::pair<int,irc::string>(count,channel));
67         }
68
69         void SortList()
70         {
71                 /* Sorts the hash into the sorted list using an insertion sort */
72                 so->clear();
73                 for (StatsIter a = sh->begin(); a != sh->end(); a++)
74                         InsertOrder(a->first, a->second);
75                 this->changed = false;
76         }
77
78         void OnEvent(Event* event)
79         {
80                 std::stringstream data("");
81
82                 if (event->GetEventID() == "httpd_url")
83                 {
84                         ServerInstance->Logs->Log("m_http_stats", DEBUG,"Handling httpd event");
85                         HTTPRequest* http = (HTTPRequest*)event->GetData();
86
87                         if ((http->GetURI() == "/stats") || (http->GetURI() == "/stats/"))
88                         {
89                                 data << "<inspircdstats>";
90
91                                 data << "<server><name>" << ServerInstance->Config->ServerName << "</name><gecos>" << ServerInstance->Config->ServerDesc << "</gecos></server>";
92
93                                 data << "<general>";
94                                 data << "<usercount>" << ServerInstance->Users->clientlist->size() << "</usercount>";
95                                 data << "<channelcount>" << ServerInstance->chanlist->size() << "</channelcount>";
96                                 data << "<opercount>" << ServerInstance->Users->all_opers.size() << "</opercount>";
97                                 data << "<socketcount>" << (ServerInstance->SE->GetMaxFds() - ServerInstance->SE->GetRemainingFds()) << "</socketcount><socketmax>" << ServerInstance->SE->GetMaxFds() <<
98                                         "</socketmax><socketengine>" << ServerInstance->SE->GetName() << "</socketengine>";
99
100                                 time_t current_time = 0;
101                                 current_time = ServerInstance->Time();
102                                 time_t server_uptime = current_time - ServerInstance->startup_time;
103                                 struct tm* stime;
104                                 stime = gmtime(&server_uptime);
105                                 data << "<uptime><days>" << stime->tm_yday << "</days><hours>" << stime->tm_hour << "</hours><mins>" << stime->tm_min << "</mins><secs>" << stime->tm_sec << "</secs></uptime>";
106
107
108                                 data << "</general>";
109                                 data << "<modulelist>";
110                                 std::vector<std::string> module_names = ServerInstance->Modules->GetAllModuleNames(0);
111                                 for (std::vector<std::string>::iterator i = module_names.begin(); i != module_names.end(); ++i)
112                                 {
113                                         Module* m = ServerInstance->Modules->Find(i->c_str());
114                                         Version v = m->GetVersion();
115                                         data << "<module><name>" << *i << "</name><version>" << v.Major << "." <<  v.Minor << "." << v.Revision << "." << v.Build << "</version></module>";
116                                 }
117                                 data << "</modulelist>";
118
119                                 data << "<channellist>";
120                                 /* If the list has changed since last time it was displayed, re-sort it
121                                  * this time only (not every time, as this would be moronic)
122                                  */
123                                 if (this->changed)
124                                         this->SortList();
125
126                                 for (SortedIter a = so->begin(); a != so->end(); a++)
127                                 {
128                                         Channel* c = ServerInstance->FindChan(a->second.c_str());
129                                         if (c && !c->IsModeSet('s') && !c->IsModeSet('p'))
130                                         {
131                                                 data << "<channel>";
132                                                 data << "<usercount>" << c->GetUsers()->size() << "</usercount><channelname>" << c->name << "</channelname>";
133                                                 data << "<channelops>" << c->GetOppedUsers()->size() << "</channelops>";
134                                                 data << "<channelhalfops>" << c->GetHalfoppedUsers()->size() << "</channelhalfops>";
135                                                 data << "<channelvoices>" << c->GetVoicedUsers()->size() << "</channelvoices>";
136                                                 data << "<channeltopic>" << c->topic << "</channeltopic>";
137                                                 data << "<channelmodes>" << c->ChanModes(false) << "</channelmodes>";
138                                                 data << "</channel>";
139                                         }
140                                 }
141
142                                 data << "</channellist>";
143
144                                 data << "<serverlist>";
145                                 
146                                 ProtoServerList sl;
147                                 ServerInstance->PI->GetServerList(sl);
148
149                                 for (ProtoServerList::iterator b = sl.begin(); b != sl.end(); ++b)
150                                 {
151                                         data << "<server>";
152                                         data << "<servername>" << b->servername << "</servername>";
153                                         data << "<parentname>" << b->parentname << "</parentname>";
154                                         data << "<usercount>" << b->usercount << "</usercount>";
155                                         data << "<opercount>" << b->opercount << "</opercount>";
156                                         data << "<lagmillisecs>" << b->latencyms << "</lagmillisecs>";
157                                         data << "</server>";
158                                 }
159                                 data << "</serverlist>";
160
161                                 data << "</inspircdstats>";
162
163                                 /* Send the document back to m_httpd */
164                                 HTTPDocument response(http->sock, &data, 200);
165                                 response.headers.SetHeader("X-Powered-By", "m_httpd_stats.so");
166                                 response.headers.SetHeader("Content-Type", "text/xml");
167                                 Request req((char*)&response, (Module*)this, event->GetSource());
168                                 req.Send();
169                         }
170                 }
171         }
172
173         void OnChannelDelete(Channel* chan)
174         {
175                 StatsIter a = sh->find(chan->name);
176                 if (a != sh->end())
177                 {
178                         sh->erase(a);
179                 }
180                 this->changed = true;
181         }
182
183         void OnUserJoin(User* user, Channel* channel, bool sync, bool &silent)
184         {
185                 StatsIter a = sh->find(channel->name);
186                 if (a != sh->end())
187                 {
188                         a->second++;
189                 }
190                 else
191                 {
192                         irc::string name = channel->name;
193                         sh->insert(std::pair<irc::string,int>(name,1));
194                 }
195                 this->changed = true;
196         }
197
198         void OnUserPart(User* user, Channel* channel, const std::string &partmessage, bool &silent)
199         {
200                 StatsIter a = sh->find(channel->name);
201                 if (a != sh->end())
202                 {
203                         a->second--;
204                 }
205                 this->changed = true;
206         }
207
208         void OnUserQuit(User* user, const std::string &message, const std::string &oper_message)
209         {
210                 for (UCListIter v = user->chans.begin(); v != user->chans.end(); v++)
211                 {
212                         Channel* c = v->first;
213                         StatsIter a = sh->find(c->name);
214                         if (a != sh->end())
215                         {
216                                 a->second--;
217                         }
218                 }
219                 this->changed = true;
220         }
221
222         const char* OnRequest(Request* request)
223         {
224                 return NULL;
225         }
226
227
228         virtual ~ModuleHttpStats()
229         {
230                 delete sh;
231                 delete so;
232         }
233
234         virtual Version GetVersion()
235         {
236                 return Version(1, 2, 0, 0, VF_VENDOR, API_VERSION);
237         }
238 };
239
240 MODULE_INIT(ModuleHttpStats)