Decompiled source of ServerRestart v1.1.5

ServerRestart.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DiscordTools;
using HarmonyLib;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Server Restart")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Server Restart")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d50b60f0-8c9a-42f8-84a4-7d602fe5283b")]
[assembly: AssemblyFileVersion("1.1.5")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.5.0")]
[module: UnverifiableCode]
internal class Helper
{
	public static bool IsDebugBuild => false;

	public static void WatchConfigFileChanges(ConfigFile config, Action onChanged = null)
	{
		WatchFileChanges(config.ConfigFilePath, (Action)config.Reload);
		config.SettingChanged += delegate
		{
			onChanged?.Invoke();
		};
	}

	public static void WatchFileChanges(string path, Action onChanged)
	{
		FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
		string directoryName = Path.GetDirectoryName(path);
		string fileName = Path.GetFileName(path);
		fileSystemWatcher.Path = directoryName;
		fileSystemWatcher.Filter = fileName;
		fileSystemWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastWrite;
		fileSystemWatcher.Changed += delegate
		{
			onChanged?.Invoke();
		};
		fileSystemWatcher.Deleted += delegate
		{
			onChanged?.Invoke();
		};
		fileSystemWatcher.Created += delegate
		{
			onChanged?.Invoke();
		};
		fileSystemWatcher.Renamed += delegate
		{
			onChanged?.Invoke();
		};
		fileSystemWatcher.EnableRaisingEvents = true;
	}

	public static void WatchFolderChanges(string path, Action onChanged)
	{
		WatchFileChanges(Path.Combine(path, "*.*"), onChanged);
	}
}
internal class Log
{
	private static Log _instance;

	private ManualLogSource _source;

	public static Log CreateInstance(ManualLogSource source)
	{
		_instance = new Log
		{
			_source = source
		};
		return _instance;
	}

	private Log()
	{
	}

	public static void Info(object msg)
	{
		_instance._source.LogInfo((object)FormatMessage(msg));
	}

	public static void Message(object msg)
	{
		_instance._source.LogMessage((object)FormatMessage(msg));
	}

	public static void Debug(object msg)
	{
		_instance._source.LogDebug((object)FormatMessage(msg));
	}

	public static void Warning(object msg)
	{
		_instance._source.LogWarning((object)FormatMessage(msg));
	}

	public static void Error(object msg)
	{
		_instance._source.LogError((object)FormatMessage(msg));
	}

	public static void Fatal(object msg)
	{
		_instance._source.LogFatal((object)FormatMessage(msg));
	}

	private static string FormatMessage(object msg)
	{
		return $"[{DateTime.UtcNow}] {msg}";
	}
}
internal static class ThreadingUtil
{
	private class DisposableThread : IDisposable
	{
		private Thread _thread;

		internal DisposableThread(Thread thread)
		{
			_thread = thread;
		}

		public void Dispose()
		{
			_thread.Abort();
		}
	}

	private class MainThreadDispatcher : MonoBehaviour
	{
		private static MainThreadDispatcher _instance;

		private ConcurrentQueue<Action> _queue = new ConcurrentQueue<Action>();

		private ConcurrentQueue<IEnumerator> _coroutinesQueue = new ConcurrentQueue<IEnumerator>();

		public static MainThreadDispatcher GetInstante()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			if ((Object)(object)_instance == (Object)null)
			{
				GameObject val = new GameObject("MainThreadDispatcher", new Type[1] { typeof(MainThreadDispatcher) });
				Object.DontDestroyOnLoad((Object)val);
				_instance = val.GetComponent<MainThreadDispatcher>();
			}
			return _instance;
		}

		public void AddAction(Action action)
		{
			_queue.Enqueue(action);
		}

		public void AddCoroutine(IEnumerator coroutine)
		{
			_coroutinesQueue.Enqueue(coroutine);
		}

		private void Update()
		{
			Action result;
			while (_queue.Count > 0 && _queue.TryDequeue(out result))
			{
				result?.Invoke();
			}
			IEnumerator result2;
			while (_coroutinesQueue.Count > 0 && _coroutinesQueue.TryDequeue(out result2))
			{
				((MonoBehaviour)this).StartCoroutine(result2);
			}
		}
	}

	internal static IDisposable RunPeriodical(Action action, int periodMilliseconds)
	{
		return new Timer(delegate
		{
			action?.Invoke();
		}, null, 0, periodMilliseconds);
	}

	internal static IDisposable RunPeriodicalInSingleThread(Action action, int periodMilliseconds)
	{
		Thread thread = new Thread((ParameterizedThreadStart)delegate
		{
			while (true)
			{
				action?.Invoke();
				Thread.Sleep(periodMilliseconds);
			}
		});
		thread.Start();
		return new DisposableThread(thread);
	}

	internal static void RunInMainThread(Action action)
	{
		MainThreadDispatcher.GetInstante().AddAction(action);
	}

	internal static void RunCoroutine(IEnumerator coroutine)
	{
		MainThreadDispatcher.GetInstante().AddCoroutine(coroutine);
	}

	internal static void RunDelayed(float delay, Action action)
	{
		MainThreadDispatcher.GetInstante().AddCoroutine(DelayedActionCoroutine(delay, action));
	}

	internal static IDisposable RunThread(Action action)
	{
		Thread thread = new Thread(action.Invoke);
		thread.Start();
		return new DisposableThread(thread);
	}

	internal static IEnumerator DelayedActionCoroutine(float delay, Action action)
	{
		yield return (object)new WaitForSeconds(delay);
		action?.Invoke();
	}
}
namespace ServerRestart
{
	internal class MaintenanceService : MonoBehaviour
	{
		private string _maintenanceFilePath;

		private void Awake()
		{
			PluginInfo val = ((IEnumerable<PluginInfo>)Chainloader.PluginInfos.Values).FirstOrDefault((Func<PluginInfo, bool>)((PluginInfo p) => p.Metadata.GUID == "org.bepinex.plugins.servercharacters"));
			if (val != null)
			{
				string directoryName = Path.GetDirectoryName(val.Location);
				Log.Debug("ServerCharacters mod found at " + directoryName);
				_maintenanceFilePath = Path.Combine(directoryName, "maintenance");
			}
		}

		private void OnEnable()
		{
			RestartService.OnScheduledRestartChanged += OnRestartDateChanged;
		}

		private void OnDisable()
		{
			RestartService.OnScheduledRestartChanged -= OnRestartDateChanged;
		}

		private void OnRestartDateChanged(DateTime date)
		{
			if (!Plugin.EnableMaintenance.Value)
			{
				return;
			}
			if (string.IsNullOrEmpty(_maintenanceFilePath))
			{
				Log.Error("Cannot enable maintenance. ServerCharacters mod not found!");
				return;
			}
			((MonoBehaviour)this).StopAllCoroutines();
			RemoveMaintenance();
			if (!(date == default(DateTime)))
			{
				((MonoBehaviour)this).StartCoroutine(ScheduleMaintenance(date.Subtract(TimeSpan.FromMinutes(Plugin.MaintenanceMinutes.Value))));
			}
		}

		private void RemoveMaintenance()
		{
			if (File.Exists(_maintenanceFilePath))
			{
				File.Delete(_maintenanceFilePath);
				Log.Info("Maintenance disabled");
			}
		}

		private IEnumerator ScheduleMaintenance(DateTime date)
		{
			yield return (object)new WaitUntil((Func<bool>)(() => DateTime.UtcNow >= date));
			using (File.Create(_maintenanceFilePath))
			{
			}
			Log.Info("Maintenance started");
		}
	}
	[BepInProcess("valheim_server.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("org.tristan.serverrestart", "Server Restart", "1.1.5")]
	internal class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch]
		private class Patch
		{
			[HarmonyPostfix]
			[HarmonyPatch(typeof(Game), "Start")]
			private static void Game_Start(Game __instance)
			{
				_service = ((Component)__instance).gameObject.AddComponent<RestartService>();
				((Component)__instance).gameObject.AddComponent<MaintenanceService>();
				((Component)__instance).gameObject.AddComponent<RestartMessages>();
				((Component)__instance).gameObject.AddComponent<RestartScheduleLogService>();
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(ZNet), "CheckForIncommingServerConnections")]
			private static bool ZNet_CheckForIncommingServerConnections()
			{
				if (_service.RestartStarted || ((Object)(object)Game.instance != (Object)null && Game.instance.IsShuttingDown()))
				{
					return false;
				}
				return true;
			}

			[HarmonyPriority(0)]
			[HarmonyFinalizer]
			[HarmonyPatch(typeof(Game), "OnApplicationQuit")]
			private static void Game_OnApplicationQuit()
			{
				Thread.Sleep(5000);
				Process.GetCurrentProcess().Kill();
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(ZNet), "UpdatePlayerList")]
			private static void ZNet_UpdatePlayerList(ZNet __instance)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				PlayerInfo val = default(PlayerInfo);
				if (!ZNet.TryGetPlayerByPlatformUserID(RestartMessages.ServerUserId, ref val) && __instance.m_players.Count != 0)
				{
					val = default(PlayerInfo);
					val.m_name = ChatName.Value;
					val.m_userInfo = new CrossNetworkUserInfo
					{
						m_displayName = ChatName.Value,
						m_id = RestartMessages.ServerUserId
					};
					val.m_serverAssignedDisplayName = ChatName.Value;
					PlayerInfo item = val;
					__instance.m_players.Add(item);
				}
			}
		}

		public const string Guid = "org.tristan.serverrestart";

		public const string Name = "Server Restart";

		public const string Version = "1.1.5";

		public static ConfigEntry<string> RestartTimes;

		public static ConfigEntry<string> Message1Hour;

		public static ConfigEntry<string> Message30Mins;

		public static ConfigEntry<string> Message10Mins;

		public static ConfigEntry<string> Message5Min;

		public static ConfigEntry<string> Message4Min;

		public static ConfigEntry<string> Message3Min;

		public static ConfigEntry<string> Message2Min;

		public static ConfigEntry<string> Message1Min;

		public static ConfigEntry<string> AnounceFormat;

		public static ConfigEntry<string> ChatName;

		public static ConfigEntry<bool> SendMessagesToChat;

		public static ConfigEntry<string> ChatFormat;

		public static ConfigEntry<string> DiscordUrl;

		public static ConfigEntry<string> DiscordName;

		public static ConfigEntry<string> DiscordFormat;

		public static ConfigEntry<bool> ShutDownServer;

		public static ConfigEntry<bool> EnableMaintenance;

		public static ConfigEntry<int> MaintenanceMinutes;

		public static ConfigEntry<bool> PrintLogs;

		public static ConfigEntry<int> PrintLogsPeriod;

		private static RestartService _service;

		private void Awake()
		{
			Log.CreateInstance(((BaseUnityPlugin)this).Logger);
			RestartTimes = ((BaseUnityPlugin)this).Config.Bind<string>("1. Restart", "Schedule (utc)", "23:00:00,11:00:00", "Restart times divied by ,");
			ShutDownServer = ((BaseUnityPlugin)this).Config.Bind<bool>("1. Restart", "Shut down", true, "Should plugin shut down server process. Disable if you use hosting restart schedule or another plugin");
			Message1Hour = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "1 hour", "Server restart in 1 hour", (ConfigDescription)null);
			Message30Mins = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "30 minutes", "Server restart in 30 minutes", (ConfigDescription)null);
			Message10Mins = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "10 minutes", "Server restart in 10 minutes", (ConfigDescription)null);
			Message5Min = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "5 minutes", "Server restart in 5 minutes", (ConfigDescription)null);
			Message4Min = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "4 minutes", "Server restart in 4 minutes", (ConfigDescription)null);
			Message3Min = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "3 minutes", "Server restart in 3 minutes", (ConfigDescription)null);
			Message2Min = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "2 minutes", "Server restart in 2 minutes", (ConfigDescription)null);
			Message1Min = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "1 minute", "Server restart in 1 minute", (ConfigDescription)null);
			AnounceFormat = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "Anounce format", "{0}", "Format of center screen message");
			ChatName = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "Chat name", "Restart", (ConfigDescription)null);
			SendMessagesToChat = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Messages", "Send to chat", true, (ConfigDescription)null);
			ChatFormat = ((BaseUnityPlugin)this).Config.Bind<string>("2. Messages", "Chat format", "{0}", "Format of chat message");
			EnableMaintenance = ((BaseUnityPlugin)this).Config.Bind<bool>("3. ServerCharacters", "Maintenance mode", false, "Should enable maintenance mode for ServerCharacters");
			MaintenanceMinutes = ((BaseUnityPlugin)this).Config.Bind<int>("3. ServerCharacters", "Maintenance time", 7, "Enable maintenance before scheduled server restart time");
			DiscordUrl = ((BaseUnityPlugin)this).Config.Bind<string>("4. Discord", "Webhook", "", (ConfigDescription)null);
			DiscordName = ((BaseUnityPlugin)this).Config.Bind<string>("4. Discord", "Display name", "Restart", (ConfigDescription)null);
			DiscordFormat = ((BaseUnityPlugin)this).Config.Bind<string>("4. Discord", "Discord format", "{0}", "Format of discord message");
			PrintLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("5. Logs", "Print logs", false, (ConfigDescription)null);
			PrintLogsPeriod = ((BaseUnityPlugin)this).Config.Bind<int>("5. Logs", "Period", 600, "Period for displaying date of next restart and remaining time");
			Helper.WatchConfigFileChanges(((BaseUnityPlugin)this).Config, OnConfigChanged);
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "org.tristan.serverrestart");
		}

		private void OnConfigChanged()
		{
			Log.Message("Config reloaded");
			((BaseUnityPlugin)this).Config.Reload();
			_service?.ScheduleNextRestart();
		}
	}
	public class RestartMessages : MonoBehaviour
	{
		public static readonly PlatformUserID ServerUserId = new PlatformUserID("Bot", 0uL, false);

		private static UserInfo User = new UserInfo
		{
			UserId = ServerUserId,
			Name = string.Empty
		};

		public static event Action<string> OnMessageSent;

		private void OnEnable()
		{
			RestartService.OnScheduledRestartChanged += ScheduleRestartMessages;
		}

		private void OnDisable()
		{
			RestartService.OnScheduledRestartChanged -= ScheduleRestartMessages;
		}

		private void ScheduleRestartMessages(DateTime date)
		{
			((MonoBehaviour)this).StopAllCoroutines();
			if (!(date == default(DateTime)))
			{
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromHours(1.0)), Plugin.Message1Hour.Value));
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromMinutes(30.0)), Plugin.Message30Mins.Value));
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromMinutes(10.0)), Plugin.Message10Mins.Value));
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromMinutes(5.0)), Plugin.Message5Min.Value));
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromMinutes(4.0)), Plugin.Message4Min.Value));
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromMinutes(3.0)), Plugin.Message3Min.Value));
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromMinutes(2.0)), Plugin.Message2Min.Value));
				((MonoBehaviour)this).StartCoroutine(ScheduleMessage(date.Subtract(TimeSpan.FromMinutes(1.0)), Plugin.Message1Min.Value));
			}
		}

		private IEnumerator ScheduleMessage(DateTime date, string message)
		{
			if (!(DateTime.UtcNow > date) && !string.IsNullOrEmpty(message))
			{
				Log.Debug($"Schedule message '{message}' at {date}");
				yield return (object)new WaitUntil((Func<bool>)(() => DateTime.UtcNow >= date));
				Log.Debug("Sending message '" + message + "'");
				SendMessageToAll(message);
				SendMessageToDiscord(message);
				SendMessageToChat(message);
				RestartMessages.OnMessageSent?.Invoke(message);
			}
		}

		private void SendMessageToAll(string message)
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ShowMessage", new object[2]
			{
				2,
				string.Format(Plugin.AnounceFormat.Value, message)
			});
		}

		private void SendMessageToDiscord(string message)
		{
			string webhookUrl = Plugin.DiscordUrl.Value;
			if (!string.IsNullOrEmpty(Plugin.DiscordUrl.Value))
			{
				string displayName = Plugin.DiscordName.Value;
				ThreadingUtil.RunThread(delegate
				{
					DiscordTool.SendMessageToDiscord(webhookUrl, displayName, string.Format(Plugin.DiscordFormat.Value, message));
				});
			}
		}

		private void SendMessageToChat(string message)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.SendMessagesToChat.Value)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ChatMessage", new object[4]
				{
					(object)new Vector3(0f, 200f, 0f),
					2,
					User,
					string.Format(Plugin.ChatFormat.Value, message)
				});
			}
		}
	}
	internal class RestartScheduleLogService : MonoBehaviour
	{
		private DateTime _nextRestartDate;

		private void OnEnable()
		{
			RestartService.OnScheduledRestartChanged += ScheduleLogMessages;
		}

		private void OnDisable()
		{
			RestartService.OnScheduledRestartChanged -= ScheduleLogMessages;
		}

		private void ScheduleLogMessages(DateTime time)
		{
			_nextRestartDate = time;
			PrintLogMessage();
			((MonoBehaviour)this).CancelInvoke();
			if (Plugin.PrintLogs.Value)
			{
				int value = Plugin.PrintLogsPeriod.Value;
				((MonoBehaviour)this).InvokeRepeating("PrintLogMessage", (float)value, (float)value);
			}
		}

		private void PrintLogMessage()
		{
			DateTime utcNow = DateTime.UtcNow;
			TimeSpan timeSpan = _nextRestartDate - utcNow;
			if (_nextRestartDate != default(DateTime))
			{
				Log.Message($"Next restart {_nextRestartDate}. Time left: {timeSpan}");
			}
			else
			{
				Log.Message("No scheduled restarts");
			}
		}
	}
	public class RestartService : MonoBehaviour
	{
		public DateTime NextRestartDate { get; private set; }

		public bool RestartStarted { get; private set; }

		public static event Action<DateTime> OnScheduledRestartChanged;

		private void Start()
		{
			ScheduleNextRestart();
		}

		public void ScheduleNextRestart()
		{
			((MonoBehaviour)this).StopAllCoroutines();
			RestartStarted = false;
			string[] array = Plugin.RestartTimes.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0)
			{
				NextRestartDate = default(DateTime);
				RestartService.OnScheduledRestartChanged?.Invoke(NextRestartDate);
				return;
			}
			NextRestartDate = GetNextRestartDate(array);
			if (Plugin.ShutDownServer.Value)
			{
				((MonoBehaviour)this).StartCoroutine(ScheduleRestart(NextRestartDate));
			}
			RestartService.OnScheduledRestartChanged?.Invoke(NextRestartDate);
		}

		private IEnumerator ScheduleRestart(DateTime date)
		{
			yield return (object)new WaitUntil((Func<bool>)(() => DateTime.UtcNow >= date));
			Log.Message("Starting restart. Disconnecting players");
			ZNet.instance.SendDisconnect();
			RestartStarted = true;
			yield return (object)new WaitWhile((Func<bool>)(() => ZNet.instance.GetPeers().Count > 0));
			yield return (object)new WaitForSeconds(5f);
			Log.Message("Shutting down server");
			Game.instance.Shutdown(true);
			yield return (object)new WaitForSeconds(10f);
			Log.Message("Stopping server");
			Application.Quit();
		}

		private DateTime GetNextRestartDate(IEnumerable<string> schedule)
		{
			DateTime nowDate = DateTime.UtcNow;
			return (from date in schedule.Select(delegate(string timeText)
				{
					TimeSpan value = TimeSpan.Parse(timeText);
					DateTime dateTime = new DateTime(nowDate.Year, nowDate.Month, nowDate.Day).Add(value);
					if (dateTime < nowDate)
					{
						dateTime = dateTime.AddDays(1.0);
					}
					return dateTime;
				})
				orderby date - nowDate
				select date).FirstOrDefault();
		}
	}
}
namespace DiscordTools
{
	internal static class DiscordTool
	{
		public static void SendMessageToDiscord(string url, string name, string message)
		{
			HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
			httpWebRequest.ContentType = "application/json";
			httpWebRequest.Method = "POST";
			using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
			{
				string value = "{\"username\":\"" + name + "\",\"content\":\"" + message + "\"}";
				streamWriter.Write(value);
			}
			httpWebRequest.GetResponse();
		}
	}
}