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 System;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal
|
namespace LeanCloud.Storage.Internal {
|
||||||
{
|
public class AppRouterState {
|
||||||
public class AppRouterState
|
const string EAST_CHINA_SUFFIX = "-9Nh9j0Va";
|
||||||
{
|
const string US_SUFFIX = "-MdYXbMMI";
|
||||||
|
|
||||||
[JsonProperty("ttl")]
|
[JsonProperty("ttl")]
|
||||||
public long TTL {
|
public long TTL {
|
||||||
get; internal set;
|
get; internal set;
|
||||||
|
@ -53,34 +54,11 @@ namespace LeanCloud.Storage.Internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AppRouterState GetFallbackServers(string appId, AVClient.Configuration.AVRegion region) {
|
public static AppRouterState GetFallbackServers(string appId) {
|
||||||
var regionValue = (int)region;
|
|
||||||
var prefix = appId.Substring(0, 8).ToLower();
|
var prefix = appId.Substring(0, 8).ToLower();
|
||||||
switch (regionValue)
|
var suffix = appId.Substring(appId.Length - 9);
|
||||||
{
|
switch (suffix) {
|
||||||
case 0:
|
case EAST_CHINA_SUFFIX:
|
||||||
// 华北
|
|
||||||
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:
|
|
||||||
// 华东
|
// 华东
|
||||||
return new AppRouterState {
|
return new AppRouterState {
|
||||||
TTL = -1,
|
TTL = -1,
|
||||||
|
@ -91,8 +69,28 @@ namespace LeanCloud.Storage.Internal
|
||||||
StatsServer = $"{prefix}.stats.lncldapi.com",
|
StatsServer = $"{prefix}.stats.lncldapi.com",
|
||||||
Source = "fallback",
|
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:
|
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>
|
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
<ReleaseVersion>0.1.0</ReleaseVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\AppRouter\AppRouter\AppRouter.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -29,6 +29,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage", "Storage\Storage\
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage.Test", "Storage\Storage.Test\Storage.Test.csproj", "{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Storage.Test", "Storage\Storage.Test\Storage.Test.csproj", "{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{659D19F0-9A40-42C0-886C-555E64F16848} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
{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}
|
{F907012C-74DF-4575-AFE6-E8DAACC26D24} = {5B895B7A-1F6E-40A5-8081-43B334D2C076}
|
||||||
{B6D2D6A4-6F02-4AA0-916C-CB78238D9634} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
{B6D2D6A4-6F02-4AA0-916C-CB78238D9634} = {CD6B6669-1A56-437A-932E-BCE7F5D4CD18}
|
||||||
{BE05B492-78CD-47CA-9F48-C3E9B4813AFF} = {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
|
EndGlobalSection
|
||||||
GlobalSection(MonoDevelopProperties) = preSolution
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
version = 0.1.0
|
version = 0.1.0
|
||||||
|
|
Loading…
Reference in New Issue