sync
This commit is contained in:
parent
8ebc5e65c1
commit
8454aaedb1
5
.gitignore
vendored
5
.gitignore
vendored
@ -28,7 +28,7 @@ ipch/
|
|||||||
modules.json
|
modules.json
|
||||||
*.sdf
|
*.sdf
|
||||||
*.opensdf
|
*.opensdf
|
||||||
|
WebService/
|
||||||
#OS junk files
|
#OS junk files
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
@ -76,5 +76,6 @@ deploy/
|
|||||||
/Mobile12306New/css/_dev
|
/Mobile12306New/css/_dev
|
||||||
/Mobile12306New/assets/js/debug.js
|
/Mobile12306New/assets/js/debug.js
|
||||||
wwwroot/
|
wwwroot/
|
||||||
|
*.sln.ide
|
||||||
wwwroot/
|
wwwroot/
|
||||||
|
App_Data/
|
46
12306.sln
46
12306.sln
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2013
|
# Visual Studio 2013
|
||||||
VisualStudioVersion = 12.0.30723.0
|
VisualStudioVersion = 12.0.31101.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web12306", "Web12306\Web12306.csproj", "{56406C67-2B6F-4152-9EC0-E6D80E86B96D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web12306", "Web12306\Web12306.csproj", "{56406C67-2B6F-4152-9EC0-E6D80E86B96D}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -24,6 +24,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeployTools", "DeployTools\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceFileUtility", "SourceFileUtility\SourceFileUtility.csproj", "{BB9C6747-DC69-4EF1-A94C-85D8193B7105}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceFileUtility", "SourceFileUtility\SourceFileUtility.csproj", "{BB9C6747-DC69-4EF1-A94C-85D8193B7105}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrainInfomationProviderService", "TrainInfomationProviderService\TrainInfomationProviderService.csproj", "{C385D043-316A-4F05-A6B9-E70BF0ED8DB6}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FishLib", "FishLib", "{5EBCE730-C2C7-478B-BD0C-C4BE3BC69C06}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSLib.Network.NET4", "..\..\Private\iFish\FSLib.Network\FSLib.Network.NET4.csproj", "{3D34B2D8-36F9-4E16-BF0F-A8905F8FE8BA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSLib_NET4", "..\..\Private\iFish\FSLib\FSLib_NET4.csproj", "{D46393A2-AEAB-4876-AEBF-84B993E66227}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSLib.Extension", "..\..\Private\iFishOs\FSLib.Extension\src\FSLib.Extension.csproj", "{6D4588AA-A0FD-4364-972C-22B0AB7938F9}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "车站车次信息", "车站车次信息", "{89D11B10-8909-4682-A182-6FE4C1664B4E}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "浏览器扩展", "浏览器扩展", "{05734BC4-9A31-46C8-B45E-C5FD72B0A83B}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WWW", "WWW", "{5879D3F4-E7BB-4192-B4E3-9266AEB27D90}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -54,8 +70,36 @@ Global
|
|||||||
{BB9C6747-DC69-4EF1-A94C-85D8193B7105}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{BB9C6747-DC69-4EF1-A94C-85D8193B7105}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{BB9C6747-DC69-4EF1-A94C-85D8193B7105}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{BB9C6747-DC69-4EF1-A94C-85D8193B7105}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{BB9C6747-DC69-4EF1-A94C-85D8193B7105}.Release|Any CPU.Build.0 = Release|Any CPU
|
{BB9C6747-DC69-4EF1-A94C-85D8193B7105}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C385D043-316A-4F05-A6B9-E70BF0ED8DB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C385D043-316A-4F05-A6B9-E70BF0ED8DB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C385D043-316A-4F05-A6B9-E70BF0ED8DB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C385D043-316A-4F05-A6B9-E70BF0ED8DB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3D34B2D8-36F9-4E16-BF0F-A8905F8FE8BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D34B2D8-36F9-4E16-BF0F-A8905F8FE8BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3D34B2D8-36F9-4E16-BF0F-A8905F8FE8BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3D34B2D8-36F9-4E16-BF0F-A8905F8FE8BA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D46393A2-AEAB-4876-AEBF-84B993E66227}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D46393A2-AEAB-4876-AEBF-84B993E66227}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D46393A2-AEAB-4876-AEBF-84B993E66227}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D46393A2-AEAB-4876-AEBF-84B993E66227}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6D4588AA-A0FD-4364-972C-22B0AB7938F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6D4588AA-A0FD-4364-972C-22B0AB7938F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6D4588AA-A0FD-4364-972C-22B0AB7938F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6D4588AA-A0FD-4364-972C-22B0AB7938F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{56406C67-2B6F-4152-9EC0-E6D80E86B96D} = {5879D3F4-E7BB-4192-B4E3-9266AEB27D90}
|
||||||
|
{0C7635A7-78F5-459D-BBDE-CEEC51E546B9} = {F6960416-F825-4800-8FD4-C72908A4A6CC}
|
||||||
|
{9D141603-1A9D-4EEC-82D8-C473EA436839} = {05734BC4-9A31-46C8-B45E-C5FD72B0A83B}
|
||||||
|
{4B41EA5E-B7CD-4FC6-B9E3-9AE5222695F6} = {5879D3F4-E7BB-4192-B4E3-9266AEB27D90}
|
||||||
|
{E958D106-A3EE-46AF-B3E5-E62FC96F2F94} = {F6960416-F825-4800-8FD4-C72908A4A6CC}
|
||||||
|
{BB9C6747-DC69-4EF1-A94C-85D8193B7105} = {F6960416-F825-4800-8FD4-C72908A4A6CC}
|
||||||
|
{C385D043-316A-4F05-A6B9-E70BF0ED8DB6} = {89D11B10-8909-4682-A182-6FE4C1664B4E}
|
||||||
|
{3D34B2D8-36F9-4E16-BF0F-A8905F8FE8BA} = {5EBCE730-C2C7-478B-BD0C-C4BE3BC69C06}
|
||||||
|
{D46393A2-AEAB-4876-AEBF-84B993E66227} = {5EBCE730-C2C7-478B-BD0C-C4BE3BC69C06}
|
||||||
|
{6D4588AA-A0FD-4364-972C-22B0AB7938F9} = {5EBCE730-C2C7-478B-BD0C-C4BE3BC69C06}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
9
TrainInfomationProviderService/App.config
Normal file
9
TrainInfomationProviderService/App.config
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="dataStoragePath" value="..\Web12306\App_Data\12306"/>
|
||||||
|
</appSettings>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
37
TrainInfomationProviderService/InformationUpdaterService.Designer.cs
generated
Normal file
37
TrainInfomationProviderService/InformationUpdaterService.Designer.cs
generated
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
namespace TrainInfomationProviderService
|
||||||
|
{
|
||||||
|
partial class InformationUpdaterService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 必需的设计器变量。
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清理所有正在使用的资源。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 组件设计器生成的代码
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设计器支持所需的方法 - 不要
|
||||||
|
/// 使用代码编辑器修改此方法的内容。
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
components = new System.ComponentModel.Container();
|
||||||
|
this.ServiceName = "Service1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
28
TrainInfomationProviderService/InformationUpdaterService.cs
Normal file
28
TrainInfomationProviderService/InformationUpdaterService.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.ServiceProcess;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService
|
||||||
|
{
|
||||||
|
public partial class InformationUpdaterService : ServiceBase
|
||||||
|
{
|
||||||
|
public InformationUpdaterService()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStart(string[] args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStop()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
TrainInfomationProviderService/Program.cs
Normal file
46
TrainInfomationProviderService/Program.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.ServiceProcess;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web.Hosting;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using TrainInfomationProviderService.StationInfo;
|
||||||
|
using TrainInfomationProviderService.StationInfo.Entities;
|
||||||
|
using TrainInfomationProviderService.TrainInfo;
|
||||||
|
using TrainInfomationProviderService.TrainInfo.Entities;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 应用程序的主入口点。
|
||||||
|
/// </summary>
|
||||||
|
private static void Main(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length > 0 && args[0].IsIgnoreCaseEqualTo("--service"))
|
||||||
|
{
|
||||||
|
var servicesToRun = new ServiceBase[]
|
||||||
|
{
|
||||||
|
new InformationUpdaterService()
|
||||||
|
};
|
||||||
|
ServiceBase.Run(servicesToRun);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.Listeners.Add(new ConsoleTraceListener());
|
||||||
|
|
||||||
|
StationManager.Instance.Init();
|
||||||
|
TrainInfoManager.Instance.Init();
|
||||||
|
//搜索?
|
||||||
|
var searchProvider = new TrainInfoSearchProvider(TrainInfoManager.Instance.Storage);
|
||||||
|
//runtime mode
|
||||||
|
MessageBox.Show(StationManager.Instance.Storage.Version.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
TrainInfomationProviderService/Properties/AssemblyInfo.cs
Normal file
36
TrainInfomationProviderService/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// 有关程序集的常规信息通过以下
|
||||||
|
// 特性集控制。更改这些特性值可修改
|
||||||
|
// 与程序集关联的信息。
|
||||||
|
[assembly: AssemblyTitle("TrainInfomationProviderService")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("TrainInfomationProviderService")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||||
|
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||||
|
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||||
|
[assembly: Guid("dfc810f3-cc44-4ce0-8a92-8a616319071f")]
|
||||||
|
|
||||||
|
// 程序集的版本信息由下面四个值组成:
|
||||||
|
//
|
||||||
|
// 主版本
|
||||||
|
// 次版本
|
||||||
|
// 生成号
|
||||||
|
// 修订号
|
||||||
|
//
|
||||||
|
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||||
|
// 方法是按如下所示使用“*”:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
50
TrainInfomationProviderService/RunTimeContext.cs
Normal file
50
TrainInfomationProviderService/RunTimeContext.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web.Hosting;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService
|
||||||
|
{
|
||||||
|
class RunTimeContext
|
||||||
|
{
|
||||||
|
public static string ServiceRoot { get; private set; }
|
||||||
|
|
||||||
|
public static string DataStorageRoot { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是web环境
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsWeb { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
static RunTimeContext()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[CONTEXT] 正在初始化上下文");
|
||||||
|
|
||||||
|
IsWeb = System.Web.Hosting.HostingEnvironment.IsHosted;
|
||||||
|
Trace.TraceInformation("[CONTEXT] WEB模式:{0}", IsWeb);
|
||||||
|
|
||||||
|
if (IsWeb)
|
||||||
|
{
|
||||||
|
ServiceRoot = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
|
||||||
|
DataStorageRoot = HostingEnvironment.MapPath(ConfigurationManager.AppSettings["dataStoragePath"]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ServiceRoot = System.Reflection.Assembly.GetEntryAssembly().GetLocation();
|
||||||
|
DataStorageRoot = ConfigurationManager.AppSettings["dataStoragePath"];
|
||||||
|
if (!Path.IsPathRooted(DataStorageRoot))
|
||||||
|
DataStorageRoot = PathUtility.Combine(ServiceRoot, DataStorageRoot);
|
||||||
|
}
|
||||||
|
Directory.CreateDirectory(DataStorageRoot);
|
||||||
|
|
||||||
|
Trace.TraceInformation("[CONTEXT] 服务根目录:{0}", ServiceRoot);
|
||||||
|
Trace.TraceInformation("[CONTEXT] 数据根目录:{0}", DataStorageRoot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.StationInfo.Entities
|
||||||
|
{
|
||||||
|
public class BasicStation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 名称
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("n")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 车站编号
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("c")]
|
||||||
|
public string Code { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.StationInfo.Entities
|
||||||
|
{
|
||||||
|
public class SameStationCollection : List<HashSet<string>>
|
||||||
|
{
|
||||||
|
private SameStationCollection()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashSet<string> FindSameStations(string code)
|
||||||
|
{
|
||||||
|
return this.FirstOrDefault(s => s.Contains(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SameStationCollection _instance;
|
||||||
|
private static readonly object _lockObject = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得实例对象
|
||||||
|
/// </summary>
|
||||||
|
public static SameStationCollection Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
var file = Path.Combine(RunTimeContext.DataStorageRoot, "samestation.json");
|
||||||
|
if (File.Exists(file))
|
||||||
|
{
|
||||||
|
_instance = JsonConvert.DeserializeObject<SameStationCollection>(File.ReadAllText(file));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_instance = new SameStationCollection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.StationInfo.Entities
|
||||||
|
{
|
||||||
|
public class StationDetailInfo : BasicStation
|
||||||
|
{
|
||||||
|
[JsonProperty("p")]
|
||||||
|
public string PyFull { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("y")]
|
||||||
|
public string Py { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("s")]
|
||||||
|
public int Sort { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.StationInfo.Entities
|
||||||
|
{
|
||||||
|
public class StationStorage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 创建 <see cref="StationStorage" /> 的新实例(StationStorage)
|
||||||
|
/// </summary>
|
||||||
|
[JsonConstructor]
|
||||||
|
protected StationStorage()
|
||||||
|
{
|
||||||
|
Stations = new Dictionary<string, StationDetailInfo>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StationStorage(int version, IEnumerable<StationDetailInfo> detail)
|
||||||
|
{
|
||||||
|
Version = version;
|
||||||
|
Stations = detail.ToDictionary(s => s.Code, s => s, StringComparer.OrdinalIgnoreCase);
|
||||||
|
StationNameMap = detail.ToDictionary(s => s.Name, s => s, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("v")]
|
||||||
|
public int Version { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("s")]
|
||||||
|
public Dictionary<string, StationDetailInfo> Stations { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Dictionary<string, StationDetailInfo> StationNameMap { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
[OnDeserialized]
|
||||||
|
void DeserializeCallback(StreamingContext context)
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化
|
||||||
|
/// </summary>
|
||||||
|
protected void Init()
|
||||||
|
{
|
||||||
|
StationNameMap = Stations.ToDictionary(s => s.Value.Name, s => s.Value, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
221
TrainInfomationProviderService/StationInfo/StationManager.cs
Normal file
221
TrainInfomationProviderService/StationInfo/StationManager.cs
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web.Caching;
|
||||||
|
using System.Web.Hosting;
|
||||||
|
using FSLib.Network.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using TrainInfomationProviderService.StationInfo.Entities;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.StationInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public class StationManager
|
||||||
|
{
|
||||||
|
private static readonly object _lockObject = new object();
|
||||||
|
private static StationManager _stationManager;
|
||||||
|
|
||||||
|
public static StationManager Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_stationManager == null)
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
if (_stationManager == null)
|
||||||
|
{
|
||||||
|
_stationManager = new StationManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _stationManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建 <see cref="StationManager" /> 的新实例(StationManager)
|
||||||
|
/// </summary>
|
||||||
|
public StationManager()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 车站管理器对象已新建");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string _dataFilePath;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 仓库
|
||||||
|
/// </summary>
|
||||||
|
public StationStorage Storage
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (RunTimeContext.IsWeb)
|
||||||
|
{
|
||||||
|
return HostingEnvironment.Cache["_12306stations"] as StationStorage;
|
||||||
|
}
|
||||||
|
return _storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 正在初始化");
|
||||||
|
|
||||||
|
_dataFilePath = PathUtility.Combine(RunTimeContext.DataStorageRoot, "stations.json");
|
||||||
|
Trace.TraceInformation("[STATION] 目标缓存文件路径:{0}", _dataFilePath);
|
||||||
|
|
||||||
|
if (RunTimeContext.IsWeb)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] WEB模式");
|
||||||
|
|
||||||
|
InitWeb();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 服务模式");
|
||||||
|
InitService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region web环境
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// web环境初始化
|
||||||
|
/// </summary>
|
||||||
|
void InitWeb()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 初始化WEB模式");
|
||||||
|
LoadCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadCache()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 正在检查缓存刷新");
|
||||||
|
_storage = null;
|
||||||
|
if (File.Exists(_dataFilePath))
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 正在加载缓存");
|
||||||
|
_storage = JsonConvert.DeserializeObject<StationStorage>(File.ReadAllText(_dataFilePath));
|
||||||
|
Trace.TraceInformation("[STATION] 缓存加载完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Storage != null)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 正在加入HttpRuntime缓存");
|
||||||
|
HostingEnvironment.Cache.Add("_12306stations", Storage, new CacheDependency(_dataFilePath),
|
||||||
|
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.High,
|
||||||
|
(_1, _2, _3) =>
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] HttpRuntime缓存已被清除,原因:{0},正在重新加载", _3);
|
||||||
|
LoadCache();
|
||||||
|
});
|
||||||
|
Trace.TraceInformation("[STATION] HttpRuntime缓存加入完成");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 服务模式
|
||||||
|
|
||||||
|
private Timer _checkStationTimer;
|
||||||
|
private StationStorage _storage;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务模式初始化
|
||||||
|
/// </summary>
|
||||||
|
void InitService()
|
||||||
|
{
|
||||||
|
if (_dataFilePath.AsFileInfo().Exists)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 正在加载文件缓存数据");
|
||||||
|
_storage = JsonConvert.DeserializeObject<StationStorage>(File.ReadAllText(_dataFilePath));
|
||||||
|
Trace.TraceInformation("[STATION] 文件缓存数据加载完成");
|
||||||
|
}
|
||||||
|
var lastestVersion = GetLatestVersionFromWeb();
|
||||||
|
var needUpdate = _storage == null || _storage.Version < lastestVersion;
|
||||||
|
Trace.TraceInformation("[STATION] 最新版本:{0}", lastestVersion);
|
||||||
|
|
||||||
|
if (needUpdate)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 正在刷新缓存");
|
||||||
|
RefreshStationInfo(lastestVersion);
|
||||||
|
Trace.TraceInformation("[STATION] 缓存数据已刷新");
|
||||||
|
}
|
||||||
|
_checkStationTimer = new Timer(_ => CheckStationVersion(), null, new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefreshStationInfo(int version)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[STATION] 正在获得最新车站信息");
|
||||||
|
var html = new HttpClient().Create(HttpMethod.Get, "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js", null, null, "").Send();
|
||||||
|
if (!html.IsValid())
|
||||||
|
{
|
||||||
|
Trace.TraceError("[STATION] 车站信息获得失败。错误:{0}", html.Exception);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Trace.TraceInformation("[STATION] 正在分析车站信息");
|
||||||
|
|
||||||
|
var mcs = Regex.Matches(html.Result, @"@([^\|]+)\|([^\|]+)\|([^\|]+)\|([^\|]+)\|([^\|]+)\|(\d+)");
|
||||||
|
var result = new List<StationDetailInfo>(mcs.Count);
|
||||||
|
foreach (Match mc in mcs)
|
||||||
|
{
|
||||||
|
var s = new StationDetailInfo()
|
||||||
|
{
|
||||||
|
Code = mc.GetGroupValue(3),
|
||||||
|
Name = mc.GetGroupValue(2),
|
||||||
|
Py = mc.GetGroupValue(5),
|
||||||
|
PyFull = mc.GetGroupValue(4),
|
||||||
|
Sort = mc.GetGroupValue(6).ToInt32()
|
||||||
|
};
|
||||||
|
result.Add(s);
|
||||||
|
}
|
||||||
|
_storage = new StationStorage(version, result);
|
||||||
|
Trace.TraceInformation("[STATION] 车站信息分析完成,{0} 车站。正在缓存车站信息", result.Count);
|
||||||
|
|
||||||
|
//save
|
||||||
|
File.WriteAllText(_dataFilePath, JsonConvert.SerializeObject(Storage));
|
||||||
|
Trace.TraceInformation("[STATION] 车站信息缓存完成。目标文件 {0}", _dataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckStationVersion()
|
||||||
|
{
|
||||||
|
var lastestVersion = GetLatestVersionFromWeb();
|
||||||
|
if (Storage == null || Storage.Version < lastestVersion)
|
||||||
|
{
|
||||||
|
RefreshStationInfo(lastestVersion);
|
||||||
|
}
|
||||||
|
_checkStationTimer.Change(new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从网络加载最新的版本号
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int GetLatestVersionFromWeb()
|
||||||
|
{
|
||||||
|
var ctx = new HttpClient().Create<string>(HttpMethod.Get, "https://kyfw.12306.cn/otn/leftTicket/init", "https://kyfw.12306.cn/otn/leftTicket/init").Send();
|
||||||
|
if (!ctx.IsValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var version = (int)(Regex.Match(ctx.Result, @"station_name\.js\?station_version=([\d\.]+)").GetGroupValue(1).ToSingle() * 100000);
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||||
|
{
|
||||||
|
public class IndexStorage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 创建 <see cref="IndexStorage" /> 的新实例(IndexStorage)
|
||||||
|
/// </summary>
|
||||||
|
public IndexStorage()
|
||||||
|
{
|
||||||
|
DateIndices = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
TrainInfoStorages = new Dictionary<string, TrainInfoStorage>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Version { get; set; }
|
||||||
|
|
||||||
|
public HashSet<string> DateIndices { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Dictionary<string, TrainInfoStorage> TrainInfoStorages { get; set; }
|
||||||
|
|
||||||
|
[OnDeserialized]
|
||||||
|
void Init(StreamingContext ctx)
|
||||||
|
{
|
||||||
|
var dataLoader = new WebDataProvider();
|
||||||
|
TrainInfoStorages.Clear();
|
||||||
|
|
||||||
|
var baseDate = DateTime.Now.Date;
|
||||||
|
DateIndices = DateIndices.Where(s => s.ToDateTime() >= baseDate).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
foreach (var dateIndex in DateIndices.ToArray())
|
||||||
|
{
|
||||||
|
var data = dataLoader.LoadCache(dateIndex);
|
||||||
|
if (data == null)
|
||||||
|
DateIndices.Remove(dateIndex);
|
||||||
|
else TrainInfoStorages.Add(dateIndex, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除过时的信息
|
||||||
|
/// </summary>
|
||||||
|
internal void RemoveOutdateStorage()
|
||||||
|
{
|
||||||
|
var baseDate = DateTime.Now.Date;
|
||||||
|
var outdates = DateIndices.Where(s => s.ToDateTime() < baseDate).ToArray();
|
||||||
|
|
||||||
|
Trace.TraceInformation("[TRAIN_INDEX_STORAGE] 正在检查过期数据");
|
||||||
|
foreach (var outdate in outdates)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TRAIN_INDEX_STORAGE] 正在移除过期数据 {0}", outdate);
|
||||||
|
DateIndices.Remove(outdate);
|
||||||
|
if (TrainInfoStorages.ContainsKey(outdate))
|
||||||
|
TrainInfoStorages.Remove(outdate);
|
||||||
|
Trace.TraceInformation("[TRAIN_INDEX_STORAGE] 完成移除过期数据 {0}", outdate);
|
||||||
|
}
|
||||||
|
Trace.TraceInformation("[TRAIN_INDEX_STORAGE] 正在移除过期数据");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
TrainInfomationProviderService/TrainInfo/Entities/Train.cs
Normal file
97
TrainInfomationProviderService/TrainInfo/Entities/Train.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using TrainInfomationProviderService.StationInfo;
|
||||||
|
using TrainInfomationProviderService.StationInfo.Entities;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||||
|
{
|
||||||
|
public class Train : IEquatable<Train>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ID
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("i")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 列车编号
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("c")]
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发站
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("f")]
|
||||||
|
public string From { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 到站
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("t")]
|
||||||
|
public string To { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("s")]
|
||||||
|
public List<TrainStop> TrainStops { get; set; }
|
||||||
|
|
||||||
|
#region Implementation of IEquatable<Train>
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指示当前对象是否等于同一类型的另一个对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// 如果当前对象等于 <paramref name="other"/> 参数,则为 true;否则为 false。
|
||||||
|
/// </returns>
|
||||||
|
/// <param name="other">与此对象进行比较的对象。</param>
|
||||||
|
public bool Equals(Train other)
|
||||||
|
{
|
||||||
|
return Key == other.Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _key;
|
||||||
|
private string Key
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_key))
|
||||||
|
{
|
||||||
|
_key = Id + Code + From + To;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用作特定类型的哈希函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// 当前 <see cref="T:System.Object"/> 的哈希代码。
|
||||||
|
/// </returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Key.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确定指定的 <see cref="T:System.Object"/> 是否等于当前的 <see cref="T:System.Object"/>。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// 如果指定的对象等于当前对象,则为 true;否则为 false。
|
||||||
|
/// </returns>
|
||||||
|
/// <param name="obj">要与当前对象进行比较的对象。</param>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj == null || !(obj is Train))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Key == (obj as Train).Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,109 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using TrainInfomationProviderService.StationInfo;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||||
|
{
|
||||||
|
public class TrainInfoStorage
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonProperty("l")]
|
||||||
|
public List<Train> Trains { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Dictionary<string, Train[]> TrainsCodeMap { get; private set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Dictionary<string, Train[]> TrainsIdMap { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 车站-发车车次信息
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public Dictionary<string, List<Train>> StationLeftTrainData { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 车站-发车车次信息
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public Dictionary<string, List<Train>> StationArriveTrainData { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 站点路由表
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public Dictionary<string, HashSet<string>> StationRouteMap { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建 <see cref="TrainInfoStorage" /> 的新实例(TrainInfoStorage)
|
||||||
|
/// </summary>
|
||||||
|
public TrainInfoStorage(IEnumerable<Train> trains)
|
||||||
|
{
|
||||||
|
Trains = trains.ToList();
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
protected TrainInfoStorage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[OnDeserialized]
|
||||||
|
void DeserializeCallback(StreamingContext context)
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化
|
||||||
|
/// </summary>
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
TrainsCodeMap = Trains.GroupBy(s => s.Code).ToDictionary(s => s.Key, s =>
|
||||||
|
{
|
||||||
|
var arr = s.ToArray();
|
||||||
|
//if (arr.Length > 1)
|
||||||
|
//{
|
||||||
|
// Trace.TraceWarning("[TRAIN_INFO_STORAGE] 警告:车次编号 {0} 出现重复数据,请查证,重复次数:{1}", s.Key, arr.Length - 1);
|
||||||
|
//}
|
||||||
|
return arr.ToArray();
|
||||||
|
}, StringComparer.OrdinalIgnoreCase);
|
||||||
|
TrainsIdMap = Trains.GroupBy(s => s.Id).ToDictionary(s => s.Key, s =>
|
||||||
|
{
|
||||||
|
var arr = s.ToArray();
|
||||||
|
//if (arr.Length > 1)
|
||||||
|
//{
|
||||||
|
// Trace.TraceWarning("[TRAIN_INFO_STORAGE] 警告:车次ID {0} 出现重复数据,请查证,重复次数:{1}", s.Key, arr.Length - 1);
|
||||||
|
//}
|
||||||
|
return arr;
|
||||||
|
}, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化车站->车次信息
|
||||||
|
/// </summary>
|
||||||
|
public void InitStationTrainData()
|
||||||
|
{
|
||||||
|
StationLeftTrainData = new Dictionary<string, List<Train>>();
|
||||||
|
StationArriveTrainData = new Dictionary<string, List<Train>>();
|
||||||
|
foreach (var train in Trains)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < train.TrainStops.Count; i++)
|
||||||
|
{
|
||||||
|
var stop = train.TrainStops[i];
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
StationArriveTrainData.GetValue(stop.Code, _ => new List<Train>()).Add(train);
|
||||||
|
if (i < train.TrainStops.Count - 1)
|
||||||
|
StationLeftTrainData.GetValue(stop.Code, _ => new List<Train>()).Add(train);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||||
|
{
|
||||||
|
public class TrainStop
|
||||||
|
{
|
||||||
|
[JsonProperty("c")]
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("i")]
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("a")]
|
||||||
|
public TimeSpan? Arrive { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("l")]
|
||||||
|
public TimeSpan? Left { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("d")]
|
||||||
|
public int Days { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
219
TrainInfomationProviderService/TrainInfo/TrainInfoManager.cs
Normal file
219
TrainInfomationProviderService/TrainInfo/TrainInfoManager.cs
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web.Caching;
|
||||||
|
using System.Web.Hosting;
|
||||||
|
using FSLib.Network.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using TrainInfomationProviderService.TrainInfo.Entities;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.TrainInfo
|
||||||
|
{
|
||||||
|
public class TrainInfoManager
|
||||||
|
{
|
||||||
|
private static readonly object _lockObject = new object();
|
||||||
|
private static TrainInfoManager _stationManager;
|
||||||
|
|
||||||
|
public static TrainInfoManager Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_stationManager == null)
|
||||||
|
{
|
||||||
|
lock (_lockObject)
|
||||||
|
{
|
||||||
|
if (_stationManager == null)
|
||||||
|
{
|
||||||
|
_stationManager = new TrainInfoManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _stationManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建 <see cref="TrainInfoManager" /> 的新实例(StationManager)
|
||||||
|
/// </summary>
|
||||||
|
protected TrainInfoManager()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 车站管理器对象已新建");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _dataFilePath;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 仓库
|
||||||
|
/// </summary>
|
||||||
|
public IndexStorage Storage
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (RunTimeContext.IsWeb)
|
||||||
|
{
|
||||||
|
return HostingEnvironment.Cache["_12306trains"] as IndexStorage;
|
||||||
|
}
|
||||||
|
return _storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 正在初始化");
|
||||||
|
|
||||||
|
_dataFilePath = PathUtility.Combine(RunTimeContext.DataStorageRoot, "trains.json");
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 目标缓存文件路径:{0}", _dataFilePath);
|
||||||
|
|
||||||
|
if (RunTimeContext.IsWeb)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] WEB模式");
|
||||||
|
|
||||||
|
InitWeb();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 服务模式");
|
||||||
|
InitService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region web环境
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// web环境初始化
|
||||||
|
/// </summary>
|
||||||
|
void InitWeb()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 初始化WEB模式");
|
||||||
|
LoadCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadCache()
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 正在检查缓存刷新");
|
||||||
|
_storage = null;
|
||||||
|
if (File.Exists(_dataFilePath))
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 正在加载缓存");
|
||||||
|
_storage = JsonConvert.DeserializeObject<IndexStorage>(File.ReadAllText(_dataFilePath));
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 缓存加载完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Storage != null)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 正在加入HttpRuntime缓存");
|
||||||
|
HostingEnvironment.Cache.Add("_12306trains", Storage, new CacheDependency(_dataFilePath),
|
||||||
|
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.High,
|
||||||
|
(_1, _2, _3) =>
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] HttpRuntime缓存已被清除,原因:{0},正在重新加载", _3);
|
||||||
|
LoadCache();
|
||||||
|
});
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] HttpRuntime缓存加入完成");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 服务模式
|
||||||
|
|
||||||
|
private Timer _checkStationTimer;
|
||||||
|
private IndexStorage _storage;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
private bool _ininitalized = true;
|
||||||
|
#else
|
||||||
|
private bool _ininitalized = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 服务模式初始化
|
||||||
|
/// </summary>
|
||||||
|
void InitService()
|
||||||
|
{
|
||||||
|
if (_dataFilePath.AsFileInfo().Exists)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 正在加载文件缓存数据");
|
||||||
|
_storage = JsonConvert.DeserializeObject<IndexStorage>(File.ReadAllText(_dataFilePath));
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 文件缓存数据加载完成");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_storage = new IndexStorage();
|
||||||
|
}
|
||||||
|
var lastestVersion = GetLatestVersionFromWeb();
|
||||||
|
var needUpdate = _storage == null || _storage.Version < lastestVersion;
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 最新版本:{0}", lastestVersion);
|
||||||
|
|
||||||
|
if (needUpdate || !_ininitalized)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 正在刷新缓存");
|
||||||
|
RefreshTrainInfo(lastestVersion);
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 缓存数据已刷新");
|
||||||
|
}
|
||||||
|
_ininitalized = true;
|
||||||
|
_checkStationTimer = new Timer(_ => CheckTrainVersion(), null, new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefreshTrainInfo(int version)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 正在刷新车次信息");
|
||||||
|
var loader = new WebDataProvider();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Storage.Version = version;
|
||||||
|
loader.LoadTrainInfo(Storage);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.TraceError("TAININFOMANGER] 车次信息更新出错:{0}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Storage = new TrainInfoStorage();
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 车次信息分析完成,车站。正在缓存车站信息");
|
||||||
|
|
||||||
|
//save
|
||||||
|
File.WriteAllText(_dataFilePath, JsonConvert.SerializeObject(Storage));
|
||||||
|
Trace.TraceInformation("[TAININFOMANGER] 车站信息缓存完成。目标文件 {0}", _dataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckTrainVersion()
|
||||||
|
{
|
||||||
|
var lastestVersion = GetLatestVersionFromWeb();
|
||||||
|
if (Storage == null || Storage.Version < lastestVersion)
|
||||||
|
{
|
||||||
|
RefreshTrainInfo(lastestVersion);
|
||||||
|
}
|
||||||
|
_checkStationTimer.Change(new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从网络加载最新的版本号
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int GetLatestVersionFromWeb()
|
||||||
|
{
|
||||||
|
var ctx = new HttpClient().Create<string>(HttpMethod.Get, "https://kyfw.12306.cn/otn/queryTrainInfo/init", "https://kyfw.12306.cn/otn/queryTrainInfo/init").Send();
|
||||||
|
if (!ctx.IsValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var version = (int)(Regex.Match(ctx.Result, @"train_list\.js\?scriptVersion=([\d\.]+)").GetGroupValue(1).ToSingle() * 100000);
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TrainInfomationProviderService.TrainInfo.Entities;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.TrainInfo
|
||||||
|
{
|
||||||
|
public class TrainInfoSearchProvider
|
||||||
|
{
|
||||||
|
public IndexStorage Storage { get; private set; }
|
||||||
|
|
||||||
|
public TrainInfoSearchProvider(IndexStorage storage)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TRAIN_INFO_SEARCH_PROVIDER] 正在创建车站-车次信息索引对象");
|
||||||
|
Storage = storage;
|
||||||
|
|
||||||
|
foreach (var trainInfoStorage in storage.TrainInfoStorages)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TRAIN_INFO_SEARCH_PROVIDER] 正在初始化 {0} 车站-车次信息索引对象", trainInfoStorage.Key);
|
||||||
|
trainInfoStorage.Value.InitStationTrainData();
|
||||||
|
}
|
||||||
|
Trace.TraceInformation("[TRAIN_INFO_SEARCH_PROVIDER] 完成创建车站-车次信息索引对象");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
220
TrainInfomationProviderService/TrainInfo/WebDataProvider.cs
Normal file
220
TrainInfomationProviderService/TrainInfo/WebDataProvider.cs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FSLib.Network.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using TrainInfomationProviderService.StationInfo;
|
||||||
|
using TrainInfomationProviderService.TrainInfo.Entities;
|
||||||
|
|
||||||
|
namespace TrainInfomationProviderService.TrainInfo
|
||||||
|
{
|
||||||
|
class WebDataProvider
|
||||||
|
{
|
||||||
|
class TrainListInfoItem
|
||||||
|
{
|
||||||
|
public string station_train_code { get; set; }
|
||||||
|
|
||||||
|
public string train_no { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainListData : Dictionary<string, Dictionary<string, List<TrainListInfoItem>>>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class TrainStopWebInfo
|
||||||
|
{
|
||||||
|
public string arrive_time { get; set; }
|
||||||
|
public string station_name { get; set; }
|
||||||
|
public string start_time { get; set; }
|
||||||
|
public string stopover_time { get; set; }
|
||||||
|
public string station_no { get; set; }
|
||||||
|
public bool isEnabled { get; set; }
|
||||||
|
|
||||||
|
public TrainStop ToTrainStop(int index, ref TimeSpan? prevTimeSpan, ref int days)
|
||||||
|
{
|
||||||
|
var st = new TrainStop();
|
||||||
|
|
||||||
|
st.Left = start_time[0] == '-' ? null : start_time.ToTimeSpanNullable();
|
||||||
|
st.Arrive = arrive_time[0] == '-' ? null : arrive_time.ToTimeSpanNullable();
|
||||||
|
if (days > 0)
|
||||||
|
{
|
||||||
|
if (st.Left != null)
|
||||||
|
st.Left = st.Left.Value.AddDays(days);
|
||||||
|
if (st.Arrive != null)
|
||||||
|
st.Arrive = st.Arrive.Value.AddDays(days);
|
||||||
|
}
|
||||||
|
if (prevTimeSpan != null && st.Arrive != null)
|
||||||
|
{
|
||||||
|
if (st.Arrive.Value < prevTimeSpan.Value)
|
||||||
|
{
|
||||||
|
st.Arrive = st.Arrive.Value.Add(new TimeSpan(24, 0, 0));
|
||||||
|
if (st.Left != null)
|
||||||
|
st.Left = st.Left.Value.Add(new TimeSpan(24, 0, 0));
|
||||||
|
days++;
|
||||||
|
}
|
||||||
|
prevTimeSpan = st.Arrive;
|
||||||
|
}
|
||||||
|
st.Days = days;
|
||||||
|
if (prevTimeSpan != null && st.Left != null)
|
||||||
|
{
|
||||||
|
if (st.Left.Value < prevTimeSpan.Value)
|
||||||
|
{
|
||||||
|
st.Left = st.Left.Value.Add(new TimeSpan(24, 0, 0));
|
||||||
|
days++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevTimeSpan = st.Left;
|
||||||
|
|
||||||
|
st.Index = index;
|
||||||
|
st.Code = StationManager.Instance.Storage.StationNameMap.GetValue(station_name).SelectValue(s => s.Code) ?? "";
|
||||||
|
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _dataFolder;
|
||||||
|
private string _sourceArchiveFolder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建 <see cref="WebDataProvider" /> 的新实例(WebDataProvider)
|
||||||
|
/// </summary>
|
||||||
|
public WebDataProvider()
|
||||||
|
{
|
||||||
|
_dataFolder = PathUtility.Combine(RunTimeContext.DataStorageRoot, "trains");
|
||||||
|
_sourceArchiveFolder = PathUtility.Combine(_dataFolder, "sources");
|
||||||
|
Directory.CreateDirectory(_dataFolder);
|
||||||
|
Directory.CreateDirectory(_sourceArchiveFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void LoadTrainInfo(IndexStorage indexStorage)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 正在获得最新车次信息");
|
||||||
|
var html = new HttpClient().Create(HttpMethod.Get, "https://kyfw.12306.cn/otn/resources/js/query/train_list.js?scriptVersion=1.1051", null, null, "").Send();
|
||||||
|
if (!html.IsValid())
|
||||||
|
{
|
||||||
|
Trace.TraceError("[TRAIN_DATA_WEB_PROVIDER] 车次信息获得失败。错误:{0}", html.Exception);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 正在缓存原始来源");
|
||||||
|
File.WriteAllText(PathUtility.Combine(_sourceArchiveFolder, "train_list_" + indexStorage.Version + ".js"), html.Result);
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 原始来源缓存成功");
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 正在分析车次信息");
|
||||||
|
|
||||||
|
//移除非JSON部分
|
||||||
|
var fromIndex = html.Result.IndexOf('{');
|
||||||
|
var endIndex = html.Result.LastIndexOf('}');
|
||||||
|
var body = html.Result.Substring(fromIndex, endIndex - fromIndex + 1);
|
||||||
|
|
||||||
|
var data = JsonConvert.DeserializeObject<TrainListData>(body);
|
||||||
|
var station = StationManager.Instance.Storage.StationNameMap;
|
||||||
|
|
||||||
|
foreach (var date in data.Keys)
|
||||||
|
{
|
||||||
|
var dateSt = data[date];
|
||||||
|
var curStorage = indexStorage.TrainInfoStorages.GetValue(date);
|
||||||
|
var curTrainList = curStorage.SelectValue(s => s.Trains);
|
||||||
|
//所有的车次
|
||||||
|
var alltrains = dateSt.Values.SelectMany(s => s).Select(s =>
|
||||||
|
{
|
||||||
|
var i = new Train();
|
||||||
|
var m = Regex.Match(s.station_train_code, @"([A-Z]\d+)\((.*?)\-(.*?)\)");
|
||||||
|
i.Code = m.GetGroupValue(1);
|
||||||
|
i.From = station.GetValue(m.Groups[2].Value.Trim()).SelectValue(x => x.Code);
|
||||||
|
i.To = station.GetValue(m.Groups[3].Value.Trim()).SelectValue(x => x.Code);
|
||||||
|
i.Id = s.train_no;
|
||||||
|
|
||||||
|
return !string.IsNullOrEmpty(i.From) && !string.IsNullOrEmpty(i.To) ? i : null;
|
||||||
|
}).Except(curTrainList ?? new List<Train>()).ExceptNull().ToList();
|
||||||
|
//加载车次停靠站信息
|
||||||
|
var index = 0;
|
||||||
|
foreach (var alltrain in alltrains)
|
||||||
|
{
|
||||||
|
LoadTrainStopInfo(++index, alltrains.Count, date, alltrain);
|
||||||
|
}
|
||||||
|
if (curStorage == null)
|
||||||
|
{
|
||||||
|
curStorage = new TrainInfoStorage(alltrains);
|
||||||
|
indexStorage.TrainInfoStorages.Add(date, curStorage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curTrainList.AddRange(alltrains);
|
||||||
|
curStorage.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
//缓存
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 开始缓存车次数据 {0}", date);
|
||||||
|
var filepath = PathUtility.Combine(_dataFolder, date + ".json");
|
||||||
|
File.WriteAllText(filepath, JsonConvert.SerializeObject(curStorage));
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 车次数据缓存成功!");
|
||||||
|
|
||||||
|
indexStorage.DateIndices.SafeAdd(date);
|
||||||
|
indexStorage.TrainInfoStorages.AddOrUpdate(date, curStorage);
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 车次信息分析完成,已加载{0}日车次信息", indexStorage.DateIndices.Count);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TrainInfoStorage LoadCache(string date)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 正在加载文件缓存 {0}", date);
|
||||||
|
var file = PathUtility.Combine(_dataFolder, date + ".json");
|
||||||
|
if (File.Exists(file))
|
||||||
|
{
|
||||||
|
return JsonConvert.DeserializeObject<TrainInfoStorage>(File.ReadAllText(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void LoadTrainStopInfo(int index, int totalcount, string date, Train train)
|
||||||
|
{
|
||||||
|
Trace.TraceInformation("[TRAIN_STOP_INFO_LOAER] [{2:#0}/{3:#0}] 正在加载车次 {1}/{0} 信息", train.Code, date, index, totalcount);
|
||||||
|
|
||||||
|
var tryCount = 0;
|
||||||
|
while (tryCount++ < 50)
|
||||||
|
{
|
||||||
|
var ctx = new HttpClient().Create(
|
||||||
|
HttpMethod.Get,
|
||||||
|
string.Format("https://kyfw.12306.cn/otn/czxx/queryByTrainNo?train_no={0}&from_station_telecode={1}&to_station_telecode={2}&depart_date={3}", train.Id, train.From, train.To, date),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new
|
||||||
|
{
|
||||||
|
data = new { data = new List<TrainStopWebInfo>() }
|
||||||
|
}).Send();
|
||||||
|
if (!ctx.IsValid() || ctx.Result.data == null)
|
||||||
|
{
|
||||||
|
Trace.TraceWarning("[TRAIN_STOP_INFO_LOAER] 第 {0} 次加载失败!", tryCount);
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpan? prevTimeSpan = null;
|
||||||
|
int days = 0;
|
||||||
|
train.TrainStops = ctx.Result.data.data.Select((obj, idx) => obj.ToTrainStop(idx + 1, ref prevTimeSpan, ref days)).ToList();
|
||||||
|
Thread.Sleep(200);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.TraceInformation("[TRAIN_STOP_INFO_LOAER] 车次 {1}/{0} 信息加载过程结束", train.Code, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{C385D043-316A-4F05-A6B9-E70BF0ED8DB6}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>TrainInfomationProviderService</RootNamespace>
|
||||||
|
<AssemblyName>TrainInfomationProviderService</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||||
|
<RestorePackages>true</RestorePackages>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>..\WebService\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>..\WebService\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<StartupObject />
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Configuration" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.ServiceProcess" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="InformationUpdaterService.cs">
|
||||||
|
<SubType>Component</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="InformationUpdaterService.Designer.cs">
|
||||||
|
<DependentUpon>InformationUpdaterService.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="RunTimeContext.cs" />
|
||||||
|
<Compile Include="StationInfo\Entities\BasicStation.cs" />
|
||||||
|
<Compile Include="StationInfo\Entities\SameStationCollection.cs" />
|
||||||
|
<Compile Include="StationInfo\Entities\StationDetailInfo.cs" />
|
||||||
|
<Compile Include="StationInfo\Entities\StationStorage.cs" />
|
||||||
|
<Compile Include="StationInfo\StationManager.cs" />
|
||||||
|
<Compile Include="TrainInfo\Entities\IndexStorage.cs" />
|
||||||
|
<Compile Include="TrainInfo\Entities\Train.cs" />
|
||||||
|
<Compile Include="TrainInfo\Entities\TrainInfoStorage.cs" />
|
||||||
|
<Compile Include="TrainInfo\Entities\TrainStop.cs" />
|
||||||
|
<Compile Include="TrainInfo\TrainInfoManager.cs" />
|
||||||
|
<Compile Include="TrainInfo\TrainInfoSearchProvider.cs" />
|
||||||
|
<Compile Include="TrainInfo\WebDataProvider.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\Private\iFishOs\FSLib.Extension\src\FSLib.Extension.csproj">
|
||||||
|
<Project>{6d4588aa-a0fd-4364-972c-22b0ab7938f9}</Project>
|
||||||
|
<Name>FSLib.Extension</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\Private\iFish\FSLib.Network\FSLib.Network.NET4.csproj">
|
||||||
|
<Project>{3d34b2d8-36f9-4e16-bf0f-a8905f8fe8ba}</Project>
|
||||||
|
<Name>FSLib.Network.NET4</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\Private\iFish\FSLib\FSLib_NET4.csproj">
|
||||||
|
<Project>{d46393a2-aeab-4876-aebf-84b993e66227}</Project>
|
||||||
|
<Name>FSLib_NET4</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
|
||||||
|
</Target>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
4
TrainInfomationProviderService/packages.config
Normal file
4
TrainInfomationProviderService/packages.config
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
|
||||||
|
</packages>
|
@ -776,8 +776,8 @@ namespace Web12306
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var startTime = StopInfos.Select(s => s.StartTime).ToArray();
|
//var startTime = StopInfos.Select(s => s.StartTime).ToArray();
|
||||||
var stopTime = StopInfos.Select(s => s.StopTime).ToArray();
|
//var stopTime = StopInfos.Select(s => s.StopTime).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ label {
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
background: url(../images/page-bg.png) repeat-x top left;
|
background-color: #f8f8f8;
|
||||||
font: 14px Helvetica, Arial, "Microsoft Yahei", SimSun, sans-serif;
|
font: 14px Helvetica, Arial, "Microsoft Yahei", SimSun, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ a:active {
|
|||||||
display: block;
|
display: block;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-bar .user-nav li.selected > a {
|
.header-bar .user-nav li.selected > a {
|
||||||
color: #f17206;
|
color: #f17206;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<header class="header-bar">
|
<header class="header-bar">
|
||||||
|
<div class="header-back"></div>
|
||||||
<div class="logo"><img src="images/logo.png" alt="" /></div>
|
<div class="logo"><img src="images/logo.png" alt="" /></div>
|
||||||
<nav>
|
<nav>
|
||||||
<ul class="user-nav">
|
<ul class="user-nav">
|
||||||
|
@ -313,6 +313,8 @@
|
|||||||
setQueryResult: function (result, queryCount) {
|
setQueryResult: function (result, queryCount) {
|
||||||
registerSameStation(result);
|
registerSameStation(result);
|
||||||
//改签或学生票,忽略
|
//改签或学生票,忽略
|
||||||
|
//TODO 屏蔽
|
||||||
|
return;
|
||||||
if (cp.reisgn || cp.studentTicket)
|
if (cp.reisgn || cp.studentTicket)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user