Skip to content

Added Authorize Command. #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions DiscordRPC.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using DiscordRPC.Message;
using DiscordRPC.Events;
using DiscordRPC.Message;
using System;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -142,6 +143,8 @@ static void FullClientExample()

//Register to the events we care about. We are registering to everyone just to show off the events

client.OnAuthorize += OnAuthorize;

client.OnReady += OnReady; //Called when the client is ready to send presences
client.OnClose += OnClose; //Called when connection to discord is lost
client.OnError += OnError; //Called when discord has a error
Expand All @@ -159,7 +162,7 @@ static void FullClientExample()
client.OnJoinRequested += OnJoinRequested; //Called when someone else has requested to join this client.

//Before we send a initial presence, we will generate a random "game ID" for this example.
// For a real game, this "game ID" can be a unique ID that your Match Maker / Master Server generates.
// For a real game, this "game ID" can be a unique ID that your Match Maker / Master Server generates.
// This is used for the Join / Specate feature. This can be ignored if you do not plan to implement that feature.
presence.Secrets = new Secrets()
{
Expand Down Expand Up @@ -192,7 +195,7 @@ static void FullClientExample()
client.SetSubscription(EventType.Join | EventType.Spectate | EventType.JoinRequest); //This will alert us if discord wants to join a game

//Set some new presence to tell Discord we are in a game.
// If the connection is not yet available, this will be queued until a Ready event is called,
// If the connection is not yet available, this will be queued until a Ready event is called,
// then it will be sent. All messages are queued until Discord is ready to receive them.
client.SetPresence(presence);

Expand All @@ -209,14 +212,14 @@ static void MainLoop()
{
/*
* Enter a infinite loop, polling the Discord Client for events.
* In game termonology, this will be equivalent to our main game loop.
* In game termonology, this will be equivalent to our main game loop.
* If you were making a GUI application without a infinite loop, you could implement
* this with timers.
*/
isRunning = true;
while (client != null && isRunning)
{
//We will invoke the client events.
//We will invoke the client events.
// In a game situation, you would do this in the Update.
// Not required if AutoEvents is enabled.
//if (client != null && !client.AutoEvents)
Expand Down Expand Up @@ -270,9 +273,17 @@ static async void ReadyTaskExample()
#region Events

#region State Events
private static void OnAuthorize(object sender, AuthorizeMessage args)
{
//This is called after the user has authorized the application.

Console.WriteLine("On Authorize. Auth code: {0}", args.Code);

}

private static void OnReady(object sender, ReadyMessage args)
{
//This is called when we are all ready to start receiving and sending discord events.
//This is called when we are all ready to start receiving and sending discord events.
// It will give us some basic information about discord to use in the future.

//DEBUG: Update the presence timestamp
Expand Down Expand Up @@ -304,7 +315,7 @@ private static void OnConnectionEstablished(object sender, ConnectionEstablished
}
private static void OnConnectionFailed(object sender, ConnectionFailedMessage args)
{
//This is called when the client fails to establish a connection to discord.
//This is called when the client fails to establish a connection to discord.
// It can be assumed that Discord is unavailable on the supplied pipe.
Console.WriteLine("Pipe Connection Failed. Could not connect to pipe #{0}", args.FailedPipe);
isRunning = false;
Expand Down Expand Up @@ -337,11 +348,11 @@ private static void OnJoin(object sender, JoinMessage args)
/*
* This is called when the Discord Client wants to join a online game to play.
* It can be triggered from a invite that your user has clicked on within discord or from an accepted invite.
*
*
* The secret should be some sort of encrypted data that will give your game the nessary information to connect.
* For example, it could be the Game ID and the Game Password which will allow you to look up from the Master Server.
* Please avoid using IP addresses within these fields, its not secure and defeats the Discord security measures.
*
*
* This feature requires the RegisterURI to be true on the client.
*/
Console.WriteLine("Joining Game '{0}'", args.Secret);
Expand All @@ -351,11 +362,11 @@ private static void OnSpectate(object sender, SpectateMessage args)
{ /*
* This is called when the Discord Client wants to join a online game to watch and spectate.
* It can be triggered from a invite that your user has clicked on within discord.
*
*
* The secret should be some sort of encrypted data that will give your game the nessary information to connect.
* For example, it could be the Game ID and the Game Password which will allow you to look up from the Master Server.
* Please avoid using IP addresses within these fields, its not secure and defeats the Discord security measures.
*
*
* This feature requires the RegisterURI to be true on the client.
*/
Console.WriteLine("Spectating Game '{0}'", args.Secret);
Expand All @@ -368,10 +379,10 @@ private static void OnJoinRequested(object sender, JoinRequestMessage args)
* You should trigger a UI prompt to your user sayings 'X wants to join your game' with a YES or NO button. You can also get
* other information about the user such as their avatar (which this library will provide a useful link) and their nickname to
* make it more personalised. You can combine this with more API if you wish. Check the Discord API documentation.
*
*
* Once a user clicks on a response, call the Respond function, passing the message, to respond to the request.
* A example is provided below.
*
*
* This feature requires the RegisterURI to be true on the client.
*/

Expand Down
76 changes: 53 additions & 23 deletions DiscordRPC/DiscordRpcClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public sealed class DiscordRpcClient : IDisposable
public int ProcessID { get; private set; }

/// <summary>
/// The maximum size of the message queue received from Discord.
/// The maximum size of the message queue received from Discord.
/// </summary>
public int MaxQueueSize { get; private set; }

Expand All @@ -65,7 +65,7 @@ public ILogger Logger
private ILogger _logger;

/// <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>
public bool AutoEvents { get; private set; }

Expand Down Expand Up @@ -126,6 +126,12 @@ public bool ShutdownOnly

#region Events

/// <summary>
/// Called when the discord client has received an Authorize response.
/// <para>If <see cref="AutoEvents"/> is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill <see cref="Invoke"/> and will be on the calling thread.</para>
/// </summary>
public event OnAuthorizeEvent OnAuthorize;

/// <summary>
/// Called when the discord client is ready to send and receive messages.
/// <para>If <see cref="AutoEvents"/> is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill <see cref="Invoke"/> and will be on the calling thread.</para>
Expand Down Expand Up @@ -288,6 +294,11 @@ private void ProcessMessage(IMessage message)
if (message == null) return;
switch (message.Type)
{
case MessageType.Authorize:
if (OnAuthorize != null)
OnAuthorize.Invoke(this, message as AuthorizeMessage);
break;

//We got a update, so we will update our current presence
case MessageType.PresenceUpdate:
lock (_sync)
Expand Down Expand Up @@ -333,14 +344,14 @@ private void ProcessMessage(IMessage message)
//Resend our presence and subscription
SynchronizeState();
}
if (OnReady != null)

if (OnReady != null)
OnReady.Invoke(this, message as ReadyMessage);

break;

case MessageType.Close:
if (OnClose != null)
if (OnClose != null)
OnClose.Invoke(this, message as CloseMessage);
break;

Expand All @@ -366,9 +377,9 @@ private void ProcessMessage(IMessage message)
{
var sub = message as SubscribeMessage;
Subscription |= sub.Event;
}
if (OnSubscribe != null)
}

if (OnSubscribe != null)
OnSubscribe.Invoke(this, message as SubscribeMessage);

break;
Expand Down Expand Up @@ -413,6 +424,25 @@ private void ProcessMessage(IMessage message)
}
#endregion

/// <summary>
/// Used to authenticate a new client with your app. By default this pops up a modal in-app that asks the user to authorize access to your app.
/// </summary>
/// <param name="clientID">The OAuth2 application id.</param>
/// <param name="scopes">The scopes to authorize.</param>
public void Authorize(string clientID, params string[] scopes)
{
if (IsDisposed)
throw new ObjectDisposedException("Discord IPC Client");

if (connection == null)
throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");

if (!IsInitialized)
throw new UninitializedException();

connection.EnqueueCommand(new AuthorizeCommand { clientID = clientID, scopes = scopes });
}

/// <summary>
/// Respond to a Join Request. All requests will timeout after 30 seconds.
/// <para>Because of the 30 second timeout, it is recommended to call <seealso cref="Invoke"/> faster than every 15 seconds to give your users adequate time to respond to the request.</para>
Expand Down Expand Up @@ -474,7 +504,7 @@ public void SetPresence(RichPresence presence)
}

//Update our local store
lock (_sync)
lock (_sync)
{
CurrentPresence = presence?.Clone();
}
Expand Down Expand Up @@ -567,7 +597,7 @@ public RichPresence UpdateDetails(string details)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
presence.Details = details;
SetPresence(presence);
return presence;
Expand All @@ -590,7 +620,7 @@ public RichPresence UpdateState(string state)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
presence.State = state;
SetPresence(presence);
return presence;
Expand All @@ -613,7 +643,7 @@ public RichPresence UpdateParty(Party party)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
presence.Party = party;
SetPresence(presence);
return presence;
Expand Down Expand Up @@ -641,7 +671,7 @@ public RichPresence UpdatePartySize(int size)
if (presence.Party == null)
throw new BadPresenceException("Cannot set the size of the party if the party does not exist");

//Update the value
//Update the value
presence.Party.Size = size;
SetPresence(presence);
return presence;
Expand Down Expand Up @@ -671,7 +701,7 @@ public RichPresence UpdatePartySize(int size, int max)
if (presence.Party == null)
throw new BadPresenceException("Cannot set the size of the party if the party does not exist");

//Update the value
//Update the value
presence.Party.Size = size;
presence.Party.Max = max;
SetPresence(presence);
Expand All @@ -696,7 +726,7 @@ public RichPresence UpdateLargeAsset(string key = null, string tooltip = null)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
if (presence.Assets == null) presence.Assets = new Assets();
presence.Assets.LargeImageKey = key ?? presence.Assets.LargeImageKey;
presence.Assets.LargeImageText = tooltip ?? presence.Assets.LargeImageText;
Expand All @@ -722,7 +752,7 @@ public RichPresence UpdateSmallAsset(string key = null, string tooltip = null)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
if (presence.Assets == null) presence.Assets = new Assets();
presence.Assets.SmallImageKey = key ?? presence.Assets.SmallImageKey;
presence.Assets.SmallImageText = tooltip ?? presence.Assets.SmallImageText;
Expand All @@ -748,7 +778,7 @@ public RichPresence UpdateSecrets(Secrets secrets)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
presence.Secrets = secrets;
SetPresence(presence);
return presence;
Expand Down Expand Up @@ -778,7 +808,7 @@ public RichPresence UpdateStartTime(DateTime time)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
if (presence.Timestamps == null) presence.Timestamps = new Timestamps();
presence.Timestamps.Start = time;
SetPresence(presence);
Expand Down Expand Up @@ -809,7 +839,7 @@ public RichPresence UpdateEndTime(DateTime time)
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
if (presence.Timestamps == null) presence.Timestamps = new Timestamps();
presence.Timestamps.End = time;
SetPresence(presence);
Expand All @@ -833,7 +863,7 @@ public RichPresence UpdateClearTime()
else { presence = CurrentPresence.Clone(); }
}

//Update the value
//Update the value
presence.Timestamps = null;
SetPresence(presence);
return presence;
Expand Down Expand Up @@ -881,7 +911,7 @@ public bool RegisterUriScheme(string steamAppID = null, string executable = null
public void Subscribe(EventType type) { SetSubscription(Subscription | type); }

/// <summary>
///
///
/// </summary>
/// <param name="type"></param>
[System.Obsolete("Replaced with Unsubscribe", true)]
Expand Down Expand Up @@ -925,7 +955,7 @@ public void SetSubscription(EventType type)
/// <param name="isUnsubscribe">Represents if the unsubscribe payload should be sent instead.</param>
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 (type == EventType.None) return;

Expand Down
7 changes: 7 additions & 0 deletions DiscordRPC/Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

namespace DiscordRPC.Events
{
/// <summary>
/// Called when the Discord Client has received an Authorize Response.
/// </summary>
/// <param name="sender">The Discord client handler that sent this event</param>
/// <param name="args">The arguments supplied with the event</param>
public delegate void OnAuthorizeEvent(object sender, AuthorizeMessage args);

/// <summary>
/// Called when the Discord Client is ready to send and receive messages.
/// </summary>
Expand Down
35 changes: 35 additions & 0 deletions DiscordRPC/Message/AuthorizeMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using DiscordRPC.RPC.Commands;
using System;
using System.Collections.Generic;
using System.Text;

namespace DiscordRPC.Message
{
/// <summary>
/// Representation of the message received by discord when an authorization response has been received.
/// </summary>
public class AuthorizeMessage : IMessage
{
/// <summary>
/// The type of message received from discord
/// </summary>
public override MessageType Type { get { return MessageType.Authorize; } }

internal AuthorizeMessage(AuthorizeResponse auth)
{
if (auth == null)
{
Code = "";
}
else
{
Code = auth.Code;
}
}

/// <summary>
/// The OAuth2 authorization code
/// </summary>
public string Code { get; internal set; }
}
}
Loading