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