chore: 将 AppRouter 提出作为共享库维护
parent
6b52376069
commit
ba39a81eb5
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Internal\" />
|
||||
<Folder Include="Internal\AppRouter\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AppRouterController {
|
||||
private AppRouterState currentState;
|
||||
private readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
|
||||
|
||||
public AppRouterState Get(string appId) {
|
||||
if (string.IsNullOrEmpty(appId)) {
|
||||
throw new ArgumentNullException(nameof(appId));
|
||||
}
|
||||
|
||||
try {
|
||||
locker.EnterUpgradeableReadLock();
|
||||
if (currentState != null && !currentState.IsExpired) {
|
||||
return currentState;
|
||||
}
|
||||
// 从 AppRouter 获取服务器地址,只触发,不等待
|
||||
QueryAsync(appId).ContinueWith(t => {
|
||||
if (t.IsFaulted) {
|
||||
|
||||
} else {
|
||||
locker.EnterWriteLock();
|
||||
currentState = t.Result;
|
||||
currentState.Source = "router";
|
||||
locker.ExitWriteLock();
|
||||
}
|
||||
});
|
||||
return AppRouterState.GetFallbackServers(appId);
|
||||
} finally {
|
||||
locker.ExitUpgradeableReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AppRouterState> QueryAsync(string appId) {
|
||||
string url = string.Format("https://app-router.leancloud.cn/2/route?appId={0}", appId);
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage {
|
||||
RequestUri = new Uri(url),
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
|
||||
HttpResponseMessage response = await client.SendAsync(request);
|
||||
client.Dispose();
|
||||
request.Dispose();
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
response.Dispose();
|
||||
|
||||
return JsonConvert.DeserializeObject<AppRouterState>(content);
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
locker.EnterWriteLock();
|
||||
currentState = null;
|
||||
locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace LeanCloud.Storage.Internal
|
||||
{
|
||||
public class AppRouterState
|
||||
{
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AppRouterState {
|
||||
const string EAST_CHINA_SUFFIX = "-9Nh9j0Va";
|
||||
const string US_SUFFIX = "-MdYXbMMI";
|
||||
|
||||
[JsonProperty("ttl")]
|
||||
public long TTL {
|
||||
get; internal set;
|
||||
|
@ -53,34 +54,11 @@ namespace LeanCloud.Storage.Internal
|
|||
}
|
||||
}
|
||||
|
||||
public static AppRouterState GetFallbackServers(string appId, AVClient.Configuration.AVRegion region) {
|
||||
var regionValue = (int)region;
|
||||
public static AppRouterState GetFallbackServers(string appId) {
|
||||
var prefix = appId.Substring(0, 8).ToLower();
|
||||
switch (regionValue)
|
||||
{
|
||||
case 0:
|
||||
// 华北
|
||||
return new AppRouterState {
|
||||
TTL = -1,
|
||||
ApiServer = $"{prefix}.api.lncld.net",
|
||||
EngineServer = $"{prefix}.engine.lncld.net",
|
||||
PushServer = $"{prefix}.push.lncld.net",
|
||||
RTMServer = $"{prefix}.rtm.lncld.net",
|
||||
StatsServer = $"{prefix}.stats.lncld.net",
|
||||
Source = "fallback",
|
||||
};
|
||||
case 1:
|
||||
// 美国
|
||||
return new AppRouterState {
|
||||
TTL = -1,
|
||||
ApiServer = $"{prefix}.api.lncldglobal.com",
|
||||
EngineServer = $"{prefix}.engine.lncldglobal.com",
|
||||
PushServer = $"{prefix}.push.lncldglobal.com",
|
||||
RTMServer = $"{prefix}.rtm.lncldglobal.com",
|
||||
StatsServer = $"{prefix}.stats.lncldglobal.com",
|
||||
Source = "fallback",
|
||||
};
|
||||
case 2:
|
||||
var suffix = appId.Substring(appId.Length - 9);
|
||||
switch (suffix) {
|
||||
case EAST_CHINA_SUFFIX:
|
||||
// 华东
|
||||
return new AppRouterState {
|
||||
TTL = -1,
|
||||
|
@ -91,8 +69,28 @@ namespace LeanCloud.Storage.Internal
|
|||
StatsServer = $"{prefix}.stats.lncldapi.com",
|
||||
Source = "fallback",
|
||||
};
|
||||
case US_SUFFIX:
|
||||
// 美国
|
||||
return new AppRouterState {
|
||||
TTL = -1,
|
||||
ApiServer = $"{prefix}.api.lncldglobal.com",
|
||||
EngineServer = $"{prefix}.engine.lncldglobal.com",
|
||||
PushServer = $"{prefix}.push.lncldglobal.com",
|
||||
RTMServer = $"{prefix}.rtm.lncldglobal.com",
|
||||
StatsServer = $"{prefix}.stats.lncldglobal.com",
|
||||
Source = "fallback",
|
||||
};
|
||||
default:
|
||||
throw new AVException(AVException.ErrorCode.OtherCause, "invalid region");
|
||||
// 华北
|
||||
return new AppRouterState {
|
||||
TTL = -1,
|
||||
ApiServer = $"{prefix}.api.lncld.net",
|
||||
EngineServer = $"{prefix}.engine.lncld.net",
|
||||
PushServer = $"{prefix}.push.lncld.net",
|
||||
RTMServer = $"{prefix}.rtm.lncld.net",
|
||||
StatsServer = $"{prefix}.stats.lncld.net",
|
||||
Source = "fallback",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<ReleaseVersion>0.1.0</ReleaseVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AppRouterController {
|
||||
private AppRouterState currentState;
|
||||
private readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
|
||||
|
||||
public AppRouterState Get() {
|
||||
if (string.IsNullOrEmpty(AVClient.CurrentConfiguration.ApplicationId)) {
|
||||
throw new AVException(AVException.ErrorCode.NotInitialized, "ApplicationId can not be null.");
|
||||
}
|
||||
|
||||
try {
|
||||
locker.EnterUpgradeableReadLock();
|
||||
if (currentState != null && !currentState.IsExpired) {
|
||||
return currentState;
|
||||
}
|
||||
// 从 AppRouter 获取服务器地址,只触发,不等待
|
||||
QueryAsync(CancellationToken.None).OnSuccess(t => {
|
||||
locker.EnterWriteLock();
|
||||
currentState = t.Result;
|
||||
currentState.Source = "router";
|
||||
locker.ExitWriteLock();
|
||||
});
|
||||
return AppRouterState.GetFallbackServers(AVClient.CurrentConfiguration.ApplicationId, AVClient.CurrentConfiguration.Region);
|
||||
} finally {
|
||||
locker.ExitUpgradeableReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AppRouterState> QueryAsync(CancellationToken cancellationToken) {
|
||||
string appId = AVClient.CurrentConfiguration.ApplicationId;
|
||||
string url = string.Format("https://app-router.leancloud.cn/2/route?appId={0}", appId);
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
HttpRequestMessage request = new HttpRequestMessage {
|
||||
RequestUri = new Uri(url),
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
try {
|
||||
HttpResponseMessage response = await client.SendAsync(request);
|
||||
client.Dispose();
|
||||
request.Dispose();
|
||||
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
response.Dispose();
|
||||
|
||||
return await JsonUtils.DeserializeObjectAsync<AppRouterState>(content);
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.ConnectionFailed, "can not reach router.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
locker.EnterWriteLock();
|
||||
currentState = null;
|
||||
locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,4 +11,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\AppRouter\AppRouter\AppRouter.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -29,6 +29,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage", "Storage\Storage\
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage.Test", "Storage\Storage.Test\Storage.Test.csproj", "{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AppRouter", "AppRouter", "{1F05195D-2CAA-4214-8DAE-FE14A6B905DD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppRouter", "AppRouter\AppRouter\AppRouter.csproj", "{D34FC092-042A-44CE-A9E2-56B996BDCF42}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -75,6 +79,10 @@ Global
|
|||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{659D19F0-9A40-42C0-886C-555E64F16848} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
||||
|
@ -87,6 +95,7 @@ Global
|
|||
{F907012C-74DF-4575-AFE6-E8DAACC26D24} = {5B895B7A-1F6E-40A5-8081-43B334D2C076}
|
||||
{B6D2D6A4-6F02-4AA0-916C-CB78238D9634} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
||||
{D34FC092-042A-44CE-A9E2-56B996BDCF42} = {1F05195D-2CAA-4214-8DAE-FE14A6B905DD}
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
version = 0.1.0
|
||||
|
|
Loading…
Reference in New Issue