mirror of
https://github.com/EnderIce2/SDR-RPC.git
synced 2025-05-25 20:14:27 +00:00
Update the plugin for SDR# 1920 ( #14 )
This commit is contained in:
parent
3173c291f5
commit
46ddb4b478
@ -1,7 +0,0 @@
|
|||||||
version = 1
|
|
||||||
|
|
||||||
exclude_patterns = ["DiscordAPI/**"]
|
|
||||||
|
|
||||||
[[analyzers]]
|
|
||||||
name = "csharp"
|
|
||||||
enabled = true
|
|
@ -1,32 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Configuration of the current RPC connection
|
|
||||||
/// </summary>
|
|
||||||
public class Configuration
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord API endpoint that should be used.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("api_endpoint")]
|
|
||||||
public string ApiEndpoint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The CDN endpoint
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("cdn_host")]
|
|
||||||
public string CdnHost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The type of enviroment the connection on. Usually Production.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("enviroment")]
|
|
||||||
public string Enviroment { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
using DiscordRPC.Helper;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts enums with the <see cref="EnumValueAttribute"/> into Json friendly terms.
|
|
||||||
/// </summary>
|
|
||||||
internal class EnumSnakeCaseConverter : JsonConverter
|
|
||||||
{
|
|
||||||
public override bool CanConvert(Type objectType)
|
|
||||||
{
|
|
||||||
return objectType.IsEnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
if (reader.Value == null) return null;
|
|
||||||
|
|
||||||
object val = null;
|
|
||||||
if (TryParseEnum(objectType, (string)reader.Value, out val))
|
|
||||||
return val;
|
|
||||||
|
|
||||||
return existingValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
var enumtype = value.GetType();
|
|
||||||
var name = Enum.GetName(enumtype, value);
|
|
||||||
|
|
||||||
//Get each member and look for hte correct one
|
|
||||||
var members = enumtype.GetMembers(BindingFlags.Public | BindingFlags.Static);
|
|
||||||
foreach (var m in members)
|
|
||||||
{
|
|
||||||
if (m.Name.Equals(name))
|
|
||||||
{
|
|
||||||
var attributes = m.GetCustomAttributes(typeof(EnumValueAttribute), true);
|
|
||||||
if (attributes.Length > 0)
|
|
||||||
{
|
|
||||||
name = ((EnumValueAttribute)attributes[0]).Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteValue(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public bool TryParseEnum(Type enumType, string str, out object obj)
|
|
||||||
{
|
|
||||||
//Make sure the string isn;t null
|
|
||||||
if (str == null)
|
|
||||||
{
|
|
||||||
obj = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get the real type
|
|
||||||
Type type = enumType;
|
|
||||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
|
||||||
type = type.GetGenericArguments().First();
|
|
||||||
|
|
||||||
//Make sure its actually a enum
|
|
||||||
if (!type.IsEnum)
|
|
||||||
{
|
|
||||||
obj = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Get each member and look for hte correct one
|
|
||||||
var members = type.GetMembers(BindingFlags.Public | BindingFlags.Static);
|
|
||||||
foreach (var m in members)
|
|
||||||
{
|
|
||||||
var attributes = m.GetCustomAttributes(typeof(EnumValueAttribute), true);
|
|
||||||
foreach(var a in attributes)
|
|
||||||
{
|
|
||||||
var enumval = (EnumValueAttribute)a;
|
|
||||||
if (str.Equals(enumval.Value))
|
|
||||||
{
|
|
||||||
obj = Enum.Parse(type, m.Name, ignoreCase: true);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//We failed
|
|
||||||
obj = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Converters
|
|
||||||
{
|
|
||||||
internal class EnumValueAttribute : Attribute
|
|
||||||
{
|
|
||||||
public string Value { get; set; }
|
|
||||||
public EnumValueAttribute(string value)
|
|
||||||
{
|
|
||||||
this.Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of event receieved by the RPC. A flag type that can be combined.
|
|
||||||
/// </summary>
|
|
||||||
[System.Flags]
|
|
||||||
public enum EventType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No event
|
|
||||||
/// </summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the Discord Client wishes to enter a game to spectate
|
|
||||||
/// </summary>
|
|
||||||
Spectate = 0x1,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the Discord Client wishes to enter a game to play.
|
|
||||||
/// </summary>
|
|
||||||
Join = 0x2,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when another Discord Client has requested permission to join this game.
|
|
||||||
/// </summary>
|
|
||||||
JoinRequest = 0x4
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Exceptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The exception that is thrown when a error occurs while communicating with a pipe or when a connection attempt fails.
|
|
||||||
/// </summary>
|
|
||||||
[System.Obsolete("Not actually used anywhere")]
|
|
||||||
public class InvalidPipeException : Exception
|
|
||||||
{
|
|
||||||
internal InvalidPipeException(string message) : base(message) { }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Helper
|
|
||||||
{
|
|
||||||
|
|
||||||
internal class BackoffDelay
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum time the backoff can reach
|
|
||||||
/// </summary>
|
|
||||||
public int Maximum { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The minimum time the backoff can start at
|
|
||||||
/// </summary>
|
|
||||||
public int Minimum { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current time of the backoff
|
|
||||||
/// </summary>
|
|
||||||
public int Current { get { return _current; } }
|
|
||||||
private int _current;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current number of failures
|
|
||||||
/// </summary>
|
|
||||||
public int Fails { get { return _fails; } }
|
|
||||||
private int _fails;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The random generator
|
|
||||||
/// </summary>
|
|
||||||
public Random Random { get; set; }
|
|
||||||
|
|
||||||
private BackoffDelay() { }
|
|
||||||
public BackoffDelay(int min, int max) : this(min, max, new Random()) { }
|
|
||||||
public BackoffDelay(int min, int max, Random random)
|
|
||||||
{
|
|
||||||
this.Minimum = min;
|
|
||||||
this.Maximum = max;
|
|
||||||
|
|
||||||
this._current = min;
|
|
||||||
this._fails = 0;
|
|
||||||
this.Random = random;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets the backoff
|
|
||||||
/// </summary>
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
_fails = 0;
|
|
||||||
_current = Minimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int NextDelay()
|
|
||||||
{
|
|
||||||
//Increment the failures
|
|
||||||
_fails++;
|
|
||||||
|
|
||||||
double diff = (Maximum - Minimum) / 100f;
|
|
||||||
_current = (int)Math.Floor(diff * _fails) + Minimum;
|
|
||||||
|
|
||||||
|
|
||||||
return Math.Min(Math.Max(_current, Minimum), Maximum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Helper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Collectin of helpful string extensions
|
|
||||||
/// </summary>
|
|
||||||
public static class StringTools
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Will return null if the string is whitespace, otherwise it will return the string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str">The string to check</param>
|
|
||||||
/// <returns>Null if the string is empty, otherwise the string</returns>
|
|
||||||
public static string GetNullOrString(this string str)
|
|
||||||
{
|
|
||||||
return str.Length == 0 || string.IsNullOrEmpty(str.Trim()) ? null : str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does the string fit within the given amount of bytes? Uses UTF8 encoding.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str">The string to check</param>
|
|
||||||
/// <param name="bytes">The maximum number of bytes the string can take up</param>
|
|
||||||
/// <returns>True if the string fits within the number of bytes</returns>
|
|
||||||
public static bool WithinLength(this string str, int bytes)
|
|
||||||
{
|
|
||||||
return str.WithinLength(bytes, Encoding.UTF8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does the string fit within the given amount of bytes?
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str">The string to check</param>
|
|
||||||
/// <param name="bytes">The maximum number of bytes the string can take up</param>
|
|
||||||
/// <param name="encoding">The encoding to count the bytes with</param>
|
|
||||||
/// <returns>True if the string fits within the number of bytes</returns>
|
|
||||||
public static bool WithinLength(this string str, int bytes, Encoding encoding)
|
|
||||||
{
|
|
||||||
return encoding.GetByteCount(str) <= bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the string into UpperCamelCase (Pascal Case).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str">The string to convert</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string ToCamelCase(this string str)
|
|
||||||
{
|
|
||||||
if (str == null) return null;
|
|
||||||
|
|
||||||
return str.ToLower()
|
|
||||||
.Split(new[] { "_", " " }, StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Select(s => char.ToUpper(s[0]) + s.Substring(1, s.Length - 1))
|
|
||||||
.Aggregate(string.Empty, (s1, s2) => s1 + s2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the string into UPPER_SNAKE_CASE
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str">The string to convert</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string ToSnakeCase(this string str)
|
|
||||||
{
|
|
||||||
if (str == null) return null;
|
|
||||||
var concat = string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString()).ToArray());
|
|
||||||
return concat.ToUpper();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.IO
|
|
||||||
{
|
|
||||||
internal class Handshake
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Version of the IPC API we are using
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("v")]
|
|
||||||
public int Version { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of the app.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("client_id")]
|
|
||||||
public string ClientID { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
using DiscordRPC.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.IO
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Pipe Client used to communicate with Discord.
|
|
||||||
/// </summary>
|
|
||||||
public interface INamedPipeClient : IDisposable
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The logger for the Pipe client to use
|
|
||||||
/// </summary>
|
|
||||||
ILogger Logger { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is the pipe client currently connected?
|
|
||||||
/// </summary>
|
|
||||||
bool IsConnected { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The pipe the client is currently connected too
|
|
||||||
/// </summary>
|
|
||||||
int ConnectedPipe { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to connect to the pipe. If 0-9 is passed to pipe, it should try to only connect to the specified pipe. If -1 is passed, the pipe will find the first available pipe.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pipe">If -1 is passed, the pipe will find the first available pipe, otherwise it connects to the pipe that was supplied</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
bool Connect(int pipe);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads a frame if there is one available. Returns false if there is none. This should be non blocking (aka use a Peek first).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="frame">The frame that has been read. Will be <code>default(PipeFrame)</code> if it fails to read</param>
|
|
||||||
/// <returns>Returns true if a frame has been read, otherwise false.</returns>
|
|
||||||
bool ReadFrame(out PipeFrame frame);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes the frame to the pipe. Returns false if any errors occur.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="frame">The frame to be written</param>
|
|
||||||
bool WriteFrame(PipeFrame frame);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Closes the connection
|
|
||||||
/// </summary>
|
|
||||||
void Close();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
namespace DiscordRPC.IO
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The operation code that the <see cref="PipeFrame"/> was sent under. This defines the type of frame and the data to expect.
|
|
||||||
/// </summary>
|
|
||||||
public enum Opcode : uint
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initial handshake frame
|
|
||||||
/// </summary>
|
|
||||||
Handshake = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generic message frame
|
|
||||||
/// </summary>
|
|
||||||
Frame = 1,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Discord has closed the connection
|
|
||||||
/// </summary>
|
|
||||||
Close = 2,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ping frame (not used?)
|
|
||||||
/// </summary>
|
|
||||||
Ping = 3,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Pong frame (not used?)
|
|
||||||
/// </summary>
|
|
||||||
Pong = 4
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,204 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.IO
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A frame received and sent to the Discord client for RPC communications.
|
|
||||||
/// </summary>
|
|
||||||
public struct PipeFrame
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The maxium size of a pipe frame (16kb).
|
|
||||||
/// </summary>
|
|
||||||
public static readonly int MAX_SIZE = 16 * 1024;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The opcode of the frame
|
|
||||||
/// </summary>
|
|
||||||
public Opcode Opcode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The length of the frame data
|
|
||||||
/// </summary>
|
|
||||||
public uint Length { get { return (uint) Data.Length; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The data in the frame
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Data { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The data represented as a string.
|
|
||||||
/// </summary>
|
|
||||||
public string Message
|
|
||||||
{
|
|
||||||
get { return GetMessage(); }
|
|
||||||
set { SetMessage(value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new pipe frame instance
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="opcode">The opcode of the frame</param>
|
|
||||||
/// <param name="data">The data of the frame that will be serialized as JSON</param>
|
|
||||||
public PipeFrame(Opcode opcode, object data)
|
|
||||||
{
|
|
||||||
//Set the opcode and a temp field for data
|
|
||||||
Opcode = opcode;
|
|
||||||
Data = null;
|
|
||||||
|
|
||||||
//Set the data
|
|
||||||
SetObject(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the encoding used for the pipe frames
|
|
||||||
/// </summary>
|
|
||||||
public Encoding MessageEncoding { get { return Encoding.UTF8; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the data based of a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="str"></param>
|
|
||||||
private void SetMessage(string str) { Data = MessageEncoding.GetBytes(str); }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a string based of the data
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string GetMessage() { return MessageEncoding.GetString(Data); }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Serializes the object into json string then encodes it into <see cref="Data"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
public void SetObject(object obj)
|
|
||||||
{
|
|
||||||
string json = JsonConvert.SerializeObject(obj);
|
|
||||||
SetMessage(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the opcodes and serializes the object into a json string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="opcode"></param>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
public void SetObject(Opcode opcode, object obj)
|
|
||||||
{
|
|
||||||
Opcode = opcode;
|
|
||||||
SetObject(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deserializes the data into the supplied type using JSON.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type to deserialize into</typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public T GetObject<T>()
|
|
||||||
{
|
|
||||||
string json = GetMessage();
|
|
||||||
return JsonConvert.DeserializeObject<T>(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to read the contents of the frame from the stream
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool ReadStream(Stream stream)
|
|
||||||
{
|
|
||||||
//Try to read the opcode
|
|
||||||
uint op;
|
|
||||||
if (!TryReadUInt32(stream, out op))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//Try to read the length
|
|
||||||
uint len;
|
|
||||||
if (!TryReadUInt32(stream, out len))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint readsRemaining = len;
|
|
||||||
|
|
||||||
//Read the contents
|
|
||||||
using (var mem = new MemoryStream())
|
|
||||||
{
|
|
||||||
byte[] buffer = new byte[Min(2048, len)]; // read in chunks of 2KB
|
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = stream.Read(buffer, 0, Min(buffer.Length, readsRemaining))) > 0)
|
|
||||||
{
|
|
||||||
readsRemaining -= len;
|
|
||||||
mem.Write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] result = mem.ToArray();
|
|
||||||
if (result.LongLength != len)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Opcode = (Opcode)op;
|
|
||||||
Data = result;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//fun
|
|
||||||
//if (a != null) { do { yield return true; switch (a) { case 1: await new Task(); default: lock (obj) { foreach (b in c) { for (int d = 0; d < 1; d++) { a++; } } } while (a is typeof(int) || (new Class()) != null) } goto MY_LABEL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns minimum value between a int and a unsigned int
|
|
||||||
/// </summary>
|
|
||||||
private int Min(int a, uint b)
|
|
||||||
{
|
|
||||||
if (b >= a) return a;
|
|
||||||
return (int) b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to read a UInt32
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream"></param>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private bool TryReadUInt32(Stream stream, out uint value)
|
|
||||||
{
|
|
||||||
//Read the bytes available to us
|
|
||||||
byte[] bytes = new byte[4];
|
|
||||||
int cnt = stream.Read(bytes, 0, bytes.Length);
|
|
||||||
|
|
||||||
//Make sure we actually have a valid value
|
|
||||||
if (cnt != 4)
|
|
||||||
{
|
|
||||||
value = default(uint);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = BitConverter.ToUInt32(bytes, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes the frame into the target frame as one big byte block.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stream"></param>
|
|
||||||
public void WriteStream(Stream stream)
|
|
||||||
{
|
|
||||||
//Get all the bytes
|
|
||||||
byte[] op = BitConverter.GetBytes((uint) Opcode);
|
|
||||||
byte[] len = BitConverter.GetBytes(Length);
|
|
||||||
|
|
||||||
//Copy it all into a buffer
|
|
||||||
byte[] buff = new byte[op.Length + len.Length + Data.Length];
|
|
||||||
op.CopyTo(buff, 0);
|
|
||||||
len.CopyTo(buff, op.Length);
|
|
||||||
Data.CopyTo(buff, op.Length + len.Length);
|
|
||||||
|
|
||||||
//Write it to the stream
|
|
||||||
stream.Write(buff, 0, buff.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Logging
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Logs the outputs to the console using <see cref="Console.WriteLine()"/>
|
|
||||||
/// </summary>
|
|
||||||
public class ConsoleLogger : ILogger
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The level of logging to apply to this logger.
|
|
||||||
/// </summary>
|
|
||||||
public LogLevel Level { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should the output be coloured?
|
|
||||||
/// </summary>
|
|
||||||
public bool Coloured { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A alias too <see cref="Coloured"/>
|
|
||||||
/// </summary>
|
|
||||||
public bool Colored { get { return Coloured; } set { Coloured = value; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of a Console Logger.
|
|
||||||
/// </summary>
|
|
||||||
public ConsoleLogger()
|
|
||||||
{
|
|
||||||
this.Level = LogLevel.Info;
|
|
||||||
Coloured = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of a Console Logger with a set log level
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="level"></param>
|
|
||||||
/// <param name="coloured"></param>
|
|
||||||
public ConsoleLogger(LogLevel level, bool coloured = false)
|
|
||||||
{
|
|
||||||
Level = level;
|
|
||||||
Coloured = coloured;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informative log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Trace(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Trace) return;
|
|
||||||
|
|
||||||
if (Coloured) Console.ForegroundColor = ConsoleColor.Gray;
|
|
||||||
Console.WriteLine("TRACE: " + message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informative log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Info(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Info) return;
|
|
||||||
|
|
||||||
if (Coloured) Console.ForegroundColor = ConsoleColor.White;
|
|
||||||
Console.WriteLine("INFO: " + message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Warning log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Warning(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Warning) return;
|
|
||||||
|
|
||||||
if (Coloured) Console.ForegroundColor = ConsoleColor.Yellow;
|
|
||||||
Console.WriteLine("WARN: " + message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Error log messsages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Error(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Error) return;
|
|
||||||
|
|
||||||
if (Coloured) Console.ForegroundColor = ConsoleColor.Red;
|
|
||||||
Console.WriteLine("ERR : " + message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Logging
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Logs the outputs to a file
|
|
||||||
/// </summary>
|
|
||||||
public class FileLogger : ILogger
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The level of logging to apply to this logger.
|
|
||||||
/// </summary>
|
|
||||||
public LogLevel Level { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should the output be coloured?
|
|
||||||
/// </summary>
|
|
||||||
public string File { get; set; }
|
|
||||||
|
|
||||||
private object filelock;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the file logger
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path of the log file.</param>
|
|
||||||
public FileLogger(string path)
|
|
||||||
: this(path, LogLevel.Info) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the file logger
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path of the log file.</param>
|
|
||||||
/// <param name="level">The level to assign to the logger.</param>
|
|
||||||
public FileLogger(string path, LogLevel level)
|
|
||||||
{
|
|
||||||
Level = level;
|
|
||||||
File = path;
|
|
||||||
filelock = new object();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informative log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Trace(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Trace) return;
|
|
||||||
lock (filelock) System.IO.File.AppendAllText(File, "\r\nTRCE: " + (args.Length > 0 ? string.Format(message, args) : message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informative log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Info(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Info) return;
|
|
||||||
lock(filelock) System.IO.File.AppendAllText(File, "\r\nINFO: " + (args.Length > 0 ? string.Format(message, args) : message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Warning log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Warning(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Warning) return;
|
|
||||||
lock (filelock)
|
|
||||||
System.IO.File.AppendAllText(File, "\r\nWARN: " + (args.Length > 0 ? string.Format(message, args) : message));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Error log messsages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Error(string message, params object[] args)
|
|
||||||
{
|
|
||||||
if (Level > LogLevel.Error) return;
|
|
||||||
lock (filelock)
|
|
||||||
System.IO.File.AppendAllText(File, "\r\nERR : " + (args.Length > 0 ? string.Format(message, args) : message));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Logging
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Logging interface to log the internal states of the pipe. Logs are sent in a NON thread safe way. They can come from multiple threads and it is upto the ILogger to account for it.
|
|
||||||
/// </summary>
|
|
||||||
public interface ILogger
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The level of logging to apply to this logger.
|
|
||||||
/// </summary>
|
|
||||||
LogLevel Level { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Debug trace messeages used for debugging internal elements.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
void Trace(string message, params object[] args);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informative log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
void Info(string message, params object[] args);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Warning log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
void Warning(string message, params object[] args);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Error log messsages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
void Error(string message, params object[] args);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Logging
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Ignores all log events
|
|
||||||
/// </summary>
|
|
||||||
public class NullLogger : ILogger
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The level of logging to apply to this logger.
|
|
||||||
/// </summary>
|
|
||||||
public LogLevel Level { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informative log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Trace(string message, params object[] args)
|
|
||||||
{
|
|
||||||
//Null Logger, so no messages are acutally sent
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Informative log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Info(string message, params object[] args)
|
|
||||||
{
|
|
||||||
//Null Logger, so no messages are acutally sent
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Warning log messages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Warning(string message, params object[] args)
|
|
||||||
{
|
|
||||||
//Null Logger, so no messages are acutally sent
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Error log messsages
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <param name="args"></param>
|
|
||||||
public void Error(string message, params object[] args)
|
|
||||||
{
|
|
||||||
//Null Logger, so no messages are acutally sent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the IPC has closed.
|
|
||||||
/// </summary>
|
|
||||||
public class CloseMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.Close; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The reason for the close
|
|
||||||
/// </summary>
|
|
||||||
public string Reason { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The closure code
|
|
||||||
/// </summary>
|
|
||||||
public int Code { get; internal set; }
|
|
||||||
|
|
||||||
internal CloseMessage() { }
|
|
||||||
internal CloseMessage(string reason) { this.Reason = reason; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The connection to the discord client was succesfull. This is called before <see cref="MessageType.Ready"/>.
|
|
||||||
/// </summary>
|
|
||||||
public class ConnectionEstablishedMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.ConnectionEstablished; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The pipe we ended up connecting too
|
|
||||||
/// </summary>
|
|
||||||
public int ConnectedPipe { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Failed to establish any connection with discord. Discord is potentially not running?
|
|
||||||
/// </summary>
|
|
||||||
public class ConnectionFailedMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.ConnectionFailed; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The pipe we failed to connect too.
|
|
||||||
/// </summary>
|
|
||||||
public int FailedPipe { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Created when a error occurs within the ipc and it is sent to the client.
|
|
||||||
/// </summary>
|
|
||||||
public class ErrorMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.Error; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord error code.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("code")]
|
|
||||||
public ErrorCode Code { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The message associated with the error code.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("message")]
|
|
||||||
public string Message { get; internal set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The error message received by discord. See https://discordapp.com/developers/docs/topics/rpc#rpc-server-payloads-rpc-errors for documentation
|
|
||||||
/// </summary>
|
|
||||||
public enum ErrorCode
|
|
||||||
{
|
|
||||||
//Pipe Error Codes
|
|
||||||
/// <summary> Pipe was Successful </summary>
|
|
||||||
Success = 0,
|
|
||||||
|
|
||||||
///<summary>The pipe had an exception</summary>
|
|
||||||
PipeException = 1,
|
|
||||||
|
|
||||||
///<summary>The pipe received corrupted data</summary>
|
|
||||||
ReadCorrupt = 2,
|
|
||||||
|
|
||||||
//Custom Error Code
|
|
||||||
///<summary>The functionality was not yet implemented</summary>
|
|
||||||
NotImplemented = 10,
|
|
||||||
|
|
||||||
//Discord RPC error codes
|
|
||||||
///<summary>Unkown Discord error</summary>
|
|
||||||
UnkownError = 1000,
|
|
||||||
|
|
||||||
///<summary>Invalid Payload received</summary>
|
|
||||||
InvalidPayload = 4000,
|
|
||||||
|
|
||||||
///<summary>Invalid command was sent</summary>
|
|
||||||
InvalidCommand = 4002,
|
|
||||||
|
|
||||||
/// <summary>Invalid event was sent </summary>
|
|
||||||
InvalidEvent = 4004,
|
|
||||||
|
|
||||||
/*
|
|
||||||
InvalidGuild = 4003,
|
|
||||||
InvalidChannel = 4005,
|
|
||||||
InvalidPermissions = 4006,
|
|
||||||
InvalidClientID = 4007,
|
|
||||||
InvalidOrigin = 4008,
|
|
||||||
InvalidToken = 4009,
|
|
||||||
InvalidUser = 4010,
|
|
||||||
OAuth2Error = 5000,
|
|
||||||
SelectChannelTimeout = 5001,
|
|
||||||
GetGuildTimeout = 5002,
|
|
||||||
SelectVoiceForceRequired = 5003,
|
|
||||||
CaptureShortcutAlreadyListening = 5004
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Messages received from discord.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public abstract MessageType Type { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The time the message was created
|
|
||||||
/// </summary>
|
|
||||||
public DateTime TimeCreated { get { return _timecreated; } }
|
|
||||||
private DateTime _timecreated;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the message
|
|
||||||
/// </summary>
|
|
||||||
public IMessage()
|
|
||||||
{
|
|
||||||
_timecreated = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the Discord Client wishes for this process to join a game. D -> C.
|
|
||||||
/// </summary>
|
|
||||||
public class JoinMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.Join; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="Secrets.JoinSecret" /> to connect with.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("secret")]
|
|
||||||
public string Secret { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called when some other person has requested access to this game. C -> D -> C.
|
|
||||||
/// </summary>
|
|
||||||
public class JoinRequestMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.JoinRequest; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The discord user that is requesting access.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("user")]
|
|
||||||
public User User { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Type of message.
|
|
||||||
/// </summary>
|
|
||||||
public enum MessageType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord Client is ready to send and receive messages.
|
|
||||||
/// </summary>
|
|
||||||
Ready,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The connection to the Discord Client is lost. The connection will remain close and unready to accept messages until the Ready event is called again.
|
|
||||||
/// </summary>
|
|
||||||
Close,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A error has occured during the transmission of a message. For example, if a bad Rich Presence payload is sent, this event will be called explaining what went wrong.
|
|
||||||
/// </summary>
|
|
||||||
Error,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord Client has updated the presence.
|
|
||||||
/// </summary>
|
|
||||||
PresenceUpdate,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord Client has subscribed to an event.
|
|
||||||
/// </summary>
|
|
||||||
Subscribe,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord Client has unsubscribed from an event.
|
|
||||||
/// </summary>
|
|
||||||
Unsubscribe,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord Client wishes for this process to join a game.
|
|
||||||
/// </summary>
|
|
||||||
Join,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Discord Client wishes for this process to spectate a game.
|
|
||||||
/// </summary>
|
|
||||||
Spectate,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Another discord user requests permission to join this game.
|
|
||||||
/// </summary>
|
|
||||||
JoinRequest,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The connection to the discord client was succesfull. This is called before <see cref="Ready"/>.
|
|
||||||
/// </summary>
|
|
||||||
ConnectionEstablished,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Failed to establish any connection with discord. Discord is potentially not running?
|
|
||||||
/// </summary>
|
|
||||||
ConnectionFailed
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Representation of the message received by discord when the presence has been updated.
|
|
||||||
/// </summary>
|
|
||||||
public class PresenceMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.PresenceUpdate; } }
|
|
||||||
|
|
||||||
internal PresenceMessage() : this(null) { }
|
|
||||||
internal PresenceMessage(RichPresenceResponse rpr)
|
|
||||||
{
|
|
||||||
if (rpr == null)
|
|
||||||
{
|
|
||||||
Presence = null;
|
|
||||||
Name = "No Rich Presence";
|
|
||||||
ApplicationID = "";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Presence = (RichPresence)rpr;
|
|
||||||
Name = rpr.Name;
|
|
||||||
ApplicationID = rpr.ClientID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The rich presence Discord has set
|
|
||||||
/// </summary>
|
|
||||||
public RichPresence Presence { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the application Discord has set it for
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of the application discord has set it for
|
|
||||||
/// </summary>
|
|
||||||
public string ApplicationID { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the ipc is ready to send arguments.
|
|
||||||
/// </summary>
|
|
||||||
public class ReadyMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.Ready; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The configuration of the connection
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("config")]
|
|
||||||
public Configuration Configuration { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// User the connection belongs too
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("user")]
|
|
||||||
public User User { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The version of the RPC
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("v")]
|
|
||||||
public int Version { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called when the Discord Client wishes for this process to spectate a game. D -> C.
|
|
||||||
/// </summary>
|
|
||||||
public class SpectateMessage : JoinMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.Spectate; } }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called as validation of a subscribe
|
|
||||||
/// </summary>
|
|
||||||
public class SubscribeMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.Subscribe; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The event that was subscribed too.
|
|
||||||
/// </summary>
|
|
||||||
public EventType Event { get; internal set; }
|
|
||||||
|
|
||||||
internal SubscribeMessage(ServerEvent evt)
|
|
||||||
{
|
|
||||||
switch (evt)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case ServerEvent.ActivityJoin:
|
|
||||||
Event = EventType.Join;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerEvent.ActivityJoinRequest:
|
|
||||||
Event = EventType.JoinRequest;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerEvent.ActivitySpectate:
|
|
||||||
Event = EventType.Spectate;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Message
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called as validation of a subscribe
|
|
||||||
/// </summary>
|
|
||||||
public class UnsubscribeMessage : IMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of message received from discord
|
|
||||||
/// </summary>
|
|
||||||
public override MessageType Type { get { return MessageType.Unsubscribe; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The event that was subscribed too.
|
|
||||||
/// </summary>
|
|
||||||
public EventType Event { get; internal set; }
|
|
||||||
|
|
||||||
internal UnsubscribeMessage(ServerEvent evt)
|
|
||||||
{
|
|
||||||
switch (evt)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case ServerEvent.ActivityJoin:
|
|
||||||
Event = EventType.Join;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerEvent.ActivityJoinRequest:
|
|
||||||
Event = EventType.JoinRequest;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerEvent.ActivitySpectate:
|
|
||||||
Event = EventType.Spectate;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Commands
|
|
||||||
{
|
|
||||||
internal class CloseCommand : ICommand
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The process ID
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("pid")]
|
|
||||||
public int PID { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The rich presence to be set. Can be null.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("close_reason")]
|
|
||||||
public string value = "Unity 5.5 doesn't handle thread aborts. Can you please close me discord?";
|
|
||||||
|
|
||||||
public IPayload PreparePayload(long nonce)
|
|
||||||
{
|
|
||||||
return new ArgumentPayload()
|
|
||||||
{
|
|
||||||
Command = Command.Dispatch,
|
|
||||||
Nonce = null,
|
|
||||||
Arguments = null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Commands
|
|
||||||
{
|
|
||||||
internal interface ICommand
|
|
||||||
{
|
|
||||||
IPayload PreparePayload(long nonce);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Commands
|
|
||||||
{
|
|
||||||
internal class PresenceCommand : ICommand
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The process ID
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("pid")]
|
|
||||||
public int PID { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The rich presence to be set. Can be null.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("activity")]
|
|
||||||
public RichPresence Presence { get; set; }
|
|
||||||
|
|
||||||
public IPayload PreparePayload(long nonce)
|
|
||||||
{
|
|
||||||
return new ArgumentPayload(this, nonce)
|
|
||||||
{
|
|
||||||
Command = Command.SetActivity
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Commands
|
|
||||||
{
|
|
||||||
internal class RespondCommand : ICommand
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The user ID that we are accepting / rejecting
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("user_id")]
|
|
||||||
public string UserID { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If true, the user will be allowed to connect.
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public bool Accept { get; set; }
|
|
||||||
|
|
||||||
public IPayload PreparePayload(long nonce)
|
|
||||||
{
|
|
||||||
return new ArgumentPayload(this, nonce)
|
|
||||||
{
|
|
||||||
Command = Accept ? Command.SendActivityJoinInvite : Command.CloseActivityJoinRequest
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Commands
|
|
||||||
{
|
|
||||||
internal class SubscribeCommand : ICommand
|
|
||||||
{
|
|
||||||
public ServerEvent Event { get; set; }
|
|
||||||
public bool IsUnsubscribe { get; set; }
|
|
||||||
|
|
||||||
public IPayload PreparePayload(long nonce)
|
|
||||||
{
|
|
||||||
return new EventPayload(nonce)
|
|
||||||
{
|
|
||||||
Command = IsUnsubscribe ? Command.Unsubscribe : Command.Subscribe,
|
|
||||||
Event = Event
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Payload
|
|
||||||
{
|
|
||||||
internal class ClosePayload : IPayload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The close code the discord gave us
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("code")]
|
|
||||||
public int Code { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The close reason discord gave us
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("message")]
|
|
||||||
public string Reason { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
using DiscordRPC.Converters;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Payload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The possible commands that can be sent and received by the server.
|
|
||||||
/// </summary>
|
|
||||||
internal enum Command
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// event dispatch
|
|
||||||
/// </summary>
|
|
||||||
[EnumValue("DISPATCH")]
|
|
||||||
Dispatch,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to set the activity
|
|
||||||
/// </summary>
|
|
||||||
[EnumValue("SET_ACTIVITY")]
|
|
||||||
SetActivity,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to subscribe to an RPC event
|
|
||||||
/// </summary>
|
|
||||||
[EnumValue("SUBSCRIBE")]
|
|
||||||
Subscribe,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to unsubscribe from an RPC event
|
|
||||||
/// </summary>
|
|
||||||
[EnumValue("UNSUBSCRIBE")]
|
|
||||||
Unsubscribe,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to accept join requests.
|
|
||||||
/// </summary>
|
|
||||||
[EnumValue("SEND_ACTIVITY_JOIN_INVITE")]
|
|
||||||
SendActivityJoinInvite,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to reject join requests.
|
|
||||||
/// </summary>
|
|
||||||
[EnumValue("CLOSE_ACTIVITY_JOIN_REQUEST")]
|
|
||||||
CloseActivityJoinRequest,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to authorize a new client with your app
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
Authorize,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to authenticate an existing client with your app
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
Authenticate,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to retrieve guild information from the client
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
GetGuild,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to retrieve a list of guilds from the client
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
GetGuilds,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to retrieve channel information from the client
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
GetChannel,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to retrieve a list of channels for a guild from the client
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
GetChannels,
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to change voice settings of users in voice channels
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
SetUserVoiceSettings,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to join or leave a voice channel, group dm, or dm
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
SelectVoiceChannel,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to get the current voice channel the client is in
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
GetSelectedVoiceChannel,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to join or leave a text channel, group dm, or dm
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
SelectTextChannel,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to retrieve the client's voice settings
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
GetVoiceSettings,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to set the client's voice settings
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
SetVoiceSettings,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// used to capture a keyboard shortcut entered by the user RPC Events
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
|
||||||
CaptureShortcut
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
using DiscordRPC.Converters;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Payload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Base Payload that is received by both client and server
|
|
||||||
/// </summary>
|
|
||||||
internal abstract class IPayload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The type of payload
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("cmd"), JsonConverter(typeof(EnumSnakeCaseConverter))]
|
|
||||||
public Command Command { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A incremental value to help identify payloads
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("nonce")]
|
|
||||||
public string Nonce { get; set; }
|
|
||||||
|
|
||||||
protected IPayload() { }
|
|
||||||
protected IPayload(long nonce)
|
|
||||||
{
|
|
||||||
Nonce = nonce.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Payload || Command: " + Command.ToString() + ", Nonce: " + (Nonce != null ? Nonce.ToString() : "NULL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
|||||||
using DiscordRPC.Converters;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Payload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The payload that is sent by the client to discord for events such as setting the rich presence.
|
|
||||||
/// <para>
|
|
||||||
/// SetPrecense
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
internal class ArgumentPayload : IPayload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The data the server sent too us
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("args", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public JObject Arguments { get; set; }
|
|
||||||
|
|
||||||
public ArgumentPayload() : base() { Arguments = null; }
|
|
||||||
public ArgumentPayload(long nonce) : base(nonce) { Arguments = null; }
|
|
||||||
public ArgumentPayload(object args, long nonce) : base(nonce)
|
|
||||||
{
|
|
||||||
SetObject(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the obejct stored within the data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
public void SetObject(object obj)
|
|
||||||
{
|
|
||||||
Arguments = JObject.FromObject(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the object stored within the Data
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public T GetObject<T>()
|
|
||||||
{
|
|
||||||
return Arguments.ToObject<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Argument " + base.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
|||||||
using DiscordRPC.Converters;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Payload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Used for Discord IPC Events
|
|
||||||
/// </summary>
|
|
||||||
internal class EventPayload : IPayload
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The data the server sent too us
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
|
|
||||||
public JObject Data { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The type of event the server sent
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("evt"), JsonConverter(typeof(EnumSnakeCaseConverter))]
|
|
||||||
public ServerEvent? Event { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a payload with empty data
|
|
||||||
/// </summary>
|
|
||||||
public EventPayload() : base() { Data = null; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a payload with empty data and a set nonce
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="nonce"></param>
|
|
||||||
public EventPayload(long nonce) : base(nonce) { Data = null; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the object stored within the Data
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <returns></returns>
|
|
||||||
public T GetObject<T>()
|
|
||||||
{
|
|
||||||
if (Data == null) return default(T);
|
|
||||||
return Data.ToObject<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts the object into a human readable string
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return "Event " + base.ToString() + ", Event: " + (Event.HasValue ? Event.ToString() : "N/A");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,869 +0,0 @@
|
|||||||
using DiscordRPC.Helper;
|
|
||||||
using DiscordRPC.Message;
|
|
||||||
using DiscordRPC.IO;
|
|
||||||
using DiscordRPC.RPC.Commands;
|
|
||||||
using DiscordRPC.RPC.Payload;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using DiscordRPC.Logging;
|
|
||||||
using DiscordRPC.Events;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Communicates between the client and discord through RPC
|
|
||||||
/// </summary>
|
|
||||||
internal class RpcConnection : IDisposable
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Version of the RPC Protocol
|
|
||||||
/// </summary>
|
|
||||||
public static readonly int VERSION = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The rate of poll to the discord pipe.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly int POLL_RATE = 1000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should we send a null presence on the fairwells?
|
|
||||||
/// </summary>
|
|
||||||
private static readonly bool CLEAR_ON_SHUTDOWN = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should we work in a lock step manner? This option is semi-obsolete and may not work as expected.
|
|
||||||
/// </summary>
|
|
||||||
private static readonly bool LOCK_STEP = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The logger used by the RPC connection
|
|
||||||
/// </summary>
|
|
||||||
public ILogger Logger
|
|
||||||
{
|
|
||||||
get { return _logger; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_logger = value;
|
|
||||||
if (namedPipe != null)
|
|
||||||
namedPipe.Logger = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private ILogger _logger;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a message is received from the RPC and is about to be enqueued. This is cross-thread and will execute on the RPC thread.
|
|
||||||
/// </summary>
|
|
||||||
public event OnRpcMessageEvent OnRpcMessage;
|
|
||||||
|
|
||||||
#region States
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current state of the RPC connection
|
|
||||||
/// </summary>
|
|
||||||
public RpcState State { get { var tmp = RpcState.Disconnected; lock (l_states) tmp = _state; return tmp; } }
|
|
||||||
private RpcState _state;
|
|
||||||
private readonly object l_states = new object();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The configuration received by the Ready
|
|
||||||
/// </summary>
|
|
||||||
public Configuration Configuration { get { Configuration tmp = null; lock (l_config) tmp = _configuration; return tmp; } }
|
|
||||||
private Configuration _configuration = null;
|
|
||||||
private readonly object l_config = new object();
|
|
||||||
|
|
||||||
private volatile bool aborting = false;
|
|
||||||
private volatile bool shutdown = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates if the RPC connection is still running in the background
|
|
||||||
/// </summary>
|
|
||||||
public bool IsRunning { get { return thread != null; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Forces the <see cref="Close"/> to call <see cref="Shutdown"/> instead, safely saying goodbye to Discord.
|
|
||||||
/// <para>This option helps prevents ghosting in applications where the Process ID is a host and the game is executed within the host (ie: the Unity3D editor). This will tell Discord that we have no presence and we are closing the connection manually, instead of waiting for the process to terminate.</para>
|
|
||||||
/// </summary>
|
|
||||||
public bool ShutdownOnly { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Privates
|
|
||||||
|
|
||||||
private string applicationID; //ID of the Discord APP
|
|
||||||
private int processID; //ID of the process to track
|
|
||||||
|
|
||||||
private long nonce; //Current command index
|
|
||||||
|
|
||||||
private Thread thread; //The current thread
|
|
||||||
private INamedPipeClient namedPipe;
|
|
||||||
|
|
||||||
private int targetPipe; //The pipe to taget. Leave as -1 for any available pipe.
|
|
||||||
|
|
||||||
private readonly object l_rtqueue = new object(); //Lock for the send queue
|
|
||||||
private readonly uint _maxRtQueueSize;
|
|
||||||
private Queue<ICommand> _rtqueue; //The send queue
|
|
||||||
|
|
||||||
private readonly object l_rxqueue = new object(); //Lock for the receive queue
|
|
||||||
private readonly uint _maxRxQueueSize; //The max size of the RX queue
|
|
||||||
private Queue<IMessage> _rxqueue; //The receive queue
|
|
||||||
|
|
||||||
private AutoResetEvent queueUpdatedEvent = new AutoResetEvent(false);
|
|
||||||
private BackoffDelay delay; //The backoff delay before reconnecting.
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the RPC.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="applicationID">The ID of the Discord App</param>
|
|
||||||
/// <param name="processID">The ID of the currently running process</param>
|
|
||||||
/// <param name="targetPipe">The target pipe to connect too</param>
|
|
||||||
/// <param name="client">The pipe client we shall use.</param>
|
|
||||||
/// <param name="maxRxQueueSize">The maximum size of the out queue</param>
|
|
||||||
/// <param name="maxRtQueueSize">The maximum size of the in queue</param>
|
|
||||||
public RpcConnection(string applicationID, int processID, int targetPipe, INamedPipeClient client, uint maxRxQueueSize = 128, uint maxRtQueueSize = 512)
|
|
||||||
{
|
|
||||||
this.applicationID = applicationID;
|
|
||||||
this.processID = processID;
|
|
||||||
this.targetPipe = targetPipe;
|
|
||||||
this.namedPipe = client;
|
|
||||||
this.ShutdownOnly = true;
|
|
||||||
|
|
||||||
//Assign a default logger
|
|
||||||
Logger = new ConsoleLogger();
|
|
||||||
|
|
||||||
delay = new BackoffDelay(500, 60 * 1000);
|
|
||||||
_maxRtQueueSize = maxRtQueueSize;
|
|
||||||
_rtqueue = new Queue<ICommand>((int)_maxRtQueueSize + 1);
|
|
||||||
|
|
||||||
_maxRxQueueSize = maxRxQueueSize;
|
|
||||||
_rxqueue = new Queue<IMessage>((int)_maxRxQueueSize + 1);
|
|
||||||
|
|
||||||
nonce = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private long GetNextNonce()
|
|
||||||
{
|
|
||||||
nonce += 1;
|
|
||||||
return nonce;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Queues
|
|
||||||
/// <summary>
|
|
||||||
/// Enqueues a command
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="command">The command to enqueue</param>
|
|
||||||
internal void EnqueueCommand(ICommand command)
|
|
||||||
{
|
|
||||||
Logger.Trace("Enqueue Command: " + command.GetType().FullName);
|
|
||||||
|
|
||||||
//We cannot add anything else if we are aborting or shutting down.
|
|
||||||
if (aborting || shutdown) return;
|
|
||||||
|
|
||||||
//Enqueue the set presence argument
|
|
||||||
lock (l_rtqueue)
|
|
||||||
{
|
|
||||||
//If we are too big drop the last element
|
|
||||||
if (_rtqueue.Count == _maxRtQueueSize)
|
|
||||||
{
|
|
||||||
Logger.Error("Too many enqueued commands, dropping oldest one. Maybe you are pushing new presences to fast?");
|
|
||||||
_rtqueue.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Enqueue the message
|
|
||||||
_rtqueue.Enqueue(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a message to the message queue. Does not copy the message, so besure to copy it yourself or dereference it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">The message to add</param>
|
|
||||||
private void EnqueueMessage(IMessage message)
|
|
||||||
{
|
|
||||||
//Invoke the message
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (OnRpcMessage != null)
|
|
||||||
OnRpcMessage.Invoke(this, message);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Error("Unhandled Exception while processing event: {0}", e.GetType().FullName);
|
|
||||||
Logger.Error(e.Message);
|
|
||||||
Logger.Error(e.StackTrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Small queue sizes should just ignore messages
|
|
||||||
if (_maxRxQueueSize <= 0)
|
|
||||||
{
|
|
||||||
Logger.Trace("Enqueued Message, but queue size is 0.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Large queue sizes should keep the queue in check
|
|
||||||
Logger.Trace("Enqueue Message: " + message.Type);
|
|
||||||
lock (l_rxqueue)
|
|
||||||
{
|
|
||||||
//If we are too big drop the last element
|
|
||||||
if (_rxqueue.Count == _maxRxQueueSize)
|
|
||||||
{
|
|
||||||
Logger.Warning("Too many enqueued messages, dropping oldest one.");
|
|
||||||
_rxqueue.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Enqueue the message
|
|
||||||
_rxqueue.Enqueue(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dequeues a single message from the event stack. Returns null if none are available.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal IMessage DequeueMessage()
|
|
||||||
{
|
|
||||||
//Logger.Trace("Deque Message");
|
|
||||||
lock (l_rxqueue)
|
|
||||||
{
|
|
||||||
//We have nothing, so just return null.
|
|
||||||
if (_rxqueue.Count == 0) return null;
|
|
||||||
|
|
||||||
//Get the value and remove it from the list at the same time
|
|
||||||
return _rxqueue.Dequeue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dequeues all messages from the event stack.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal IMessage[] DequeueMessages()
|
|
||||||
{
|
|
||||||
//Logger.Trace("Deque Multiple Messages");
|
|
||||||
lock (l_rxqueue)
|
|
||||||
{
|
|
||||||
//Copy the messages into an array
|
|
||||||
IMessage[] messages = _rxqueue.ToArray();
|
|
||||||
|
|
||||||
//Clear the entire queue
|
|
||||||
_rxqueue.Clear();
|
|
||||||
|
|
||||||
//return the array
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Main thread loop
|
|
||||||
/// </summary>
|
|
||||||
private void MainLoop()
|
|
||||||
{
|
|
||||||
//initialize the pipe
|
|
||||||
Logger.Info("RPC Connection Started");
|
|
||||||
if (Logger.Level <= LogLevel.Trace)
|
|
||||||
{
|
|
||||||
Logger.Trace("============================");
|
|
||||||
Logger.Trace("Assembly: " + System.Reflection.Assembly.GetAssembly(typeof(RichPresence)).FullName);
|
|
||||||
Logger.Trace("Pipe: " + namedPipe.GetType().FullName);
|
|
||||||
Logger.Trace("Platform: " + Environment.OSVersion.ToString());
|
|
||||||
Logger.Trace("applicationID: " + applicationID);
|
|
||||||
Logger.Trace("targetPipe: " + targetPipe);
|
|
||||||
Logger.Trace("POLL_RATE: " + POLL_RATE);
|
|
||||||
Logger.Trace("_maxRtQueueSize: " + _maxRtQueueSize);
|
|
||||||
Logger.Trace("_maxRxQueueSize: " + _maxRxQueueSize);
|
|
||||||
Logger.Trace("============================");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Forever trying to connect unless the abort signal is sent
|
|
||||||
//Keep Alive Loop
|
|
||||||
while (!aborting && !shutdown)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Wrap everything up in a try get
|
|
||||||
//Dispose of the pipe if we have any (could be broken)
|
|
||||||
if (namedPipe == null)
|
|
||||||
{
|
|
||||||
Logger.Error("Something bad has happened with our pipe client!");
|
|
||||||
aborting = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Connect to a new pipe
|
|
||||||
Logger.Trace("Connecting to the pipe through the {0}", namedPipe.GetType().FullName);
|
|
||||||
if (namedPipe.Connect(targetPipe))
|
|
||||||
{
|
|
||||||
#region Connected
|
|
||||||
//We connected to a pipe! Reset the delay
|
|
||||||
Logger.Trace("Connected to the pipe. Attempting to establish handshake...");
|
|
||||||
EnqueueMessage(new ConnectionEstablishedMessage() { ConnectedPipe = namedPipe.ConnectedPipe });
|
|
||||||
|
|
||||||
//Attempt to establish a handshake
|
|
||||||
EstablishHandshake();
|
|
||||||
Logger.Trace("Connection Established. Starting reading loop...");
|
|
||||||
|
|
||||||
//Continously iterate, waiting for the frame
|
|
||||||
//We want to only stop reading if the inside tells us (mainloop), if we are aborting (abort) or the pipe disconnects
|
|
||||||
// We dont want to exit on a shutdown, as we still have information
|
|
||||||
PipeFrame frame;
|
|
||||||
bool mainloop = true;
|
|
||||||
while (mainloop && !aborting && !shutdown && namedPipe.IsConnected)
|
|
||||||
{
|
|
||||||
#region Read Loop
|
|
||||||
|
|
||||||
//Iterate over every frame we have queued up, processing its contents
|
|
||||||
if (namedPipe.ReadFrame(out frame))
|
|
||||||
{
|
|
||||||
#region Read Payload
|
|
||||||
Logger.Trace("Read Payload: {0}", frame.Opcode);
|
|
||||||
|
|
||||||
//Do some basic processing on the frame
|
|
||||||
switch (frame.Opcode)
|
|
||||||
{
|
|
||||||
//We have been told by discord to close, so we will consider it an abort
|
|
||||||
case Opcode.Close:
|
|
||||||
|
|
||||||
ClosePayload close = frame.GetObject<ClosePayload>();
|
|
||||||
Logger.Warning("We have been told to terminate by discord: ({0}) {1}", close.Code, close.Reason);
|
|
||||||
EnqueueMessage(new CloseMessage() { Code = close.Code, Reason = close.Reason });
|
|
||||||
mainloop = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//We have pinged, so we will flip it and respond back with pong
|
|
||||||
case Opcode.Ping:
|
|
||||||
Logger.Trace("PING");
|
|
||||||
frame.Opcode = Opcode.Pong;
|
|
||||||
namedPipe.WriteFrame(frame);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//We have ponged? I have no idea if Discord actually sends ping/pongs.
|
|
||||||
case Opcode.Pong:
|
|
||||||
Logger.Trace("PONG");
|
|
||||||
break;
|
|
||||||
|
|
||||||
//A frame has been sent, we should deal with that
|
|
||||||
case Opcode.Frame:
|
|
||||||
if (shutdown)
|
|
||||||
{
|
|
||||||
//We are shutting down, so skip it
|
|
||||||
Logger.Warning("Skipping frame because we are shutting down.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame.Data == null)
|
|
||||||
{
|
|
||||||
//We have invalid data, thats not good.
|
|
||||||
Logger.Error("We received no data from the frame so we cannot get the event payload!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//We have a frame, so we are going to process the payload and add it to the stack
|
|
||||||
EventPayload response = null;
|
|
||||||
try { response = frame.GetObject<EventPayload>(); } catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Error("Failed to parse event! " + e.Message);
|
|
||||||
Logger.Error("Data: " + frame.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response != null) ProcessFrame(response);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
|
||||||
case Opcode.Handshake:
|
|
||||||
//We have a invalid opcode, better terminate to be safe
|
|
||||||
Logger.Error("Invalid opcode: {0}", frame.Opcode);
|
|
||||||
mainloop = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aborting && namedPipe.IsConnected)
|
|
||||||
{
|
|
||||||
//Process the entire command queue we have left
|
|
||||||
ProcessCommandQueue();
|
|
||||||
|
|
||||||
//Wait for some time, or until a command has been queued up
|
|
||||||
queueUpdatedEvent.WaitOne(POLL_RATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
Logger.Trace("Left main read loop for some reason. Aborting: {0}, Shutting Down: {1}", aborting, shutdown);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Error("Failed to connect for some reason.");
|
|
||||||
EnqueueMessage(new ConnectionFailedMessage() { FailedPipe = targetPipe });
|
|
||||||
}
|
|
||||||
|
|
||||||
//If we are not aborting, we have to wait a bit before trying to connect again
|
|
||||||
if (!aborting && !shutdown)
|
|
||||||
{
|
|
||||||
//We have disconnected for some reason, either a failed pipe or a bad reading,
|
|
||||||
// so we are going to wait a bit before doing it again
|
|
||||||
long sleep = delay.NextDelay();
|
|
||||||
|
|
||||||
Logger.Trace("Waiting {0}ms before attempting to connect again", sleep);
|
|
||||||
Thread.Sleep(delay.NextDelay());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//catch(InvalidPipeException e)
|
|
||||||
//{
|
|
||||||
// Logger.Error("Invalid Pipe Exception: {0}", e.Message);
|
|
||||||
//}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Error("Unhandled Exception: {0}", e.GetType().FullName);
|
|
||||||
Logger.Error(e.Message);
|
|
||||||
Logger.Error(e.StackTrace);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
//Disconnect from the pipe because something bad has happened. An exception has been thrown or the main read loop has terminated.
|
|
||||||
if (namedPipe.IsConnected)
|
|
||||||
{
|
|
||||||
//Terminate the pipe
|
|
||||||
Logger.Trace("Closing the named pipe.");
|
|
||||||
namedPipe.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Update our state
|
|
||||||
SetConnectionState(RpcState.Disconnected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//We have disconnected, so dispose of the thread and the pipe.
|
|
||||||
Logger.Trace("Left Main Loop");
|
|
||||||
if (namedPipe != null)
|
|
||||||
namedPipe.Dispose();
|
|
||||||
|
|
||||||
Logger.Info("Thread Terminated, no longer performing RPC connection.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Reading
|
|
||||||
|
|
||||||
/// <summary>Handles the response from the pipe and calls appropriate events and changes states.</summary>
|
|
||||||
/// <param name="response">The response received by the server.</param>
|
|
||||||
private void ProcessFrame(EventPayload response)
|
|
||||||
{
|
|
||||||
Logger.Info("Handling Response. Cmd: {0}, Event: {1}", response.Command, response.Event);
|
|
||||||
|
|
||||||
//Check if it is an error
|
|
||||||
if (response.Event.HasValue && response.Event.Value == ServerEvent.Error)
|
|
||||||
{
|
|
||||||
//We have an error
|
|
||||||
Logger.Error("Error received from the RPC");
|
|
||||||
|
|
||||||
//Create the event objetc and push it to the queue
|
|
||||||
ErrorMessage err = response.GetObject<ErrorMessage>();
|
|
||||||
Logger.Error("Server responded with an error message: ({0}) {1}", err.Code.ToString(), err.Message);
|
|
||||||
|
|
||||||
//Enqueue the messsage and then end
|
|
||||||
EnqueueMessage(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if its a handshake
|
|
||||||
if (State == RpcState.Connecting)
|
|
||||||
{
|
|
||||||
if (response.Command == Command.Dispatch && response.Event.HasValue && response.Event.Value == ServerEvent.Ready)
|
|
||||||
{
|
|
||||||
Logger.Info("Connection established with the RPC");
|
|
||||||
SetConnectionState(RpcState.Connected);
|
|
||||||
delay.Reset();
|
|
||||||
|
|
||||||
//Prepare the object
|
|
||||||
ReadyMessage ready = response.GetObject<ReadyMessage>();
|
|
||||||
lock (l_config)
|
|
||||||
{
|
|
||||||
_configuration = ready.Configuration;
|
|
||||||
ready.User.SetConfiguration(_configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Enqueue the message
|
|
||||||
EnqueueMessage(ready);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (State == RpcState.Connected)
|
|
||||||
{
|
|
||||||
switch(response.Command)
|
|
||||||
{
|
|
||||||
//We were sent a dispatch, better process it
|
|
||||||
case Command.Dispatch:
|
|
||||||
ProcessDispatch(response);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//We were sent a Activity Update, better enqueue it
|
|
||||||
case Command.SetActivity:
|
|
||||||
if (response.Data == null)
|
|
||||||
{
|
|
||||||
EnqueueMessage(new PresenceMessage());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RichPresenceResponse rp = response.GetObject<RichPresenceResponse>();
|
|
||||||
EnqueueMessage(new PresenceMessage(rp));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Command.Unsubscribe:
|
|
||||||
case Command.Subscribe:
|
|
||||||
|
|
||||||
//Prepare a serializer that can account for snake_case enums.
|
|
||||||
JsonSerializer serializer = new JsonSerializer();
|
|
||||||
serializer.Converters.Add(new Converters.EnumSnakeCaseConverter());
|
|
||||||
|
|
||||||
//Go through the data, looking for the evt property, casting it to a server event
|
|
||||||
var evt = response.GetObject<EventPayload>().Event.Value;
|
|
||||||
|
|
||||||
//Enqueue the appropriate message.
|
|
||||||
if (response.Command == Command.Subscribe)
|
|
||||||
EnqueueMessage(new SubscribeMessage(evt));
|
|
||||||
else
|
|
||||||
EnqueueMessage(new UnsubscribeMessage(evt));
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case Command.SendActivityJoinInvite:
|
|
||||||
Logger.Trace("Got invite response ack.");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Command.CloseActivityJoinRequest:
|
|
||||||
Logger.Trace("Got invite response reject ack.");
|
|
||||||
break;
|
|
||||||
|
|
||||||
//we have no idea what we were sent
|
|
||||||
default:
|
|
||||||
Logger.Error("Unkown frame was received! {0}", response.Command);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.Trace("Received a frame while we are disconnected. Ignoring. Cmd: {0}, Event: {1}", response.Command, response.Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessDispatch(EventPayload response)
|
|
||||||
{
|
|
||||||
if (response.Command != Command.Dispatch) return;
|
|
||||||
if (!response.Event.HasValue) return;
|
|
||||||
|
|
||||||
switch(response.Event.Value)
|
|
||||||
{
|
|
||||||
//We are to join the server
|
|
||||||
case ServerEvent.ActivitySpectate:
|
|
||||||
var spectate = response.GetObject<SpectateMessage>();
|
|
||||||
EnqueueMessage(spectate);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerEvent.ActivityJoin:
|
|
||||||
var join = response.GetObject<JoinMessage>();
|
|
||||||
EnqueueMessage(join);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerEvent.ActivityJoinRequest:
|
|
||||||
var request = response.GetObject<JoinRequestMessage>();
|
|
||||||
EnqueueMessage(request);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//Unkown dispatch event received. We should just ignore it.
|
|
||||||
default:
|
|
||||||
Logger.Warning("Ignoring {0}", response.Event.Value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Writting
|
|
||||||
|
|
||||||
private void ProcessCommandQueue()
|
|
||||||
{
|
|
||||||
//Logger.Info("Checking command queue");
|
|
||||||
|
|
||||||
//We are not ready yet, dont even try
|
|
||||||
if (State != RpcState.Connected)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//We are aborting, so we will just log a warning so we know this is probably only going to send the CLOSE
|
|
||||||
if (aborting)
|
|
||||||
Logger.Warning("We have been told to write a queue but we have also been aborted.");
|
|
||||||
|
|
||||||
//Prepare some variabels we will clone into with locks
|
|
||||||
bool needsWriting = true;
|
|
||||||
ICommand item = null;
|
|
||||||
|
|
||||||
//Continue looping until we dont need anymore messages
|
|
||||||
while (needsWriting && namedPipe.IsConnected)
|
|
||||||
{
|
|
||||||
lock (l_rtqueue)
|
|
||||||
{
|
|
||||||
//Pull the value and update our writing needs
|
|
||||||
// If we have nothing to write, exit the loop
|
|
||||||
needsWriting = _rtqueue.Count > 0;
|
|
||||||
if (!needsWriting) break;
|
|
||||||
|
|
||||||
//Peek at the item
|
|
||||||
item = _rtqueue.Peek();
|
|
||||||
}
|
|
||||||
|
|
||||||
//BReak out of the loop as soon as we send this item
|
|
||||||
if (shutdown || (!aborting && LOCK_STEP))
|
|
||||||
needsWriting = false;
|
|
||||||
|
|
||||||
//Prepare the payload
|
|
||||||
IPayload payload = item.PreparePayload(GetNextNonce());
|
|
||||||
Logger.Trace("Attempting to send payload: " + payload.Command);
|
|
||||||
|
|
||||||
//Prepare the frame
|
|
||||||
PipeFrame frame = new PipeFrame();
|
|
||||||
if (item is CloseCommand)
|
|
||||||
{
|
|
||||||
//We have been sent a close frame. We better just send a handwave
|
|
||||||
//Send it off to the server
|
|
||||||
SendHandwave();
|
|
||||||
|
|
||||||
//Queue the item
|
|
||||||
Logger.Trace("Handwave sent, ending queue processing.");
|
|
||||||
lock (l_rtqueue) _rtqueue.Dequeue();
|
|
||||||
|
|
||||||
//Stop sending any more messages
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (aborting)
|
|
||||||
{
|
|
||||||
//We are aborting, so just dequeue the message and dont bother sending it
|
|
||||||
Logger.Warning("- skipping frame because of abort.");
|
|
||||||
lock (l_rtqueue) _rtqueue.Dequeue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Prepare the frame
|
|
||||||
frame.SetObject(Opcode.Frame, payload);
|
|
||||||
|
|
||||||
//Write it and if it wrote perfectly fine, we will dequeue it
|
|
||||||
Logger.Trace("Sending payload: " + payload.Command);
|
|
||||||
if (namedPipe.WriteFrame(frame))
|
|
||||||
{
|
|
||||||
//We sent it, so now dequeue it
|
|
||||||
Logger.Trace("Sent Successfully.");
|
|
||||||
lock (l_rtqueue) _rtqueue.Dequeue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Something went wrong, so just giveup and wait for the next time around.
|
|
||||||
Logger.Warning("Something went wrong during writing!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Connection
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Establishes the handshake with the server.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
private void EstablishHandshake()
|
|
||||||
{
|
|
||||||
Logger.Trace("Attempting to establish a handshake...");
|
|
||||||
|
|
||||||
//We are establishing a lock and not releasing it until we sent the handshake message.
|
|
||||||
// We need to set the key, and it would not be nice if someone did things between us setting the key.
|
|
||||||
|
|
||||||
//Check its state
|
|
||||||
if (State != RpcState.Disconnected)
|
|
||||||
{
|
|
||||||
Logger.Error("State must be disconnected in order to start a handshake!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Send it off to the server
|
|
||||||
Logger.Trace("Sending Handshake...");
|
|
||||||
if (!namedPipe.WriteFrame(new PipeFrame(Opcode.Handshake, new Handshake() { Version = VERSION, ClientID = applicationID })))
|
|
||||||
{
|
|
||||||
Logger.Error("Failed to write a handshake.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//This has to be done outside the lock
|
|
||||||
SetConnectionState(RpcState.Connecting);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Establishes a fairwell with the server by sending a handwave.
|
|
||||||
/// </summary>
|
|
||||||
private void SendHandwave()
|
|
||||||
{
|
|
||||||
Logger.Info("Attempting to wave goodbye...");
|
|
||||||
|
|
||||||
//Check its state
|
|
||||||
if (State == RpcState.Disconnected)
|
|
||||||
{
|
|
||||||
Logger.Error("State must NOT be disconnected in order to send a handwave!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Send the handwave
|
|
||||||
if (!namedPipe.WriteFrame(new PipeFrame(Opcode.Close, new Handshake() { Version = VERSION, ClientID = applicationID })))
|
|
||||||
{
|
|
||||||
Logger.Error("failed to write a handwave.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to connect to the pipe. Returns true on success
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool AttemptConnection()
|
|
||||||
{
|
|
||||||
Logger.Info("Attempting a new connection");
|
|
||||||
|
|
||||||
//The thread mustn't exist already
|
|
||||||
if (thread != null)
|
|
||||||
{
|
|
||||||
Logger.Error("Cannot attempt a new connection as the previous connection thread is not null!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//We have to be in the disconnected state
|
|
||||||
if (State != RpcState.Disconnected)
|
|
||||||
{
|
|
||||||
Logger.Warning("Cannot attempt a new connection as the previous connection hasn't changed state yet.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aborting)
|
|
||||||
{
|
|
||||||
Logger.Error("Cannot attempt a new connection while aborting!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Start the thread up
|
|
||||||
thread = new Thread(MainLoop);
|
|
||||||
thread.Name = "Discord IPC Thread";
|
|
||||||
thread.IsBackground = true;
|
|
||||||
thread.Start();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the current state of the pipe, locking the l_states object for thread saftey.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="state">The state to set it too.</param>
|
|
||||||
private void SetConnectionState(RpcState state)
|
|
||||||
{
|
|
||||||
Logger.Trace("Setting the connection state to {0}", state.ToString().ToSnakeCase().ToUpperInvariant());
|
|
||||||
lock (l_states)
|
|
||||||
{
|
|
||||||
_state = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Closes the connection and disposes of resources. This will not force termination, but instead allow Discord disconnect us after we say goodbye.
|
|
||||||
/// <para>This option helps prevents ghosting in applications where the Process ID is a host and the game is executed within the host (ie: the Unity3D editor). This will tell Discord that we have no presence and we are closing the connection manually, instead of waiting for the process to terminate.</para>
|
|
||||||
/// </summary>
|
|
||||||
public void Shutdown()
|
|
||||||
{
|
|
||||||
//Enable the flag
|
|
||||||
Logger.Trace("Initiated shutdown procedure");
|
|
||||||
shutdown = true;
|
|
||||||
|
|
||||||
//Clear the commands and enqueue the close
|
|
||||||
lock(l_rtqueue)
|
|
||||||
{
|
|
||||||
_rtqueue.Clear();
|
|
||||||
if (CLEAR_ON_SHUTDOWN) _rtqueue.Enqueue(new PresenceCommand() { PID = processID, Presence = null });
|
|
||||||
_rtqueue.Enqueue(new CloseCommand());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Trigger the event
|
|
||||||
queueUpdatedEvent.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Closes the connection and disposes of resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Close()
|
|
||||||
{
|
|
||||||
if (thread == null)
|
|
||||||
{
|
|
||||||
Logger.Error("Cannot close as it is not available!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aborting)
|
|
||||||
{
|
|
||||||
Logger.Error("Cannot abort as it has already been aborted");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Set the abort state
|
|
||||||
if (ShutdownOnly)
|
|
||||||
{
|
|
||||||
Shutdown();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Terminate
|
|
||||||
Logger.Trace("Updating Abort State...");
|
|
||||||
aborting = true;
|
|
||||||
queueUpdatedEvent.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Closes the connection and disposes resources. Identical to <see cref="Close"/> but ignores the "ShutdownOnly" value.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
ShutdownOnly = false;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// State of the RPC connection
|
|
||||||
/// </summary>
|
|
||||||
internal enum RpcState
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Disconnected from the discord client
|
|
||||||
/// </summary>
|
|
||||||
Disconnected,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Connecting to the discord client. The handshake has been sent and we are awaiting the ready event
|
|
||||||
/// </summary>
|
|
||||||
Connecting,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// We are connect to the client and can send and receive messages.
|
|
||||||
/// </summary>
|
|
||||||
Connected
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,229 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Object representing a Discord user. This is used for join requests.
|
|
||||||
/// </summary>
|
|
||||||
public class User
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Possible formats for avatars
|
|
||||||
/// </summary>
|
|
||||||
public enum AvatarFormat
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Portable Network Graphics format (.png)
|
|
||||||
/// <para>Losses format that supports transparent avatars. Most recommended for stationary formats with wide support from many libraries.</para>
|
|
||||||
/// </summary>
|
|
||||||
PNG,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Joint Photographic Experts Group format (.jpeg)
|
|
||||||
/// <para>The format most cameras use. Lossy and does not support transparent avatars.</para>
|
|
||||||
/// </summary>
|
|
||||||
JPEG,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// WebP format (.webp)
|
|
||||||
/// <para>Picture only version of WebM. Pronounced "weeb p".</para>
|
|
||||||
/// </summary>
|
|
||||||
WebP,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Graphics Interchange Format (.gif)
|
|
||||||
/// <para>Animated avatars that Discord Nitro users are able to use. If the user doesn't have an animated avatar, then it will just be a single frame gif.</para>
|
|
||||||
/// </summary>
|
|
||||||
GIF //Gif, as in gift.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Possible square sizes of avatars.
|
|
||||||
/// </summary>
|
|
||||||
public enum AvatarSize
|
|
||||||
{
|
|
||||||
/// <summary> 16 x 16 pixels.</summary>
|
|
||||||
x16 = 16,
|
|
||||||
/// <summary> 32 x 32 pixels.</summary>
|
|
||||||
x32 = 32,
|
|
||||||
/// <summary> 64 x 64 pixels.</summary>
|
|
||||||
x64 = 64,
|
|
||||||
/// <summary> 128 x 128 pixels.</summary>
|
|
||||||
x128 = 128,
|
|
||||||
/// <summary> 256 x 256 pixels.</summary>
|
|
||||||
x256 = 256,
|
|
||||||
/// <summary> 512 x 512 pixels.</summary>
|
|
||||||
x512 = 512,
|
|
||||||
/// <summary> 1024 x 1024 pixels.</summary>
|
|
||||||
x1024 = 1024,
|
|
||||||
/// <summary> 2048 x 2048 pixels.</summary>
|
|
||||||
x2048 = 2048
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The snowflake ID of the user.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("id")]
|
|
||||||
public ulong ID { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The username of the player.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("username")]
|
|
||||||
public string Username { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The discriminator of the user.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("discriminator")]
|
|
||||||
public int Discriminator { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The avatar hash of the user. Too get a URL for the avatar, use the <see cref="GetAvatarURL(AvatarFormat, AvatarSize)"/>. This can be null if the user has no avatar. The <see cref="GetAvatarURL(AvatarFormat, AvatarSize)"/> will account for this and return the discord default.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("avatar")]
|
|
||||||
public string Avatar { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The flags on a users account, often represented as a badge.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("flags")]
|
|
||||||
public Flag Flags { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A flag on the user account
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum Flag
|
|
||||||
{
|
|
||||||
/// <summary>No flag</summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>Staff of Discord.</summary>
|
|
||||||
Employee = 1 << 0,
|
|
||||||
|
|
||||||
/// <summary>Partners of Discord.</summary>
|
|
||||||
Partner = 1 << 1,
|
|
||||||
|
|
||||||
/// <summary>Original HypeSquad which organise events.</summary>
|
|
||||||
HypeSquad = 1 << 2,
|
|
||||||
|
|
||||||
/// <summary>Bug Hunters that found and reported bugs in Discord.</summary>
|
|
||||||
BugHunter = 1 << 3,
|
|
||||||
|
|
||||||
//These 2 are mistery types
|
|
||||||
//A = 1 << 4,
|
|
||||||
//B = 1 << 5,
|
|
||||||
|
|
||||||
/// <summary>The HypeSquad House of Bravery.</summary>
|
|
||||||
HouseBravery = 1 << 6,
|
|
||||||
|
|
||||||
/// <summary>The HypeSquad House of Brilliance.</summary>
|
|
||||||
HouseBrilliance = 1 << 7,
|
|
||||||
|
|
||||||
/// <summary>The HypeSquad House of Balance (the best one).</summary>
|
|
||||||
HouseBalance = 1 << 8,
|
|
||||||
|
|
||||||
/// <summary>Early Supporter of Discord and had Nitro before the store was released.</summary>
|
|
||||||
EarlySupporter = 1 << 9,
|
|
||||||
|
|
||||||
/// <summary>Apart of a team.
|
|
||||||
/// <para>Unclear if it is reserved for members that share a team with the current application.</para>
|
|
||||||
/// </summary>
|
|
||||||
TeamUser = 1 << 10
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The premium type of the user.
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("premium_type")]
|
|
||||||
public PremiumType Premium { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Type of premium
|
|
||||||
/// </summary>
|
|
||||||
public enum PremiumType
|
|
||||||
{
|
|
||||||
/// <summary>No subscription to any forms of Nitro.</summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>Nitro Classic subscription. Has chat perks and animated avatars.</summary>
|
|
||||||
NitroClassic = 1,
|
|
||||||
|
|
||||||
/// <summary>Nitro subscription. Has chat perks, animated avatars, server boosting, and access to free Nitro Games.</summary>
|
|
||||||
Nitro = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The endpoint for the CDN. Normally cdn.discordapp.com.
|
|
||||||
/// </summary>
|
|
||||||
public string CdnEndpoint { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new User instance.
|
|
||||||
/// </summary>
|
|
||||||
internal User()
|
|
||||||
{
|
|
||||||
CdnEndpoint = "cdn.discordapp.com";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the URL paths to the appropriate configuration
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="configuration">The configuration received by the OnReady event.</param>
|
|
||||||
internal void SetConfiguration(Configuration configuration)
|
|
||||||
{
|
|
||||||
this.CdnEndpoint = configuration.CdnHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a URL that can be used to download the user's avatar. If the user has not yet set their avatar, it will return the default one that discord is using. The default avatar only supports the <see cref="AvatarFormat.PNG"/> format.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format">The format of the target avatar</param>
|
|
||||||
/// <param name="size">The optional size of the avatar you wish for. Defaults to x128.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public string GetAvatarURL(AvatarFormat format, AvatarSize size = AvatarSize.x128)
|
|
||||||
{
|
|
||||||
//Prepare the endpoint
|
|
||||||
string endpoint = "/avatars/" + ID + "/" + Avatar;
|
|
||||||
|
|
||||||
//The user has no avatar, so we better replace it with the default
|
|
||||||
if (string.IsNullOrEmpty(Avatar))
|
|
||||||
{
|
|
||||||
//Make sure we are only using PNG
|
|
||||||
if (format != AvatarFormat.PNG)
|
|
||||||
throw new BadImageFormatException("The user has no avatar and the requested format " + format.ToString() + " is not supported. (Only supports PNG).");
|
|
||||||
|
|
||||||
//Get the endpoint
|
|
||||||
int descrim = Discriminator % 5;
|
|
||||||
endpoint = "/embed/avatars/" + descrim;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Finish of the endpoint
|
|
||||||
return string.Format("https://{0}{1}{2}?size={3}", this.CdnEndpoint, endpoint, GetAvatarExtension(format), (int)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the file extension of the specified format.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format">The format to get the extention off</param>
|
|
||||||
/// <returns>Returns a period prefixed file extension.</returns>
|
|
||||||
public string GetAvatarExtension(AvatarFormat format)
|
|
||||||
{
|
|
||||||
return "." + format.ToString().ToLowerInvariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Formats the user into username#discriminator
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Username + "#" + Discriminator.ToString("D4");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
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("Show on Discord what are you listening on AIRSPY SDR#")]
|
|
||||||
[assembly: AssemblyDescription("Show on Discord what are you listening on AIRSPY SDR#")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("SDR# Discord RPC Plugin")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © EnderIce2 2023")]
|
|
||||||
[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("72e8628f-ba39-4915-bf3c-dd48bf477d30")]
|
|
||||||
|
|
||||||
// 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.2.0.2")]
|
|
||||||
[assembly: AssemblyFileVersion("1.2.0.2")]
|
|
73
Properties/Resources.Designer.cs
generated
73
Properties/Resources.Designer.cs
generated
@ -1,73 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// <auto-generated>
|
|
||||||
// This code was generated by a tool.
|
|
||||||
// Runtime Version:4.0.30319.42000
|
|
||||||
//
|
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
|
||||||
// the code is regenerated.
|
|
||||||
// </auto-generated>
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace DiscordRPC.Properties {
|
|
||||||
using System;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
|
||||||
/// </summary>
|
|
||||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
|
||||||
// class via a tool like ResGen or Visual Studio.
|
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
|
||||||
// with the /str option, or rebuild your VS project.
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
|
||||||
internal class Resources {
|
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
|
||||||
|
|
||||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
|
||||||
|
|
||||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
|
||||||
internal Resources() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the cached ResourceManager instance used by this class.
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
|
||||||
get {
|
|
||||||
if (object.ReferenceEquals(resourceMan, null)) {
|
|
||||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DiscordRPC.Properties.Resources", typeof(Resources).Assembly);
|
|
||||||
resourceMan = temp;
|
|
||||||
}
|
|
||||||
return resourceMan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overrides the current thread's CurrentUICulture property for all
|
|
||||||
/// resource lookups using this strongly typed resource class.
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Globalization.CultureInfo Culture {
|
|
||||||
get {
|
|
||||||
return resourceCulture;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
resourceCulture = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap gear {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("gear", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
<add key="Discord RPC" value="EnderIce2.SDRSharpPlugin.MainPlugin,SDR-RPC" />
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB |
31
SDR-RPC.sln
Normal file
31
SDR-RPC.sln
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.3.32901.215
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SDR-RPC", "SDR-RPC\SDR-RPC.csproj", "{7249303D-EB57-44E6-B270-942A0D54A8AB}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{7249303D-EB57-44E6-B270-942A0D54A8AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7249303D-EB57-44E6-B270-942A0D54A8AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7249303D-EB57-44E6-B270-942A0D54A8AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7249303D-EB57-44E6-B270-942A0D54A8AB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {7ECEC65D-47BE-487D-BC90-9BC261B61569}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SubversionScc) = preSolution
|
||||||
|
Svn-Managed = True
|
||||||
|
Manager = AnkhSVN - Subversion Support for Visual Studio
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(Performance) = preSolution
|
||||||
|
HasPerformanceSessions = true
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
199
SDR-RPC/ControlPanel.Designer.cs
generated
Normal file
199
SDR-RPC/ControlPanel.Designer.cs
generated
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
namespace EnderIce2.SDRSharpPlugin
|
||||||
|
{
|
||||||
|
partial class ControlPanel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Component Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||||
|
groupBox1 = new System.Windows.Forms.GroupBox();
|
||||||
|
helpBtn = new System.Windows.Forms.Button();
|
||||||
|
creditsBtn = new System.Windows.Forms.Button();
|
||||||
|
dbgCheckBox = new System.Windows.Forms.CheckBox();
|
||||||
|
IDtxtBox = new System.Windows.Forms.TextBox();
|
||||||
|
label2 = new System.Windows.Forms.Label();
|
||||||
|
groupBox2 = new System.Windows.Forms.GroupBox();
|
||||||
|
statusLbl = new System.Windows.Forms.Label();
|
||||||
|
versionLbl = new System.Windows.Forms.Label();
|
||||||
|
tableLayoutPanel1.SuspendLayout();
|
||||||
|
groupBox1.SuspendLayout();
|
||||||
|
groupBox2.SuspendLayout();
|
||||||
|
SuspendLayout();
|
||||||
|
//
|
||||||
|
// tableLayoutPanel1
|
||||||
|
//
|
||||||
|
tableLayoutPanel1.AutoScroll = true;
|
||||||
|
tableLayoutPanel1.ColumnCount = 1;
|
||||||
|
tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||||
|
tableLayoutPanel1.Controls.Add(groupBox1, 0, 1);
|
||||||
|
tableLayoutPanel1.Controls.Add(groupBox2, 0, 0);
|
||||||
|
tableLayoutPanel1.Controls.Add(versionLbl, 0, 2);
|
||||||
|
tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
|
||||||
|
tableLayoutPanel1.MinimumSize = new System.Drawing.Size(200, 200);
|
||||||
|
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||||
|
tableLayoutPanel1.RowCount = 3;
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 50F));
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 18F));
|
||||||
|
tableLayoutPanel1.Size = new System.Drawing.Size(200, 200);
|
||||||
|
tableLayoutPanel1.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// groupBox1
|
||||||
|
//
|
||||||
|
groupBox1.AutoSize = true;
|
||||||
|
groupBox1.Controls.Add(helpBtn);
|
||||||
|
groupBox1.Controls.Add(creditsBtn);
|
||||||
|
groupBox1.Controls.Add(dbgCheckBox);
|
||||||
|
groupBox1.Controls.Add(IDtxtBox);
|
||||||
|
groupBox1.Controls.Add(label2);
|
||||||
|
groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
groupBox1.Location = new System.Drawing.Point(3, 53);
|
||||||
|
groupBox1.Name = "groupBox1";
|
||||||
|
groupBox1.Size = new System.Drawing.Size(194, 126);
|
||||||
|
groupBox1.TabIndex = 0;
|
||||||
|
groupBox1.TabStop = false;
|
||||||
|
groupBox1.Text = "Settings";
|
||||||
|
//
|
||||||
|
// helpBtn
|
||||||
|
//
|
||||||
|
helpBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
helpBtn.Location = new System.Drawing.Point(6, 71);
|
||||||
|
helpBtn.Name = "helpBtn";
|
||||||
|
helpBtn.Size = new System.Drawing.Size(67, 23);
|
||||||
|
helpBtn.TabIndex = 2;
|
||||||
|
helpBtn.Text = "Help";
|
||||||
|
helpBtn.UseVisualStyleBackColor = true;
|
||||||
|
helpBtn.Click += helpBtn_Click;
|
||||||
|
//
|
||||||
|
// creditsBtn
|
||||||
|
//
|
||||||
|
creditsBtn.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
creditsBtn.Location = new System.Drawing.Point(79, 71);
|
||||||
|
creditsBtn.Name = "creditsBtn";
|
||||||
|
creditsBtn.Size = new System.Drawing.Size(67, 23);
|
||||||
|
creditsBtn.TabIndex = 3;
|
||||||
|
creditsBtn.Text = "Credits";
|
||||||
|
creditsBtn.UseVisualStyleBackColor = true;
|
||||||
|
creditsBtn.Click += creditsBtn_Click;
|
||||||
|
//
|
||||||
|
// dbgCheckBox
|
||||||
|
//
|
||||||
|
dbgCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
|
||||||
|
dbgCheckBox.AutoSize = true;
|
||||||
|
dbgCheckBox.Location = new System.Drawing.Point(6, 100);
|
||||||
|
dbgCheckBox.Name = "dbgCheckBox";
|
||||||
|
dbgCheckBox.Size = new System.Drawing.Size(150, 19);
|
||||||
|
dbgCheckBox.TabIndex = 4;
|
||||||
|
dbgCheckBox.Text = "Enable logging (debug)";
|
||||||
|
dbgCheckBox.UseVisualStyleBackColor = true;
|
||||||
|
dbgCheckBox.CheckedChanged += dbgCheckBox_CheckedChanged;
|
||||||
|
//
|
||||||
|
// IDtxtBox
|
||||||
|
//
|
||||||
|
IDtxtBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
IDtxtBox.Location = new System.Drawing.Point(6, 37);
|
||||||
|
IDtxtBox.MaxLength = 18;
|
||||||
|
IDtxtBox.Name = "IDtxtBox";
|
||||||
|
IDtxtBox.PlaceholderText = "765213507321856078";
|
||||||
|
IDtxtBox.Size = new System.Drawing.Size(117, 16);
|
||||||
|
IDtxtBox.TabIndex = 1;
|
||||||
|
IDtxtBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||||
|
IDtxtBox.KeyDown += IDtxtBox_KeyDown;
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
label2.AutoSize = true;
|
||||||
|
label2.Location = new System.Drawing.Point(6, 19);
|
||||||
|
label2.Name = "label2";
|
||||||
|
label2.Size = new System.Drawing.Size(97, 15);
|
||||||
|
label2.TabIndex = 0;
|
||||||
|
label2.Text = "Custom Client ID";
|
||||||
|
//
|
||||||
|
// groupBox2
|
||||||
|
//
|
||||||
|
groupBox2.AutoSize = true;
|
||||||
|
groupBox2.Controls.Add(statusLbl);
|
||||||
|
groupBox2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
groupBox2.Location = new System.Drawing.Point(3, 3);
|
||||||
|
groupBox2.Name = "groupBox2";
|
||||||
|
groupBox2.Size = new System.Drawing.Size(194, 44);
|
||||||
|
groupBox2.TabIndex = 3;
|
||||||
|
groupBox2.TabStop = false;
|
||||||
|
groupBox2.Text = "Status";
|
||||||
|
//
|
||||||
|
// statusLbl
|
||||||
|
//
|
||||||
|
statusLbl.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
statusLbl.Location = new System.Drawing.Point(3, 19);
|
||||||
|
statusLbl.Name = "statusLbl";
|
||||||
|
statusLbl.Size = new System.Drawing.Size(188, 22);
|
||||||
|
statusLbl.TabIndex = 1;
|
||||||
|
statusLbl.Text = "Status Label";
|
||||||
|
statusLbl.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||||
|
//
|
||||||
|
// versionLbl
|
||||||
|
//
|
||||||
|
versionLbl.AutoSize = true;
|
||||||
|
versionLbl.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
versionLbl.Location = new System.Drawing.Point(3, 182);
|
||||||
|
versionLbl.Name = "versionLbl";
|
||||||
|
versionLbl.Size = new System.Drawing.Size(194, 18);
|
||||||
|
versionLbl.TabIndex = 4;
|
||||||
|
versionLbl.Text = "v0.0.0.0";
|
||||||
|
versionLbl.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||||
|
versionLbl.DoubleClick += versionLbl_DoubleClick;
|
||||||
|
//
|
||||||
|
// ControlPanel
|
||||||
|
//
|
||||||
|
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
|
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
AutoScroll = true;
|
||||||
|
AutoScrollMinSize = new System.Drawing.Size(200, 200);
|
||||||
|
Controls.Add(tableLayoutPanel1);
|
||||||
|
Name = "ControlPanel";
|
||||||
|
Size = new System.Drawing.Size(200, 200);
|
||||||
|
tableLayoutPanel1.ResumeLayout(false);
|
||||||
|
tableLayoutPanel1.PerformLayout();
|
||||||
|
groupBox1.ResumeLayout(false);
|
||||||
|
groupBox1.PerformLayout();
|
||||||
|
groupBox2.ResumeLayout(false);
|
||||||
|
ResumeLayout(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||||
|
private System.Windows.Forms.GroupBox groupBox1;
|
||||||
|
private System.Windows.Forms.TextBox IDtxtBox;
|
||||||
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.CheckBox dbgCheckBox;
|
||||||
|
private System.Windows.Forms.Button helpBtn;
|
||||||
|
private System.Windows.Forms.Button creditsBtn;
|
||||||
|
private System.Windows.Forms.GroupBox groupBox2;
|
||||||
|
private System.Windows.Forms.Label statusLbl;
|
||||||
|
private System.Windows.Forms.Label versionLbl;
|
||||||
|
}
|
||||||
|
}
|
79
SDR-RPC/ControlPanel.cs
Normal file
79
SDR-RPC/ControlPanel.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using SDRSharp.Common;
|
||||||
|
using SDRSharp.Radio;
|
||||||
|
using DiscordRPC;
|
||||||
|
using DiscordRPC.Logging;
|
||||||
|
using DiscordRPC.Message;
|
||||||
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
||||||
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button;
|
||||||
|
using EnderIce2.SDRSharpPlugin;
|
||||||
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolTip;
|
||||||
|
|
||||||
|
namespace EnderIce2.SDRSharpPlugin
|
||||||
|
{
|
||||||
|
public partial class ControlPanel : UserControl
|
||||||
|
{
|
||||||
|
private string _ChangeStatus;
|
||||||
|
private ISharpControl _control;
|
||||||
|
|
||||||
|
public string ChangeStatus
|
||||||
|
{
|
||||||
|
get => _ChangeStatus;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_ChangeStatus = value;
|
||||||
|
statusLbl.Text = value;
|
||||||
|
LogWriter.WriteToFile(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControlPanel(ISharpControl control)
|
||||||
|
{
|
||||||
|
_control = control;
|
||||||
|
InitializeComponent();
|
||||||
|
versionLbl.Text = $"v{Assembly.GetExecutingAssembly().GetName().Version.ToString()}";
|
||||||
|
IDtxtBox.Text = Utils.GetStringSetting("ClientID");
|
||||||
|
dbgCheckBox.Checked = Utils.GetBooleanSetting("LogRPC", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IDtxtBox_KeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.KeyCode != Keys.Enter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IDtxtBox.Text.Replace(" ", "").Replace("\n", "").Replace("\r", "");
|
||||||
|
|
||||||
|
if (IDtxtBox.Text.All(char.IsWhiteSpace))
|
||||||
|
{
|
||||||
|
IDtxtBox.Text = "765213507321856078";
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.SaveSetting("ClientID", IDtxtBox.Text);
|
||||||
|
ChangeStatus = "Configuration Updated";
|
||||||
|
e.Handled = true;
|
||||||
|
e.SuppressKeyPress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dbgCheckBox_CheckedChanged(object sender, EventArgs e) => Utils.SaveSetting("LogRPC", dbgCheckBox.Checked);
|
||||||
|
|
||||||
|
private void versionLbl_DoubleClick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo("https://enderice2.github.io/SDR-RPC/") { UseShellExecute = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void helpBtn_Click(object sender, EventArgs e) => new HelpForm().ShowDialog();
|
||||||
|
|
||||||
|
private void creditsBtn_Click(object sender, EventArgs e) => new CreditsForm().ShowDialog();
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
|
||||||
Version 2.0
|
Version 2.0
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
The primary goals of this format is to allow a simple XML format
|
||||||
that is mostly human readable. The generation and parsing of the
|
that is mostly human readable. The generation and parsing of the
|
||||||
various data types are done through the TypeConverter classes
|
various data types are done through the TypeConverter classes
|
||||||
associated with the data types.
|
associated with the data types.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
... ado.net/XML headers & schema ...
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
<resheader name="version">2.0</resheader>
|
<resheader name="version">2.0</resheader>
|
||||||
@ -26,36 +26,36 @@
|
|||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
<comment>This is a comment</comment>
|
<comment>This is a comment</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
There are any number of "resheader" rows that contain simple
|
||||||
name/value pairs.
|
name/value pairs.
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
Each data row contains a name, and value. The row also contains a
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
text/value conversion through the TypeConverter architecture.
|
text/value conversion through the TypeConverter architecture.
|
||||||
Classes that don't support this are serialized and stored with the
|
Classes that don't support this are serialized and stored with the
|
||||||
mimetype set.
|
mimetype set.
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
The mimetype is used for serialized objects, and tells the
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
read any of the formats listed below.
|
read any of the formats listed below.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
value : The object must be serialized into a byte array
|
value : The object must be serialized into a byte array
|
||||||
: using a System.ComponentModel.TypeConverter
|
: using a System.ComponentModel.TypeConverter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
-->
|
-->
|
156
SDR-RPC/CreditsForm.Designer.cs
generated
Normal file
156
SDR-RPC/CreditsForm.Designer.cs
generated
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
namespace EnderIce2.SDRSharpPlugin
|
||||||
|
{
|
||||||
|
partial class CreditsForm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
groupBox1 = new System.Windows.Forms.GroupBox();
|
||||||
|
lacheeLic = new System.Windows.Forms.LinkLabel();
|
||||||
|
lacheeSrc = new System.Windows.Forms.LinkLabel();
|
||||||
|
groupBox2 = new System.Windows.Forms.GroupBox();
|
||||||
|
jamesLic = new System.Windows.Forms.LinkLabel();
|
||||||
|
jamesSrc = new System.Windows.Forms.LinkLabel();
|
||||||
|
groupBox1.SuspendLayout();
|
||||||
|
groupBox2.SuspendLayout();
|
||||||
|
SuspendLayout();
|
||||||
|
//
|
||||||
|
// groupBox1
|
||||||
|
//
|
||||||
|
groupBox1.Controls.Add(lacheeLic);
|
||||||
|
groupBox1.Controls.Add(lacheeSrc);
|
||||||
|
groupBox1.ForeColor = System.Drawing.Color.White;
|
||||||
|
groupBox1.Location = new System.Drawing.Point(12, 12);
|
||||||
|
groupBox1.Name = "groupBox1";
|
||||||
|
groupBox1.Size = new System.Drawing.Size(171, 47);
|
||||||
|
groupBox1.TabIndex = 0;
|
||||||
|
groupBox1.TabStop = false;
|
||||||
|
groupBox1.Text = "Lachee/discord-rpc-csharp";
|
||||||
|
//
|
||||||
|
// lacheeLic
|
||||||
|
//
|
||||||
|
lacheeLic.ActiveLinkColor = System.Drawing.Color.White;
|
||||||
|
lacheeLic.AutoSize = true;
|
||||||
|
lacheeLic.DisabledLinkColor = System.Drawing.Color.Silver;
|
||||||
|
lacheeLic.LinkColor = System.Drawing.Color.White;
|
||||||
|
lacheeLic.Location = new System.Drawing.Point(6, 19);
|
||||||
|
lacheeLic.Name = "lacheeLic";
|
||||||
|
lacheeLic.Size = new System.Drawing.Size(71, 15);
|
||||||
|
lacheeLic.TabIndex = 1;
|
||||||
|
lacheeLic.TabStop = true;
|
||||||
|
lacheeLic.Text = "View license";
|
||||||
|
lacheeLic.VisitedLinkColor = System.Drawing.Color.FromArgb(224, 224, 224);
|
||||||
|
lacheeLic.LinkClicked += lacheeLic_LinkClicked;
|
||||||
|
//
|
||||||
|
// lacheeSrc
|
||||||
|
//
|
||||||
|
lacheeSrc.ActiveLinkColor = System.Drawing.Color.White;
|
||||||
|
lacheeSrc.AutoSize = true;
|
||||||
|
lacheeSrc.DisabledLinkColor = System.Drawing.Color.Silver;
|
||||||
|
lacheeSrc.LinkColor = System.Drawing.Color.White;
|
||||||
|
lacheeSrc.Location = new System.Drawing.Point(83, 19);
|
||||||
|
lacheeSrc.Name = "lacheeSrc";
|
||||||
|
lacheeSrc.Size = new System.Drawing.Size(70, 15);
|
||||||
|
lacheeSrc.TabIndex = 0;
|
||||||
|
lacheeSrc.TabStop = true;
|
||||||
|
lacheeSrc.Text = "View source";
|
||||||
|
lacheeSrc.VisitedLinkColor = System.Drawing.Color.FromArgb(224, 224, 224);
|
||||||
|
lacheeSrc.LinkClicked += lacheeSrc_LinkClicked;
|
||||||
|
//
|
||||||
|
// groupBox2
|
||||||
|
//
|
||||||
|
groupBox2.Controls.Add(jamesLic);
|
||||||
|
groupBox2.Controls.Add(jamesSrc);
|
||||||
|
groupBox2.ForeColor = System.Drawing.Color.White;
|
||||||
|
groupBox2.Location = new System.Drawing.Point(12, 65);
|
||||||
|
groupBox2.Name = "groupBox2";
|
||||||
|
groupBox2.Size = new System.Drawing.Size(171, 47);
|
||||||
|
groupBox2.TabIndex = 1;
|
||||||
|
groupBox2.TabStop = false;
|
||||||
|
groupBox2.Text = "JamesNK/Newtonsoft.Json";
|
||||||
|
//
|
||||||
|
// jamesLic
|
||||||
|
//
|
||||||
|
jamesLic.ActiveLinkColor = System.Drawing.Color.White;
|
||||||
|
jamesLic.AutoSize = true;
|
||||||
|
jamesLic.DisabledLinkColor = System.Drawing.Color.Silver;
|
||||||
|
jamesLic.LinkColor = System.Drawing.Color.White;
|
||||||
|
jamesLic.Location = new System.Drawing.Point(6, 19);
|
||||||
|
jamesLic.Name = "jamesLic";
|
||||||
|
jamesLic.Size = new System.Drawing.Size(71, 15);
|
||||||
|
jamesLic.TabIndex = 3;
|
||||||
|
jamesLic.TabStop = true;
|
||||||
|
jamesLic.Text = "View license";
|
||||||
|
jamesLic.VisitedLinkColor = System.Drawing.Color.FromArgb(224, 224, 224);
|
||||||
|
jamesLic.LinkClicked += jamesLic_LinkClicked;
|
||||||
|
//
|
||||||
|
// jamesSrc
|
||||||
|
//
|
||||||
|
jamesSrc.ActiveLinkColor = System.Drawing.Color.White;
|
||||||
|
jamesSrc.AutoSize = true;
|
||||||
|
jamesSrc.DisabledLinkColor = System.Drawing.Color.Silver;
|
||||||
|
jamesSrc.LinkColor = System.Drawing.Color.White;
|
||||||
|
jamesSrc.Location = new System.Drawing.Point(83, 19);
|
||||||
|
jamesSrc.Name = "jamesSrc";
|
||||||
|
jamesSrc.Size = new System.Drawing.Size(70, 15);
|
||||||
|
jamesSrc.TabIndex = 2;
|
||||||
|
jamesSrc.TabStop = true;
|
||||||
|
jamesSrc.Text = "View source";
|
||||||
|
jamesSrc.VisitedLinkColor = System.Drawing.Color.FromArgb(224, 224, 224);
|
||||||
|
jamesSrc.LinkClicked += jamesSrc_LinkClicked;
|
||||||
|
//
|
||||||
|
// CreditsForm
|
||||||
|
//
|
||||||
|
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
|
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
BackColor = System.Drawing.Color.FromArgb(28, 28, 28);
|
||||||
|
ClientSize = new System.Drawing.Size(196, 123);
|
||||||
|
Controls.Add(groupBox2);
|
||||||
|
Controls.Add(groupBox1);
|
||||||
|
ForeColor = System.Drawing.Color.White;
|
||||||
|
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
|
MaximizeBox = false;
|
||||||
|
MinimizeBox = false;
|
||||||
|
Name = "CreditsForm";
|
||||||
|
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
|
Text = "Credits";
|
||||||
|
groupBox1.ResumeLayout(false);
|
||||||
|
groupBox1.PerformLayout();
|
||||||
|
groupBox2.ResumeLayout(false);
|
||||||
|
groupBox2.PerformLayout();
|
||||||
|
ResumeLayout(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.GroupBox groupBox1;
|
||||||
|
private System.Windows.Forms.GroupBox groupBox2;
|
||||||
|
private System.Windows.Forms.LinkLabel lacheeLic;
|
||||||
|
private System.Windows.Forms.LinkLabel lacheeSrc;
|
||||||
|
private System.Windows.Forms.LinkLabel jamesLic;
|
||||||
|
private System.Windows.Forms.LinkLabel jamesSrc;
|
||||||
|
}
|
||||||
|
}
|
@ -1,46 +1,41 @@
|
|||||||
using SDRSharp.Radio;
|
using System;
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace EnderIce2.SDRSharpPlugin
|
namespace EnderIce2.SDRSharpPlugin
|
||||||
{
|
{
|
||||||
public partial class SettingsForm : Form
|
public partial class CreditsForm : Form
|
||||||
{
|
{
|
||||||
public SettingsForm()
|
public CreditsForm()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
textBox1.Text = Utils.GetStringSetting("ClientID");
|
|
||||||
checkBox1.Checked = Utils.GetBooleanSetting("LogRPC", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button2_Click(object sender, EventArgs e)
|
private void lacheeLic_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
{
|
|
||||||
Process.Start(new ProcessStartInfo("https://ko-fi.com/enderice2") { UseShellExecute = true });
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Button1_Click(object sender, EventArgs e) => Close();
|
|
||||||
|
|
||||||
private void Button5_Click(object sender, EventArgs e)
|
|
||||||
{
|
{
|
||||||
MessageBox.Show("MIT License\n\nCopyright (c) 2018 Lachee\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", "discord-rpc-csharp");
|
MessageBox.Show("MIT License\n\nCopyright (c) 2018 Lachee\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.", "discord-rpc-csharp");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lacheeSrc_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo("https://github.com/Lachee/discord-rpc-csharp") { UseShellExecute = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void jamesLic_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
{
|
||||||
MessageBox.Show("The MIT License (MIT)\n\nCopyright(c) 2007 James Newton-King\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", "Newtonsoft.Json");
|
MessageBox.Show("The MIT License (MIT)\n\nCopyright(c) 2007 James Newton-King\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", "Newtonsoft.Json");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckBox1_CheckedChanged(object sender, EventArgs e) => Utils.SaveSetting("LogRPC", checkBox1.Checked);
|
private void jamesSrc_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||||
|
|
||||||
private void Button4_Click(object sender, EventArgs e)
|
|
||||||
{
|
{
|
||||||
textBox1.Text.Replace(" ", "").Replace("\n", "").Replace("\r", "");
|
Process.Start(new ProcessStartInfo("https://github.com/JamesNK/Newtonsoft.Json") { UseShellExecute = true });
|
||||||
Utils.SaveSetting("ClientID", textBox1.Text);
|
|
||||||
label1.Text = $"Configuration Updated.\nNew ID: {Utils.GetStringSetting("ClientID")}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Button3_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
Utils.SaveSetting("ClientID", "765213507321856078");
|
|
||||||
textBox1.Text = "765213507321856078";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
|
|
||||||
Version 2.0
|
Version 2.0
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
The primary goals of this format is to allow a simple XML format
|
||||||
that is mostly human readable. The generation and parsing of the
|
that is mostly human readable. The generation and parsing of the
|
||||||
various data types are done through the TypeConverter classes
|
various data types are done through the TypeConverter classes
|
||||||
associated with the data types.
|
associated with the data types.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
... ado.net/XML headers & schema ...
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
<resheader name="version">2.0</resheader>
|
<resheader name="version">2.0</resheader>
|
||||||
@ -26,36 +26,36 @@
|
|||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
<comment>This is a comment</comment>
|
<comment>This is a comment</comment>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
There are any number of "resheader" rows that contain simple
|
||||||
name/value pairs.
|
name/value pairs.
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
Each data row contains a name, and value. The row also contains a
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
text/value conversion through the TypeConverter architecture.
|
text/value conversion through the TypeConverter architecture.
|
||||||
Classes that don't support this are serialized and stored with the
|
Classes that don't support this are serialized and stored with the
|
||||||
mimetype set.
|
mimetype set.
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
The mimetype is used for serialized objects, and tells the
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
read any of the formats listed below.
|
read any of the formats listed below.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
value : The object must be serialized with
|
value : The object must be serialized with
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
value : The object must be serialized into a byte array
|
value : The object must be serialized into a byte array
|
||||||
: using a System.ComponentModel.TypeConverter
|
: using a System.ComponentModel.TypeConverter
|
||||||
: and then encoded with base64 encoding.
|
: and then encoded with base64 encoding.
|
||||||
-->
|
-->
|
28
SDR-RPC/DiscordAPI/Configuration.cs
Normal file
28
SDR-RPC/DiscordAPI/Configuration.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration of the current RPC connection
|
||||||
|
/// </summary>
|
||||||
|
public class Configuration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord API endpoint that should be used.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("api_endpoint")]
|
||||||
|
public string ApiEndpoint { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CDN endpoint
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("cdn_host")]
|
||||||
|
public string CdnHost { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of enviroment the connection on. Usually Production.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("enviroment")]
|
||||||
|
public string Enviroment { get; set; }
|
||||||
|
}
|
||||||
|
}
|
94
SDR-RPC/DiscordAPI/Converters/EnumSnakeCaseConverter.cs
Normal file
94
SDR-RPC/DiscordAPI/Converters/EnumSnakeCaseConverter.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Converters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts enums with the <see cref="EnumValueAttribute"/> into Json friendly terms.
|
||||||
|
/// </summary>
|
||||||
|
internal class EnumSnakeCaseConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return objectType.IsEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.Value == null) return null;
|
||||||
|
|
||||||
|
object val = null;
|
||||||
|
if (TryParseEnum(objectType, (string)reader.Value, out val))
|
||||||
|
return val;
|
||||||
|
|
||||||
|
return existingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var enumtype = value.GetType();
|
||||||
|
var name = Enum.GetName(enumtype, value);
|
||||||
|
|
||||||
|
//Get each member and look for hte correct one
|
||||||
|
var members = enumtype.GetMembers(BindingFlags.Public | BindingFlags.Static);
|
||||||
|
foreach (var m in members)
|
||||||
|
{
|
||||||
|
if (m.Name.Equals(name))
|
||||||
|
{
|
||||||
|
var attributes = m.GetCustomAttributes(typeof(EnumValueAttribute), true);
|
||||||
|
if (attributes.Length > 0)
|
||||||
|
{
|
||||||
|
name = ((EnumValueAttribute)attributes[0]).Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteValue(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryParseEnum(Type enumType, string str, out object obj)
|
||||||
|
{
|
||||||
|
//Make sure the string isn;t null
|
||||||
|
if (str == null)
|
||||||
|
{
|
||||||
|
obj = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the real type
|
||||||
|
Type type = enumType;
|
||||||
|
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||||
|
type = type.GetGenericArguments().First();
|
||||||
|
|
||||||
|
//Make sure its actually a enum
|
||||||
|
if (!type.IsEnum)
|
||||||
|
{
|
||||||
|
obj = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get each member and look for hte correct one
|
||||||
|
var members = type.GetMembers(BindingFlags.Public | BindingFlags.Static);
|
||||||
|
foreach (var m in members)
|
||||||
|
{
|
||||||
|
var attributes = m.GetCustomAttributes(typeof(EnumValueAttribute), true);
|
||||||
|
foreach (var a in attributes)
|
||||||
|
{
|
||||||
|
var enumval = (EnumValueAttribute)a;
|
||||||
|
if (str.Equals(enumval.Value))
|
||||||
|
{
|
||||||
|
obj = Enum.Parse(type, m.Name, ignoreCase: true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//We failed
|
||||||
|
obj = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
SDR-RPC/DiscordAPI/Converters/EnumValueAttribute.cs
Normal file
14
SDR-RPC/DiscordAPI/Converters/EnumValueAttribute.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Converters
|
||||||
|
{
|
||||||
|
internal class EnumValueAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
public EnumValueAttribute(string value)
|
||||||
|
{
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,6 @@ using System;
|
|||||||
|
|
||||||
namespace DiscordRPC
|
namespace DiscordRPC
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A Discord RPC Client which is used to send Rich Presence updates and receive Join / Spectate events.
|
/// A Discord RPC Client which is used to send Rich Presence updates and receive Join / Spectate events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -18,7 +17,6 @@ namespace DiscordRPC
|
|||||||
{
|
{
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating if the client has registered a URI Scheme. If this is false, Join / Spectate events will fail.
|
/// Gets a value indicating if the client has registered a URI Scheme. If this is false, Join / Spectate events will fail.
|
||||||
/// <para>To register a URI Scheme, call <see cref="RegisterUriScheme(string, string)"/>.</para>
|
/// <para>To register a URI Scheme, call <see cref="RegisterUriScheme(string, string)"/>.</para>
|
||||||
@ -41,7 +39,7 @@ namespace DiscordRPC
|
|||||||
public int ProcessID { get; private set; }
|
public int ProcessID { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum size of the message queue received from Discord.
|
/// The maximum size of the message queue received from Discord.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int MaxQueueSize { get; private set; }
|
public int MaxQueueSize { get; private set; }
|
||||||
|
|
||||||
@ -62,10 +60,11 @@ namespace DiscordRPC
|
|||||||
if (connection != null) connection.Logger = value;
|
if (connection != null) connection.Logger = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the client will automatically invoke the events without <see cref="Invoke"/> having to be called.
|
/// Indicates if the client will automatically invoke the events without <see cref="Invoke"/> having to be called.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AutoEvents { get; private set; }
|
public bool AutoEvents { get; private set; }
|
||||||
|
|
||||||
@ -73,7 +72,8 @@ namespace DiscordRPC
|
|||||||
/// Skips sending presences that are identical to the current one.
|
/// Skips sending presences that are identical to the current one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SkipIdenticalPresence { get; set; }
|
public bool SkipIdenticalPresence { get; set; }
|
||||||
#endregion
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pipe the discord client is on, ranging from 0 to 9. Use -1 to scan through all pipes.
|
/// The pipe the discord client is on, ranging from 0 to 9. Use -1 to scan through all pipes.
|
||||||
@ -121,6 +121,7 @@ namespace DiscordRPC
|
|||||||
if (connection != null) connection.ShutdownOnly = value;
|
if (connection != null) connection.ShutdownOnly = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _shutdownOnly = true;
|
private bool _shutdownOnly = true;
|
||||||
private object _sync = new object();
|
private object _sync = new object();
|
||||||
|
|
||||||
@ -196,7 +197,8 @@ namespace DiscordRPC
|
|||||||
/// The RPC Connection has sent a message. Called before any other event and executed from the RPC Thread.
|
/// The RPC Connection has sent a message. Called before any other event and executed from the RPC Thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event OnRpcMessageEvent OnRpcMessage;
|
public event OnRpcMessageEvent OnRpcMessage;
|
||||||
#endregion
|
|
||||||
|
#endregion Events
|
||||||
|
|
||||||
#region Initialization
|
#region Initialization
|
||||||
|
|
||||||
@ -253,9 +255,10 @@ namespace DiscordRPC
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion Initialization
|
||||||
|
|
||||||
#region Message Handling
|
#region Message Handling
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dequeues all the messages from Discord, processes them and then invoke appropriate event handlers. This will process the message and update the internal state before invoking the events. Returns the messages that were invoked in the order they were invoked.
|
/// Dequeues all the messages from Discord, processes them and then invoke appropriate event handlers. This will process the message and update the internal state before invoking the events. Returns the messages that were invoked in the order they were invoked.
|
||||||
/// <para>This method cannot be used if <see cref="AutoEvents"/> is enabled.</para>
|
/// <para>This method cannot be used if <see cref="AutoEvents"/> is enabled.</para>
|
||||||
@ -420,7 +423,8 @@ namespace DiscordRPC
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
#endregion Message Handling
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Respond to a Join Request. All requests will timeout after 30 seconds.
|
/// Respond to a Join Request. All requests will timeout after 30 seconds.
|
||||||
@ -487,6 +491,7 @@ namespace DiscordRPC
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Updates
|
#region Updates
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates only the <see cref="RichPresence.Details"/> of the <see cref="CurrentPresence"/> and sends the updated presence to Discord. Returns the newly edited Rich Presence.
|
/// Updates only the <see cref="RichPresence.Details"/> of the <see cref="CurrentPresence"/> and sends the updated presence to Discord. Returns the newly edited Rich Presence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -505,6 +510,7 @@ namespace DiscordRPC
|
|||||||
}
|
}
|
||||||
return CurrentPresence;
|
return CurrentPresence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates only the <see cref="RichPresence.State"/> of the <see cref="CurrentPresence"/> and sends the updated presence to Discord. Returns the newly edited Rich Presence.
|
/// Updates only the <see cref="RichPresence.State"/> of the <see cref="CurrentPresence"/> and sends the updated presence to Discord. Returns the newly edited Rich Presence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -523,6 +529,7 @@ namespace DiscordRPC
|
|||||||
}
|
}
|
||||||
return CurrentPresence;
|
return CurrentPresence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates only the <see cref="RichPresence.Party"/> of the <see cref="CurrentPresence"/> and sends the updated presence to Discord. Returns the newly edited Rich Presence.
|
/// Updates only the <see cref="RichPresence.Party"/> of the <see cref="CurrentPresence"/> and sends the updated presence to Discord. Returns the newly edited Rich Presence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -542,6 +549,7 @@ namespace DiscordRPC
|
|||||||
SetPresence(CurrentPresence);
|
SetPresence(CurrentPresence);
|
||||||
return CurrentPresence;
|
return CurrentPresence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the <see cref="Party.Size"/> of the <see cref="CurrentPresence"/> and sends the update presence to Discord. Returns the newly edited Rich Presence.
|
/// Updates the <see cref="Party.Size"/> of the <see cref="CurrentPresence"/> and sends the update presence to Discord. Returns the newly edited Rich Presence.
|
||||||
/// <para>Will return null if no presence exists and will throw a new <see cref="NullReferenceException"/> if the Party does not exist.</para>
|
/// <para>Will return null if no presence exists and will throw a new <see cref="NullReferenceException"/> if the Party does not exist.</para>
|
||||||
@ -560,6 +568,7 @@ namespace DiscordRPC
|
|||||||
try { UpdatePartySize(size, CurrentPresence.Party.Max); } catch (Exception) { throw; }
|
try { UpdatePartySize(size, CurrentPresence.Party.Max); } catch (Exception) { throw; }
|
||||||
return CurrentPresence;
|
return CurrentPresence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the <see cref="Party.Size"/> of the <see cref="CurrentPresence"/> and sends the update presence to Discord. Returns the newly edited Rich Presence.
|
/// Updates the <see cref="Party.Size"/> of the <see cref="CurrentPresence"/> and sends the update presence to Discord. Returns the newly edited Rich Presence.
|
||||||
/// <para>Will return null if no presence exists and will throw a new <see cref="NullReferenceException"/> if the Party does not exist.</para>
|
/// <para>Will return null if no presence exists and will throw a new <see cref="NullReferenceException"/> if the Party does not exist.</para>
|
||||||
@ -656,7 +665,8 @@ namespace DiscordRPC
|
|||||||
/// Sets the start time of the <see cref="CurrentPresence"/> to now and sends the updated presence to Discord.
|
/// Sets the start time of the <see cref="CurrentPresence"/> to now and sends the updated presence to Discord.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Updated Rich Presence</returns>
|
/// <returns>Updated Rich Presence</returns>
|
||||||
public RichPresence UpdateStartTime() { try { return UpdateStartTime(DateTime.UtcNow); } catch (Exception) { throw; } }
|
public RichPresence UpdateStartTime()
|
||||||
|
{ try { return UpdateStartTime(DateTime.UtcNow); } catch (Exception) { throw; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the start time of the <see cref="CurrentPresence"/> and sends the updated presence to Discord.
|
/// Sets the start time of the <see cref="CurrentPresence"/> and sends the updated presence to Discord.
|
||||||
@ -683,7 +693,8 @@ namespace DiscordRPC
|
|||||||
/// Sets the end time of the <see cref="CurrentPresence"/> to now and sends the updated presence to Discord.
|
/// Sets the end time of the <see cref="CurrentPresence"/> to now and sends the updated presence to Discord.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Updated Rich Presence</returns>
|
/// <returns>Updated Rich Presence</returns>
|
||||||
public RichPresence UpdateEndTime() { try { return UpdateEndTime(DateTime.UtcNow); } catch (Exception) { throw; } }
|
public RichPresence UpdateEndTime()
|
||||||
|
{ try { return UpdateEndTime(DateTime.UtcNow); } catch (Exception) { throw; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the end time of the <see cref="CurrentPresence"/> and sends the updated presence to Discord.
|
/// Sets the end time of the <see cref="CurrentPresence"/> and sends the updated presence to Discord.
|
||||||
@ -724,7 +735,8 @@ namespace DiscordRPC
|
|||||||
SetPresence(CurrentPresence);
|
SetPresence(CurrentPresence);
|
||||||
return CurrentPresence;
|
return CurrentPresence;
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
#endregion Updates
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the Rich Presence. Use this just before disposal to prevent ghosting.
|
/// Clears the Rich Presence. Use this just before disposal to prevent ghosting.
|
||||||
@ -764,21 +776,24 @@ namespace DiscordRPC
|
|||||||
/// <para>Requires the UriScheme to be registered.</para>
|
/// <para>Requires the UriScheme to be registered.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The event type to subscribe to</param>
|
/// <param name="type">The event type to subscribe to</param>
|
||||||
public void Subscribe(EventType type) { SetSubscription(Subscription | type); }
|
public void Subscribe(EventType type)
|
||||||
|
{ SetSubscription(Subscription | type); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
[System.Obsolete("Replaced with Unsubscribe", true)]
|
[System.Obsolete("Replaced with Unsubscribe", true)]
|
||||||
public void Unubscribe(EventType type) { SetSubscription(Subscription & ~type); }
|
public void Unubscribe(EventType type)
|
||||||
|
{ SetSubscription(Subscription & ~type); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unsubscribe from the event sent by discord. Used for Join / Spectate feature.
|
/// Unsubscribe from the event sent by discord. Used for Join / Spectate feature.
|
||||||
/// <para>Requires the UriScheme to be registered.</para>
|
/// <para>Requires the UriScheme to be registered.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The event type to unsubscribe from</param>
|
/// <param name="type">The event type to unsubscribe from</param>
|
||||||
public void Unsubscribe(EventType type) { SetSubscription(Subscription & ~type); }
|
public void Unsubscribe(EventType type)
|
||||||
|
{ SetSubscription(Subscription & ~type); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the subscription to the events sent from Discord.
|
/// Sets the subscription to the events sent from Discord.
|
||||||
@ -811,7 +826,7 @@ namespace DiscordRPC
|
|||||||
/// <param name="isUnsubscribe">Represents if the unsubscribe payload should be sent instead.</param>
|
/// <param name="isUnsubscribe">Represents if the unsubscribe payload should be sent instead.</param>
|
||||||
private void SubscribeToTypes(EventType type, bool isUnsubscribe)
|
private void SubscribeToTypes(EventType type, bool isUnsubscribe)
|
||||||
{
|
{
|
||||||
//Because of SetSubscription, this can actually be none as there is no differences.
|
//Because of SetSubscription, this can actually be none as there is no differences.
|
||||||
//If that is the case, we should just stop here
|
//If that is the case, we should just stop here
|
||||||
if (type == EventType.None) return;
|
if (type == EventType.None) return;
|
||||||
|
|
||||||
@ -840,7 +855,7 @@ namespace DiscordRPC
|
|||||||
connection.EnqueueCommand(new SubscribeCommand() { Event = RPC.Payload.ServerEvent.ActivityJoinRequest, IsUnsubscribe = isUnsubscribe });
|
connection.EnqueueCommand(new SubscribeCommand() { Event = RPC.Payload.ServerEvent.ActivityJoinRequest, IsUnsubscribe = isUnsubscribe });
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion Subscriptions
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resends the current presence and subscription. This is used when Ready is called to keep the current state within discord.
|
/// Resends the current presence and subscription. This is used when Ready is called to keep the current state within discord.
|
||||||
@ -896,6 +911,5 @@ namespace DiscordRPC
|
|||||||
if (IsInitialized) Deinitialize();
|
if (IsInitialized) Deinitialize();
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
29
SDR-RPC/DiscordAPI/EventType.cs
Normal file
29
SDR-RPC/DiscordAPI/EventType.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
namespace DiscordRPC
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of event receieved by the RPC. A flag type that can be combined.
|
||||||
|
/// </summary>
|
||||||
|
[System.Flags]
|
||||||
|
public enum EventType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No event
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the Discord Client wishes to enter a game to spectate
|
||||||
|
/// </summary>
|
||||||
|
Spectate = 0x1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the Discord Client wishes to enter a game to play.
|
||||||
|
/// </summary>
|
||||||
|
Join = 0x2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when another Discord Client has requested permission to join this game.
|
||||||
|
/// </summary>
|
||||||
|
JoinRequest = 0x4
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,4 @@
|
|||||||
using DiscordRPC.Message;
|
using DiscordRPC.Message;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Events
|
namespace DiscordRPC.Events
|
||||||
{
|
{
|
||||||
@ -69,7 +65,6 @@ namespace DiscordRPC.Events
|
|||||||
/// <param name="args">The arguments supplied with the event</param>
|
/// <param name="args">The arguments supplied with the event</param>
|
||||||
public delegate void OnJoinRequestedEvent(object sender, JoinRequestMessage args);
|
public delegate void OnJoinRequestedEvent(object sender, JoinRequestMessage args);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The connection to the discord client was succesfull. This is called before <see cref="OnReadyEvent"/>.
|
/// The connection to the discord client was succesfull. This is called before <see cref="OnReadyEvent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -84,11 +79,10 @@ namespace DiscordRPC.Events
|
|||||||
/// <param name="args">The arguments supplied with the event</param>
|
/// <param name="args">The arguments supplied with the event</param>
|
||||||
public delegate void OnConnectionFailedEvent(object sender, ConnectionFailedMessage args);
|
public delegate void OnConnectionFailedEvent(object sender, ConnectionFailedMessage args);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A RPC Message is received.
|
/// A RPC Message is received.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender">The handler that sent this event</param>
|
/// <param name="sender">The handler that sent this event</param>
|
||||||
/// <param name="msg">The raw message from the RPC</param>
|
/// <param name="msg">The raw message from the RPC</param>
|
||||||
public delegate void OnRpcMessageEvent(object sender, IMessage msg);
|
public delegate void OnRpcMessageEvent(object sender, IMessage msg);
|
||||||
}
|
}
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Exceptions
|
namespace DiscordRPC.Exceptions
|
||||||
{
|
{
|
||||||
@ -9,7 +6,9 @@ namespace DiscordRPC.Exceptions
|
|||||||
/// A BadPresenceException is thrown when invalid, incompatible or conflicting properties and is unable to be sent.
|
/// A BadPresenceException is thrown when invalid, incompatible or conflicting properties and is unable to be sent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BadPresenceException : Exception
|
public class BadPresenceException : Exception
|
||||||
{
|
{
|
||||||
internal BadPresenceException(string message) : base(message) { }
|
internal BadPresenceException(string message) : base(message)
|
||||||
}
|
{
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Exceptions
|
namespace DiscordRPC.Exceptions
|
||||||
{
|
{
|
||||||
@ -9,7 +6,9 @@ namespace DiscordRPC.Exceptions
|
|||||||
/// A InvalidConfigurationException is thrown when trying to perform a action that conflicts with the current configuration.
|
/// A InvalidConfigurationException is thrown when trying to perform a action that conflicts with the current configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InvalidConfigurationException : Exception
|
public class InvalidConfigurationException : Exception
|
||||||
{
|
{
|
||||||
internal InvalidConfigurationException(string message) : base(message) { }
|
internal InvalidConfigurationException(string message) : base(message)
|
||||||
}
|
{
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
15
SDR-RPC/DiscordAPI/Exceptions/InvalidPipeException.cs
Normal file
15
SDR-RPC/DiscordAPI/Exceptions/InvalidPipeException.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The exception that is thrown when a error occurs while communicating with a pipe or when a connection attempt fails.
|
||||||
|
/// </summary>
|
||||||
|
[System.Obsolete("Not actually used anywhere")]
|
||||||
|
public class InvalidPipeException : Exception
|
||||||
|
{
|
||||||
|
internal InvalidPipeException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Exceptions
|
namespace DiscordRPC.Exceptions
|
||||||
{
|
{
|
||||||
@ -9,7 +6,7 @@ namespace DiscordRPC.Exceptions
|
|||||||
/// A StringOutOfRangeException is thrown when the length of a string exceeds the allowed limit.
|
/// A StringOutOfRangeException is thrown when the length of a string exceeds the allowed limit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StringOutOfRangeException : Exception
|
public class StringOutOfRangeException : Exception
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum length the string is allowed to be.
|
/// Maximum length the string is allowed to be.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -26,7 +23,7 @@ namespace DiscordRPC.Exceptions
|
|||||||
/// <param name="message">The custom message</param>
|
/// <param name="message">The custom message</param>
|
||||||
/// <param name="min">Minimum length the string can be</param>
|
/// <param name="min">Minimum length the string can be</param>
|
||||||
/// <param name="max">Maximum length the string can be</param>
|
/// <param name="max">Maximum length the string can be</param>
|
||||||
internal StringOutOfRangeException(string message, int min, int max) : base(message)
|
internal StringOutOfRangeException(string message, int min, int max) : base(message)
|
||||||
{
|
{
|
||||||
MinimumLength = min;
|
MinimumLength = min;
|
||||||
MaximumLength = max;
|
MaximumLength = max;
|
||||||
@ -37,14 +34,14 @@ namespace DiscordRPC.Exceptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="minumum"></param>
|
/// <param name="minumum"></param>
|
||||||
/// <param name="max"></param>
|
/// <param name="max"></param>
|
||||||
internal StringOutOfRangeException(int minumum, int max)
|
internal StringOutOfRangeException(int minumum, int max)
|
||||||
: this("Length of string is out of range. Expected a value between " + minumum + " and " + max, minumum, max) { }
|
: this("Length of string is out of range. Expected a value between " + minumum + " and " + max, minumum, max) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new sting out of range exception with a range of 0 to max
|
/// Creates a new sting out of range exception with a range of 0 to max
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="max"></param>
|
/// <param name="max"></param>
|
||||||
internal StringOutOfRangeException(int max)
|
internal StringOutOfRangeException(int max)
|
||||||
: this("Length of string is out of range. Expected a value with a maximum length of " + max, 0, max) { }
|
: this("Length of string is out of range. Expected a value with a maximum length of " + max, 0, max) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Exceptions
|
namespace DiscordRPC.Exceptions
|
||||||
{
|
{
|
||||||
@ -21,4 +18,4 @@ namespace DiscordRPC.Exceptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal UninitializedException() : this("Cannot perform action because the client has not been initialized yet or has been deinitialized.") { }
|
internal UninitializedException() : this("Cannot perform action because the client has not been initialized yet or has been deinitialized.") { }
|
||||||
}
|
}
|
||||||
}
|
}
|
75
SDR-RPC/DiscordAPI/Helper/BackoffDelay.cs
Normal file
75
SDR-RPC/DiscordAPI/Helper/BackoffDelay.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Helper
|
||||||
|
{
|
||||||
|
internal class BackoffDelay
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum time the backoff can reach
|
||||||
|
/// </summary>
|
||||||
|
public int Maximum { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum time the backoff can start at
|
||||||
|
/// </summary>
|
||||||
|
public int Minimum { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current time of the backoff
|
||||||
|
/// </summary>
|
||||||
|
public int Current
|
||||||
|
{ get { return _current; } }
|
||||||
|
|
||||||
|
private int _current;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current number of failures
|
||||||
|
/// </summary>
|
||||||
|
public int Fails
|
||||||
|
{ get { return _fails; } }
|
||||||
|
|
||||||
|
private int _fails;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The random generator
|
||||||
|
/// </summary>
|
||||||
|
public Random Random { get; set; }
|
||||||
|
|
||||||
|
private BackoffDelay()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public BackoffDelay(int min, int max) : this(min, max, new Random())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public BackoffDelay(int min, int max, Random random)
|
||||||
|
{
|
||||||
|
this.Minimum = min;
|
||||||
|
this.Maximum = max;
|
||||||
|
|
||||||
|
this._current = min;
|
||||||
|
this._fails = 0;
|
||||||
|
this.Random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the backoff
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_fails = 0;
|
||||||
|
_current = Minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int NextDelay()
|
||||||
|
{
|
||||||
|
//Increment the failures
|
||||||
|
_fails++;
|
||||||
|
|
||||||
|
double diff = (Maximum - Minimum) / 100f;
|
||||||
|
_current = (int)Math.Floor(diff * _fails) + Minimum;
|
||||||
|
|
||||||
|
return Math.Min(Math.Max(_current, Minimum), Maximum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
SDR-RPC/DiscordAPI/Helper/StringTools.cs
Normal file
72
SDR-RPC/DiscordAPI/Helper/StringTools.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Helper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Collectin of helpful string extensions
|
||||||
|
/// </summary>
|
||||||
|
public static class StringTools
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Will return null if the string is whitespace, otherwise it will return the string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The string to check</param>
|
||||||
|
/// <returns>Null if the string is empty, otherwise the string</returns>
|
||||||
|
public static string GetNullOrString(this string str)
|
||||||
|
{
|
||||||
|
return str.Length == 0 || string.IsNullOrEmpty(str.Trim()) ? null : str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does the string fit within the given amount of bytes? Uses UTF8 encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The string to check</param>
|
||||||
|
/// <param name="bytes">The maximum number of bytes the string can take up</param>
|
||||||
|
/// <returns>True if the string fits within the number of bytes</returns>
|
||||||
|
public static bool WithinLength(this string str, int bytes)
|
||||||
|
{
|
||||||
|
return str.WithinLength(bytes, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does the string fit within the given amount of bytes?
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The string to check</param>
|
||||||
|
/// <param name="bytes">The maximum number of bytes the string can take up</param>
|
||||||
|
/// <param name="encoding">The encoding to count the bytes with</param>
|
||||||
|
/// <returns>True if the string fits within the number of bytes</returns>
|
||||||
|
public static bool WithinLength(this string str, int bytes, Encoding encoding)
|
||||||
|
{
|
||||||
|
return encoding.GetByteCount(str) <= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the string into UpperCamelCase (Pascal Case).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The string to convert</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToCamelCase(this string str)
|
||||||
|
{
|
||||||
|
if (str == null) return null;
|
||||||
|
|
||||||
|
return str.ToLower()
|
||||||
|
.Split(new[] { "_", " " }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(s => char.ToUpper(s[0]) + s.Substring(1, s.Length - 1))
|
||||||
|
.Aggregate(string.Empty, (s1, s2) => s1 + s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the string into UPPER_SNAKE_CASE
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">The string to convert</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToSnakeCase(this string str)
|
||||||
|
{
|
||||||
|
if (str == null) return null;
|
||||||
|
var concat = string.Concat(str.Select((x, i) => i > 0 && char.IsUpper(x) ? "_" + x.ToString() : x.ToString()).ToArray());
|
||||||
|
return concat.ToUpper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
SDR-RPC/DiscordAPI/IO/Handshake.cs
Normal file
19
SDR-RPC/DiscordAPI/IO/Handshake.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.IO
|
||||||
|
{
|
||||||
|
internal class Handshake
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Version of the IPC API we are using
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("v")]
|
||||||
|
public int Version { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the app.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("client_id")]
|
||||||
|
public string ClientID { get; set; }
|
||||||
|
}
|
||||||
|
}
|
51
SDR-RPC/DiscordAPI/IO/INamedPipeClient.cs
Normal file
51
SDR-RPC/DiscordAPI/IO/INamedPipeClient.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using DiscordRPC.Logging;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordRPC.IO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Pipe Client used to communicate with Discord.
|
||||||
|
/// </summary>
|
||||||
|
public interface INamedPipeClient : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The logger for the Pipe client to use
|
||||||
|
/// </summary>
|
||||||
|
ILogger Logger { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the pipe client currently connected?
|
||||||
|
/// </summary>
|
||||||
|
bool IsConnected { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The pipe the client is currently connected too
|
||||||
|
/// </summary>
|
||||||
|
int ConnectedPipe { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to connect to the pipe. If 0-9 is passed to pipe, it should try to only connect to the specified pipe. If -1 is passed, the pipe will find the first available pipe.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pipe">If -1 is passed, the pipe will find the first available pipe, otherwise it connects to the pipe that was supplied</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool Connect(int pipe);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a frame if there is one available. Returns false if there is none. This should be non blocking (aka use a Peek first).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frame">The frame that has been read. Will be <code>default(PipeFrame)</code> if it fails to read</param>
|
||||||
|
/// <returns>Returns true if a frame has been read, otherwise false.</returns>
|
||||||
|
bool ReadFrame(out PipeFrame frame);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the frame to the pipe. Returns false if any errors occur.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frame">The frame to be written</param>
|
||||||
|
bool WriteFrame(PipeFrame frame);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes the connection
|
||||||
|
/// </summary>
|
||||||
|
void Close();
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,9 @@
|
|||||||
using System;
|
using DiscordRPC.Logging;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.IO;
|
||||||
using System.Text;
|
|
||||||
using DiscordRPC.Logging;
|
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace DiscordRPC.IO
|
namespace DiscordRPC.IO
|
||||||
{
|
{
|
||||||
@ -17,7 +15,7 @@ namespace DiscordRPC.IO
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name format of the pipe
|
/// Name format of the pipe
|
||||||
/// </summary>
|
/// </summary>
|
||||||
const string PIPE_NAME = @"discord-ipc-{0}";
|
private const string PIPE_NAME = @"discord-ipc-{0}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The logger for the Pipe client to use
|
/// The logger for the Pipe client to use
|
||||||
@ -44,7 +42,8 @@ namespace DiscordRPC.IO
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pipe we are currently connected too.
|
/// The pipe we are currently connected too.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ConnectedPipe { get { return _connectedPipe; } }
|
public int ConnectedPipe
|
||||||
|
{ get { return _connectedPipe; } }
|
||||||
|
|
||||||
private int _connectedPipe;
|
private int _connectedPipe;
|
||||||
private NamedPipeClientStream _stream;
|
private NamedPipeClientStream _stream;
|
||||||
@ -378,7 +377,7 @@ namespace DiscordRPC.IO
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//flush and dispose
|
//flush and dispose
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Wait for the stream object to become available.
|
//Wait for the stream object to become available.
|
||||||
@ -469,6 +468,7 @@ namespace DiscordRPC.IO
|
|||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
case PlatformID.Unix:
|
case PlatformID.Unix:
|
||||||
return "snap.discord/";
|
return "snap.discord/";
|
||||||
}
|
}
|
||||||
@ -506,4 +506,4 @@ namespace DiscordRPC.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
33
SDR-RPC/DiscordAPI/IO/Opcode.cs
Normal file
33
SDR-RPC/DiscordAPI/IO/Opcode.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace DiscordRPC.IO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The operation code that the <see cref="PipeFrame"/> was sent under. This defines the type of frame and the data to expect.
|
||||||
|
/// </summary>
|
||||||
|
public enum Opcode : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initial handshake frame
|
||||||
|
/// </summary>
|
||||||
|
Handshake = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generic message frame
|
||||||
|
/// </summary>
|
||||||
|
Frame = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Discord has closed the connection
|
||||||
|
/// </summary>
|
||||||
|
Close = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ping frame (not used?)
|
||||||
|
/// </summary>
|
||||||
|
Ping = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pong frame (not used?)
|
||||||
|
/// </summary>
|
||||||
|
Pong = 4
|
||||||
|
}
|
||||||
|
}
|
203
SDR-RPC/DiscordAPI/IO/PipeFrame.cs
Normal file
203
SDR-RPC/DiscordAPI/IO/PipeFrame.cs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DiscordRPC.IO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A frame received and sent to the Discord client for RPC communications.
|
||||||
|
/// </summary>
|
||||||
|
public struct PipeFrame
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maxium size of a pipe frame (16kb).
|
||||||
|
/// </summary>
|
||||||
|
public static readonly int MAX_SIZE = 16 * 1024;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The opcode of the frame
|
||||||
|
/// </summary>
|
||||||
|
public Opcode Opcode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The length of the frame data
|
||||||
|
/// </summary>
|
||||||
|
public uint Length { get { return (uint)Data.Length; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data in the frame
|
||||||
|
/// </summary>
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data represented as a string.
|
||||||
|
/// </summary>
|
||||||
|
public string Message
|
||||||
|
{
|
||||||
|
get { return GetMessage(); }
|
||||||
|
set { SetMessage(value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new pipe frame instance
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode">The opcode of the frame</param>
|
||||||
|
/// <param name="data">The data of the frame that will be serialized as JSON</param>
|
||||||
|
public PipeFrame(Opcode opcode, object data)
|
||||||
|
{
|
||||||
|
//Set the opcode and a temp field for data
|
||||||
|
Opcode = opcode;
|
||||||
|
Data = null;
|
||||||
|
|
||||||
|
//Set the data
|
||||||
|
SetObject(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the encoding used for the pipe frames
|
||||||
|
/// </summary>
|
||||||
|
public Encoding MessageEncoding { get { return Encoding.UTF8; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the data based of a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
private void SetMessage(string str)
|
||||||
|
{ Data = MessageEncoding.GetBytes(str); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string based of the data
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private string GetMessage()
|
||||||
|
{ return MessageEncoding.GetString(Data); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializes the object into json string then encodes it into <see cref="Data"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
public void SetObject(object obj)
|
||||||
|
{
|
||||||
|
string json = JsonConvert.SerializeObject(obj);
|
||||||
|
SetMessage(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the opcodes and serializes the object into a json string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="opcode"></param>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
public void SetObject(Opcode opcode, object obj)
|
||||||
|
{
|
||||||
|
Opcode = opcode;
|
||||||
|
SetObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deserializes the data into the supplied type using JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type to deserialize into</typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public T GetObject<T>()
|
||||||
|
{
|
||||||
|
string json = GetMessage();
|
||||||
|
return JsonConvert.DeserializeObject<T>(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to read the contents of the frame from the stream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool ReadStream(Stream stream)
|
||||||
|
{
|
||||||
|
//Try to read the opcode
|
||||||
|
uint op;
|
||||||
|
if (!TryReadUInt32(stream, out op))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//Try to read the length
|
||||||
|
uint len;
|
||||||
|
if (!TryReadUInt32(stream, out len))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint readsRemaining = len;
|
||||||
|
|
||||||
|
//Read the contents
|
||||||
|
using (var mem = new MemoryStream())
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[Min(2048, len)]; // read in chunks of 2KB
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = stream.Read(buffer, 0, Min(buffer.Length, readsRemaining))) > 0)
|
||||||
|
{
|
||||||
|
readsRemaining -= len;
|
||||||
|
mem.Write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] result = mem.ToArray();
|
||||||
|
if (result.LongLength != len)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Opcode = (Opcode)op;
|
||||||
|
Data = result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//fun
|
||||||
|
//if (a != null) { do { yield return true; switch (a) { case 1: await new Task(); default: lock (obj) { foreach (b in c) { for (int d = 0; d < 1; d++) { a++; } } } while (a is typeof(int) || (new Class()) != null) } goto MY_LABEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns minimum value between a int and a unsigned int
|
||||||
|
/// </summary>
|
||||||
|
private int Min(int a, uint b)
|
||||||
|
{
|
||||||
|
if (b >= a) return a;
|
||||||
|
return (int)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to read a UInt32
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool TryReadUInt32(Stream stream, out uint value)
|
||||||
|
{
|
||||||
|
//Read the bytes available to us
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
int cnt = stream.Read(bytes, 0, bytes.Length);
|
||||||
|
|
||||||
|
//Make sure we actually have a valid value
|
||||||
|
if (cnt != 4)
|
||||||
|
{
|
||||||
|
value = default(uint);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = BitConverter.ToUInt32(bytes, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the frame into the target frame as one big byte block.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
public void WriteStream(Stream stream)
|
||||||
|
{
|
||||||
|
//Get all the bytes
|
||||||
|
byte[] op = BitConverter.GetBytes((uint)Opcode);
|
||||||
|
byte[] len = BitConverter.GetBytes(Length);
|
||||||
|
|
||||||
|
//Copy it all into a buffer
|
||||||
|
byte[] buff = new byte[op.Length + len.Length + Data.Length];
|
||||||
|
op.CopyTo(buff, 0);
|
||||||
|
len.CopyTo(buff, op.Length);
|
||||||
|
Data.CopyTo(buff, op.Length + len.Length);
|
||||||
|
|
||||||
|
//Write it to the stream
|
||||||
|
stream.Write(buff, 0, buff.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
98
SDR-RPC/DiscordAPI/Logging/ConsoleLogger.cs
Normal file
98
SDR-RPC/DiscordAPI/Logging/ConsoleLogger.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Logging
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Logs the outputs to the console using <see cref="Console.WriteLine()"/>
|
||||||
|
/// </summary>
|
||||||
|
public class ConsoleLogger : ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The level of logging to apply to this logger.
|
||||||
|
/// </summary>
|
||||||
|
public LogLevel Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should the output be coloured?
|
||||||
|
/// </summary>
|
||||||
|
public bool Coloured { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A alias too <see cref="Coloured"/>
|
||||||
|
/// </summary>
|
||||||
|
public bool Colored
|
||||||
|
{ get { return Coloured; } set { Coloured = value; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of a Console Logger.
|
||||||
|
/// </summary>
|
||||||
|
public ConsoleLogger()
|
||||||
|
{
|
||||||
|
this.Level = LogLevel.Info;
|
||||||
|
Coloured = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of a Console Logger with a set log level
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level"></param>
|
||||||
|
/// <param name="coloured"></param>
|
||||||
|
public ConsoleLogger(LogLevel level, bool coloured = false)
|
||||||
|
{
|
||||||
|
Level = level;
|
||||||
|
Coloured = coloured;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informative log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Trace(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Trace) return;
|
||||||
|
|
||||||
|
if (Coloured) Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
Console.WriteLine("TRACE: " + message, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informative log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Info(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Info) return;
|
||||||
|
|
||||||
|
if (Coloured) Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.WriteLine("INFO: " + message, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Warning log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Warning(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Warning) return;
|
||||||
|
|
||||||
|
if (Coloured) Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Console.WriteLine("WARN: " + message, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error log messsages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Error(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Error) return;
|
||||||
|
|
||||||
|
if (Coloured) Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine("ERR : " + message, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
SDR-RPC/DiscordAPI/Logging/FileLogger.cs
Normal file
85
SDR-RPC/DiscordAPI/Logging/FileLogger.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
namespace DiscordRPC.Logging
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Logs the outputs to a file
|
||||||
|
/// </summary>
|
||||||
|
public class FileLogger : ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The level of logging to apply to this logger.
|
||||||
|
/// </summary>
|
||||||
|
public LogLevel Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should the output be coloured?
|
||||||
|
/// </summary>
|
||||||
|
public string File { get; set; }
|
||||||
|
|
||||||
|
private object filelock;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the file logger
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the log file.</param>
|
||||||
|
public FileLogger(string path)
|
||||||
|
: this(path, LogLevel.Info) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the file logger
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the log file.</param>
|
||||||
|
/// <param name="level">The level to assign to the logger.</param>
|
||||||
|
public FileLogger(string path, LogLevel level)
|
||||||
|
{
|
||||||
|
Level = level;
|
||||||
|
File = path;
|
||||||
|
filelock = new object();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informative log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Trace(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Trace) return;
|
||||||
|
lock (filelock) System.IO.File.AppendAllText(File, "\r\nTRCE: " + (args.Length > 0 ? string.Format(message, args) : message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informative log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Info(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Info) return;
|
||||||
|
lock (filelock) System.IO.File.AppendAllText(File, "\r\nINFO: " + (args.Length > 0 ? string.Format(message, args) : message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Warning log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Warning(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Warning) return;
|
||||||
|
lock (filelock)
|
||||||
|
System.IO.File.AppendAllText(File, "\r\nWARN: " + (args.Length > 0 ? string.Format(message, args) : message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error log messsages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Error(string message, params object[] args)
|
||||||
|
{
|
||||||
|
if (Level > LogLevel.Error) return;
|
||||||
|
lock (filelock)
|
||||||
|
System.IO.File.AppendAllText(File, "\r\nERR : " + (args.Length > 0 ? string.Format(message, args) : message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
SDR-RPC/DiscordAPI/Logging/ILogger.cs
Normal file
41
SDR-RPC/DiscordAPI/Logging/ILogger.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
namespace DiscordRPC.Logging
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Logging interface to log the internal states of the pipe. Logs are sent in a NON thread safe way. They can come from multiple threads and it is upto the ILogger to account for it.
|
||||||
|
/// </summary>
|
||||||
|
public interface ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The level of logging to apply to this logger.
|
||||||
|
/// </summary>
|
||||||
|
LogLevel Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Debug trace messeages used for debugging internal elements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void Trace(string message, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informative log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void Info(string message, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Warning log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void Warning(string message, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error log messsages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
void Error(string message, params object[] args);
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,10 @@
|
|||||||
using System;
|
namespace DiscordRPC.Logging
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DiscordRPC.Logging
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Level of logging to use.
|
/// Level of logging to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum LogLevel
|
public enum LogLevel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Trace, Info, Warning and Errors are logged
|
/// Trace, Info, Warning and Errors are logged
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -30,9 +25,9 @@ namespace DiscordRPC.Logging
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Error = 4,
|
Error = 4,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Nothing is logged
|
/// Nothing is logged
|
||||||
/// </summary>
|
/// </summary>
|
||||||
None = 256
|
None = 256
|
||||||
}
|
}
|
||||||
}
|
}
|
53
SDR-RPC/DiscordAPI/Logging/NullLogger.cs
Normal file
53
SDR-RPC/DiscordAPI/Logging/NullLogger.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
namespace DiscordRPC.Logging
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ignores all log events
|
||||||
|
/// </summary>
|
||||||
|
public class NullLogger : ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The level of logging to apply to this logger.
|
||||||
|
/// </summary>
|
||||||
|
public LogLevel Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informative log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Trace(string message, params object[] args)
|
||||||
|
{
|
||||||
|
//Null Logger, so no messages are acutally sent
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Informative log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Info(string message, params object[] args)
|
||||||
|
{
|
||||||
|
//Null Logger, so no messages are acutally sent
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Warning log messages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Warning(string message, params object[] args)
|
||||||
|
{
|
||||||
|
//Null Logger, so no messages are acutally sent
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error log messsages
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
public void Error(string message, params object[] args)
|
||||||
|
{
|
||||||
|
//Null Logger, so no messages are acutally sent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
SDR-RPC/DiscordAPI/Message/CloseMessage.cs
Normal file
30
SDR-RPC/DiscordAPI/Message/CloseMessage.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the IPC has closed.
|
||||||
|
/// </summary>
|
||||||
|
public class CloseMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.Close; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reason for the close
|
||||||
|
/// </summary>
|
||||||
|
public string Reason { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The closure code
|
||||||
|
/// </summary>
|
||||||
|
public int Code { get; internal set; }
|
||||||
|
|
||||||
|
internal CloseMessage()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
internal CloseMessage(string reason)
|
||||||
|
{ this.Reason = reason; }
|
||||||
|
}
|
||||||
|
}
|
19
SDR-RPC/DiscordAPI/Message/ConnectionEstablishedMessage.cs
Normal file
19
SDR-RPC/DiscordAPI/Message/ConnectionEstablishedMessage.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The connection to the discord client was succesfull. This is called before <see cref="MessageType.Ready"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class ConnectionEstablishedMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.ConnectionEstablished; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The pipe we ended up connecting too
|
||||||
|
/// </summary>
|
||||||
|
public int ConnectedPipe { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
19
SDR-RPC/DiscordAPI/Message/ConnectionFailedMessage.cs
Normal file
19
SDR-RPC/DiscordAPI/Message/ConnectionFailedMessage.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Failed to establish any connection with discord. Discord is potentially not running?
|
||||||
|
/// </summary>
|
||||||
|
public class ConnectionFailedMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.ConnectionFailed; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The pipe we failed to connect too.
|
||||||
|
/// </summary>
|
||||||
|
public int FailedPipe { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
76
SDR-RPC/DiscordAPI/Message/ErrorMessage.cs
Normal file
76
SDR-RPC/DiscordAPI/Message/ErrorMessage.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Created when a error occurs within the ipc and it is sent to the client.
|
||||||
|
/// </summary>
|
||||||
|
public class ErrorMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.Error; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord error code.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("code")]
|
||||||
|
public ErrorCode Code { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message associated with the error code.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("message")]
|
||||||
|
public string Message { get; internal set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The error message received by discord. See https://discordapp.com/developers/docs/topics/rpc#rpc-server-payloads-rpc-errors for documentation
|
||||||
|
/// </summary>
|
||||||
|
public enum ErrorCode
|
||||||
|
{
|
||||||
|
//Pipe Error Codes
|
||||||
|
/// <summary> Pipe was Successful </summary>
|
||||||
|
Success = 0,
|
||||||
|
|
||||||
|
///<summary>The pipe had an exception</summary>
|
||||||
|
PipeException = 1,
|
||||||
|
|
||||||
|
///<summary>The pipe received corrupted data</summary>
|
||||||
|
ReadCorrupt = 2,
|
||||||
|
|
||||||
|
//Custom Error Code
|
||||||
|
///<summary>The functionality was not yet implemented</summary>
|
||||||
|
NotImplemented = 10,
|
||||||
|
|
||||||
|
//Discord RPC error codes
|
||||||
|
///<summary>Unkown Discord error</summary>
|
||||||
|
UnkownError = 1000,
|
||||||
|
|
||||||
|
///<summary>Invalid Payload received</summary>
|
||||||
|
InvalidPayload = 4000,
|
||||||
|
|
||||||
|
///<summary>Invalid command was sent</summary>
|
||||||
|
InvalidCommand = 4002,
|
||||||
|
|
||||||
|
/// <summary>Invalid event was sent </summary>
|
||||||
|
InvalidEvent = 4004,
|
||||||
|
|
||||||
|
/*
|
||||||
|
InvalidGuild = 4003,
|
||||||
|
InvalidChannel = 4005,
|
||||||
|
InvalidPermissions = 4006,
|
||||||
|
InvalidClientID = 4007,
|
||||||
|
InvalidOrigin = 4008,
|
||||||
|
InvalidToken = 4009,
|
||||||
|
InvalidUser = 4010,
|
||||||
|
OAuth2Error = 5000,
|
||||||
|
SelectChannelTimeout = 5001,
|
||||||
|
GetGuildTimeout = 5002,
|
||||||
|
SelectVoiceForceRequired = 5003,
|
||||||
|
CaptureShortcutAlreadyListening = 5004
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
31
SDR-RPC/DiscordAPI/Message/IMessage.cs
Normal file
31
SDR-RPC/DiscordAPI/Message/IMessage.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Messages received from discord.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public abstract MessageType Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time the message was created
|
||||||
|
/// </summary>
|
||||||
|
public DateTime TimeCreated
|
||||||
|
{ get { return _timecreated; } }
|
||||||
|
|
||||||
|
private DateTime _timecreated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the message
|
||||||
|
/// </summary>
|
||||||
|
public IMessage()
|
||||||
|
{
|
||||||
|
_timecreated = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
SDR-RPC/DiscordAPI/Message/JoinMessage.cs
Normal file
22
SDR-RPC/DiscordAPI/Message/JoinMessage.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the Discord Client wishes for this process to join a game. D -> C.
|
||||||
|
/// </summary>
|
||||||
|
public class JoinMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.Join; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="Secrets.JoinSecret" /> to connect with.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("secret")]
|
||||||
|
public string Secret { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
22
SDR-RPC/DiscordAPI/Message/JoinRequestMessage.cs
Normal file
22
SDR-RPC/DiscordAPI/Message/JoinRequestMessage.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called when some other person has requested access to this game. C -> D -> C.
|
||||||
|
/// </summary>
|
||||||
|
public class JoinRequestMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.JoinRequest; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The discord user that is requesting access.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("user")]
|
||||||
|
public User User { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
63
SDR-RPC/DiscordAPI/Message/MessageType.cs
Normal file
63
SDR-RPC/DiscordAPI/Message/MessageType.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Type of message.
|
||||||
|
/// </summary>
|
||||||
|
public enum MessageType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord Client is ready to send and receive messages.
|
||||||
|
/// </summary>
|
||||||
|
Ready,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The connection to the Discord Client is lost. The connection will remain close and unready to accept messages until the Ready event is called again.
|
||||||
|
/// </summary>
|
||||||
|
Close,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A error has occured during the transmission of a message. For example, if a bad Rich Presence payload is sent, this event will be called explaining what went wrong.
|
||||||
|
/// </summary>
|
||||||
|
Error,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord Client has updated the presence.
|
||||||
|
/// </summary>
|
||||||
|
PresenceUpdate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord Client has subscribed to an event.
|
||||||
|
/// </summary>
|
||||||
|
Subscribe,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord Client has unsubscribed from an event.
|
||||||
|
/// </summary>
|
||||||
|
Unsubscribe,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord Client wishes for this process to join a game.
|
||||||
|
/// </summary>
|
||||||
|
Join,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Discord Client wishes for this process to spectate a game.
|
||||||
|
/// </summary>
|
||||||
|
Spectate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Another discord user requests permission to join this game.
|
||||||
|
/// </summary>
|
||||||
|
JoinRequest,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The connection to the discord client was succesfull. This is called before <see cref="Ready"/>.
|
||||||
|
/// </summary>
|
||||||
|
ConnectionEstablished,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Failed to establish any connection with discord. Discord is potentially not running?
|
||||||
|
/// </summary>
|
||||||
|
ConnectionFailed
|
||||||
|
}
|
||||||
|
}
|
49
SDR-RPC/DiscordAPI/Message/PresenceMessage.cs
Normal file
49
SDR-RPC/DiscordAPI/Message/PresenceMessage.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Representation of the message received by discord when the presence has been updated.
|
||||||
|
/// </summary>
|
||||||
|
public class PresenceMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.PresenceUpdate; } }
|
||||||
|
|
||||||
|
internal PresenceMessage() : this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal PresenceMessage(RichPresenceResponse rpr)
|
||||||
|
{
|
||||||
|
if (rpr == null)
|
||||||
|
{
|
||||||
|
Presence = null;
|
||||||
|
Name = "No Rich Presence";
|
||||||
|
ApplicationID = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Presence = (RichPresence)rpr;
|
||||||
|
Name = rpr.Name;
|
||||||
|
ApplicationID = rpr.ClientID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The rich presence Discord has set
|
||||||
|
/// </summary>
|
||||||
|
public RichPresence Presence { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the application Discord has set it for
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the application discord has set it for
|
||||||
|
/// </summary>
|
||||||
|
public string ApplicationID { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
34
SDR-RPC/DiscordAPI/Message/ReadyMessage.cs
Normal file
34
SDR-RPC/DiscordAPI/Message/ReadyMessage.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the ipc is ready to send arguments.
|
||||||
|
/// </summary>
|
||||||
|
public class ReadyMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.Ready; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The configuration of the connection
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("config")]
|
||||||
|
public Configuration Configuration { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User the connection belongs too
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("user")]
|
||||||
|
public User User { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The version of the RPC
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("v")]
|
||||||
|
public int Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
14
SDR-RPC/DiscordAPI/Message/SpectateMessage.cs
Normal file
14
SDR-RPC/DiscordAPI/Message/SpectateMessage.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the Discord Client wishes for this process to spectate a game. D -> C.
|
||||||
|
/// </summary>
|
||||||
|
public class SpectateMessage : JoinMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.Spectate; } }
|
||||||
|
}
|
||||||
|
}
|
40
SDR-RPC/DiscordAPI/Message/SubscribeMessage.cs
Normal file
40
SDR-RPC/DiscordAPI/Message/SubscribeMessage.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using DiscordRPC.RPC.Payload;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called as validation of a subscribe
|
||||||
|
/// </summary>
|
||||||
|
public class SubscribeMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.Subscribe; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The event that was subscribed too.
|
||||||
|
/// </summary>
|
||||||
|
public EventType Event { get; internal set; }
|
||||||
|
|
||||||
|
internal SubscribeMessage(ServerEvent evt)
|
||||||
|
{
|
||||||
|
switch (evt)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case ServerEvent.ActivityJoin:
|
||||||
|
Event = EventType.Join;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerEvent.ActivityJoinRequest:
|
||||||
|
Event = EventType.JoinRequest;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerEvent.ActivitySpectate:
|
||||||
|
Event = EventType.Spectate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
SDR-RPC/DiscordAPI/Message/UnsubscribeMsesage.cs
Normal file
40
SDR-RPC/DiscordAPI/Message/UnsubscribeMsesage.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using DiscordRPC.RPC.Payload;
|
||||||
|
|
||||||
|
namespace DiscordRPC.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called as validation of a subscribe
|
||||||
|
/// </summary>
|
||||||
|
public class UnsubscribeMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of message received from discord
|
||||||
|
/// </summary>
|
||||||
|
public override MessageType Type
|
||||||
|
{ get { return MessageType.Unsubscribe; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The event that was subscribed too.
|
||||||
|
/// </summary>
|
||||||
|
public EventType Event { get; internal set; }
|
||||||
|
|
||||||
|
internal UnsubscribeMessage(ServerEvent evt)
|
||||||
|
{
|
||||||
|
switch (evt)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case ServerEvent.ActivityJoin:
|
||||||
|
Event = EventType.Join;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerEvent.ActivityJoinRequest:
|
||||||
|
Event = EventType.JoinRequest;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerEvent.ActivitySpectate:
|
||||||
|
Event = EventType.Spectate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
SDR-RPC/DiscordAPI/RPC/Commands/CloseCommand.cs
Normal file
30
SDR-RPC/DiscordAPI/RPC/Commands/CloseCommand.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using DiscordRPC.RPC.Payload;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Commands
|
||||||
|
{
|
||||||
|
internal class CloseCommand : ICommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The process ID
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("pid")]
|
||||||
|
public int PID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The rich presence to be set. Can be null.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("close_reason")]
|
||||||
|
public string value = "Unity 5.5 doesn't handle thread aborts. Can you please close me discord?";
|
||||||
|
|
||||||
|
public IPayload PreparePayload(long nonce)
|
||||||
|
{
|
||||||
|
return new ArgumentPayload()
|
||||||
|
{
|
||||||
|
Command = Command.Dispatch,
|
||||||
|
Nonce = null,
|
||||||
|
Arguments = null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
SDR-RPC/DiscordAPI/RPC/Commands/ICommand.cs
Normal file
9
SDR-RPC/DiscordAPI/RPC/Commands/ICommand.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using DiscordRPC.RPC.Payload;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Commands
|
||||||
|
{
|
||||||
|
internal interface ICommand
|
||||||
|
{
|
||||||
|
IPayload PreparePayload(long nonce);
|
||||||
|
}
|
||||||
|
}
|
28
SDR-RPC/DiscordAPI/RPC/Commands/PresenceCommand.cs
Normal file
28
SDR-RPC/DiscordAPI/RPC/Commands/PresenceCommand.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using DiscordRPC.RPC.Payload;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Commands
|
||||||
|
{
|
||||||
|
internal class PresenceCommand : ICommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The process ID
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("pid")]
|
||||||
|
public int PID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The rich presence to be set. Can be null.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("activity")]
|
||||||
|
public RichPresence Presence { get; set; }
|
||||||
|
|
||||||
|
public IPayload PreparePayload(long nonce)
|
||||||
|
{
|
||||||
|
return new ArgumentPayload(this, nonce)
|
||||||
|
{
|
||||||
|
Command = Command.SetActivity
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
SDR-RPC/DiscordAPI/RPC/Commands/RespondCommand.cs
Normal file
28
SDR-RPC/DiscordAPI/RPC/Commands/RespondCommand.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using DiscordRPC.RPC.Payload;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Commands
|
||||||
|
{
|
||||||
|
internal class RespondCommand : ICommand
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The user ID that we are accepting / rejecting
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("user_id")]
|
||||||
|
public string UserID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the user will be allowed to connect.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool Accept { get; set; }
|
||||||
|
|
||||||
|
public IPayload PreparePayload(long nonce)
|
||||||
|
{
|
||||||
|
return new ArgumentPayload(this, nonce)
|
||||||
|
{
|
||||||
|
Command = Accept ? Command.SendActivityJoinInvite : Command.CloseActivityJoinRequest
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
SDR-RPC/DiscordAPI/RPC/Commands/SubscribeCommand.cs
Normal file
19
SDR-RPC/DiscordAPI/RPC/Commands/SubscribeCommand.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using DiscordRPC.RPC.Payload;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Commands
|
||||||
|
{
|
||||||
|
internal class SubscribeCommand : ICommand
|
||||||
|
{
|
||||||
|
public ServerEvent Event { get; set; }
|
||||||
|
public bool IsUnsubscribe { get; set; }
|
||||||
|
|
||||||
|
public IPayload PreparePayload(long nonce)
|
||||||
|
{
|
||||||
|
return new EventPayload(nonce)
|
||||||
|
{
|
||||||
|
Command = IsUnsubscribe ? Command.Unsubscribe : Command.Subscribe,
|
||||||
|
Event = Event
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
SDR-RPC/DiscordAPI/RPC/Payload/ClosePayload.cs
Normal file
19
SDR-RPC/DiscordAPI/RPC/Payload/ClosePayload.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Payload
|
||||||
|
{
|
||||||
|
internal class ClosePayload : IPayload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The close code the discord gave us
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("code")]
|
||||||
|
public int Code { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The close reason discord gave us
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("message")]
|
||||||
|
public string Reason { get; set; }
|
||||||
|
}
|
||||||
|
}
|
125
SDR-RPC/DiscordAPI/RPC/Payload/Command.cs
Normal file
125
SDR-RPC/DiscordAPI/RPC/Payload/Command.cs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
using DiscordRPC.Converters;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Payload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The possible commands that can be sent and received by the server.
|
||||||
|
/// </summary>
|
||||||
|
internal enum Command
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// event dispatch
|
||||||
|
/// </summary>
|
||||||
|
[EnumValue("DISPATCH")]
|
||||||
|
Dispatch,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called to set the activity
|
||||||
|
/// </summary>
|
||||||
|
[EnumValue("SET_ACTIVITY")]
|
||||||
|
SetActivity,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to subscribe to an RPC event
|
||||||
|
/// </summary>
|
||||||
|
[EnumValue("SUBSCRIBE")]
|
||||||
|
Subscribe,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to unsubscribe from an RPC event
|
||||||
|
/// </summary>
|
||||||
|
[EnumValue("UNSUBSCRIBE")]
|
||||||
|
Unsubscribe,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to accept join requests.
|
||||||
|
/// </summary>
|
||||||
|
[EnumValue("SEND_ACTIVITY_JOIN_INVITE")]
|
||||||
|
SendActivityJoinInvite,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to reject join requests.
|
||||||
|
/// </summary>
|
||||||
|
[EnumValue("CLOSE_ACTIVITY_JOIN_REQUEST")]
|
||||||
|
CloseActivityJoinRequest,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to authorize a new client with your app
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
Authorize,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to authenticate an existing client with your app
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
Authenticate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to retrieve guild information from the client
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
GetGuild,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to retrieve a list of guilds from the client
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
GetGuilds,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to retrieve channel information from the client
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
GetChannel,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to retrieve a list of channels for a guild from the client
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
GetChannels,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to change voice settings of users in voice channels
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
SetUserVoiceSettings,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to join or leave a voice channel, group dm, or dm
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
SelectVoiceChannel,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to get the current voice channel the client is in
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
GetSelectedVoiceChannel,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to join or leave a text channel, group dm, or dm
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
SelectTextChannel,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to retrieve the client's voice settings
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
GetVoiceSettings,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to set the client's voice settings
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
SetVoiceSettings,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// used to capture a keyboard shortcut entered by the user RPC Events
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
|
||||||
|
CaptureShortcut
|
||||||
|
}
|
||||||
|
}
|
36
SDR-RPC/DiscordAPI/RPC/Payload/IPayload.cs
Normal file
36
SDR-RPC/DiscordAPI/RPC/Payload/IPayload.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using DiscordRPC.Converters;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Payload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base Payload that is received by both client and server
|
||||||
|
/// </summary>
|
||||||
|
internal abstract class IPayload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of payload
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("cmd"), JsonConverter(typeof(EnumSnakeCaseConverter))]
|
||||||
|
public Command Command { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A incremental value to help identify payloads
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("nonce")]
|
||||||
|
public string Nonce { get; set; }
|
||||||
|
|
||||||
|
protected IPayload()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected IPayload(long nonce)
|
||||||
|
{
|
||||||
|
Nonce = nonce.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Payload || Command: " + Command.ToString() + ", Nonce: " + (Nonce != null ? Nonce.ToString() : "NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
SDR-RPC/DiscordAPI/RPC/Payload/PayloadArgument.cs
Normal file
59
SDR-RPC/DiscordAPI/RPC/Payload/PayloadArgument.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Payload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The payload that is sent by the client to discord for events such as setting the rich presence.
|
||||||
|
/// <para>
|
||||||
|
/// SetPrecense
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
internal class ArgumentPayload : IPayload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The data the server sent too us
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("args", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public JObject Arguments { get; set; }
|
||||||
|
|
||||||
|
public ArgumentPayload() : base()
|
||||||
|
{
|
||||||
|
Arguments = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArgumentPayload(long nonce) : base(nonce)
|
||||||
|
{
|
||||||
|
Arguments = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArgumentPayload(object args, long nonce) : base(nonce)
|
||||||
|
{
|
||||||
|
SetObject(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the obejct stored within the data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
public void SetObject(object obj)
|
||||||
|
{
|
||||||
|
Arguments = JObject.FromObject(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the object stored within the Data
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public T GetObject<T>()
|
||||||
|
{
|
||||||
|
return Arguments.ToObject<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Argument " + base.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
SDR-RPC/DiscordAPI/RPC/Payload/PayloadEvent.cs
Normal file
55
SDR-RPC/DiscordAPI/RPC/Payload/PayloadEvent.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using DiscordRPC.Converters;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace DiscordRPC.RPC.Payload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used for Discord IPC Events
|
||||||
|
/// </summary>
|
||||||
|
internal class EventPayload : IPayload
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The data the server sent too us
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public JObject Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of event the server sent
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("evt"), JsonConverter(typeof(EnumSnakeCaseConverter))]
|
||||||
|
public ServerEvent? Event { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a payload with empty data
|
||||||
|
/// </summary>
|
||||||
|
public EventPayload() : base() { Data = null; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a payload with empty data and a set nonce
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nonce"></param>
|
||||||
|
public EventPayload(long nonce) : base(nonce) { Data = null; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the object stored within the Data
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public T GetObject<T>()
|
||||||
|
{
|
||||||
|
if (Data == null) return default(T);
|
||||||
|
return Data.ToObject<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the object into a human readable string
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Event " + base.ToString() + ", Event: " + (Event.HasValue ? Event.ToString() : "N/A");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
using DiscordRPC.Converters;
|
using DiscordRPC.Converters;
|
||||||
using System;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
|
|
||||||
namespace DiscordRPC.RPC.Payload
|
namespace DiscordRPC.RPC.Payload
|
||||||
{
|
{
|
||||||
@ -8,37 +6,36 @@ namespace DiscordRPC.RPC.Payload
|
|||||||
/// See https://discordapp.com/developers/docs/topics/rpc#rpc-server-payloads-rpc-events for documentation
|
/// See https://discordapp.com/developers/docs/topics/rpc#rpc-server-payloads-rpc-events for documentation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal enum ServerEvent
|
internal enum ServerEvent
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sent when the server is ready to accept messages
|
||||||
|
/// </summary>
|
||||||
|
[EnumValue("READY")]
|
||||||
|
Ready,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sent when the server is ready to accept messages
|
/// Sent when something bad has happened
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumValue("READY")]
|
[EnumValue("ERROR")]
|
||||||
Ready,
|
Error,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sent when something bad has happened
|
/// Join Event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumValue("ERROR")]
|
[EnumValue("ACTIVITY_JOIN")]
|
||||||
Error,
|
ActivityJoin,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Join Event
|
/// Spectate Event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumValue("ACTIVITY_JOIN")]
|
[EnumValue("ACTIVITY_SPECTATE")]
|
||||||
ActivityJoin,
|
ActivitySpectate,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spectate Event
|
/// Request Event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumValue("ACTIVITY_SPECTATE")]
|
[EnumValue("ACTIVITY_JOIN_REQUEST")]
|
||||||
ActivitySpectate,
|
ActivityJoinRequest,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Request Event
|
|
||||||
/// </summary>
|
|
||||||
[EnumValue("ACTIVITY_JOIN_REQUEST")]
|
|
||||||
ActivityJoinRequest,
|
|
||||||
|
|
||||||
#if INCLUDE_FULL_RPC
|
#if INCLUDE_FULL_RPC
|
||||||
//Old things that are obsolete
|
//Old things that are obsolete
|
||||||
@ -92,4 +89,4 @@ namespace DiscordRPC.RPC.Payload
|
|||||||
CaptureShortcutChange
|
CaptureShortcutChange
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user