An XMPP reminder bot written in C#.
https://starbeamrainbowlabs.com/blog/article.php?article=posts/328-RhinoReminds.html
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
5.5 KiB
177 lines
5.5 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.IO; |
|
using System.Reflection; |
|
using System.Threading.Tasks; |
|
using RhinoReminds.Utilities; |
|
using S22.Xmpp; |
|
using S22.Xmpp.Client; |
|
using S22.Xmpp.Im; |
|
using SBRL.Utilities; |
|
|
|
namespace RhinoReminds |
|
{ |
|
public class ProgramSettings |
|
{ |
|
public string AllowedDomain = "*"; |
|
public string Filepath = "./reminders.xml"; |
|
public string Jid = null; |
|
|
|
public string AvatarFilepath = string.Empty; |
|
public string PidFile = null; |
|
|
|
public bool ExitOnModify = false; |
|
|
|
public string Password = null; |
|
} |
|
|
|
public static class Program |
|
{ |
|
public static string Version { |
|
get { |
|
return $"v{Assembly.GetExecutingAssembly().GetName().Version}" + |
|
$"-{EmbeddedFiles.ReadAllText("RhinoReminds.git-hash.txt").Substring(0, 7)}"; |
|
} |
|
} |
|
private static ProgramSettings settings = new ProgramSettings(); |
|
|
|
public static int Main(string[] args) |
|
{ |
|
List<string> extras = new List<string>(); |
|
for (int i = 0; i < args.Length; i++) |
|
{ |
|
if (!args[i].StartsWith("-")) { |
|
extras.Add(args[i]); |
|
continue; |
|
} |
|
|
|
switch (args[i]) { |
|
case "-h": |
|
case "--help": |
|
Console.WriteLine($"--- RhinoReminds {Version} ---"); |
|
Console.WriteLine("> An XMPP reminder bot"); |
|
Console.WriteLine(" By Starbeamrainbowlabs"); |
|
Console.WriteLine(); |
|
Console.WriteLine("Usage:"); |
|
Console.WriteLine(" mono RhinoReminds.exe {options}"); |
|
Console.WriteLine(); |
|
Console.WriteLine("Options:"); |
|
Console.WriteLine(" -h --help Show this message"); |
|
Console.WriteLine($" -f --file Specify where to save reminders (default: {settings.Filepath})"); |
|
Console.WriteLine(" --domain {domain} Set the domain users are allowed to originate at. Defaults to any domain."); |
|
Console.WriteLine(" --avatar Update the XMPP account's avatar to the specified image. By default the avatar is not updated."); |
|
Console.WriteLine(" --pidfile Save our process ID to the specified file, and delete it on exit"); |
|
Console.WriteLine(" --auto-exit Watch for changes to the executable on disk and automatically quit with an exit code of 0 if a modification is detected. Useful for integration with a service manager and continuous deployment."); |
|
Console.WriteLine(); |
|
Console.WriteLine("Environment Variables:"); |
|
Console.WriteLine(" XMPP_JID The JID to login to"); |
|
Console.WriteLine(" XMPP_PASSWORD The password to login with"); |
|
return 0; |
|
|
|
case "--jid": |
|
settings.Jid = args[++i]; |
|
break; |
|
|
|
case "-d": |
|
case "--domain": |
|
settings.AllowedDomain = args[++i]; |
|
break; |
|
|
|
|
|
case "--avatar": |
|
settings.AvatarFilepath = args[++i]; |
|
break; |
|
|
|
case "--pidfile": |
|
settings.PidFile = args[++i]; |
|
break; |
|
|
|
case "--auto-exit": |
|
settings.ExitOnModify = true; |
|
break; |
|
|
|
default: |
|
Console.Error.WriteLine($"Error: Unknown argument '{args[i]}'."); |
|
return 14; |
|
} |
|
} |
|
|
|
settings.Jid = Environment.GetEnvironmentVariable("XMPP_JID"); |
|
settings.Password = Environment.GetEnvironmentVariable("XMPP_PASSWORD"); |
|
|
|
if (settings.Jid == null) { |
|
Console.Error.WriteLine("Error: No JID specified to login with."); |
|
Console.Error.WriteLine("Do so with the XMPP_JID environment variable!"); |
|
return 15; |
|
} |
|
if (settings.Password == null) { |
|
Console.Error.WriteLine("Error: No password specified to login with."); |
|
Console.Error.WriteLine("Do so with the XMPP_PASSWORD environment variable!"); |
|
return 16; |
|
} |
|
|
|
if (settings.PidFile != null) |
|
setupPidFile(); |
|
|
|
run(); |
|
// We shouldn't ever end up here, but just in case..... |
|
cleanupPidFile(); |
|
return 0; |
|
} |
|
|
|
private static void setupPidFile() |
|
{ |
|
File.WriteAllText(settings.PidFile, Process.GetCurrentProcess().Id.ToString()); |
|
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => cleanupPidFile(); |
|
AppDomain.CurrentDomain.DomainUnload += (object sender, EventArgs e) => cleanupPidFile(); |
|
} |
|
|
|
private static void cleanupPidFile() { |
|
// Make sure we only do cleanup once |
|
if (settings.PidFile == null) |
|
return; |
|
|
|
File.Delete(settings.PidFile); |
|
settings.PidFile = null; |
|
} |
|
|
|
private static void run() |
|
{ |
|
Console.WriteLine("************************************"); |
|
Console.WriteLine("***** RhinoReminds is starting *****"); |
|
Console.WriteLine("************************************"); |
|
Console.WriteLine($"[Program] Running {Version}"); |
|
|
|
if (settings.ExitOnModify) { |
|
ExitWatcher.EnableExitOnModify(); |
|
} |
|
|
|
ClientListener client = new ClientListener(settings.Jid, settings.Password) { |
|
ReminderFilePath = settings.Filepath |
|
}; |
|
client.AllowedDomains.Add(settings.AllowedDomain); |
|
// Update the avatar if appropriate |
|
if (settings.AvatarFilepath != string.Empty) { |
|
OnConnectedHandler handler = null; |
|
handler = (object sender, OnConnectedEventArgs eventArgs) => { |
|
client.SetAvatar(settings.AvatarFilepath); |
|
Console.WriteLine($"[Program] Set avatar to '{settings.AvatarFilepath}'."); |
|
client.OnConnected -= handler; |
|
}; |
|
client.OnConnected += handler; |
|
} |
|
// Connect to the server & start listening |
|
// Make sure the program doesn't exit whilst we're connected |
|
try { |
|
client.Start().Wait(); |
|
} catch (Exception) { |
|
// Ensure we tidy up after ourselves by deleting the PID file |
|
if (settings.PidFile != null) |
|
cleanupPidFile(); |
|
// Re-throw the error |
|
throw; |
|
} |
|
} |
|
} |
|
}
|
|
|