csharp-sdk-upm/RTM/Source/Internal/Router/AVRouterController.cs

174 lines
7.1 KiB
C#

using LeanCloud.Storage.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Realtime.Internal
{
internal class AVRouterController : IAVRouterController
{
const string routerUrl = "http://router.g0.push.leancloud.cn/v1/route?appId={0}";
const string routerKey = "LeanCloud_RouterState";
public Task<PushRouterState> GetAsync(string pushRouter = null, bool secure = true, CancellationToken cancellationToken = default(CancellationToken))
{
//return Task.FromResult(new PushRouterState()
//{
// server = "wss://rtm57.leancloud.cn/"
//});
return LoadAysnc(cancellationToken).OnSuccess(_ =>
{
var cache = _.Result;
var task = Task.FromResult<PushRouterState>(cache);
if (cache == null || cache.expire < DateTime.Now.ToUnixTimeStamp())
{
task = QueryAsync(pushRouter, secure, cancellationToken);
}
return task;
}).Unwrap();
}
/// <summary>
/// 清理地址缓存
/// </summary>
/// <returns>The cache.</returns>
public Task ClearCache() {
var tcs = new TaskCompletionSource<bool>();
AVPlugins.Instance.StorageController.LoadAsync().ContinueWith(t => {
if (t.IsFaulted) {
tcs.SetResult(true);
} else {
var storage = t.Result;
if (storage.ContainsKey(routerKey)) {
storage.RemoveAsync(routerKey).ContinueWith(_ => tcs.SetResult(true));
} else {
tcs.SetResult(true);
}
}
});
return tcs.Task;
}
Task<PushRouterState> LoadAysnc(CancellationToken cancellationToken)
{
try
{
return AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(_ =>
{
var currentCache = _.Result;
object routeCacheStr = null;
if (currentCache.TryGetValue(routerKey, out routeCacheStr))
{
var routeCache = routeCacheStr as IDictionary<string, object>;
var routerState = new PushRouterState()
{
groupId = routeCache["groupId"] as string,
server = routeCache["server"] as string,
secondary = routeCache["secondary"] as string,
ttl = long.Parse(routeCache["ttl"].ToString()),
expire = long.Parse(routeCache["expire"].ToString()),
source = "localCache"
};
return routerState;
}
return null;
});
}
catch
{
return Task.FromResult<PushRouterState>(null);
}
}
Task<PushRouterState> QueryAsync(string pushRouter, bool secure, CancellationToken cancellationToken)
{
var routerHost = pushRouter;
if (routerHost == null) {
var appRouter = AVPlugins.Instance.AppRouterController.Get();
routerHost = string.Format("https://{0}/v1/route?appId={1}", appRouter.RealtimeRouterServer, AVClient.CurrentConfiguration.ApplicationId) ?? appRouter.RealtimeRouterServer ?? string.Format(routerUrl, AVClient.CurrentConfiguration.ApplicationId);
}
AVRealtime.PrintLog($"router: {routerHost}");
AVRealtime.PrintLog($"push: {pushRouter}");
if (!string.IsNullOrEmpty(pushRouter))
{
var rtmUri = new Uri(pushRouter);
if (!string.IsNullOrEmpty(rtmUri.Scheme))
{
var url = new Uri(rtmUri, "v1/route").ToString();
routerHost = string.Format("{0}?appId={1}", url, AVClient.CurrentConfiguration.ApplicationId);
}
else
{
routerHost = string.Format("https://{0}/v1/route?appId={1}", pushRouter, AVClient.CurrentConfiguration.ApplicationId);
}
}
if (secure)
{
routerHost += "&secure=1";
}
AVRealtime.PrintLog("use push router url:" + routerHost);
return AVClient.RequestAsync(uri: new Uri(routerHost),
method: "GET",
headers: null,
data: null,
contentType: "application/json",
cancellationToken: CancellationToken.None).ContinueWith<PushRouterState>(t =>
{
if (t.Exception != null)
{
var innnerException = t.Exception.InnerException;
AVRealtime.PrintLog(innnerException.Message);
throw innnerException;
}
var httpStatus = (int)t.Result.Item1;
if (httpStatus != 200)
{
return null;
}
try
{
var result = t.Result.Item2;
var routerState = Json.Parse(result) as IDictionary<string, object>;
if (routerState.Keys.Count == 0)
{
throw new KeyNotFoundException("Can not get websocket url from server,please check the appId.");
}
var ttl = long.Parse(routerState["ttl"].ToString());
var expire = DateTime.Now.AddSeconds(ttl);
routerState["expire"] = expire.ToUnixTimeStamp();
//save to local cache async.
AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(storage => storage.Result.AddAsync(routerKey, routerState));
var routerStateObj = new PushRouterState()
{
groupId = routerState["groupId"] as string,
server = routerState["server"] as string,
secondary = routerState["secondary"] as string,
ttl = long.Parse(routerState["ttl"].ToString()),
expire = expire.ToUnixTimeStamp(),
source = "online"
};
return routerStateObj;
}
catch (Exception e)
{
if (e is KeyNotFoundException)
{
throw e;
}
return null;
}
});
}
}
}