Add basic websocket redirect support
This commit is contained in:
@@ -15,9 +15,11 @@ namespace Discord.API.Models
|
|||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "op")]
|
[JsonProperty(PropertyName = "op")]
|
||||||
public int Operation;
|
public int Operation;
|
||||||
[JsonProperty(PropertyName = "t")]
|
[JsonProperty(PropertyName = "t", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public string Type;
|
public string Type;
|
||||||
[JsonProperty(PropertyName = "d")]
|
[JsonProperty(PropertyName = "s", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public int? Sequence;
|
||||||
|
[JsonProperty(PropertyName = "d", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public object Payload;
|
public object Payload;
|
||||||
}
|
}
|
||||||
internal abstract class WebSocketMessage<T> : WebSocketMessage
|
internal abstract class WebSocketMessage<T> : WebSocketMessage
|
||||||
@@ -78,5 +80,16 @@ namespace Discord.API.Models
|
|||||||
public string SelfDeaf;
|
public string SelfDeaf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public sealed class Resume : WebSocketMessage<Resume.Data>
|
||||||
|
{
|
||||||
|
public Resume() : base(6) { }
|
||||||
|
public class Data
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "session_id")]
|
||||||
|
public string SessionId;
|
||||||
|
[JsonProperty(PropertyName = "seq")]
|
||||||
|
public int Sequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ namespace Discord.API.Models
|
|||||||
public int HeartbeatInterval;
|
public int HeartbeatInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class Redirect
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "url")]
|
||||||
|
public string Url;
|
||||||
|
}
|
||||||
|
|
||||||
//Servers
|
//Servers
|
||||||
public sealed class GuildCreate : ExtendedServerInfo { }
|
public sealed class GuildCreate : ExtendedServerInfo { }
|
||||||
public sealed class GuildUpdate : ServerInfo { }
|
public sealed class GuildUpdate : ServerInfo { }
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ namespace Discord
|
|||||||
internal sealed partial class DiscordDataSocket : DiscordWebSocket
|
internal sealed partial class DiscordDataSocket : DiscordWebSocket
|
||||||
{
|
{
|
||||||
private readonly ManualResetEventSlim _connectWaitOnLogin, _connectWaitOnLogin2;
|
private readonly ManualResetEventSlim _connectWaitOnLogin, _connectWaitOnLogin2;
|
||||||
|
private string _lastSession, _redirectServer;
|
||||||
|
private int _lastSeq;
|
||||||
|
|
||||||
public DiscordDataSocket(DiscordClient client, int timeout, int interval, bool isDebug)
|
public DiscordDataSocket(DiscordClient client, int timeout, int interval, bool isDebug)
|
||||||
: base(client, timeout, interval, isDebug)
|
: base(client, timeout, interval, isDebug)
|
||||||
@@ -20,10 +22,13 @@ namespace Discord
|
|||||||
_connectWaitOnLogin2 = new ManualResetEventSlim(false);
|
_connectWaitOnLogin2 = new ManualResetEventSlim(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task ConnectAsync(string url)
|
public override async Task ConnectAsync(string url)
|
||||||
{
|
{
|
||||||
BeginConnect();
|
_lastSeq = 0;
|
||||||
return base.ConnectAsync(url);
|
_lastSession = null;
|
||||||
|
_redirectServer = null;
|
||||||
|
await BeginConnect();
|
||||||
|
await base.ConnectAsync(url);
|
||||||
}
|
}
|
||||||
public async Task Login(string token)
|
public async Task Login(string token)
|
||||||
{
|
{
|
||||||
@@ -65,6 +70,8 @@ namespace Discord
|
|||||||
protected override Task ProcessMessage(string json)
|
protected override Task ProcessMessage(string json)
|
||||||
{
|
{
|
||||||
var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json);
|
var msg = JsonConvert.DeserializeObject<WebSocketMessage>(json);
|
||||||
|
if (msg.Sequence.HasValue)
|
||||||
|
_lastSeq = msg.Sequence.Value;
|
||||||
switch (msg.Operation)
|
switch (msg.Operation)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
@@ -72,6 +79,7 @@ namespace Discord
|
|||||||
if (msg.Type == "READY")
|
if (msg.Type == "READY")
|
||||||
{
|
{
|
||||||
var payload = (msg.Payload as JToken).ToObject<TextWebSocketEvents.Ready>();
|
var payload = (msg.Payload as JToken).ToObject<TextWebSocketEvents.Ready>();
|
||||||
|
_lastSession = payload.SessionId;
|
||||||
_heartbeatInterval = payload.HeartbeatInterval;
|
_heartbeatInterval = payload.HeartbeatInterval;
|
||||||
QueueMessage(new TextWebSocketCommands.UpdateStatus());
|
QueueMessage(new TextWebSocketCommands.UpdateStatus());
|
||||||
//QueueMessage(GetKeepAlive());
|
//QueueMessage(GetKeepAlive());
|
||||||
@@ -82,6 +90,15 @@ namespace Discord
|
|||||||
_connectWaitOnLogin2.Set(); //Post-Event
|
_connectWaitOnLogin2.Set(); //Post-Event
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 7:
|
||||||
|
{
|
||||||
|
var payload = (msg.Payload as JToken).ToObject<TextWebSocketEvents.Redirect>();
|
||||||
|
if (_isDebug)
|
||||||
|
RaiseOnDebugMessage(DebugMessageType.Connection, $"Redirected to {payload.Url}.");
|
||||||
|
_host = payload.Url;
|
||||||
|
DisconnectInternal(new Exception("Server is redirecting."), true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (_isDebug)
|
if (_isDebug)
|
||||||
RaiseOnDebugMessage(DebugMessageType.WebSocketUnknownOpCode, "Unknown Opcode: " + msg.Operation);
|
RaiseOnDebugMessage(DebugMessageType.WebSocketUnknownOpCode, "Unknown Opcode: " + msg.Operation);
|
||||||
@@ -107,5 +124,17 @@ namespace Discord
|
|||||||
var joinVoice = new TextWebSocketCommands.JoinVoice();
|
var joinVoice = new TextWebSocketCommands.JoinVoice();
|
||||||
QueueMessage(joinVoice);
|
QueueMessage(joinVoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnConnect()
|
||||||
|
{
|
||||||
|
if (_redirectServer != null)
|
||||||
|
{
|
||||||
|
var resumeMsg = new TextWebSocketCommands.Resume();
|
||||||
|
resumeMsg.Payload.SessionId = _lastSession;
|
||||||
|
resumeMsg.Payload.Sequence = _lastSeq;
|
||||||
|
SendMessage(resumeMsg, _disconnectToken.Token);
|
||||||
|
}
|
||||||
|
_redirectServer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ namespace Discord
|
|||||||
|
|
||||||
public new async Task BeginConnect()
|
public new async Task BeginConnect()
|
||||||
{
|
{
|
||||||
base.BeginConnect();
|
await base.BeginConnect();
|
||||||
var cancelToken = _disconnectToken.Token;
|
var cancelToken = _disconnectToken.Token;
|
||||||
|
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
|
|||||||
@@ -40,14 +40,15 @@ namespace Discord
|
|||||||
_sendQueue = new ConcurrentQueue<byte[]>();
|
_sendQueue = new ConcurrentQueue<byte[]>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void BeginConnect()
|
protected virtual async Task BeginConnect()
|
||||||
{
|
{
|
||||||
|
await DisconnectAsync();
|
||||||
_disconnectToken = new CancellationTokenSource();
|
_disconnectToken = new CancellationTokenSource();
|
||||||
_disconnectReason = null;
|
_disconnectReason = null;
|
||||||
}
|
}
|
||||||
public virtual async Task ConnectAsync(string url)
|
public virtual async Task ConnectAsync(string url)
|
||||||
{
|
{
|
||||||
await DisconnectAsync();
|
//await DisconnectAsync();
|
||||||
|
|
||||||
var cancelToken = _disconnectToken.Token;
|
var cancelToken = _disconnectToken.Token;
|
||||||
|
|
||||||
@@ -152,7 +153,7 @@ namespace Discord
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancelToken);
|
result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancelToken);
|
||||||
}
|
}
|
||||||
catch (Win32Exception ex)
|
catch (Win32Exception ex)
|
||||||
when (ex.HResult == HR_TIMEOUT)
|
when (ex.HResult == HR_TIMEOUT)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user