diff --git a/.gitignore b/.gitignore index 38139b3..e8f7433 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +git-hash.txt + *.tar.gz *.backup # Created by https://www.gitignore.io/api/monodevelop,visualstudio,csharp,git diff --git a/RhinoReminds/ClientListener.cs b/RhinoReminds/ClientListener.cs index 1f83e0c..b8dcf5c 100644 --- a/RhinoReminds/ClientListener.cs +++ b/RhinoReminds/ClientListener.cs @@ -200,9 +200,14 @@ namespace RhinoReminds client.SendChatReply(message, "**Remind:** Set a reminder"); client.SendChatReply(message, "**List / Show:** List the reminders I have set"); client.SendChatReply(message, "**Delete / Remove:** Delete a reminder by it's number (find this in the reminder list from the instruction above)"); + client.SendChatReply(message, "**Version:** Show the program version I am currently running"); client.SendChatReply(message, "\nExample: 'Remind me to feed the cat tomorrow at 6pm'"); break; + case "version": + client.SendChatReply(message, $"I'm currently running {Program.Version}."); + break; + case "delete": case "remove": List failed = new List(), diff --git a/RhinoReminds/Program.cs b/RhinoReminds/Program.cs index 9d1e163..055ab05 100644 --- a/RhinoReminds/Program.cs +++ b/RhinoReminds/Program.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Reflection; using System.Threading.Tasks; using S22.Xmpp; using S22.Xmpp.Client; using S22.Xmpp.Im; +using SBRL.Utilities; namespace RhinoReminds { @@ -23,6 +25,12 @@ namespace RhinoReminds 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) @@ -38,7 +46,7 @@ namespace RhinoReminds switch (args[i]) { case "-h": case "--help": - Console.WriteLine("--- RhinoReminds ---"); + Console.WriteLine($"--- RhinoReminds {Version} ---"); Console.WriteLine("> An XMPP reminder bot"); Console.WriteLine(" By Starbeamrainbowlabs"); Console.WriteLine(); @@ -125,6 +133,7 @@ namespace RhinoReminds Console.WriteLine("************************************"); Console.WriteLine("***** RhinoReminds is starting *****"); Console.WriteLine("************************************"); + Console.WriteLine($"[Program] Running {Version}"); ClientListener client = new ClientListener(settings.Jid, settings.Password) { ReminderFilePath = settings.Filepath diff --git a/RhinoReminds/RhinoReminds.csproj b/RhinoReminds/RhinoReminds.csproj index 26a5044..f642a39 100644 --- a/RhinoReminds/RhinoReminds.csproj +++ b/RhinoReminds/RhinoReminds.csproj @@ -68,6 +68,7 @@ + @@ -76,4 +77,11 @@ + + + + + + + diff --git a/RhinoReminds/Utilities/EmbeddedFiles.cs b/RhinoReminds/Utilities/EmbeddedFiles.cs new file mode 100644 index 0000000..c1df720 --- /dev/null +++ b/RhinoReminds/Utilities/EmbeddedFiles.cs @@ -0,0 +1,287 @@ +using System; +using System.Reflection; +using System.IO; +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace SBRL.Utilities +{ + /// + /// A collection of static methods for manipulating embedded resources. + /// + /// + /// From https://gist.github.com/sbrl/aabfcfe87396b8c05d3263887b807d23. You may have seen + /// this in several other ACWs I've done. Proof I wrote this is available upon request, + /// of course. + /// + /// v0.6.2, by Starbeamrainbowlabs + /// Last updated 28th November 2018. + /// Licensed under MPL-2.0. + /// + /// Changelog: + /// v0.1 (25th July 2016): + /// - Initial release. + /// v0.2 (8th August 2016): + /// - Changed namespace. + /// v0.3 (21st January 2017): + /// - Added GetRawReader(). + /// v0.4 (8th April 2017): + /// - Removed unnecessary using statement. + /// v0.5 (3rd September 2017): + /// - Changed namespace + /// v0.6 (12th October 2018): + /// - Fixed assembly / calling assembly bugs + /// v0.6.1 (17th october 2018): + /// - Fix crash in ReadAllText(filename) + /// v0.6.2 (28th November 2018): + /// - Fix assembly targeting bug in ReadAllBytesAsync() + /// + public static class EmbeddedFiles + { + /// + /// An array of the filenames of all the resources embedded in the target assembly. + /// + /// The target assembly to extract a resource list for. + /// The resource list. + public static string[] ResourceList(Assembly targetAssembly) + { + return targetAssembly.GetManifestResourceNames(); + } + /// + /// An array of the filenames of all the resources embedded in the calling assembly. + /// + /// The resource list. + public static string[] ResourceList() + { + return ResourceList(Assembly.GetCallingAssembly()); + } + + /// + /// Gets a list of resources embedded in the calling assembly as a string. + /// + public static string GetResourceListText() + { + return GetResourceListText(Assembly.GetCallingAssembly()); + } + + /// + /// Gets a list of resources embedded in the target assembly as a string. + /// + /// The target assembly to extract a resource list from. + public static string GetResourceListText(Assembly targetAssembly) + { + StringWriter result = new StringWriter(); + result.WriteLine("Files embedded in {0}:", targetAssembly.GetName().Name); + foreach (string filename in ResourceList(targetAssembly)) + result.WriteLine(" - {0}", filename); + return result.ToString(); + } + /// + /// Writes a list of resources embedded in the calling assembly to the standard output. + /// + public static void WriteResourceList() + { + Console.WriteLine(GetResourceListText(Assembly.GetCallingAssembly())); + } + + /// + /// Gets a StreamReader attached to the specified embedded resource. + /// + /// The filename of the embedded resource to get a StreamReader of. + /// A StreamReader attached to the specified embedded resource. + public static StreamReader GetReader(string filename) + { + return new StreamReader(GetRawReader(filename)); + } + + /// + /// Gets a raw Stream that's attached to the specified embedded resource + /// in the calling assembly. + /// Useful when you want to copy an embedded resource to some other stream. + /// + /// The path to the embedded resource. + /// A raw Stream object attached to the specified file. + public static Stream GetRawReader(string filename) + { + return GetRawReader(Assembly.GetCallingAssembly(), filename); + } + /// + /// Gets a raw Stream that's attached to the specified embedded resource + /// in the specified assembly. + /// Useful when you want to copy an embedded resource to some other stream. + /// + /// The assembly to search for the filename in. + /// The path to the embedded resource. + /// A raw Stream object attached to the specified file. + public static Stream GetRawReader(Assembly targetAssembly, string filename) + { + return targetAssembly.GetManifestResourceStream(filename); + } + + /// + /// Gets the specified embedded resource's content as a byte array. + /// + /// The filename of the embedded resource to get conteent of. + /// The specified embedded resource's content as a byte array. + public static byte[] ReadAllBytes(string filename) + { + // Referencing the Result property will block until the async method completes + return ReadAllBytesAsync(filename).Result; + } + /// + /// Gets the content of the resource that's embedded in the specified + /// assembly as a byte array asynchronously. + /// + /// The assembly to search for the file in. + /// The filename of the embedded resource to get content of. + /// The specified embedded resource's content as a byte array. + public static async Task ReadAllBytesAsync(Assembly targetAssembly, string filename) + { + using (Stream resourceStream = targetAssembly.GetManifestResourceStream(filename)) + using (MemoryStream temp = new MemoryStream()) + { + await resourceStream.CopyToAsync(temp); + return temp.ToArray(); + } + } + public static async Task ReadAllBytesAsync(string filename) + { + return await ReadAllBytesAsync(Assembly.GetCallingAssembly(), filename); + } + + + /// + /// Gets all the text stored in the resource that's embedded in the + /// calling assembly. + /// + /// The filename to fetch the content of. + /// All the text stored in the specified embedded resource. + public static string ReadAllText(string filename) + { + return ReadAllTextAsync(Assembly.GetCallingAssembly(), filename).Result; + } + /// + /// Gets all the text stored in the resource that's embedded in the + /// specified assembly. + /// + /// The assembly from in which to look for the target embedded resource. + /// The filename to fetch the content of. + /// All the text stored in the specified embedded resource. + public static string ReadAllText(Assembly targetAssembly, string filename) + { + return ReadAllTextAsync(targetAssembly, filename).Result; + } + + /// + /// Gets all the text stored in the resource that's embedded in the + /// specified assembly asynchronously. + /// + /// The filename to fetch the content of. + /// All the text stored in the specified embedded resource. + public static async Task ReadAllTextAsync(Assembly targetAssembly, string filename) + { + using (StreamReader resourceReader = new StreamReader(targetAssembly.GetManifestResourceStream(filename))) + { + return await resourceReader.ReadToEndAsync(); + } + } + /// + /// Gets all the text stored in the resource that's embedded in the + /// calling assembly asynchronously. + /// + /// The filename to fetch the content of. + /// All the text stored in the specified embedded resource. + public static async Task ReadAllTextAsync(string filename) + { + return await ReadAllTextAsync(Assembly.GetCallingAssembly(), filename); + } + + + /// + /// Enumerates the lines of text in the embedded resource that's + /// embedded in the calling assembly. + /// + /// The filename of the embedded resource to enumerate. + /// An IEnumerator that enumerates the specified embedded resource. + public static IEnumerable EnumerateLines(string filename) + { + return EnumerateLines(Assembly.GetCallingAssembly(), filename); + } + /// + /// Enumerates the lines of text in the embedded resource that's + /// embedded in the specified assembly. + /// + /// The filename of the embedded resource to enumerate. + /// An IEnumerator that enumerates the specified embedded resource. + public static IEnumerable EnumerateLines(Assembly targetAssembly, string filename) + { + foreach (Task nextLine in EnumerateLinesAsync(targetAssembly, filename)) + yield return nextLine.Result; + } + + /// + /// Enumerates the lines of text in the resource that's embedded in the + /// specified assembly asynchronously. + /// Each successive call returns a task that, when complete, returns + /// the next line of text stored in the embedded resource. + /// + /// The target assembly in which to look for the embedded resource. + /// The filename of the embedded resource to enumerate. + /// An IEnumerator that enumerates the specified embedded resource. + public static IEnumerable> EnumerateLinesAsync(Assembly targetAssembly, string filename) + { + using (StreamReader resourceReader = new StreamReader(targetAssembly.GetManifestResourceStream(filename))) + { + while (!resourceReader.EndOfStream) + yield return resourceReader.ReadLineAsync(); + } + } + /// + /// Enumerates the lines of text in the resource that's embedded in the + /// calling assembly asynchronously. + /// Each successive call returns a task that, when complete, returns + /// the next line of text stored in the embedded resource. + /// + /// The filename of the embedded resource to enumerate. + /// An IEnumerator that enumerates the specified embedded resource. + public static IEnumerable> EnumerateLinesAsync(string filename) + { + return EnumerateLinesAsync(Assembly.GetCallingAssembly(), filename); + } + + /// + /// Gets all the lines of text in the specified embedded resource. + /// You might find EnumerateLines(string filename) more useful depending on your situation. + /// + /// The filename to obtain the lines of text from. + /// A list of lines in the specified embedded resource. + public static List GetAllLines(string filename) + { + // Referencing the Result property will block until the async method completes + return GetAllLinesAsync(filename).Result; + } + /// + /// Gets all the lines of text in the resource that's embedded in the + /// calling assembly asynchronously. + /// + /// The filename to obtain the lines of text from. + /// A list of lines in the specified embedded resource. + public static async Task> GetAllLinesAsync(string filename) + { + return await GetAllLinesAsync(Assembly.GetCallingAssembly(), filename); + } + /// + /// Gets all the lines of text in the resource that's embedded in the + /// specified assembly asynchronously. + /// + /// The filename to obtain the lines of text from. + /// A list of lines in the specified embedded resource. + public static async Task> GetAllLinesAsync(Assembly targetAssembly, string filename) + { + List result = new List(); + foreach (Task nextLine in EnumerateLinesAsync(targetAssembly, filename)) + result.Add(await nextLine); + return result; + } + } +}