public static WriteNow ( string Message, |
||
Message | string |
/// If set to |
MessageType |
/// If set to |
|
Résultat | bool |
private static void ExecuteThread() { try { TcpListener server = new TcpListener(IPAddress.Any, Configuration.Network.SystemPort); server.Start(); Online = true; Syslog.WriteNow("Network console is online on port: " + Configuration.Network.SystemPort); while (Core.IsRunning) { TcpClient connection = server.AcceptTcpClient(); Session session = new Session(); lock (SessionList) { SessionList.Add(session); } Thread client = new Thread(session.ThreadExec) { Name = "Telnet:" + connection.Client.RemoteEndPoint }; Core.ThreadManager.RegisterThread(client); client.Start(connection); Thread.Sleep(100); } } catch (Exception fail) { Online = false; Syslog.WriteNow("Network console is down", true); Core.HandleException(fail); } Core.ThreadManager.UnregisterThread(Thread.CurrentThread); }
private static Dictionary <string, string> File2Dict() { Dictionary <string, string> Values = new Dictionary <string, string>(); string[] xx = File.ReadAllLines(Variables.ConfigurationDirectory + Path.DirectorySeparatorChar + Paths.ConfigFile); string LastName = null; foreach (string line in xx) { string content; if (String.IsNullOrEmpty(line) || line.TrimStart(' ').StartsWith("//")) { continue; } Syslog.DebugWrite("Parsing line: " + line, 8); if (LastName == null && line.Contains("=")) { LastName = line.Substring(0, line.IndexOf("=")); if (Values.ContainsKey(LastName)) { throw new Exception("You can't redefine same value in configuration multiple times, error reading: " + LastName); } content = line.Substring(line.IndexOf("=") + 1); if (content.Contains(";")) { content = content.Substring(0, content.IndexOf(";")); } Values.Add(LastName, content); Syslog.DebugWrite("Stored config value: " + LastName + ": " + content); if (line.Contains(";")) { LastName = null; } continue; } if (LastName != null) { // we remove extra space from beginning so that we can indent in config file content = line.TrimStart(' '); if (!content.Contains(";")) { Syslog.DebugWrite("Append config value: " + LastName + ": " + content); Values[LastName] += "\n" + content; } else { content = content.Substring(0, content.IndexOf(";")); Values[LastName] += "\n" + content; Syslog.DebugWrite("Append config value: " + LastName + ": " + content); LastName = null; } continue; } Syslog.WriteNow("Invalid configuration line: " + line, true); } return(Values); }
/// <summary> /// This is used to handle UNIX signals /// </summary> /// <param name='sender'>Sender</param> /// <param name='args'>Arguments</param> protected static void SigInt(object sender, ConsoleCancelEventArgs args) { if (!Core.IsRunning) { // in case that user hit ctrl + c multiple times, we don't want to // call this, once is just enough return; } Syslog.WriteNow("SIGINT - Shutting down", true); try { Core.Kill(); } catch (Exception fail) { Core.HandleException(fail); } Syslog.WriteNow("Terminated (emergency)"); Process.GetCurrentProcess().Kill(); }
/// <summary> /// Load config of bot /// </summary> public static int Load() { if (Directory.Exists(Variables.ConfigurationDirectory) == false) { Directory.CreateDirectory(Variables.ConfigurationDirectory); } if (!File.Exists(Variables.ConfigurationDirectory + Path.DirectorySeparatorChar + Paths.ConfigFile)) { Console.WriteLine("Error: unable to find config file in configuration/" + Paths.ConfigFile); Console.WriteLine("You can get a configuration file here: https://github.com/benapetr/wikimedia-bot/blob/master/configuration/wmib.conf"); return(2); } ConfigurationData = File2Dict(); IRC.Username = RetrieveConfig("username"); IRC.NetworkHost = RetrieveConfig("network"); IRC.NickName = RetrieveConfig("nick"); IRC.LoginNick = RetrieveConfig("nick"); IRC.Hostname = RetrieveConfig("host", "wikimedia/bot/wm-bot"); System.DebugChan = RetrieveConfig("debug"); System.MaxGrantableRoleLevel = RetrieveConfig("maximal_grantable_role_level", System.MaxGrantableRoleLevel); System.ModulesToLoad = RetrieveConfig("modules", ""); Network.BouncerPort = RetrieveConfig("bouncerp", Network.BouncerPort); WebPages.WebpageURL = RetrieveConfig("web", ""); IRC.LoginPw = RetrieveConfig("password", ""); IRC.Interval = RetrieveConfig("interval", IRC.Interval); MySQL.MysqlPw = RetrieveConfig("mysql_pw"); MySQL.Mysqldb = RetrieveConfig("mysql_db", MySQL.Mysqldb); MySQL.MysqlUser = RetrieveConfig("mysql_user"); MySQL.MysqlPort = RetrieveConfig("mysql_port", MySQL.MysqlPort); MySQL.MysqlHost = RetrieveConfig("mysql_host"); WebPages.Css = RetrieveConfig("style_html_file", ""); Network.SystemPort = RetrieveConfig("system_port", Network.SystemPort); Postgres.DBNM = RetrieveConfig("pg_name"); Postgres.Host = RetrieveConfig("pg_host"); Postgres.Pass = RetrieveConfig("pg_pass"); Postgres.Unwritten = RetrieveConfig("pg_unwritten_log", Postgres.Unwritten); Postgres.Port = RetrieveConfig("pg_port", Postgres.Port); Postgres.User = RetrieveConfig("pg_user"); if (string.IsNullOrEmpty(IRC.LoginNick)) { Console.WriteLine("Error there is no login for bot (nick key is missing?)"); return(1); } if (string.IsNullOrEmpty(IRC.NetworkHost)) { Console.WriteLine("Error irc server is wrong (network key is missing?)"); return(4); } if (string.IsNullOrEmpty(IRC.NickName)) { Console.WriteLine("Error there is no username for bot"); return(6); } System.prefix = RetrieveConfig("system_prefix", System.prefix); IRC.UsingBouncer = bool.Parse(RetrieveConfig("serverIO", "false")); Syslog.Log("Loading instances"); Instance.PrimaryInstance = Instance.CreateInstance(IRC.NickName, Network.BouncerPort); int CurrentInstance = 0; while (CurrentInstance < 20) { if (!ConfigurationData.ContainsKey("instancename" + CurrentInstance)) { break; } string InstanceName = ConfigurationData["instancename" + CurrentInstance]; Syslog.DebugLog("Instance found: " + InstanceName); if (IRC.UsingBouncer) { Syslog.DebugLog("Using bouncer, looking for instance port"); if (!ConfigurationData.ContainsKey("instanceport" + CurrentInstance)) { Syslog.WriteNow("Instance " + InstanceName + " has invalid port, not using", true); continue; } int port = int.Parse(ConfigurationData["instanceport" + CurrentInstance]); Instance.CreateInstance(InstanceName, port); } else { Instance.CreateInstance(InstanceName); } CurrentInstance++; } if (!File.Exists(Paths.GetChannelFile())) { Console.WriteLine("Error there is no channel file (" + Paths.GetChannelFile() + ") to load channels from"); return(20); } List <string> channels = new List <string>(File.ReadAllLines(Paths.GetChannelFile())); foreach (string x in channels) { string name = x.Replace(" ", ""); if (!string.IsNullOrEmpty(name)) { lock (Channels) { Channels.Add(new Channel(name)); } } } if (!string.IsNullOrEmpty(Configuration.System.DebugChan) && !channels.Contains(Configuration.System.DebugChan)) { lock (Channels) { Channels.Add(new Channel(Configuration.System.DebugChan)); } Syslog.DebugLog("Debug channel was missing in channel list (fixed by join)"); } Syslog.Log("Channels were all loaded, linking databases"); // Now when all chans are loaded let's link them together lock (Channels) { foreach (Channel channel in Channels) { channel.InitializeShares(); } } Syslog.Log("Channel db's working"); if (!Directory.Exists(Paths.DumpDir)) { Directory.CreateDirectory(Paths.DumpDir); } return(0); }
/// <summary> /// This will disable bot and close this process /// </summary> public static void Kill() { try { if (!IsRunning) { Syslog.DebugLog("Attempt to kill bot while it's already being killed", 2); return; } _Status = Status.ShuttingDown; Instance.Kill(); StorageWriter.IsRunning = false; Thread modules = new Thread(Terminate) { Name = "KERNEL: Core helper shutdown thread" }; modules.Start(); Syslog.WriteNow("Giving grace time for all modules to finish ok"); int kill = 0; while (kill < 20) { kill++; if (ExtensionHandler.ExtensionList.Count == 0) { Syslog.WriteNow("KERNEL: Modules are all down"); if (WriterThread.ThreadState == ThreadState.Running || WriterThread.ThreadState == ThreadState.WaitSleepJoin) { Syslog.WriteNow("KERNEL: Writer thread didn't shut down gracefully, waiting 2 seconds", true); Thread.Sleep(2000); if (WriterThread.ThreadState == ThreadState.Running || WriterThread.ThreadState == ThreadState.WaitSleepJoin) { Syslog.WriteNow("KERNEL: Writer thread didn't shut down gracefully, killing", true); WriterThread.Abort(); } else { Syslog.WriteNow("KERNEL: Writer thread is shut down", true); } } else { Syslog.WriteNow("KERNEL: Writer thread is down ok"); } break; } Thread.Sleep(1000); } if (ExtensionHandler.ExtensionList.Count == 0) { Syslog.WriteNow("KERNEL: Giving a grace time to other threads to finish"); Thread.Sleep(200); Syslog.WriteNow("KERNEL: Terminated (ok)"); Environment.Exit(0); } } catch (Exception fail) { HandleException(fail); } Syslog.WriteNow("There was problem shutting down " + ExtensionHandler.ExtensionList.Count + " modules, terminating process"); Syslog.WriteNow("KERNEL: Terminated (error)"); Process.GetCurrentProcess().Kill(); }
/// <summary> /// Processes the terminal parameters /// </summary> /// <param name='args'> /// What user has provided in terminal /// </param> private static void ParseArgs(string[] args) { int i = 0; List <string> parameters = new List <string>(args); foreach (string item in parameters) { i++; if (item == "--nocolors") { Configuration.System.Colors = false; continue; } if (item == "--traffic") { Configuration.Network.Logging = true; } if (item == "-h" || item == "--help") { Console.WriteLine("This is a wikimedia bot binary\n\n" + "Parameters:\n" + " --nocolors: Disable colors in system logs\n" + " -h [--help]: Display help\n" + " --pid file: Write a pid to a file\n" + " --modules: Try to load all module files and list all modules that are available, separated by comma\n" + " --traffic: Enable traffic logs\n" + " --security: Will load a security subsystem and serialize all roles and print them to standard output\n" + " this can be used to create a custom security configuration if you store the output\n" + " to configuration/security.xml and restart the bot\n" + " -v: Increases verbosity\n\n" + "This software is open source, licensed under GPLv3"); Environment.Exit(0); } if (item == "--modules") { ExtensionHandler.DumpMods(); Environment.Exit(0); } if (item == "--security") { Syslog.IsQuiet = true; if (Configuration.Load() != 0) { Syslog.IsQuiet = false; Syslog.WriteNow("Error while loading the config file, exiting", true); Environment.Exit(-2); } ExtensionHandler.SearchMods(); Security.Init(); Console.WriteLine(Security.Dump()); Environment.Exit(0); } if (item == "--pid") { if (parameters.Count <= i) { Console.WriteLine("You didn't provide a name for pid file"); Environment.Exit(0); } File.WriteAllText(parameters[i], Process.GetCurrentProcess().Id.ToString()); } if (item.StartsWith("-v", StringComparison.InvariantCulture)) { foreach (char x in item) { if (x == 'v') { Configuration.System.SelectedVerbosity++; } } } } if (Configuration.System.SelectedVerbosity >= 1) { Syslog.DebugLog("System verbosity: " + Configuration.System.SelectedVerbosity); } }
/// <summary> /// The entry point of the program, where the program control starts and ends. /// </summary> /// <param name='args'> /// The command-line arguments. /// </param> private static void Main(string[] args) { try { Configuration.System.UpTime = DateTime.Now; Core.KernelThread = Thread.CurrentThread; Core.KernelThread.Name = "Kernel"; Configuration.System.Version += " [libirc v. " + libirc.Defs.Version.ToString() + "]"; Thread logger = new Thread(Logging.Exec) { Name = "Logger" }; Core.ThreadManager.RegisterThread(logger); ParseArgs(args); Syslog.WriteNow(Configuration.System.Version); Syslog.WriteNow("Loading..."); logger.Start(); Console.CancelKeyPress += SigInt; messages.LoadLD(); if (Configuration.Load() != 0) { Syslog.WriteNow("Error while loading the config file, exiting", true); Environment.Exit(-2); } Terminal.Init(); Core.Help.CreateHelp(); Core.WriterThread = new Thread(StorageWriter.Exec); Core.ThreadManager.RegisterThread(Core.WriterThread); Core.WriterThread.Name = "Writer"; Core.WriterThread.Start(); if (WMIBMySQL.IsAvailable) { Syslog.Log("Initializing MySQL"); Core.MysqlDB = new WMIBMySQL(); } else { Syslog.Log("Mysql is not configured, not using"); } if (PostgreSQL.IsAvailable) { Syslog.Log("Opening connection to PostgreDB"); Core.PostgreDB = new PostgreSQL(); Core.PostgreDB.Connect(); } else { Syslog.Log("Postgres is not configured, not using"); } // let's use postgre as default if (Core.PostgreDB != null) { Syslog.Log("Using Postgres as a default SQL provider"); Core.DB = Core.PostgreDB; } else if (Core.MysqlDB != null) { Syslog.Log("Using MySQL as a default SQL"); Core.DB = Core.MysqlDB; } // register all commands Commands.InitAdminCommands(); Syslog.Log("Loading modules"); ExtensionHandler.SearchMods(); Security.Init(); Security.Global(); Syslog.Log("Connecting"); IRC.Connect(); #if __MonoCS__ UnixSignal[] signals = { new UnixSignal(Signum.SIGINT), new UnixSignal(Signum.SIGTERM), new UnixSignal(Signum.SIGQUIT), new UnixSignal(Signum.SIGHUP) }; #endif while (Core.IsRunning) { #if __MonoCS__ int index = UnixSignal.WaitAny(signals, -1); Signum signal = signals [index].Signum; switch (signal) { case Signum.SIGINT: SigInt(null, null); goto exit; case Signum.SIGTERM: Syslog.WriteNow("SIGTERM - Shutting down", true); Core.Kill(); goto exit; } #endif Thread.Sleep(200); } #if __MonoCS__ exit: #endif // memory cleanup if (Core.DB != null) { ((WMIBMySQL)Core.DB).Dispose(); } } catch (Exception fatal) { Syslog.WriteNow("bot crashed, bellow is debugging information", Syslog.Type.Error); Console.WriteLine("------------------------------------------------------------------------"); Console.WriteLine("Description: " + fatal.Message); Console.WriteLine("Stack trace: " + fatal.StackTrace); Environment.Exit(-2); } }