]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modmanager_static.cpp
bb8fda400bd33b8672a2bb8e26a67bd315b16a51
[user/henk/code/inspircd.git] / src / modmanager_static.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #define MODNAME cmd_all
21
22 #include "inspircd.h"
23 #include "exitcodes.h"
24
25 #ifdef PURE_STATIC
26
27 typedef std::map<std::string, AllModuleList*> modmap;
28 static std::vector<AllCommandList::fn>* cmdlist = NULL;
29 static modmap* modlist = NULL;
30
31 AllCommandList::AllCommandList(fn cmd)
32 {
33         if (!cmdlist)
34                 cmdlist = new std::vector<AllCommandList::fn>();
35         cmdlist->push_back(cmd);
36 }
37
38 AllModuleList::AllModuleList(AllModuleList::fn mod, const std::string& Name) : init(mod), name(Name)
39 {
40         if (!modlist)
41                 modlist = new modmap();
42         modlist->insert(std::make_pair(Name, this));
43 }
44
45 class AllModule : public Module
46 {
47         std::vector<Command*> cmds;
48  public:
49         AllModule()
50         {
51                 if (!cmdlist)
52                         return;
53                 try
54                 {
55                         cmds.reserve(cmdlist->size());
56                         for(std::vector<AllCommandList::fn>::iterator i = cmdlist->begin(); i != cmdlist->end(); ++i)
57                         {
58                                 Command* c = (*i)(this);
59                                 cmds.push_back(c);
60                                 ServerInstance->AddCommand(c);
61                         }
62                 }
63                 catch (...)
64                 {
65                         this->AllModule::~AllModule();
66                         throw;
67                 }
68         }
69
70         ~AllModule()
71         {
72                 for(std::vector<Command*>::iterator i = cmds.begin(); i != cmds.end(); ++i)
73                         delete *i;
74         }
75
76         Version GetVersion()
77         {
78                 return Version("All commands", VF_VENDOR|VF_CORE);
79         }
80 };
81
82 MODULE_INIT(AllModule)
83
84 bool ModuleManager::Load(const std::string& name, bool defer)
85 {
86         modmap::iterator it = modlist->find(name);
87         if (it == modlist->end())
88                 return false;
89         Module* mod = NULL;
90         try
91         {
92                 mod = (*it->second->init)();
93                 mod->ModuleSourceFile = name;
94                 mod->ModuleDLLManager = NULL;
95                 Modules[name] = mod;
96                 if (defer)
97                 {
98                         ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s", name.c_str());
99                         return true;
100                 }
101                 else
102                 {
103                         mod->init();
104                 }
105         }
106         catch (CoreException& modexcept)
107         {
108                 if (mod)
109                         DoSafeUnload(mod);
110                 ServerInstance->Logs->Log("MODULE", DEFAULT, "Unable to load " + name + ": " + modexcept.GetReason());
111                 return false;
112         }
113         FOREACH_MOD(I_OnLoadModule,OnLoadModule(mod));
114         /* We give every module a chance to re-prioritize when we introduce a new one,
115          * not just the one thats loading, as the new module could affect the preference
116          * of others
117          */
118         for(int tries = 0; tries < 20; tries++)
119         {
120                 prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
121                 for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
122                         n->second->Prioritize();
123
124                 if (prioritizationState == PRIO_STATE_LAST)
125                         break;
126                 if (tries == 19)
127                         ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + name);
128         }
129
130         ServerInstance->BuildISupport();
131         return true;
132 }
133
134 namespace {
135         struct UnloadAction : public HandlerBase0<void>
136         {
137                 Module* const mod;
138                 UnloadAction(Module* m) : mod(m) {}
139                 void Call()
140                 {
141                         ServerInstance->Modules->DoSafeUnload(mod);
142                         ServerInstance->GlobalCulls.Apply();
143                         ServerInstance->GlobalCulls.AddItem(this);
144                 }
145         };
146
147         struct ReloadAction : public HandlerBase0<void>
148         {
149                 Module* const mod;
150                 HandlerBase1<void, bool>* const callback;
151                 ReloadAction(Module* m, HandlerBase1<void, bool>* c)
152                         : mod(m), callback(c) {}
153                 void Call()
154                 {
155                         std::string name = mod->ModuleSourceFile;
156                         ServerInstance->Modules->DoSafeUnload(mod);
157                         ServerInstance->GlobalCulls.Apply();
158                         bool rv = ServerInstance->Modules->Load(name.c_str());
159                         callback->Call(rv);
160                         ServerInstance->GlobalCulls.AddItem(this);
161                 }
162         };
163 }
164
165 bool ModuleManager::Unload(Module* mod)
166 {
167         if (!CanUnload(mod))
168                 return false;
169         ServerInstance->AtomicActions.AddAction(new UnloadAction(mod));
170         return true;
171 }
172
173 void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback)
174 {
175         if (CanUnload(mod))
176                 ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback));
177         else
178                 callback->Call(false);
179 }
180
181 void ModuleManager::LoadAll()
182 {
183         Load("cmd_all", true);
184         Load("cmd_whowas.so", true);
185
186         ConfigTagList tags = ServerInstance->Config->ConfTags("module");
187         for(ConfigIter i = tags.first; i != tags.second; ++i)
188         {
189                 ConfigTag* tag = i->second;
190                 std::string name = tag->getString("name");
191                 printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",name.c_str());
192
193                 if (!this->Load(name, true))
194                 {
195                         ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError());
196                         printf_c("\n[\033[1;31m*\033[0m] %s\n\n", this->LastError().c_str());
197                         ServerInstance->Exit(EXIT_STATUS_MODULE);
198                 }
199         }
200
201         for(std::map<std::string, Module*>::iterator i = Modules.begin(); i != Modules.end(); i++)
202         {
203                 Module* mod = i->second;
204                 try 
205                 {
206                         mod->init();
207                 }
208                 catch (CoreException& modexcept)
209                 {
210                         LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason();
211                         ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError);
212                         printf_c("\n[\033[1;31m*\033[0m] %s\n\n", LastModuleError.c_str());
213                         ServerInstance->Exit(EXIT_STATUS_MODULE);
214                 }
215         }
216
217         /* We give every module a chance to re-prioritize when we introduce a new one,
218          * not just the one thats loading, as the new module could affect the preference
219          * of others
220          */
221         for(int tries = 0; tries < 20; tries++)
222         {
223                 prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST;
224                 for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n)
225                         n->second->Prioritize();
226
227                 if (prioritizationState == PRIO_STATE_LAST)
228                         break;
229                 if (tries == 19)
230                 {
231                         ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected");
232                         ServerInstance->Exit(EXIT_STATUS_MODULE);
233                 }
234         }
235 }
236
237 #endif