mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-25 14:06:41 +01:00
Merge upstream
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
codecov:
|
||||
strict_yaml_branch: master
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 0
|
||||
if_no_uploads: failure
|
||||
if_ci_failed: failure
|
||||
patch: off
|
||||
changes:
|
||||
default:
|
||||
if_no_uploads: failure
|
||||
if_ci_failed: failure
|
||||
only_pulls: yes
|
||||
comment:
|
||||
layout: "header, diff, changes"
|
||||
@@ -13,3 +13,4 @@ packages/*
|
||||
*.user
|
||||
*.dmb
|
||||
*.int
|
||||
/TestResults
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
# Tgstation Toolkit:
|
||||
|
||||
[](https://ci.appveyor.com/project/Cyberboss/tgstation-server-tools) [](https://travis-ci.org/tgstation/tgstation-server) [](https://codecov.io/gh/tgstation/tgstation-server)
|
||||
|
||||
[](https://github.com/tgstation/tgstation-server/blob/master/LICENSE) [](http://isitmaintained.com/project/tgstation/tgstation-server "Average time to resolve an issue") [](https://badge.fury.io/nu/TGServiceInterface)
|
||||
|
||||
[](http://forthebadge.com) [](https://www.reddit.com/r/SS13/comments/5oplxp/what_is_the_main_problem_with_byond_as_an_engine/dclbu1a)
|
||||
|
||||
[](http://forthebadge.com) [](http://forthebadge.com)
|
||||
|
||||
|
||||
This is a toolset to manage a production server of /tg/Station13 (and its forks). It includes the ability to update the server without having to stop or shutdown the server (the update will take effect next round) the ability start the server and restart it if it crashes, as well as systems for fixing errors and merging GitHub Pull Requests locally.
|
||||
|
||||
Generally, updates force a live tracking of the configured git repo, resetting local modifications. If you plan to make modifications, set up a new git repo to store your version of the code in, and point this script to that in the config (explained below). This can be on github or a local repo using file:/// urls.
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace TGServerService
|
||||
/// <summary>
|
||||
/// Convert the settings version 6 .NET settings file to a config json
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="InstanceConfig"/> based off the old .NET setting file</returns>
|
||||
public static InstanceConfig CreateFromNETSettings()
|
||||
/// <returns>An <see cref="IInstanceConfig"/> based off the old .NET setting file</returns>
|
||||
public static IInstanceConfig CreateFromNETSettings()
|
||||
{
|
||||
var Config = Properties.Settings.Default;
|
||||
var result = new DeprecatedInstanceConfig(LoadPreviousNetPropertyOrDefault("ServerDirectory", "C:\\tgstation-server-3"));
|
||||
|
||||
@@ -4,122 +4,198 @@ using TGServiceInterface;
|
||||
|
||||
namespace TGServerService
|
||||
{
|
||||
class InstanceConfig
|
||||
/// <summary>
|
||||
/// Configuration settings for a <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
interface IInstanceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ServerInstance"/> directory this <see cref="IInstanceConfig"/> is for
|
||||
/// </summary>
|
||||
string Directory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Actual version of the <see cref="IInstanceConfig"/>. Migrated up via <see cref="DeprecatedInstanceConfig"/>
|
||||
/// </summary>
|
||||
ulong Version { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="ServerInstance"/> is active
|
||||
/// </summary>
|
||||
bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the .dme/.dmb the <see cref="ServerInstance"/> uses
|
||||
/// </summary>
|
||||
string ProjectName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The port the <see cref="ServerInstance"/> runs on
|
||||
/// </summary>
|
||||
ushort Port { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DreamDaemonSecurity"/> level for the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
DreamDaemonSecurity Security { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the <see cref="ServerInstance"/> should immediately start DreamDaemon when activated
|
||||
/// </summary>
|
||||
bool Autostart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not DreamDaemon allows connections from webclients
|
||||
/// </summary>
|
||||
bool Webclient { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Author and committer name for synchronize commits
|
||||
/// </summary>
|
||||
string CommitterName { get; set; }
|
||||
/// <summary>
|
||||
/// Author and committer e-mail for synchronize commits
|
||||
/// </summary>
|
||||
string CommitterEmail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encrypted serialized <see cref="ChatSetupInfo"/>s
|
||||
/// </summary>
|
||||
string ChatProviderData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Entropy for <see cref="ChatProviderData"/>
|
||||
/// </summary>
|
||||
string ChatProviderEntropy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="ServerInstance"/> should reattach to a running DreamDaemon <see cref="System.Diagnostics.Process"/>
|
||||
/// </summary>
|
||||
bool ReattachRequired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="System.Diagnostics.Process.Id"/> of the runnning DreamDaemon <see cref="System.Diagnostics.Process"/>
|
||||
/// </summary>
|
||||
int ReattachProcessID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The port the runnning DreamDaemon <see cref="System.Diagnostics.Process"/> was launched on
|
||||
/// </summary>
|
||||
ushort ReattachPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The serviceCommsKey the runnning DreamDaemon <see cref="System.Diagnostics.Process"/> was launched on
|
||||
/// </summary>
|
||||
string ReattachCommsKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The API version of the runnning DreamDaemon <see cref="System.Diagnostics.Process"/>
|
||||
/// </summary>
|
||||
string ReattachAPIVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user group allowed to use the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
string AuthorizedUserGroupSID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The auto update interval for the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
ulong AutoUpdateInterval { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not testmerge commits are published to a temporary remote branch
|
||||
/// </summary>
|
||||
bool PushTestmergeCommits { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Saves the <see cref="IInstanceConfig"/> to it's <see cref="ServerInstance"/> <see cref="Directory"/>
|
||||
/// </summary>
|
||||
void Save();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
class InstanceConfig : IInstanceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// The name the file is saved as in the <see cref="Directory"/>
|
||||
/// </summary>
|
||||
//tell javascriptserializer to ignore these fields
|
||||
[ScriptIgnore]
|
||||
public const string JSONFilename = "Instance.json";
|
||||
|
||||
/// <summary>
|
||||
/// The current version of the config
|
||||
/// </summary>
|
||||
[ScriptIgnore]
|
||||
protected const ulong CurrentVersion = 0; //Literally any time you add/deprecated a field, this number needs to be bumped
|
||||
/// <summary>
|
||||
/// The <see cref="ServerInstance"/> directory this <see cref="InstanceConfig"/> is for
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc />
|
||||
[ScriptIgnore]
|
||||
public string Directory { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Actual version of the <see cref="InstanceConfig"/>. Migrated up via <see cref="DeprecatedInstanceConfig"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public ulong Version { get; protected set; } = CurrentVersion;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string Name { get; set; } = "TG Station Server";
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="ServerInstance"/> is active
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the .dme/.dmb the <see cref="ServerInstance"/> uses
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string ProjectName { get; set; } = "tgstation";
|
||||
|
||||
/// <summary>
|
||||
/// The port the <see cref="ServerInstance"/> runs on
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public ushort Port { get; set; } = 1337;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DreamDaemonSecurity"/> level for the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public DreamDaemonSecurity Security { get; set; } = DreamDaemonSecurity.Trusted;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the <see cref="ServerInstance"/> should immediately start DreamDaemon when activated
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool Autostart { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not DreamDaemon allows connections from webclients
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool Webclient { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Author and committer name for synchronize commits
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string CommitterName { get; set; } = "tgstation-server";
|
||||
/// <summary>
|
||||
/// Author and committer e-mail for synchronize commits
|
||||
/// </summary>
|
||||
|
||||
/// <inheritdoc />
|
||||
public string CommitterEmail { get; set; } = "tgstation-server@tgstation13.org";
|
||||
|
||||
/// <summary>
|
||||
/// Encrypted serialized <see cref="ChatSetupInfo"/>s
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string ChatProviderData { get; set; } = ServerInstance.UninitializedString;
|
||||
|
||||
/// <summary>
|
||||
/// Entropy for <see cref="ChatProviderData"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string ChatProviderEntropy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="ServerInstance"/> should reattach to a running DreamDaemon <see cref="System.Diagnostics.Process"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool ReattachRequired { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="System.Diagnostics.Process.Id"/> of the runnning DreamDaemon <see cref="System.Diagnostics.Process"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public int ReattachProcessID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The port the runnning DreamDaemon <see cref="System.Diagnostics.Process"/> was launched on
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public ushort ReattachPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The serviceCommsKey the runnning DreamDaemon <see cref="System.Diagnostics.Process"/> was launched on
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string ReattachCommsKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The API version of the runnning DreamDaemon <see cref="System.Diagnostics.Process"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string ReattachAPIVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user group allowed to use the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public string AuthorizedUserGroupSID { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// The auto update interval for the <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public ulong AutoUpdateInterval { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not testmerge commits are published to a temporary remote branch
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public bool PushTestmergeCommits { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -131,9 +207,7 @@ namespace TGServerService
|
||||
Directory = path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the <see cref="InstanceConfig"/> to it's <see cref="ServerInstance"/> <see cref="Directory"/>
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public void Save()
|
||||
{
|
||||
var data = new JavaScriptSerializer().Serialize(this);
|
||||
@@ -142,11 +216,11 @@ namespace TGServerService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads and migrates an <see cref="InstanceConfig"/> from a <see cref="ServerInstance"/> at <paramref name="path"/>
|
||||
/// Loads and migrates an <see cref="IInstanceConfig"/> from a <see cref="ServerInstance"/> at <paramref name="path"/>
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the <see cref="ServerInstance"/> directory</param>
|
||||
/// <returns>The migrated <see cref="InstanceConfig"/></returns>
|
||||
public static InstanceConfig Load(string path)
|
||||
/// <returns>The migrated <see cref="IInstanceConfig"/></returns>
|
||||
public static IInstanceConfig Load(string path)
|
||||
{
|
||||
var configtext = File.ReadAllText(Path.Combine(path, JSONFilename));
|
||||
var res = new JavaScriptSerializer().Deserialize<DeprecatedInstanceConfig>(configtext);
|
||||
|
||||
@@ -343,7 +343,7 @@ namespace TGServerService
|
||||
var Now = DateTime.Now;
|
||||
lock (watchdogLock)
|
||||
{
|
||||
CurrentDDLog = String.Format("{0} {1} Diagnostics.txt", Now.ToLongDateString(), Now.ToLongTimeString()).Replace(':', '-');
|
||||
CurrentDDLog = DateTime.UtcNow.ToString("yyyy-MM-ddTHH-mm-ssZ");
|
||||
WriteCurrentDDLog("Starting monitoring...");
|
||||
}
|
||||
pcpu = new PerformanceCounter("Process", "% Processor Time", Proc.ProcessName, true);
|
||||
|
||||
@@ -24,11 +24,11 @@ namespace TGServerService
|
||||
/// <summary>
|
||||
/// The configuration settings for the instance
|
||||
/// </summary>
|
||||
readonly InstanceConfig Config;
|
||||
readonly IInstanceConfig Config;
|
||||
/// <summary>
|
||||
/// Constructs and a <see cref="ServerInstance"/>
|
||||
/// </summary>
|
||||
public ServerInstance(InstanceConfig config, byte logID)
|
||||
public ServerInstance(IInstanceConfig config, byte logID)
|
||||
{
|
||||
LoggingID = logID;
|
||||
Config = config;
|
||||
|
||||
+11
-11
@@ -118,10 +118,10 @@ namespace TGServerService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates configured <see cref="InstanceConfig"/>s. Detaches those that fail to load
|
||||
/// Enumerates configured <see cref="IInstanceConfig"/>s. Detaches those that fail to load
|
||||
/// </summary>
|
||||
/// <returns>Each configured <see cref="InstanceConfig"/></returns>
|
||||
IEnumerable<InstanceConfig> GetInstanceConfigs()
|
||||
/// <returns>Each configured <see cref="IInstanceConfig"/></returns>
|
||||
IEnumerable<IInstanceConfig> GetInstanceConfigs()
|
||||
{
|
||||
var pathsToRemove = new List<string>();
|
||||
lock (this)
|
||||
@@ -129,7 +129,7 @@ namespace TGServerService
|
||||
var IPS = Properties.Settings.Default.InstancePaths;
|
||||
foreach (var I in IPS)
|
||||
{
|
||||
InstanceConfig ic;
|
||||
IInstanceConfig ic;
|
||||
try
|
||||
{
|
||||
ic = InstanceConfig.Load(I);
|
||||
@@ -319,9 +319,9 @@ namespace TGServerService
|
||||
/// <summary>
|
||||
/// Creates and starts a <see cref="ServiceHost"/> for a <see cref="ServerInstance"/> at <paramref name="config"/>
|
||||
/// </summary>
|
||||
/// <param name="config">The <see cref="InstanceConfig"/> for the <see cref="ServerInstance"/></param>
|
||||
/// <param name="config">The <see cref="IInstanceConfig"/> for the <see cref="ServerInstance"/></param>
|
||||
/// <returns>The inactive <see cref="ServiceHost"/> on success, <see langword="null"/> on failure</returns>
|
||||
ServiceHost SetupInstance(InstanceConfig config)
|
||||
ServiceHost SetupInstance(IInstanceConfig config)
|
||||
{
|
||||
ServerInstance instance;
|
||||
string instanceName;
|
||||
@@ -484,7 +484,7 @@ namespace TGServerService
|
||||
foreach (var oic in GetInstanceConfigs())
|
||||
if (Name == oic.Name)
|
||||
return String.Format("Instance named {0} already exists!", oic.Name);
|
||||
InstanceConfig ic;
|
||||
IInstanceConfig ic;
|
||||
try
|
||||
{
|
||||
ic = new InstanceConfig(path)
|
||||
@@ -506,9 +506,9 @@ namespace TGServerService
|
||||
/// <summary>
|
||||
/// Starts and onlines an instance located at <paramref name="config"/>
|
||||
/// </summary>
|
||||
/// <param name="config">The <see cref="InstanceConfig"/> for the <see cref="ServerInstance"/></param>
|
||||
/// <param name="config">The <see cref="IInstanceConfig"/> for the <see cref="ServerInstance"/></param>
|
||||
/// <returns><see langword="null"/> on success, error message on failure</returns>
|
||||
string SetupOneInstance(InstanceConfig config)
|
||||
string SetupOneInstance(IInstanceConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -536,7 +536,7 @@ namespace TGServerService
|
||||
return String.Format("Instance at {0} already exists!", path);
|
||||
if(!Directory.Exists(path))
|
||||
return String.Format("There is no instance located at {0}!", path);
|
||||
InstanceConfig ic;
|
||||
IInstanceConfig ic;
|
||||
try
|
||||
{
|
||||
ic = InstanceConfig.Load(path);
|
||||
@@ -635,7 +635,7 @@ namespace TGServerService
|
||||
lock (this)
|
||||
{
|
||||
//we have to check em all anyway
|
||||
InstanceConfig the_droid_were_looking_for = null;
|
||||
IInstanceConfig the_droid_were_looking_for = null;
|
||||
foreach (var ic in GetInstanceConfigs())
|
||||
if (ic.Name == name)
|
||||
{
|
||||
|
||||
+328
-328
@@ -1,235 +1,235 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Web.Script.Serialization;
|
||||
|
||||
namespace TGServiceInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// For setting up authentication no matter the chat provider
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
[KnownType(typeof(IRCSetupInfo))]
|
||||
[KnownType(typeof(DiscordSetupInfo))]
|
||||
public class ChatSetupInfo
|
||||
{
|
||||
const int AdminListIndex = 0;
|
||||
const int AdminModeIndex = 1;
|
||||
const int AdminChannelIndex = 2;
|
||||
const int DevChannelIndex = 3;
|
||||
const int WDChannelIndex = 4;
|
||||
const int GameChannelIndex = 5;
|
||||
const int ProviderIndex = 6;
|
||||
const int EnabledIndex = 7;
|
||||
/// <summary>
|
||||
/// Starting index of <see cref="DataFields"/> which child classes should use to write their custom data to
|
||||
/// </summary>
|
||||
protected const int BaseIndex = 8;
|
||||
/// <summary>
|
||||
/// Set to <see langword="true"/> if a child constructor should use the baseInfo parameter of <see cref="ChatSetupInfo.ChatSetupInfo(ChatProvider, ChatSetupInfo, int)"/> to initialize it's property fields, <see langword="false"/> otherwise
|
||||
/// </summary>
|
||||
protected readonly bool InitializeFields;
|
||||
|
||||
/// <summary>
|
||||
/// Raw access to the underlying data
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Web.Script.Serialization;
|
||||
|
||||
namespace TGServiceInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// For setting up authentication no matter the chat provider
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
[KnownType(typeof(IRCSetupInfo))]
|
||||
[KnownType(typeof(DiscordSetupInfo))]
|
||||
public class ChatSetupInfo
|
||||
{
|
||||
const int AdminListIndex = 0;
|
||||
const int AdminModeIndex = 1;
|
||||
const int AdminChannelIndex = 2;
|
||||
const int DevChannelIndex = 3;
|
||||
const int WDChannelIndex = 4;
|
||||
const int GameChannelIndex = 5;
|
||||
const int ProviderIndex = 6;
|
||||
const int EnabledIndex = 7;
|
||||
/// <summary>
|
||||
/// Starting index of <see cref="DataFields"/> which child classes should use to write their custom data to
|
||||
/// </summary>
|
||||
protected const int BaseIndex = 8;
|
||||
/// <summary>
|
||||
/// Set to <see langword="true"/> if a child constructor should use the baseInfo parameter of <see cref="ChatSetupInfo.ChatSetupInfo(ChatProvider, ChatSetupInfo, int)"/> to initialize it's property fields, <see langword="false"/> otherwise
|
||||
/// </summary>
|
||||
protected readonly bool InitializeFields;
|
||||
|
||||
/// <summary>
|
||||
/// Raw access to the underlying data
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IList<string> DataFields { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="ChatSetupInfo"/> from optional <paramref name="baseInfo"/>
|
||||
/// </summary>
|
||||
/// <param name="provider">The <see cref="ChatProvider"/> that this <see cref="ChatSetupInfo"/> is for</param>
|
||||
/// <param name="baseInfo">Optional past data</param>
|
||||
/// <param name="numFields">The number of fields in this chat provider</param>
|
||||
protected internal ChatSetupInfo(ChatProvider provider, ChatSetupInfo baseInfo, int numFields)
|
||||
{
|
||||
numFields += BaseIndex;
|
||||
InitializeFields = baseInfo == null || baseInfo.DataFields.Count != numFields;
|
||||
|
||||
if (InitializeFields)
|
||||
{
|
||||
DataFields = new List<string>(numFields);
|
||||
for (var I = 0; I < numFields; ++I)
|
||||
DataFields.Add(null);
|
||||
|
||||
AdminList = new List<string>();
|
||||
AdminChannels = new List<string>();
|
||||
DevChannels = new List<string>();
|
||||
GameChannels = new List<string>();
|
||||
WatchdogChannels = new List<string>();
|
||||
AdminsAreSpecial = false;
|
||||
Enabled = false;
|
||||
}
|
||||
else
|
||||
DataFields = baseInfo.DataFields;
|
||||
Provider = provider;
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="ChatSetupInfo"/> from optional <paramref name="baseInfo"/>
|
||||
/// </summary>
|
||||
/// <param name="provider">The <see cref="ChatProvider"/> that this <see cref="ChatSetupInfo"/> is for</param>
|
||||
/// <param name="baseInfo">Optional past data</param>
|
||||
/// <param name="numFields">The number of fields in this chat provider</param>
|
||||
protected internal ChatSetupInfo(ChatProvider provider, ChatSetupInfo baseInfo, int numFields)
|
||||
{
|
||||
numFields += BaseIndex;
|
||||
InitializeFields = baseInfo == null || baseInfo.DataFields.Count != numFields;
|
||||
|
||||
if (InitializeFields)
|
||||
{
|
||||
DataFields = new List<string>(numFields);
|
||||
for (var I = 0; I < numFields; ++I)
|
||||
DataFields.Add(null);
|
||||
|
||||
AdminList = new List<string>();
|
||||
AdminChannels = new List<string>();
|
||||
DevChannels = new List<string>();
|
||||
GameChannels = new List<string>();
|
||||
WatchdogChannels = new List<string>();
|
||||
AdminsAreSpecial = false;
|
||||
Enabled = false;
|
||||
}
|
||||
else
|
||||
DataFields = baseInfo.DataFields;
|
||||
Provider = provider;
|
||||
Specialize(true); //to check we have a valid provider
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recreates <see langword="this"/> as the correct child <see cref="ChatSetupInfo"/>
|
||||
/// </summary>
|
||||
/// <param name="checkOnly">If <see langword="true"/>, <see langword="null"/> is returned provided <see cref="Provider"/> is a valid <see cref="ChatProvider"/></param>
|
||||
/// <returns>A new <see cref="ChatSetupInfo"/> based on the <see cref="Provider"/> type</returns>
|
||||
ChatSetupInfo Specialize(bool checkOnly)
|
||||
{
|
||||
switch (Provider)
|
||||
{
|
||||
case ChatProvider.IRC:
|
||||
if (!checkOnly)
|
||||
return new IRCSetupInfo(this);
|
||||
break;
|
||||
case ChatProvider.Discord:
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recreates <see langword="this"/> as the correct child <see cref="ChatSetupInfo"/>
|
||||
/// </summary>
|
||||
/// <param name="checkOnly">If <see langword="true"/>, <see langword="null"/> is returned provided <see cref="Provider"/> is a valid <see cref="ChatProvider"/></param>
|
||||
/// <returns>A new <see cref="ChatSetupInfo"/> based on the <see cref="Provider"/> type</returns>
|
||||
ChatSetupInfo Specialize(bool checkOnly)
|
||||
{
|
||||
switch (Provider)
|
||||
{
|
||||
case ChatProvider.IRC:
|
||||
if (!checkOnly)
|
||||
return new DiscordSetupInfo(this);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid provider!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Properly formats a <paramref name="channel"/> name for the <see cref="ChatProvider"/>
|
||||
/// </summary>
|
||||
/// <param name="channel">The <see cref="string"/> to format</param>
|
||||
/// <returns>The formatted <see cref="string"/></returns>
|
||||
protected virtual string SanitizeChannelName(string channel)
|
||||
{
|
||||
return Specialize(false).SanitizeChannelName(channel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanitizes a list of <paramref name="channelnames"/>
|
||||
/// </summary>
|
||||
/// <param name="channelnames">An <see cref="IList{T}"/> of strings</param>
|
||||
void SanitizeChannelNames(IList<string> channelnames)
|
||||
{
|
||||
for (var I = 0; I < channelnames.Count; ++I)
|
||||
|
||||
if (String.IsNullOrWhiteSpace(channelnames[I]))
|
||||
{
|
||||
channelnames.RemoveAt(I);
|
||||
--I;
|
||||
}
|
||||
else
|
||||
channelnames[I] = SanitizeChannelName(channelnames[I].Trim());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="ChatSetupInfo"/> from a data list
|
||||
/// </summary>
|
||||
/// <param name="DeserializedData">The data</param>
|
||||
public ChatSetupInfo(IList<string> DeserializedData)
|
||||
{
|
||||
DataFields = DeserializedData;
|
||||
Specialize(false); //ensure provider type is valid
|
||||
}
|
||||
/// <summary>
|
||||
/// The list of admin entries
|
||||
/// </summary>
|
||||
public IList<string> AdminList
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[AdminListIndex]); }
|
||||
set { DataFields[AdminListIndex] = new JavaScriptSerializer().Serialize(value); }
|
||||
}
|
||||
/// <summary>
|
||||
/// If AdminList corresponds to a Provider specific recognization method
|
||||
/// </summary>
|
||||
public bool AdminsAreSpecial
|
||||
{
|
||||
get { return Convert.ToBoolean(DataFields[AdminModeIndex]); }
|
||||
set { DataFields[AdminModeIndex] = Convert.ToString(value); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels from which admin commands/messages can be sent/received
|
||||
/// </summary>
|
||||
public IList<string> AdminChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[AdminChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[AdminChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which repo and compile messages are sent
|
||||
/// </summary>
|
||||
public IList<string> DevChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[DevChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[DevChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which watchdog messages are sent
|
||||
/// </summary>
|
||||
public IList<string> WatchdogChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[WDChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[WDChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which game messages are sent
|
||||
/// </summary>
|
||||
public IList<string> GameChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[GameChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[GameChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// If this chat provider is enabled
|
||||
/// </summary>
|
||||
public bool Enabled
|
||||
{
|
||||
get { return Convert.ToBoolean(DataFields[EnabledIndex]); }
|
||||
set { DataFields[EnabledIndex] = Convert.ToString(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of provider
|
||||
/// </summary>
|
||||
public ChatProvider Provider
|
||||
{
|
||||
get { return (ChatProvider)Convert.ToInt32(DataFields[ProviderIndex]); }
|
||||
set { DataFields[ProviderIndex] = Convert.ToString((int)value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat provider for IRC. Admin entries should be user nicknames in normal mode or required channel flags in special mode
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public sealed class IRCSetupInfo : ChatSetupInfo
|
||||
{
|
||||
const int URLIndex = 0;
|
||||
const int PortIndex = 1;
|
||||
const int NickIndex = 2;
|
||||
const int AuthTargetIndex = 3;
|
||||
const int AuthMessageIndex = 4;
|
||||
const int AuthLevelIndex = 5;
|
||||
return new IRCSetupInfo(this);
|
||||
break;
|
||||
case ChatProvider.Discord:
|
||||
if (!checkOnly)
|
||||
return new DiscordSetupInfo(this);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid provider!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Properly formats a <paramref name="channel"/> name for the <see cref="ChatProvider"/>
|
||||
/// </summary>
|
||||
/// <param name="channel">The <see cref="string"/> to format</param>
|
||||
/// <returns>The formatted <see cref="string"/></returns>
|
||||
protected virtual string SanitizeChannelName(string channel)
|
||||
{
|
||||
return Specialize(false).SanitizeChannelName(channel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sanitizes a list of <paramref name="channelnames"/>
|
||||
/// </summary>
|
||||
/// <param name="channelnames">An <see cref="IList{T}"/> of strings</param>
|
||||
void SanitizeChannelNames(IList<string> channelnames)
|
||||
{
|
||||
for (var I = 0; I < channelnames.Count; ++I)
|
||||
|
||||
if (String.IsNullOrWhiteSpace(channelnames[I]))
|
||||
{
|
||||
channelnames.RemoveAt(I);
|
||||
--I;
|
||||
}
|
||||
else
|
||||
channelnames[I] = SanitizeChannelName(channelnames[I].Trim());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="ChatSetupInfo"/> from a data list
|
||||
/// </summary>
|
||||
/// <param name="DeserializedData">The data</param>
|
||||
public ChatSetupInfo(IList<string> DeserializedData)
|
||||
{
|
||||
DataFields = DeserializedData;
|
||||
Specialize(false); //ensure provider type is valid
|
||||
}
|
||||
/// <summary>
|
||||
/// The list of admin entries
|
||||
/// </summary>
|
||||
public IList<string> AdminList
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[AdminListIndex]); }
|
||||
set { DataFields[AdminListIndex] = new JavaScriptSerializer().Serialize(value); }
|
||||
}
|
||||
/// <summary>
|
||||
/// If AdminList corresponds to a Provider specific recognization method
|
||||
/// </summary>
|
||||
public bool AdminsAreSpecial
|
||||
{
|
||||
get { return Convert.ToBoolean(DataFields[AdminModeIndex]); }
|
||||
set { DataFields[AdminModeIndex] = Convert.ToString(value); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels from which admin commands/messages can be sent/received
|
||||
/// </summary>
|
||||
public IList<string> AdminChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[AdminChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[AdminChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which repo and compile messages are sent
|
||||
/// </summary>
|
||||
public IList<string> DevChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[DevChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[DevChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which watchdog messages are sent
|
||||
/// </summary>
|
||||
public IList<string> WatchdogChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[WDChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[WDChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which game messages are sent
|
||||
/// </summary>
|
||||
public IList<string> GameChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[GameChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[GameChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// If this chat provider is enabled
|
||||
/// </summary>
|
||||
public bool Enabled
|
||||
{
|
||||
get { return Convert.ToBoolean(DataFields[EnabledIndex]); }
|
||||
set { DataFields[EnabledIndex] = Convert.ToString(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of provider
|
||||
/// </summary>
|
||||
public ChatProvider Provider
|
||||
{
|
||||
get { return (ChatProvider)Convert.ToInt32(DataFields[ProviderIndex]); }
|
||||
set { DataFields[ProviderIndex] = Convert.ToString((int)value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat provider for IRC. Admin entries should be user nicknames in normal mode or required channel flags in special mode
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public sealed class IRCSetupInfo : ChatSetupInfo
|
||||
{
|
||||
const int URLIndex = 0;
|
||||
const int PortIndex = 1;
|
||||
const int NickIndex = 2;
|
||||
const int AuthTargetIndex = 3;
|
||||
const int AuthMessageIndex = 4;
|
||||
const int AuthLevelIndex = 5;
|
||||
const int FieldsLen = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Construct IRC setup info from optional generic info. Defaults to TGS3 on rizons IRC server
|
||||
/// </summary>
|
||||
/// <param name="baseInfo">Optional generic info</param>
|
||||
public IRCSetupInfo(ChatSetupInfo baseInfo = null) : base(ChatProvider.IRC, baseInfo, FieldsLen)
|
||||
{
|
||||
if (!InitializeFields)
|
||||
/// <summary>
|
||||
/// Construct IRC setup info from optional generic info. Defaults to TGS3 on rizons IRC server
|
||||
/// </summary>
|
||||
/// <param name="baseInfo">Optional generic info</param>
|
||||
public IRCSetupInfo(ChatSetupInfo baseInfo = null) : base(ChatProvider.IRC, baseInfo, FieldsLen)
|
||||
{
|
||||
if (!InitializeFields)
|
||||
return;
|
||||
|
||||
Nickname = "TGS3";
|
||||
@@ -239,106 +239,106 @@ namespace TGServiceInterface
|
||||
AuthMessage = "";
|
||||
AdminsAreSpecial = true;
|
||||
AuthLevel = IRCMode.Op;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string SanitizeChannelName(string working)
|
||||
{
|
||||
if (working[0] != '#')
|
||||
return "#" + working;
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The port of the IRC server
|
||||
/// </summary>
|
||||
public ushort Port
|
||||
{
|
||||
get { return Convert.ToUInt16(DataFields[BaseIndex + PortIndex]); }
|
||||
set { DataFields[BaseIndex + PortIndex] = value.ToString(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The URL of the IRC server
|
||||
/// </summary>
|
||||
public string URL
|
||||
{
|
||||
get { return DataFields[BaseIndex + URLIndex]; }
|
||||
set { DataFields[BaseIndex + URLIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The nickname of the IRC bot
|
||||
/// </summary>
|
||||
public string Nickname
|
||||
{
|
||||
get { return DataFields[BaseIndex + NickIndex]; }
|
||||
set { DataFields[BaseIndex + NickIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The target for sending authentication messages
|
||||
/// </summary>
|
||||
public string AuthTarget
|
||||
{
|
||||
get { return DataFields[BaseIndex + AuthTargetIndex]; }
|
||||
set { DataFields[BaseIndex + AuthTargetIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The authentication message
|
||||
/// </summary>
|
||||
public string AuthMessage
|
||||
{
|
||||
get { return DataFields[BaseIndex + AuthMessageIndex]; }
|
||||
set { DataFields[BaseIndex + AuthMessageIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The minimum mode required to use admin bot commands when in special auth mode
|
||||
/// </summary>
|
||||
public IRCMode AuthLevel
|
||||
{
|
||||
get { return (IRCMode)Convert.ToInt32(DataFields[BaseIndex + AuthLevelIndex]); }
|
||||
set { DataFields[BaseIndex + AuthLevelIndex] = Convert.ToString((int)value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat provider for Discord. Admin entires should be user ids in normal mode or group ids in special mode
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public sealed class DiscordSetupInfo : ChatSetupInfo
|
||||
{
|
||||
const int BotTokenIndex = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string SanitizeChannelName(string working)
|
||||
{
|
||||
if (working[0] != '#')
|
||||
return "#" + working;
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The port of the IRC server
|
||||
/// </summary>
|
||||
public ushort Port
|
||||
{
|
||||
get { return Convert.ToUInt16(DataFields[BaseIndex + PortIndex]); }
|
||||
set { DataFields[BaseIndex + PortIndex] = value.ToString(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The URL of the IRC server
|
||||
/// </summary>
|
||||
public string URL
|
||||
{
|
||||
get { return DataFields[BaseIndex + URLIndex]; }
|
||||
set { DataFields[BaseIndex + URLIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The nickname of the IRC bot
|
||||
/// </summary>
|
||||
public string Nickname
|
||||
{
|
||||
get { return DataFields[BaseIndex + NickIndex]; }
|
||||
set { DataFields[BaseIndex + NickIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The target for sending authentication messages
|
||||
/// </summary>
|
||||
public string AuthTarget
|
||||
{
|
||||
get { return DataFields[BaseIndex + AuthTargetIndex]; }
|
||||
set { DataFields[BaseIndex + AuthTargetIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The authentication message
|
||||
/// </summary>
|
||||
public string AuthMessage
|
||||
{
|
||||
get { return DataFields[BaseIndex + AuthMessageIndex]; }
|
||||
set { DataFields[BaseIndex + AuthMessageIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The minimum mode required to use admin bot commands when in special auth mode
|
||||
/// </summary>
|
||||
public IRCMode AuthLevel
|
||||
{
|
||||
get { return (IRCMode)Convert.ToInt32(DataFields[BaseIndex + AuthLevelIndex]); }
|
||||
set { DataFields[BaseIndex + AuthLevelIndex] = Convert.ToString((int)value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat provider for Discord. Admin entires should be user ids in normal mode or group ids in special mode
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public sealed class DiscordSetupInfo : ChatSetupInfo
|
||||
{
|
||||
const int BotTokenIndex = 0;
|
||||
const int FieldsLen = 1;
|
||||
/// <summary>
|
||||
/// Construct Discord setup info from optional generic info. Default is not a valid discord bot tokent
|
||||
/// </summary>
|
||||
/// <param name="baseInfo">Optional generic info</param>
|
||||
public DiscordSetupInfo(ChatSetupInfo baseInfo = null) : base(ChatProvider.Discord, baseInfo, FieldsLen)
|
||||
{
|
||||
if (!InitializeFields)
|
||||
return;
|
||||
BotToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; //needless to say, this is fake
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override string SanitizeChannelName(string working)
|
||||
{
|
||||
working = working.Replace("<", "").Replace(">", "").Replace("&", ""); //filter out some stuff that can come in the copypasta
|
||||
try
|
||||
{
|
||||
Convert.ToUInt64(working);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Invalid Discord channel ID!");
|
||||
}
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Discord bot token to use. See https://discordapp.com/developers/applications/me for registering bot accounts
|
||||
/// </summary>
|
||||
public string BotToken
|
||||
{
|
||||
get { return DataFields[BaseIndex + BotTokenIndex]; }
|
||||
set { DataFields[BaseIndex + BotTokenIndex] = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Construct Discord setup info from optional generic info. Default is not a valid discord bot tokent
|
||||
/// </summary>
|
||||
/// <param name="baseInfo">Optional generic info</param>
|
||||
public DiscordSetupInfo(ChatSetupInfo baseInfo = null) : base(ChatProvider.Discord, baseInfo, FieldsLen)
|
||||
{
|
||||
if (!InitializeFields)
|
||||
return;
|
||||
BotToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; //needless to say, this is fake
|
||||
}
|
||||
/// <inheritdoc />
|
||||
protected override string SanitizeChannelName(string working)
|
||||
{
|
||||
working = working.Replace("<", "").Replace(">", "").Replace("&", ""); //filter out some stuff that can come in the copypasta
|
||||
try
|
||||
{
|
||||
Convert.ToUInt64(working);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Invalid Discord channel ID!");
|
||||
}
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Discord bot token to use. See https://discordapp.com/developers/applications/me for registering bot accounts
|
||||
/// </summary>
|
||||
public string BotToken
|
||||
{
|
||||
get { return DataFields[BaseIndex + BotTokenIndex]; }
|
||||
set { DataFields[BaseIndex + BotTokenIndex] = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace TGServerService.Tests
|
||||
/// Creates a default <see cref="InstanceConfig"/> at <see cref="TempPath"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
InstanceConfig CreateTempConfig()
|
||||
IInstanceConfig CreateTempConfig()
|
||||
{
|
||||
return new InstanceConfig(TempPath);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace TGServiceTests
|
||||
/// <summary>
|
||||
/// To be the parent of test classes that required a temporary directory
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public abstract class TempDirectoryRequiredTest
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2006
|
||||
VisualStudioVersion = 15.0.26730.16
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TGServerService", "TGServerService\TGServerService.csproj", "{F32EDA25-0855-411C-AF5E-F0D042917E2D}"
|
||||
EndProject
|
||||
@@ -15,6 +15,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "TGServiceInstaller", "TGSer
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2D8FC6AA-1D33-44B6-81C2-35ED7A87EDBC}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.codecov.yml = .codecov.yml
|
||||
.gitignore = .gitignore
|
||||
.travis.yml = .travis.yml
|
||||
appveyor.yml = appveyor.yml
|
||||
@@ -74,11 +75,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{081BB0BB
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Tools\build_byond.sh = Tools\build_byond.sh
|
||||
Tools\Config.dm = Tools\Config.dm
|
||||
Tools\CoverageExclusions.runsettings = Tools\CoverageExclusions.runsettings
|
||||
Tools\DMAPITravisTester.dme = Tools\DMAPITravisTester.dme
|
||||
Tools\Doxyfile = Tools\Doxyfile
|
||||
Tools\install_byond.sh = Tools\install_byond.sh
|
||||
Tools\Test.dm = Tools\Test.dm
|
||||
Tools\TGS3Build.ps1 = Tools\TGS3Build.ps1
|
||||
Tools\UploadCoverage.ps1 = Tools\UploadCoverage.ps1
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{287B900C-1AFB-49B8-8BDD-C9058971C20C}"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- File name extension must be .runsettings -->
|
||||
<RunSettings>
|
||||
<DataCollectionRunSettings>
|
||||
<DataCollectors>
|
||||
<DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<Configuration>
|
||||
<CodeCoverage>
|
||||
|
||||
<!-- Match the path of the source files in which each method is defined: -->
|
||||
<Sources>
|
||||
<Exclude>
|
||||
<Source>.*\\TGServiceTests\\.*</Source>
|
||||
</Exclude>
|
||||
</Sources>
|
||||
|
||||
<!-- We recommend you do not change the following values: -->
|
||||
<UseVerifiableInstrumentation>True</UseVerifiableInstrumentation>
|
||||
<AllowLowIntegrityProcesses>True</AllowLowIntegrityProcesses>
|
||||
<CollectFromChildProcesses>True</CollectFromChildProcesses>
|
||||
<CollectAspDotNet>False</CollectAspDotNet>
|
||||
|
||||
</CodeCoverage>
|
||||
</Configuration>
|
||||
</DataCollector>
|
||||
</DataCollectors>
|
||||
</DataCollectionRunSettings>
|
||||
</RunSettings>
|
||||
+1
-1
@@ -2206,7 +2206,7 @@ HIDE_UNDOC_RELATIONS = NO
|
||||
# set to NO
|
||||
# The default value is: NO.
|
||||
|
||||
HAVE_DOT = YES
|
||||
# Generated in appveyor
|
||||
|
||||
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
|
||||
# to run in parallel. When set to 0 doxygen will base this on the number of
|
||||
|
||||
+3
-1
@@ -13,9 +13,11 @@ if($publish_dox){
|
||||
echo "Cloning https://git@$github_url..."
|
||||
git clone -b gh-pages --single-branch "https://git@$github_url" "$doxdir" 2>$null
|
||||
rm -r "$doxdir\*"
|
||||
Add-Content "$bf\Tools\Doxyfile" "`nPROJECT_NUMBER = $version`nINPUT = $bf`nOUTPUT_DIRECTORY = $doxdir`nPROJECT_LOGO = $bf/tgs.ico`nHAVE_DOT=YES"
|
||||
}else{
|
||||
Add-Content "$bf\Tools\Doxyfile" "`nPROJECT_NUMBER = $version`nINPUT = $bf`nOUTPUT_DIRECTORY = $doxdir`nPROJECT_LOGO = $bf/tgs.ico"
|
||||
}
|
||||
|
||||
Add-Content "$bf\Tools\Doxyfile" "`nPROJECT_NUMBER = $version`nINPUT = $bf`nOUTPUT_DIRECTORY = $doxdir`nPROJECT_LOGO = $bf/tgs.ico"
|
||||
doxygen.exe "$bf\Tools\Doxyfile"
|
||||
|
||||
if($publish_dox){
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
$coverageFilePath = Resolve-Path -path "TestResults\*\*.coverage"
|
||||
|
||||
$coverageFilePath = $coverageFilePath.ToString()
|
||||
|
||||
Write-Host "Running CodeCoverage.exe..."
|
||||
&"C:\Program Files (x86)\Microsoft Visual Studio\2017\TestAgent\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" analyze /output:coverage.coveragexml "$coverageFilePath"
|
||||
|
||||
rm -r TestResults
|
||||
|
||||
codecov -f coverage.coveragexml
|
||||
+6
-1
@@ -21,7 +21,7 @@ cache:
|
||||
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||
install:
|
||||
- choco install fciv doxygen.portable graphviz.portable
|
||||
- choco install fciv doxygen.portable graphviz.portable opencover.portable codecov
|
||||
before_build:
|
||||
- nuget restore TGStationServer3.sln
|
||||
build:
|
||||
@@ -33,6 +33,11 @@ after_build:
|
||||
- ps: .\Tools\TGS3Build.ps1
|
||||
- ps: if($env:APPVEYOR_REPO_COMMIT_MESSAGE -match "\[TGSDeploy\]"){$env:TGSDeploy = "Do it."}
|
||||
- ps: $env:TGSVersion = [System.Diagnostics.FileVersionInfo]::GetVersionInfo("$env:APPVEYOR_BUILD_FOLDER/TGServerService/bin/Release/TGServerService.exe").FileVersion
|
||||
test_script:
|
||||
- set path=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\TestAgent\Common7\IDE\CommonExtensions\Microsoft\TestWindow;%path%
|
||||
- copy "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\Extensions\appveyor.*" "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\TestAgent\Common7\IDE\CommonExtensions\Microsoft\TestWindow\Extensions" /y
|
||||
- vstest.console /logger:Appveyor "TGServiceTests\bin\Release\TGServiceTests.dll" /Enablecodecoverage /Settings:"Tools/CoverageExclusions.runsettings" /inIsolation /Platform:x64
|
||||
- powershell -Command "Tools/UploadCoverage.ps1"
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
release: "tgstation-server-v$(TGSVersion)"
|
||||
|
||||
Reference in New Issue
Block a user