chore: 将 AppRouter 提出作为共享库维护

oneRain 2019-08-09 17:53:19 +08:00
parent 6b52376069
commit ba39a81eb5
7 changed files with 121 additions and 96 deletions

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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",
};
} }
} }

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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>

View File

@ -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