From 8233be32a3a049f682e3df8ad5f3227804553122 Mon Sep 17 00:00:00 2001 From: slothdpal <16717792+SlothDpal@users.noreply.github.com> Date: Thu, 23 May 2024 20:55:23 +0300 Subject: [PATCH] some fix --- Discord/DiscordWebHook.cs | 103 ++++++++++++++++ Discord/Structs.cs | 229 +++++++++++++++++++++++++++++++++++ Discord/Utils.cs | 108 +++++++++++++++++ Process Auto Relaunch.csproj | 11 +- Process Auto Relaunch.sln | 17 --- packages.config | 4 + 6 files changed, 453 insertions(+), 19 deletions(-) create mode 100644 Discord/DiscordWebHook.cs create mode 100644 Discord/Structs.cs create mode 100644 Discord/Utils.cs create mode 100644 packages.config diff --git a/Discord/DiscordWebHook.cs b/Discord/DiscordWebHook.cs new file mode 100644 index 0000000..25c8640 --- /dev/null +++ b/Discord/DiscordWebHook.cs @@ -0,0 +1,103 @@ +using System; +using System.IO; +using System.Net; +using System.Text; + +namespace Discord.Webhook +{ + public class DiscordWebhook + { + /// + /// Webhook url + /// + public string Url { get; set; } + + private void AddField(MemoryStream stream, string bound, string cDisposition, string cType, byte[] data) + { + string prefix = stream.Length > 0 ? "\r\n--" : "--"; + string fBegin = $"{prefix}{bound}\r\n"; + + byte[] fBeginBuffer = Utils.Encode(fBegin); + byte[] cDispositionBuffer = Utils.Encode(cDisposition); + byte[] cTypeBuffer = Utils.Encode(cType); + + stream.Write(fBeginBuffer, 0, fBeginBuffer.Length); + stream.Write(cDispositionBuffer, 0, cDispositionBuffer.Length); + stream.Write(cTypeBuffer, 0, cTypeBuffer.Length); + stream.Write(data, 0, data.Length); + } + + private void SetJsonPayload(MemoryStream stream, string bound, string json) + { + string cDisposition = "Content-Disposition: form-data; name=\"payload_json\"\r\n"; + string cType = "Content-Type: application/octet-stream\r\n\r\n"; + AddField(stream, bound, cDisposition, cType, Utils.Encode(json)); + } + + private void SetFile(MemoryStream stream, string bound, int index, FileInfo file) + { + string cDisposition = $"Content-Disposition: form-data; name=\"file_{index}\"; filename=\"{file.Name}\"\r\n"; + string cType = "Content-Type: application/octet-stream\r\n\r\n"; + AddField(stream, bound, cDisposition, cType, File.ReadAllBytes(file.FullName)); + } + + /// + /// Send webhook message + /// + public void Send(DiscordMessage message, params FileInfo[] files) + { + if (string.IsNullOrEmpty(Url)) + throw new ArgumentNullException("Invalid Webhook URL."); + + string bound = "------------------------" + DateTime.Now.Ticks.ToString("x"); + WebClient webhookRequest = new WebClient(); + webhookRequest.Headers.Add("Content-Type", "multipart/form-data; boundary=" + bound); + + MemoryStream stream = new MemoryStream(); + for (int i = 0; i < files.Length; i++) + SetFile(stream, bound, i, files[i]); + + string json = message.ToString(); + SetJsonPayload(stream, bound, json); + + byte[] bodyEnd = Utils.Encode($"\r\n--{bound}--"); + stream.Write(bodyEnd, 0, bodyEnd.Length); + + //byte[] beginBodyBuffer = Encoding.UTF8.GetBytes("--" + bound + "\r\n"); + //stream.Write(beginBodyBuffer, 0, beginBodyBuffer.Length); + //bool flag = file != null && file.Exists; + //if (flag) + //{ + // string fileBody = "Content-Disposition: form-data; name=\"file\"; filename=\"" + file.Name + "\"\r\nContent-Type: application/octet-stream\r\n\r\n"; + // byte[] fileBodyBuffer = Encoding.UTF8.GetBytes(fileBody); + // stream.Write(fileBodyBuffer, 0, fileBodyBuffer.Length); + // byte[] fileBuffer = File.ReadAllBytes(file.FullName); + // stream.Write(fileBuffer, 0, fileBuffer.Length); + // string fileBodyEnd = "\r\n--" + bound + "\r\n"; + // byte[] fileBodyEndBuffer = Encoding.UTF8.GetBytes(fileBodyEnd); + // stream.Write(fileBodyEndBuffer, 0, fileBodyEndBuffer.Length); + //} + //string jsonBody = string.Concat(new string[] + //{ + // "Content-Disposition: form-data; name=\"payload_json\"\r\nContent-Type: application/json\r\n\r\n", + // string.Format("{0}\r\n", message), + // "--", + // bound, + // "--" + //}); + //byte[] jsonBodyBuffer = Encoding.UTF8.GetBytes(jsonBody); + //stream.Write(jsonBodyBuffer, 0, jsonBodyBuffer.Length); + + try + { + webhookRequest.UploadData(this.Url, stream.ToArray()); + } + catch (WebException ex) + { + throw new WebException(Utils.Decode(ex.Response.GetResponseStream())); + } + + stream.Dispose(); + } + } +} diff --git a/Discord/Structs.cs b/Discord/Structs.cs new file mode 100644 index 0000000..a528c88 --- /dev/null +++ b/Discord/Structs.cs @@ -0,0 +1,229 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace Discord +{ + + /// + /// Discord message data object + /// + public struct DiscordMessage + { + /// + /// Message content + /// + public string Content; + + /// + /// Read message to everyone on the channel + /// + public bool TTS; + + /// + /// Webhook profile username to be shown + /// + public string Username; + + /// + /// Webhook profile avater to be shown + /// + public string AvatarUrl; + + /// + /// List of embeds + /// + public List Embeds; + + public override string ToString() => Utils.StructToJson(this).ToString(Formatting.None); + } + + /// + /// Discord embed data object + /// + public struct DiscordEmbed + { + /// + /// Embed title + /// + public string Title; + + /// + /// Embed description + /// + public string Description; + + /// + /// Embed url + /// + public string Url; + + /// + /// Embed timestamp + /// + public DateTime? Timestamp; + + /// + /// Embed color + /// + public Color? Color; + + /// + /// Embed footer + /// + public EmbedFooter? Footer; + + /// + /// Embed image + /// + public EmbedMedia? Image; + + /// + /// Embed thumbnail + /// + public EmbedMedia? Thumbnail; + + /// + /// Embed video + /// + public EmbedMedia? Video; + + /// + /// Embed provider + /// + public EmbedProvider? Provider; + + /// + /// Embed author + /// + public EmbedAuthor? Author; + + /// + /// Embed fields list + /// + public List Fields; + + public override string ToString() => Utils.StructToJson(this).ToString(Formatting.None); + } + + /// + /// Discord embed footer data object + /// + public struct EmbedFooter + { + /// + /// Footer text + /// + public string Text; + + /// + /// Footer icon + /// + public string IconUrl; + + /// + /// Footer icon proxy + /// + public string ProxyIconUrl; + + public override string ToString() => Utils.StructToJson(this).ToString(Formatting.None); + } + + /// + /// Discord embed media data object (images/thumbs/videos) + /// + public struct EmbedMedia + { + /// + /// Media url + /// + public string Url; + + /// + /// Media proxy url + /// + public string ProxyUrl; + + /// + /// Media height + /// + public int? Height; + + /// + /// Media width + /// + public int? Width; + + public override string ToString() => Utils.StructToJson(this).ToString(Formatting.None); + } + + /// + /// Discord embed provider data object + /// + public struct EmbedProvider + { + /// + /// Provider name + /// + public string Name; + + /// + /// Provider url + /// + public string Url; + + public override string ToString() => Utils.StructToJson(this).ToString(Formatting.None); + } + + /// + /// Discord embed author data object + /// + public struct EmbedAuthor + { + /// + /// Author name + /// + public string Name; + + /// + /// Author url + /// + public string Url; + + /// + /// Author icon + /// + public string IconUrl; + + /// + /// Author icon proxy + /// + public string ProxyIconUrl; + + public override string ToString() => Utils.StructToJson(this).ToString(Formatting.None); + } + + /// + /// Discord embed field data object + /// + public struct EmbedField + { + /// + /// Field name + /// + public string Name; + + /// + /// Field value + /// + public string Value; + + /// + /// Field align + /// + public bool InLine; + + public override string ToString() => Utils.StructToJson(this).ToString(Formatting.None); + } +} diff --git a/Discord/Utils.cs b/Discord/Utils.cs new file mode 100644 index 0000000..ce9476e --- /dev/null +++ b/Discord/Utils.cs @@ -0,0 +1,108 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Discord +{ + public static class Utils + { + /// + /// Convert Color object into hex integer + /// + /// Color to be converted + /// Converted hex integer + public static int ColorToHex(Color color) + { + string HS = + color.R.ToString("X2") + + color.G.ToString("X2") + + color.B.ToString("X2"); + + return int.Parse(HS, System.Globalization.NumberStyles.HexNumber); + } + + internal static JObject StructToJson(object @struct) + { + Type type = @struct.GetType(); + JObject json = new JObject(); + + FieldInfo[] fields = type.GetFields(); + foreach (FieldInfo field in fields) + { + string name = FieldNameToJsonName(field.Name); + object value = field.GetValue(@struct); + if (value == null) + continue; + + if (value is bool) + json.Add(name, (bool)value); + else if (value is int) + json.Add(name, (int)value); + else if (value is Color) + json.Add(name, ColorToHex((Color)value)); + else if (value is string) + json.Add(name, value as string); + else if (value is DateTime) + json.Add(name, ((DateTime)value).ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz")); + else if (value is IList && value.GetType().IsGenericType) + { + JArray array = new JArray(); + foreach (object obj in value as IList) + array.Add(StructToJson(obj)); + json.Add(name, array); + } + else json.Add(name, StructToJson(value)); + } + return json; + } + + static string[] ignore = { "InLine" }; + internal static string FieldNameToJsonName(string name) + { + if (ignore.ToList().Contains(name)) + return name.ToLower(); + + List result = new List(); + + if (IsFullUpper(name)) + result.AddRange(name.ToLower().ToCharArray()); + else + for (int i = 0; i < name.Length; i++) + { + if (i > 0 && char.IsUpper(name[i])) + result.AddRange(new[] { '_', char.ToLower(name[i]) }); + else result.Add(char.ToLower(name[i])); + } + return string.Join("", result); + } + + internal static bool IsFullUpper(string str) + { + bool upper = true; + for (int i = 0; i < str.Length; i++) + { + if (!char.IsUpper(str[i])) + { + upper = false; + break; + } + } + return upper; + } + + public static string Decode(Stream source) + { + using (StreamReader reader = new StreamReader(source)) + return reader.ReadToEnd(); + } + + public static byte[] Encode(string source, string encoding = "utf-8") + => Encoding.GetEncoding(encoding).GetBytes(source); + } +} diff --git a/Process Auto Relaunch.csproj b/Process Auto Relaunch.csproj index e265fbb..3a337ee 100644 --- a/Process Auto Relaunch.csproj +++ b/Process Auto Relaunch.csproj @@ -67,6 +67,9 @@ False .\CSharpDiscordWebhook.dll + + packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + @@ -80,6 +83,9 @@ + + + Form @@ -112,6 +118,7 @@ Resources.resx True + SettingsSingleFileGenerator Settings.Designer.cs @@ -142,7 +149,7 @@ - copy $(ProjectDir)\CSharpDiscordWebhook\CSharpDiscordWebhook\$(OutDir)\* $(TargetDir) -copy $(ProjectDir)\CSharpDiscordWebhook\CSharpDiscordWebhook\$(OutDir)\* $(ProjectDir) + rem copy $(ProjectDir)\CSharpDiscordWebhook\CSharpDiscordWebhook\$(OutDir)\* $(TargetDir) +rem copy $(ProjectDir)\CSharpDiscordWebhook\CSharpDiscordWebhook\$(OutDir)\* $(ProjectDir) \ No newline at end of file diff --git a/Process Auto Relaunch.sln b/Process Auto Relaunch.sln index 7188f0d..14cd0e9 100644 --- a/Process Auto Relaunch.sln +++ b/Process Auto Relaunch.sln @@ -4,11 +4,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.9.34622.214 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Process Auto Relaunch", "Process Auto Relaunch.csproj", "{B48F106C-F4E2-4BFB-9BAA-42FC13C03FDD}" - ProjectSection(ProjectDependencies) = postProject - {11C71B78-004A-471F-B29D-C2CBE4673579} = {11C71B78-004A-471F-B29D-C2CBE4673579} - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSharpDiscordWebhook", "CSharpDiscordWebhook\CSharpDiscordWebhook\CSharpDiscordWebhook.csproj", "{11C71B78-004A-471F-B29D-C2CBE4673579}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -32,18 +27,6 @@ Global {B48F106C-F4E2-4BFB-9BAA-42FC13C03FDD}.Release|Any CPU.Build.0 = Release|Any CPU {B48F106C-F4E2-4BFB-9BAA-42FC13C03FDD}.Release|x64.ActiveCfg = Release|x64 {B48F106C-F4E2-4BFB-9BAA-42FC13C03FDD}.Release|x64.Build.0 = Release|x64 - {11C71B78-004A-471F-B29D-C2CBE4673579}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.Debug|Any CPU.Build.0 = Debug|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.Debug|x64.ActiveCfg = Debug|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.Debug|x64.Build.0 = Debug|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.DebugFULL|Any CPU.ActiveCfg = Debug|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.DebugFULL|Any CPU.Build.0 = Debug|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.DebugFULL|x64.ActiveCfg = DebugFULL|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.DebugFULL|x64.Build.0 = DebugFULL|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.Release|Any CPU.ActiveCfg = Release|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.Release|Any CPU.Build.0 = Release|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.Release|x64.ActiveCfg = Release|Any CPU - {11C71B78-004A-471F-B29D-C2CBE4673579}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..0b14af3 --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file