Merge pull request #3418 from VistaPOWA/pr_announce

[CONFIG][BACKEND] Adds PR announcing to the game.
This commit is contained in:
Razharas
2014-04-18 19:05:44 -07:00
20 changed files with 520 additions and 3 deletions
+2 -1
View File
@@ -11,8 +11,9 @@
#define CHAT_PRAYER 256
#define CHAT_RADIO 512
#define MEMBER_PUBLIC 1024
#define CHAT_PULLR 2048
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|MEMBER_PUBLIC)
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|MEMBER_PUBLIC|CHAT_PULLR)
#define BE_TRAITOR 1
#define BE_OPERATIVE 2
+7
View File
@@ -102,6 +102,9 @@
var/rename_cyborg = 0
var/ooc_during_round = 0
var/comms_key = "default_pwd" //Server API key
var/comms_allowed = 0 //By default, the server does not allow messages to be sent to it, unless the key is strong enough (this is to prevent misconfigured servers from becoming victims)
//Used for modifying movement speed for mobs.
//Unversal modifiers
var/run_speed = 0
@@ -266,6 +269,10 @@
Tickcomp = 1
if("automute_on")
automute_on = 1
if("comms_key")
comms_key = value
if(value != "default_pwd" && length(value) > 6) //It's the default value or less than 6 characters long, warn badmins
comms_allowed = 1
else
diary << "Unknown setting in configuration: '[name]'"
+2
View File
@@ -130,6 +130,8 @@ var/next_external_rsc = 0
if(holder)
add_admin_verbs()
admin_memo_show()
if((config.comms_key == "default_pwd" || length(config.comms_key) <= 6) && config.comms_allowed) //It's the default value or less than 6 characters long, but it somehow didn't disable comms.
src << "<span class='danger'>The server's API key is either too short or is the default value! Consider changing it immediately!</span>"
log_client_to_db()
+3 -1
View File
@@ -208,6 +208,7 @@ datum/preferences
dat += "<b>Play lobby music:</b> <a href='?_src_=prefs;preference=lobby_music'>[(toggles & SOUND_LOBBY) ? "Yes" : "No"]</a><br>"
dat += "<b>Ghost ears:</b> <a href='?_src_=prefs;preference=ghost_ears'>[(toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]</a><br>"
dat += "<b>Ghost sight:</b> <a href='?_src_=prefs;preference=ghost_sight'>[(toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]</a><br>"
dat += "<b>Pull requests:</b> <a href='?_src_=prefs;preference=pull_requests'>[(toggles & CHAT_PULLR) ? "Yes" : "No"]</a><br>"
if(config.allow_Metadata)
dat += "<b>OOC Notes:</b> <a href='?_src_=prefs;preference=metadata;task=input'> Edit </a><br>"
@@ -684,7 +685,8 @@ datum/preferences
if("ghost_sight")
toggles ^= CHAT_GHOSTSIGHT
if("pull_requests")
toggles ^= CHAT_PULLR
if("save")
save_preferences()
save_character()
@@ -55,6 +55,15 @@
src << "You will [(prefs.toggles & CHAT_PRAYER) ? "now" : "no longer"] see prayerchat."
feedback_add_details("admin_verb","TP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/togglePRs()
set name = "Show/Hide Pull Request Announcements"
set category = "Preferences"
set desc = "Toggles receiving a notification when new pull requests are created."
prefs.toggles ^= CHAT_PULLR
prefs.save_preferences()
src << "You will [(prefs.toggles & CHAT_PULLR) ? "now" : "no longer"] see new pull request announcements."
feedback_add_details("admin_verb","TPullR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/verb/toggletitlemusic()
set name = "Hear/Silence LobbyMusic"
set category = "Preferences"
+11 -1
View File
@@ -160,7 +160,17 @@
s["map_name"] = map_name ? map_name : "Unknown"
return list2params(s)
else if (copytext(T,1,9) == "announce")
var/input[] = params2list(T)
if(config.comms_allowed)
if(input["key"] != config.comms_key)
return "Bad Key"
else
#define CHAT_PULLR 2048
for(var/client/C in clients)
if(C.prefs && (C.prefs.toggles & CHAT_PULLR))
C << "<span class='announce'>PR: [input["announce"]]</span>"
#undef CHAT_PULLR
/world/Reboot(var/reason)
#ifdef dellogging
+3
View File
@@ -144,3 +144,6 @@ TICKCOMP 0
## Comment this out to disable automuting
#AUTOMUTE_ON
## Communication key for receiving data through world/Topic(), you don't want to give this out
#COMMS_KEY default_pwd
+1
View File
@@ -50,6 +50,7 @@ h1.alert, h2.alert {color: #000000;}
.userdanger {color: #ff0000; font-weight: bold;}
.danger {color: #ff0000;}
.warning {color: #ff0000; font-style: italic;}
.announce {color: #228b22; font-weight: bold;}
.rose {color: #ff5050;}
.info {color: #0000CC;}
.notice {color: #000099;}
Binary file not shown.
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
serverip = 127.0.0.1 //SS13 server IP
serverport = 7812
commskey = this_is_a_test_key
GitHub_bot_name = testbot_github //It'll get the data from this bot
IRC_bot_name = testbot_BYOND //This'll be our name
IRC_server = irc.rizon.net:6670 //format - server:port
IRC_channel = #ircchannel
+1
View File
@@ -0,0 +1 @@
0131022900006397110110111117110991016191451161034511511697116105111110933286105115116978079876532111112101110101100321121171081083211410111311710111511632651001001153211511110910132981111141033210210197116117114101115329710811511132102105120101115321151111091013211511611710210246323551485248583210997115116101114464646106117115116951111101019510911111410195116101115116951001111101169510710510810895109101413210411611611211558474710310511610411798469911110947116103115116971161051111104745116103451151169711610511111047112117108108475148524832381071011216111610410511595105115959795116101115116951071011210
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sendkeys_ss13", "sendkeys_ss13\sendkeys_ss13.csproj", "{5D939FCB-F326-4B9B-8CEC-B2538126392E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5D939FCB-F326-4B9B-8CEC-B2538126392E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D939FCB-F326-4B9B-8CEC-B2538126392E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D939FCB-F326-4B9B-8CEC-B2538126392E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D939FCB-F326-4B9B-8CEC-B2538126392E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
</configuration>
@@ -0,0 +1,341 @@
//////////////////////////////////////////////////////////////////
/////GitHub pull request announcer bot for IRC////////////////////
/////Made by VistaPOWA for the /tg/station 13 code project.///////
/////This software is licensed under GPL3.////////////////////////
/////Prequisites: Meebey's SmartIrc4Net library (incl, under GPL)/
///// StarkSoft Proxy library (incl, under GPL)///////
/////Usage: Edit the config.txt file to match the settings////////
/////of your server's. Start the executable. Set up a Github hook/
/////if you hadn't before to send IRC notifications to the////////
/////channel of your choosing. Leave it running.//////////////////
/////IT IS PREFERABLE IF YOU RAN THIS LOCALLY. YOUR SERVER'S//////
/////API/COMMS KEY WILL BE SENT PLAINTEXT! ENSURE THAT THE API////
/////KEY IS NOT PUBLICALLY AVAILABLE! IF LEAKED, CHANGE IT.///////
/////Support available @ Rizon's #coderbus, ask for VistaPOWA.////
//////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Meebey.SmartIrc4net;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace sendkeys_ss13
{
public class Program
{
//default values
public static string serverIP = "127.0.0.1";
public static int serverPort = 11111;
public static string commskey = "this_is_a_test_key";
public static string Github_bot_name = "testbot_github";
public static string IRC_bot_name = "testbot";
public static string IRC_server = "test.net";
public static int IRC_port = 11111;
public static string IRC_channel = "#channel";
public static string[] merge_archive;
public static bool mergeflag = false;
public static IrcClient irc = new IrcClient();
public static int IRCReconnectAttempt = 0;
public static void Main(string[]args)
{
ReadConf();
irc.OnChannelMessage += new IrcEventHandler(OnChannelMessage);
irc.SupportNonRfc = true;
try
{
irc.Connect(IRC_server, IRC_port);
IRCReconnectAttempt = 0;
}
catch (Exception)
{
IRCReconnectAttempt++;
if (IRCReconnectAttempt <= 3)
{
Console.WriteLine("IRC server is unavaible at the moment. Reconnect attempt {0}...", IRCReconnectAttempt);
System.Threading.Thread.Sleep(3000); //Reconnecting after 5 seconds.
Main(args);
}
else
{
Console.WriteLine("IRC server unreachable. Please check your configuration file.");
Console.ReadLine();
return;
}
}
Console.WriteLine("Connected to IRC");
irc.Login(IRC_bot_name, IRC_bot_name);
Console.WriteLine("Logged in");
irc.RfcJoin(IRC_channel);
Console.WriteLine("Joining {0}", IRC_channel);
irc.Listen();
}
public static void ReadConf()
{
if (File.Exists("config.txt"))
{
StreamReader reader = new StreamReader("config.txt");
string[] line = reader.ReadLine().Split(' ');
if (line[2] != null)
{
Match match1 = Regex.Match(line[2], @"(\d{1,3}.?){4}"); //rudimentary IP validation
if (match1.Success)
{
serverIP = line[2];
Console.WriteLine("Read IP: " + serverIP);
}
else
{
Console.WriteLine("IP cannot be validated.");
return;
}
}
line = reader.ReadLine().Split(' ');
if (line[2] != null)
{
Match match2 = Regex.Match(line[2], @"\d{1,5}"); //rudimentary port validation
if (match2.Success && (Convert.ToInt32(line[2]) < 65535))
{
serverPort = Convert.ToInt32(line[2]);
Console.WriteLine("Read port: " + serverPort);
}
else
{
Console.WriteLine("Port cannot be validated.");
return;
}
}
line = reader.ReadLine().Split(' ');
if (line[2] != null)
{
commskey = line[2];
Console.WriteLine("Commskey read.");
}
else
{
Console.WriteLine("No Commskey!");
return;
}
line = reader.ReadLine().Split(' ');
if (line[2] != null)
{
Github_bot_name = line[2];
Console.WriteLine("Read Github bot name: " + Github_bot_name);
}
else
{
Console.WriteLine("No botname found.");
return;
}
line = reader.ReadLine().Split(' ');
if (line[2] != null)
{
IRC_bot_name = line[2];
Console.WriteLine("Read IRC bot name: " + Github_bot_name);
}
else
{
Console.WriteLine("No botname found.");
return;
}
line = reader.ReadLine().Split(' ');
if (line[2] != null)
{
Match match3 = Regex.Match(line[2], @"(.+)\:(\d{1,5})"); //rudimentary port validation
if (match3.Success)
{
IRC_server = Convert.ToString(match3.Groups[1]);
Int32.TryParse(Convert.ToString(match3.Groups[2]), out IRC_port);
Console.WriteLine("Read IRC server: " + IRC_server + ":" + Convert.ToString(IRC_port));
}
else
{
Console.WriteLine("Server:port invalid.");
return;
}
}
line = reader.ReadLine().Split(' ');
if (line[2] != null)
{
IRC_channel = line[2];
Console.WriteLine("Read channel: " + IRC_channel);
}
else
{
Console.WriteLine("No channel found.");
return;
}
reader.Close();
}
else
{
Console.WriteLine("Config file doesn't exist, using defaults");
return;
}
}
public static void OnChannelMessage(object sender, IrcEventArgs e)
{
if (e.Data.Nick == Github_bot_name)
{
string[] msg = e.Data.Message.Split(' ');
for (int i = 0; i < msg.Length; i++)
{
msg[i] = Regex.Replace(msg[i], @"[\x02\x1F\x0F\x16]|\x03(\d\d?(,\d\d?)?)?", String.Empty); //Sanitizing color codes
msg[i] = Regex.Replace(msg[i], @"[\\\&\=\;\<\>]", " "); //Filtering out some iffy characters
}
FormMessage(msg);
}
}
private static void FormMessage(string[] msg, bool ShortenedURL = false)
{
using (StreamWriter output = new StreamWriter("output.txt"))
{
if (msg[2] == "closed")
{
merge_archive = msg;
mergeflag = true;
output.Close();
}
else if ((msg[2] == "opened" || mergeflag) && msg[1] != "meant:") //Either we open a new PR or a PR was closed in the last message. Also protection from Whibyl's correction thingy!
{
if (msg[2] == "pushed")
{
msg = merge_archive; //We copy the "close" message and replace "close" with merge! The players won't know what him 'em!
msg[2] = "merged";
}
mergeflag = false;
merge_archive = null;
string URL = msg[msg.Length - 1];
if(!ShortenedURL)
URL = ShortenURL(URL);
msg[5] = "<a href=" + URL + ">" + msg[5] + "</a>";
msg[0] = ""; //Repo name
msg[msg.Length - 1] = ""; //The URL itself
msg[msg.Length - 2] = ""; //Branch info
byte[] PACKETS = CreatePacket(msg);
PACKETS[1] = 0x83;
int len = 0;
for (int i = 1; i < msg.Length - 1; i++)
{
len += msg[i].Length + 1; //The length of the word and the space following it.
Console.Write(msg[i] + " ");
}
len -= 1; //Compensating for the lack of space at the end.
len += 14 + commskey.Length + 6; //Argument names + Commskey length + 6 null bytes
PACKETS[3] = (byte)len;
StringBuilder test = new StringBuilder();
for (int i = 0; i < PACKETS.Length; i++)
{
test.Append(Convert.ToString(PACKETS[i]));
}
output.WriteLine(Convert.ToString(test));
SendPacket(output, PACKETS);
}
else
{
mergeflag = false;
merge_archive = null;
output.Close();
}
}
}
public static int ServerReconnectAttempt = 0;
private static void SendPacket(StreamWriter output, byte[] PACKETS)
{
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ip = new IPEndPoint(IPAddress.Parse(serverIP), serverPort);
try
{
server.Connect(ip);
server.Send(PACKETS);
Console.WriteLine("- sent ;)");
output.Close();
Console.WriteLine();
}
catch (Exception)
{
ServerReconnectAttempt++;
if(ServerReconnectAttempt <= 5)
{
Console.WriteLine("Server is not available at the moment. Reconnect attempt {0}...", ServerReconnectAttempt);
System.Threading.Thread.Sleep(5000); //Reconnecting after 5 seconds.
SendPacket(output, PACKETS);
}
else
{
output.Close();
Console.WriteLine("Server appears to be down for good. Press ENTER when you have restarted the server to continue.");
Console.ReadLine();
ServerReconnectAttempt = 0;
SendPacket(output, PACKETS);
}
}
}
public static int GitReconnectAttempt = 0;
private static string ShortenURL(string URL) //derived from GitIoSharp by dimapasko
{
WebRequest request = WebRequest.Create("http://git.io");
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
byte[] packet = Encoding.ASCII.GetBytes("url=" + URL);
request.ContentLength = packet.Length;
try
{
using (Stream stream = request.GetRequestStream())
{
stream.Write(packet, 0, packet.Length);
GitReconnectAttempt = 0;
}
}
catch (Exception)
{
GitReconnectAttempt++;
if (GitReconnectAttempt <= 3)
{
Console.WriteLine("Git.IO is not available at the moment. Reconnect attempt {0}...", GitReconnectAttempt);
System.Threading.Thread.Sleep(3000); //Attempt to reconnect after 3 seconds.
ShortenURL(URL);
}
else
{
Console.WriteLine("Git.IO is down. Returning long URL.");
GitReconnectAttempt = 0; //Reset counter
return URL;
}
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return Convert.ToString(new Uri(response.Headers[HttpResponseHeader.Location]));
}
private static byte[] CreatePacket(string[] msg)
{
StringBuilder packet = new StringBuilder();
packet.Append((char)'\x00', 8); //packet[1] is 0x83, packet[3] contain length
packet.Append("?announce=");
for (int i = 1; i < msg.Length - 1; i++)
{
if(i == msg.Length - 2)
packet.Append(msg[i]);
else
packet.Append(msg[i] + " ");
}
packet.Append("&key=");
packet.Append(commskey);
packet.Append((char)'\x00');
return Encoding.ASCII.GetBytes(packet.ToString());
}
}
}
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("sendkeys_ss13")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("sendkeys_ss13")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("197641d3-a97a-4255-b833-d6481ca4ef54")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5D939FCB-F326-4B9B-8CEC-B2538126392E}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>sendkeys_ss13</RootNamespace>
<AssemblyName>sendkeys_ss13</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Meebey.SmartIrc4net">
<HintPath>.\Meebey.SmartIrc4net.dll</HintPath>
</Reference>
<Reference Include="StarkSoftProxy">
<HintPath>.\StarkSoftProxy.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="IrcDotNet.dll" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>