@@ -61,6 +61,9 @@ namespace Discord.Collections | |||||
protected TValue Get(string key) | protected TValue Get(string key) | ||||
{ | { | ||||
if (key == null) | |||||
return null; | |||||
TValue result; | TValue result; | ||||
if (!_dictionary.TryGetValue(key, out result)) | if (!_dictionary.TryGetValue(key, out result)) | ||||
return null; | return null; | ||||
@@ -1,7 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | |||||
namespace Discord.Collections | namespace Discord.Collections | ||||
{ | { | ||||
@@ -15,7 +14,8 @@ namespace Discord.Collections | |||||
protected override void OnCreated(Channel item) | protected override void OnCreated(Channel item) | ||||
{ | { | ||||
item.Server.AddChannel(item.Id); | |||||
if (item.ServerId != null) | |||||
item.Server.AddChannel(item.Id); | |||||
if (item.RecipientId != null) | if (item.RecipientId != null) | ||||
{ | { | ||||
var user = item.Recipient; | var user = item.Recipient; | ||||
@@ -27,8 +27,8 @@ namespace Discord.Collections | |||||
} | } | ||||
protected override void OnRemoved(Channel item) | protected override void OnRemoved(Channel item) | ||||
{ | { | ||||
item.Server.RemoveChannel(item.Id); | |||||
if (item.ServerId != null) | |||||
item.Server.RemoveChannel(item.Id); | |||||
if (item.RecipientId != null) | if (item.RecipientId != null) | ||||
{ | { | ||||
var user = item.Recipient; | var user = item.Recipient; | ||||
@@ -376,7 +376,7 @@ namespace Discord | |||||
case "PRESENCE_UPDATE": | case "PRESENCE_UPDATE": | ||||
{ | { | ||||
var data = e.Payload.ToObject<Events.PresenceUpdate>(_serializer); | var data = e.Payload.ToObject<Events.PresenceUpdate>(_serializer); | ||||
var member = _members[data.UserId, data.GuildId]; | |||||
var member = _members[data.User.Id, data.GuildId]; | |||||
/*if (_config.TrackActivity) | /*if (_config.TrackActivity) | ||||
{ | { | ||||
var user = _users[data.User.Id]; | var user = _users[data.User.Id]; | ||||
@@ -539,8 +539,8 @@ namespace Discord | |||||
} | } | ||||
/// <summary> Disconnects from the Discord server, canceling any pending requests. </summary> | /// <summary> Disconnects from the Discord server, canceling any pending requests. </summary> | ||||
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user.")); | |||||
protected async Task DisconnectInternal(Exception ex, bool isUnexpected = true) | |||||
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user."), isUnexpected: false); | |||||
protected async Task DisconnectInternal(Exception ex, bool isUnexpected = true, bool skipAwait = false) | |||||
{ | { | ||||
int oldState; | int oldState; | ||||
bool hasWriterLock; | bool hasWriterLock; | ||||
@@ -563,9 +563,12 @@ namespace Discord | |||||
_cancelToken.Cancel(); | _cancelToken.Cancel(); | ||||
} | } | ||||
Task task = _runTask; | |||||
if (task != null) | |||||
await task.ConfigureAwait(false); | |||||
if (!skipAwait) | |||||
{ | |||||
Task task = _runTask; | |||||
if (task != null) | |||||
await task.ConfigureAwait(false); | |||||
} | |||||
if (hasWriterLock) | if (hasWriterLock) | ||||
{ | { | ||||
@@ -587,7 +590,7 @@ namespace Discord | |||||
{ | { | ||||
await task.ConfigureAwait(false); | await task.ConfigureAwait(false); | ||||
} | } | ||||
catch (Exception ex) { await DisconnectInternal(ex).ConfigureAwait(false); } | |||||
catch (Exception ex) { await DisconnectInternal(ex, skipAwait: true).ConfigureAwait(false); } | |||||
await Cleanup().ConfigureAwait(false); | await Cleanup().ConfigureAwait(false); | ||||
_runTask = null; | _runTask = null; | ||||
@@ -129,8 +129,8 @@ namespace Discord | |||||
var members = _client.Members; | var members = _client.Members; | ||||
foreach (var subModel in model.Members) | foreach (var subModel in model.Members) | ||||
{ | { | ||||
var user = users.GetOrAdd(subModel.UserId); | |||||
var member = members.GetOrAdd(subModel.UserId, Id); | |||||
var user = users.GetOrAdd(subModel.User.Id); | |||||
var member = members.GetOrAdd(subModel.User.Id, Id); | |||||
user.Update(subModel.User); | user.Update(subModel.User); | ||||
member.Update(subModel); | member.Update(subModel); | ||||
} | } | ||||
@@ -141,7 +141,7 @@ namespace Discord | |||||
} | } | ||||
foreach (var subModel in model.Presences) | foreach (var subModel in model.Presences) | ||||
{ | { | ||||
var member = members.GetOrAdd(subModel.UserId, Id); | |||||
var member = members.GetOrAdd(subModel.User.Id, Id); | |||||
member.Update(subModel); | member.Update(subModel); | ||||
} | } | ||||
} | } | ||||
@@ -11,12 +11,12 @@ namespace Discord.Net.WebSockets | |||||
{ | { | ||||
internal static class Commands | internal static class Commands | ||||
{ | { | ||||
public sealed class KeepAlive : WebSocketMessage<int> | |||||
public sealed class KeepAlive : WebSocketMessage<ulong> | |||||
{ | { | ||||
public KeepAlive() : base(1, GetTimestamp()) { } | public KeepAlive() : base(1, GetTimestamp()) { } | ||||
private static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | private static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | ||||
private static int GetTimestamp() | |||||
=> (int)(DateTime.UtcNow - epoch).TotalMilliseconds; | |||||
private static ulong GetTimestamp() | |||||
=> (ulong)(DateTime.UtcNow - epoch).TotalMilliseconds; | |||||
} | } | ||||
public sealed class Login : WebSocketMessage<Login.Data> | public sealed class Login : WebSocketMessage<Login.Data> | ||||
{ | { | ||||
@@ -24,11 +24,7 @@ namespace Discord.Net.WebSockets | |||||
Commands.Login msg = new Commands.Login(); | Commands.Login msg = new Commands.Login(); | ||||
msg.Payload.Token = token; | msg.Payload.Token = token; | ||||
//msg.Payload.Properties["$os"] = ""; | |||||
//msg.Payload.Properties["$browser"] = ""; | |||||
msg.Payload.Properties["$device"] = "Discord.Net"; | msg.Payload.Properties["$device"] = "Discord.Net"; | ||||
//msg.Payload.Properties["$referrer"] = ""; | |||||
//msg.Payload.Properties["$referring_domain"] = ""; | |||||
QueueMessage(msg); | QueueMessage(msg); | ||||
} | } | ||||
@@ -1,6 +1,7 @@ | |||||
using Discord.Helpers; | using Discord.Helpers; | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System; | using System; | ||||
using System.Linq; | |||||
using System.Runtime.ExceptionServices; | using System.Runtime.ExceptionServices; | ||||
using System.Text; | using System.Text; | ||||
using System.Threading; | using System.Threading; | ||||
@@ -96,8 +97,8 @@ namespace Discord.Net.WebSockets | |||||
public Task Reconnect() | public Task Reconnect() | ||||
=> Connect(_host); | => Connect(_host); | ||||
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user.")); | |||||
protected async Task DisconnectInternal(Exception ex, bool isUnexpected = true) | |||||
public Task Disconnect() => DisconnectInternal(new Exception("Disconnect was requested by user."), isUnexpected: false); | |||||
protected async Task DisconnectInternal(Exception ex, bool isUnexpected = true, bool skipAwait = false) | |||||
{ | { | ||||
int oldState; | int oldState; | ||||
bool hasWriterLock; | bool hasWriterLock; | ||||
@@ -120,9 +121,12 @@ namespace Discord.Net.WebSockets | |||||
_cancelToken.Cancel(); | _cancelToken.Cancel(); | ||||
} | } | ||||
Task task = _runTask; | |||||
if (task != null) | |||||
await task.ConfigureAwait(false); | |||||
if (!skipAwait) | |||||
{ | |||||
Task task = _runTask; | |||||
if (task != null) | |||||
await task.ConfigureAwait(false); | |||||
} | |||||
if (hasWriterLock) | if (hasWriterLock) | ||||
{ | { | ||||
@@ -133,12 +137,13 @@ namespace Discord.Net.WebSockets | |||||
protected virtual async Task RunTasks() | protected virtual async Task RunTasks() | ||||
{ | { | ||||
Task[] tasks = Run(); | |||||
Task task = Task.WhenAll(Run()); | |||||
try | try | ||||
{ | { | ||||
await Task.WhenAll(tasks).ConfigureAwait(false); | |||||
await task.ConfigureAwait(false); | |||||
} | } | ||||
catch (Exception ex) { await DisconnectInternal(ex).ConfigureAwait(false); } | |||||
catch (Exception ex) { await DisconnectInternal(ex, skipAwait: true).ConfigureAwait(false); } | |||||
bool wasUnexpected = _wasDisconnectUnexpected; | bool wasUnexpected = _wasDisconnectUnexpected; | ||||
_wasDisconnectUnexpected = false; | _wasDisconnectUnexpected = false; | ||||
@@ -147,7 +152,13 @@ namespace Discord.Net.WebSockets | |||||
await Cleanup().ConfigureAwait(false); | await Cleanup().ConfigureAwait(false); | ||||
_runTask = null; | _runTask = null; | ||||
} | } | ||||
protected virtual Task[] Run() { return _engine.RunTasks(_cancelToken.Token); } | |||||
protected virtual Task[] Run() | |||||
{ | |||||
var cancelToken = _cancelToken.Token; | |||||
return _engine.RunTasks(cancelToken) | |||||
.Concat(new Task[] { HeartbeatAsync(cancelToken) }) | |||||
.ToArray(); | |||||
} | |||||
protected virtual Task Cleanup() { return TaskHelper.CompletedTask; } | protected virtual Task Cleanup() { return TaskHelper.CompletedTask; } | ||||
protected abstract Task ProcessMessage(string json); | protected abstract Task ProcessMessage(string json); | ||||