<commit_before>﻿using Discord;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TGServiceInterface;

namespace TGServerService
{
	class TGDiscordChatProvider : ITGChatProvider
	{
		public event OnChatMessage OnChatMessage;
		DiscordClient client;
		TGDiscordSetupInfo DiscordConfig;
		object DiscordLock = new object();

		IDictionary<ulong, Channel> SeenPrivateChannels = new Dictionary<ulong, Channel>();

		public TGDiscordChatProvider(TGChatSetupInfo info)
		{
			Init(info);
		}

		public TGChatSetupInfo ProviderInfo()
		{
			return DiscordConfig;
		}

		void Init(TGChatSetupInfo info)
		{
			DiscordConfig = new TGDiscordSetupInfo(info);
			client = new DiscordClient();
			client.MessageReceived += Client_MessageReceived;
		}

		private bool CheckAdmin(User u)
		{
			if (!DiscordConfig.AdminsAreSpecial)
				return DiscordConfig.AdminList.Contains(u.Id.ToString());
			foreach (var I in u.Roles)
				if (DiscordConfig.AdminList.Contains(I.Id.ToString()))
					return true;
			return false;
		}

		private void Client_MessageReceived(object sender, MessageEventArgs e)
		{
			var pm = e.Channel.IsPrivate && e.User.Id != client.CurrentUser.Id;
	
			if (pm && !SeenPrivateChannels.ContainsKey(e.Channel.Id))
				SeenPrivateChannels.Add(e.Channel.Id, e.Channel);

			bool found = false;

			var formattedMessage = e.Message.RawText;
			foreach (var u in e.Message.MentionedUsers)
				if(u.Id == client.CurrentUser.Id)
				{
					found = true;
					formattedMessage = formattedMessage.Replace(u.Mention, "");
					break;
				}

			if (!found && !pm)
				return;

			formattedMessage = formattedMessage.Trim();
			
			var cid = e.Channel.Id.ToString();

			OnChatMessage(this, e.User.Id.ToString(), cid, formattedMessage, CheckAdmin(e.User), pm || DiscordConfig.AdminChannels.Contains(cid));
		}

		public string Connect()
		{
			try
			{
				if (Connected() || !DiscordConfig.Enabled)
					return null;
				lock (DiscordLock)
				{
					SeenPrivateChannels.Clear();
					client.Connect(DiscordConfig.BotToken, TokenType.Bot).Wait();
				}
				return !Connected() ? "Connection failed!" : null;
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}

		public bool Connected()
		{
			lock (DiscordLock)
			{
				return client.State == ConnectionState.Connected;
			}
		}

		public void Disconnect()
		{
			try
			{
				if (!Connected())
					return;
				lock (DiscordLock)
				{
					SeenPrivateChannels.Clear();
					client.Disconnect().Wait();
				}
			}
			catch { }
		}

		public string Reconnect()
		{
			try
			{
				lock (DiscordLock)
				{
					SeenPrivateChannels.Clear();
					if (client.State == ConnectionState.Connected)
						client.Disconnect().Wait();
					client.Connect(DiscordConfig.BotToken, TokenType.Bot).Wait();
				}
				return !Connected() ? "Connection failed!" : null;
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}

		public void SendMessage(string msg, ChatMessageType mt)
		{
			if (!Connected())
				return;
			lock (DiscordLock)
			{
				var tasks = new List<Task>();
				var Config = Properties.Settings.Default;
				foreach (var I in client.Servers)
					foreach (var J in I.TextChannels)
					{
						var cid = J.Id.ToString();
						var wdc = DiscordConfig.WatchdogChannels;
						bool SendToThisChannel = (mt.HasFlag(ChatMessageType.AdminInfo) && DiscordConfig.AdminChannels.Contains(cid))
							|| (mt.HasFlag(ChatMessageType.DeveloperInfo) && DiscordConfig.DevChannels.Contains(cid))
							|| (mt.HasFlag(ChatMessageType.GameInfo) && DiscordConfig.GameChannels.Contains(cid))
							|| (mt.HasFlag(ChatMessageType.WatchdogInfo) && DiscordConfig.WatchdogChannels.Contains(cid));

						if (SendToThisChannel)
							tasks.Add(J.SendMessage(msg));
					}
				foreach (var I in tasks)
					I.Wait();
			}
		}

		public string SendMessageDirect(string message, string channelname)
		{
			if (!Connected())
				return "Disconnected.";
			try
			{
				lock (DiscordLock)
				{
					var tasks = new List<Task>();
					var Config = Properties.Settings.Default;
					var channel = Convert.ToUInt64(channelname);
					if (SeenPrivateChannels.ContainsKey(channel))
						SeenPrivateChannels[channel].SendMessage(message).Wait();
					else
						foreach (var I in client.Servers)
							foreach (var J in I.TextChannels)
								if (J.Id == channel)
									J.SendMessage(message).Wait();
					TGServerService.WriteInfo(String.Format("Discord Send ({0}): {1}", channelname, message), TGServerService.EventID.ChatSend);
					return null;
				}
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}
		void DisconnectAndDispose()
		{
			try
			{
				client.Disconnect().Wait();
			}
			catch (Exception e) {
				TGServerService.WriteError("Discord failed DnD: " + e.ToString(), TGServerService.EventID.ChatDisconnectFail);
			}
			client.Dispose();
		}

		public string SetProviderInfo(TGChatSetupInfo info)
		{
			try
			{
				lock (DiscordLock)
				{
					var odc = DiscordConfig;
					DiscordConfig = new TGDiscordSetupInfo(info);
					if (DiscordConfig.BotToken != odc.BotToken)
					{
						DisconnectAndDispose();
						Init(info);
					}
					if (DiscordConfig.Enabled)
					{
						if (!Connected())
							return Reconnect();
					}
					else
						Disconnect();
				}
				return null;
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}

		#region IDisposable Support
		private bool disposedValue = false; // To detect redundant calls

		protected virtual void Dispose(bool disposing)
		{
			if (!disposedValue)
			{
				if (disposing)
				{
					DisconnectAndDispose();
					// TODO: dispose managed state (managed objects).
				}

				// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
				// TODO: set large fields to null.

				disposedValue = true;
			}
		}

		// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
		// ~TGDiscordChatProvider() {
		//   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
		//   Dispose(false);
		// }

		// This code added to correctly implement the disposable pattern.
		public void Dispose()
		{
			// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
			Dispose(true);
			// TODO: uncomment the following line if the finalizer is overridden above.
			// GC.SuppressFinalize(this);
		}
		#endregion
	}
}
<commit_msg>keeps the discord bot from being triggered by its own messages<commit_after>﻿using Discord;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TGServiceInterface;

namespace TGServerService
{
	class TGDiscordChatProvider : ITGChatProvider
	{
		public event OnChatMessage OnChatMessage;
		DiscordClient client;
		TGDiscordSetupInfo DiscordConfig;
		object DiscordLock = new object();

		IDictionary<ulong, Channel> SeenPrivateChannels = new Dictionary<ulong, Channel>();

		public TGDiscordChatProvider(TGChatSetupInfo info)
		{
			Init(info);
		}

		public TGChatSetupInfo ProviderInfo()
		{
			return DiscordConfig;
		}

		void Init(TGChatSetupInfo info)
		{
			DiscordConfig = new TGDiscordSetupInfo(info);
			client = new DiscordClient();
			client.MessageReceived += Client_MessageReceived;
		}

		private bool CheckAdmin(User u)
		{
			if (!DiscordConfig.AdminsAreSpecial)
				return DiscordConfig.AdminList.Contains(u.Id.ToString());
			foreach (var I in u.Roles)
				if (DiscordConfig.AdminList.Contains(I.Id.ToString()))
					return true;
			return false;
		}

		private void Client_MessageReceived(object sender, MessageEventArgs e)
		{
			if (e.User.Id == client.CurrentUser.Id)
				return
			var pm = e.Channel.IsPrivate;
	
			if (pm && !SeenPrivateChannels.ContainsKey(e.Channel.Id))
				SeenPrivateChannels.Add(e.Channel.Id, e.Channel);

			bool found = false;

			var formattedMessage = e.Message.RawText;
			foreach (var u in e.Message.MentionedUsers)
				if(u.Id == client.CurrentUser.Id)
				{
					found = true;
					formattedMessage = formattedMessage.Replace(u.Mention, "");
					break;
				}

			if (!found && !pm)
				return;

			formattedMessage = formattedMessage.Trim();
			
			var cid = e.Channel.Id.ToString();

			OnChatMessage(this, e.User.Id.ToString(), cid, formattedMessage, CheckAdmin(e.User), pm || DiscordConfig.AdminChannels.Contains(cid));
		}

		public string Connect()
		{
			try
			{
				if (Connected() || !DiscordConfig.Enabled)
					return null;
				lock (DiscordLock)
				{
					SeenPrivateChannels.Clear();
					client.Connect(DiscordConfig.BotToken, TokenType.Bot).Wait();
				}
				return !Connected() ? "Connection failed!" : null;
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}

		public bool Connected()
		{
			lock (DiscordLock)
			{
				return client.State == ConnectionState.Connected;
			}
		}

		public void Disconnect()
		{
			try
			{
				if (!Connected())
					return;
				lock (DiscordLock)
				{
					SeenPrivateChannels.Clear();
					client.Disconnect().Wait();
				}
			}
			catch { }
		}

		public string Reconnect()
		{
			try
			{
				lock (DiscordLock)
				{
					SeenPrivateChannels.Clear();
					if (client.State == ConnectionState.Connected)
						client.Disconnect().Wait();
					client.Connect(DiscordConfig.BotToken, TokenType.Bot).Wait();
				}
				return !Connected() ? "Connection failed!" : null;
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}

		public void SendMessage(string msg, ChatMessageType mt)
		{
			if (!Connected())
				return;
			lock (DiscordLock)
			{
				var tasks = new List<Task>();
				var Config = Properties.Settings.Default;
				foreach (var I in client.Servers)
					foreach (var J in I.TextChannels)
					{
						var cid = J.Id.ToString();
						var wdc = DiscordConfig.WatchdogChannels;
						bool SendToThisChannel = (mt.HasFlag(ChatMessageType.AdminInfo) && DiscordConfig.AdminChannels.Contains(cid))
							|| (mt.HasFlag(ChatMessageType.DeveloperInfo) && DiscordConfig.DevChannels.Contains(cid))
							|| (mt.HasFlag(ChatMessageType.GameInfo) && DiscordConfig.GameChannels.Contains(cid))
							|| (mt.HasFlag(ChatMessageType.WatchdogInfo) && DiscordConfig.WatchdogChannels.Contains(cid));

						if (SendToThisChannel)
							tasks.Add(J.SendMessage(msg));
					}
				foreach (var I in tasks)
					I.Wait();
			}
		}

		public string SendMessageDirect(string message, string channelname)
		{
			if (!Connected())
				return "Disconnected.";
			try
			{
				lock (DiscordLock)
				{
					var tasks = new List<Task>();
					var Config = Properties.Settings.Default;
					var channel = Convert.ToUInt64(channelname);
					if (SeenPrivateChannels.ContainsKey(channel))
						SeenPrivateChannels[channel].SendMessage(message).Wait();
					else
						foreach (var I in client.Servers)
							foreach (var J in I.TextChannels)
								if (J.Id == channel)
									J.SendMessage(message).Wait();
					TGServerService.WriteInfo(String.Format("Discord Send ({0}): {1}", channelname, message), TGServerService.EventID.ChatSend);
					return null;
				}
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}
		void DisconnectAndDispose()
		{
			try
			{
				client.Disconnect().Wait();
			}
			catch (Exception e) {
				TGServerService.WriteError("Discord failed DnD: " + e.ToString(), TGServerService.EventID.ChatDisconnectFail);
			}
			client.Dispose();
		}

		public string SetProviderInfo(TGChatSetupInfo info)
		{
			try
			{
				lock (DiscordLock)
				{
					var odc = DiscordConfig;
					DiscordConfig = new TGDiscordSetupInfo(info);
					if (DiscordConfig.BotToken != odc.BotToken)
					{
						DisconnectAndDispose();
						Init(info);
					}
					if (DiscordConfig.Enabled)
					{
						if (!Connected())
							return Reconnect();
					}
					else
						Disconnect();
				}
				return null;
			}
			catch (Exception e)
			{
				return e.ToString();
			}
		}

		#region IDisposable Support
		private bool disposedValue = false; // To detect redundant calls

		protected virtual void Dispose(bool disposing)
		{
			if (!disposedValue)
			{
				if (disposing)
				{
					DisconnectAndDispose();
					// TODO: dispose managed state (managed objects).
				}

				// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
				// TODO: set large fields to null.

				disposedValue = true;
			}
		}

		// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
		// ~TGDiscordChatProvider() {
		//   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
		//   Dispose(false);
		// }

		// This code added to correctly implement the disposable pattern.
		public void Dispose()
		{
			// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
			Dispose(true);
			// TODO: uncomment the following line if the finalizer is overridden above.
			// GC.SuppressFinalize(this);
		}
		#endregion
	}
}

{'fraction_non_alphanumeric': 0.11468208092485549, 'fraction_numerical': 0.0006165703275529866, 'mean_word_length': 3.006174745291757, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6169664', 'n_tokens_mistral': 5309, 'n_tokens_neox': 4068, 'n_words': 928}