sync
This commit is contained in:
parent
dceda08407
commit
3015fb0407
@ -36,8 +36,20 @@ namespace TrainInfomationProviderService
|
||||
|
||||
StationManager.Instance.Init();
|
||||
TrainInfoManager.Instance.Init();
|
||||
SameStationManager.Init();
|
||||
//搜索?
|
||||
var searchProvider = new TrainInfoSearchProvider(TrainInfoManager.Instance.Storage);
|
||||
var searchProvider = new TrainInfoSearchProvider();
|
||||
var lines = searchProvider.FindDirectTrains(DateTime.Parse("2014-12-10"), "NVH", "JJG").ToArray();
|
||||
var maxTimeRage = lines.Max(s => s.CalculatedMinutesBase);
|
||||
var altLines = searchProvider.FindOnceTransitTrains(DateTime.Parse("2014-12-12"), "CCT", "ZHQ", new TrainTransitSearchOptions() { MaxExtraMinutes = int.MaxValue }).ToArray();
|
||||
|
||||
var availableLines = lines.Select(s => s.Train.Code + "," + s.FromStation.Name + "," + s.ToStation.Name + "," + s.ElapsedTime).ToArray();
|
||||
Array.ForEach(altLines.Select(s =>
|
||||
s.First.Train.Code + "," + s.First.FromStation.Name + "," + s.First.ToStation.Name + "," + s.First.From.Left.Value + " - " + s.First.To.Arrive.Value + " / " + s.First.ElapsedTime
|
||||
+ " -> " + s.Second.Train.Code + "," + s.Second.FromStation.Name + "," + s.Second.ToStation.Name + "," + s.Second.From.Left.Value + " - " + s.Second.To.Arrive.Value + " / " + s.Second.ElapsedTime + " / 等待 " + s.WaitElaspsedTime + " / 总耗时 " + s.TotalElapsedTime
|
||||
+ (s.NotRecommand ? " / 不推荐" : "")
|
||||
).ToArray(), _ => Trace.TraceInformation(_));
|
||||
|
||||
//runtime mode
|
||||
MessageBox.Show(StationManager.Instance.Storage.Version.ToString());
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
154
TrainInfomationProviderService/StationInfo/SameStationManager.cs
Normal file
154
TrainInfomationProviderService/StationInfo/SameStationManager.cs
Normal file
@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Policy;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
using FSLib.Network.Http;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace TrainInfomationProviderService.StationInfo
|
||||
{
|
||||
class SameStationManager
|
||||
{
|
||||
public static Dictionary<string, HashSet<string>> SameStationMap { get; private set; }
|
||||
|
||||
private static Timer _timer;
|
||||
private static string _cacheUrl;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_cacheUrl = PathUtility.Combine(RunTimeContext.DataStorageRoot, "samestation.json");
|
||||
SameStationMap = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
LoadCache();
|
||||
|
||||
_timer = new Timer(_ => Grabber(), null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
|
||||
Grabber();
|
||||
if (StationManager.Instance.Storage != null)
|
||||
{
|
||||
AutoRefreshFromSource();
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadCache()
|
||||
{
|
||||
if (!File.Exists(_cacheUrl)) return;
|
||||
|
||||
var list = JsonConvert.DeserializeObject<List<HashSet<string>>>(File.ReadAllText(_cacheUrl));
|
||||
foreach (var hashSet in list)
|
||||
{
|
||||
foreach (var s in hashSet)
|
||||
{
|
||||
SameStationMap.AddOrUpdate(s, hashSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Grabber()
|
||||
{
|
||||
try
|
||||
{
|
||||
GrabberFromWeb();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
_timer.Change(new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||
}
|
||||
|
||||
internal static void Save()
|
||||
{
|
||||
lock (_cacheUrl)
|
||||
{
|
||||
File.WriteAllText(_cacheUrl, JsonConvert.SerializeObject(SameStationMap.Values.Distinct().ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
internal static void AutoRefreshFromSource()
|
||||
{
|
||||
var map = SameStationMap;
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
var count = map.Count;
|
||||
var stations = StationManager.Instance.Storage.StationNameMap.Values.OrderByDescending(s => s.Name.Length).ToList();
|
||||
|
||||
while (stations.Count > 0)
|
||||
{
|
||||
var st = stations.Last();
|
||||
stations.RemoveAt(stations.Count - 1);
|
||||
|
||||
HashSet<string> collection = null;
|
||||
for (var i = stations.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (stations[i].Name.IndexOf(st.Name) != 0)
|
||||
continue;
|
||||
|
||||
(collection ?? (collection = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { st.Code })).Add(stations[i].Code);
|
||||
stations.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
if (collection != null && collection.Count > 1)
|
||||
{
|
||||
var curSet = collection.Select(map.GetValue).FirstOrDefault(s => s != null) ?? new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var s1 in collection)
|
||||
{
|
||||
curSet.SafeAdd(s1);
|
||||
}
|
||||
|
||||
foreach (var s in collection)
|
||||
{
|
||||
map.AddOrUpdate(s, curSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SameStationMap.Count != count)
|
||||
{
|
||||
//有变化
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
private static string _url = "http://service.fishlee.net/ss.json";
|
||||
|
||||
static bool GrabberFromWeb()
|
||||
{
|
||||
var ctx = new HttpClient().Create<string>(HttpMethod.Get, _url).Send();
|
||||
if (!ctx.IsValid())
|
||||
return false;
|
||||
|
||||
//缓存
|
||||
File.WriteAllText(_cacheUrl, ctx.Result);
|
||||
|
||||
var list = JsonConvert.DeserializeObject<List<HashSet<string>>>(File.ReadAllText(_cacheUrl));
|
||||
var map = SameStationMap;
|
||||
var count = SameStationMap.Count;
|
||||
foreach (var hashSet in list)
|
||||
{
|
||||
var curSet = hashSet.Select(map.GetValue).FirstOrDefault(s => s != null) ?? new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var s1 in hashSet)
|
||||
{
|
||||
curSet.SafeAdd(s1);
|
||||
}
|
||||
|
||||
foreach (var s in hashSet)
|
||||
{
|
||||
map.AddOrUpdate(s, curSet);
|
||||
}
|
||||
}
|
||||
if (SameStationMap.Count != count)
|
||||
{
|
||||
//有变化
|
||||
Save();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -60,10 +60,6 @@ namespace TrainInfomationProviderService.StationInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (RunTimeContext.IsWeb)
|
||||
{
|
||||
return HostingEnvironment.Cache["_12306stations"] as StationStorage;
|
||||
}
|
||||
return _storage;
|
||||
}
|
||||
}
|
||||
@ -75,54 +71,54 @@ namespace TrainInfomationProviderService.StationInfo
|
||||
_dataFilePath = PathUtility.Combine(RunTimeContext.DataStorageRoot, "stations.json");
|
||||
Trace.TraceInformation("[STATION] 目标缓存文件路径:{0}", _dataFilePath);
|
||||
|
||||
if (RunTimeContext.IsWeb)
|
||||
{
|
||||
Trace.TraceInformation("[STATION] WEB模式");
|
||||
//if (RunTimeContext.IsWeb)
|
||||
//{
|
||||
// Trace.TraceInformation("[STATION] WEB模式");
|
||||
|
||||
InitWeb();
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.TraceInformation("[STATION] 服务模式");
|
||||
InitService();
|
||||
}
|
||||
// InitWeb();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
Trace.TraceInformation("[STATION] 服务模式");
|
||||
InitService();
|
||||
//}
|
||||
}
|
||||
|
||||
#region web环境
|
||||
|
||||
/// <summary>
|
||||
/// web环境初始化
|
||||
/// </summary>
|
||||
void InitWeb()
|
||||
{
|
||||
Trace.TraceInformation("[STATION] 初始化WEB模式");
|
||||
LoadCache();
|
||||
}
|
||||
///// <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] 缓存加载完成");
|
||||
}
|
||||
//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缓存加入完成");
|
||||
}
|
||||
}
|
||||
// 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
|
||||
@ -151,6 +147,7 @@ namespace TrainInfomationProviderService.StationInfo
|
||||
{
|
||||
Trace.TraceInformation("[STATION] 正在刷新缓存");
|
||||
RefreshStationInfo(lastestVersion);
|
||||
SameStationManager.AutoRefreshFromSource();
|
||||
Trace.TraceInformation("[STATION] 缓存数据已刷新");
|
||||
}
|
||||
_checkStationTimer = new Timer(_ => CheckStationVersion(), null, new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||
|
@ -11,6 +11,8 @@ namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
{
|
||||
public class IndexStorage
|
||||
{
|
||||
private readonly object _lockObject = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 创建 <see cref="IndexStorage" /> 的新实例(IndexStorage)
|
||||
/// </summary>
|
||||
@ -30,17 +32,20 @@ namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
[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())
|
||||
lock (_lockObject)
|
||||
{
|
||||
var data = dataLoader.LoadCache(dateIndex);
|
||||
if (data == null)
|
||||
DateIndices.Remove(dateIndex);
|
||||
else TrainInfoStorages.Add(dateIndex, data);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,19 +54,23 @@ namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
/// </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)
|
||||
lock (_lockObject)
|
||||
{
|
||||
Trace.TraceInformation("[TRAIN_INDEX_STORAGE] 正在移除过期数据 {0}", outdate);
|
||||
DateIndices.Remove(outdate);
|
||||
if (TrainInfoStorages.ContainsKey(outdate))
|
||||
TrainInfoStorages.Remove(outdate);
|
||||
Trace.TraceInformation("[TRAIN_INDEX_STORAGE] 完成移除过期数据 {0}", outdate);
|
||||
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] 正在移除过期数据");
|
||||
}
|
||||
Trace.TraceInformation("[TRAIN_INDEX_STORAGE] 正在移除过期数据");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
@ -38,6 +39,15 @@ namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
[JsonProperty("s")]
|
||||
public List<TrainStop> TrainStops { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Dictionary<string, TrainStop> TrainStopMap { get; private set; }
|
||||
|
||||
[OnDeserialized]
|
||||
void Init(StreamingContext ctx)
|
||||
{
|
||||
TrainStopMap = TrainStops == null ? null : TrainStops.Where(s => !string.IsNullOrEmpty(s.Code)).ToDictionary(s => s.Code, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
#region Implementation of IEquatable<Train>
|
||||
|
||||
/// <summary>
|
||||
@ -93,5 +103,25 @@ namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
char? _trainClass;
|
||||
|
||||
/// <summary>
|
||||
/// 列车等级
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public char TrainClass
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_trainClass == null)
|
||||
{
|
||||
if (Code[0] == 'G' || Code[0] == 'D' || Code[0] == 'Z' || Code[0] == 'T')
|
||||
_trainClass = Code[0];
|
||||
}
|
||||
|
||||
return _trainClass ?? '*';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TrainInfomationProviderService.StationInfo;
|
||||
using TrainInfomationProviderService.StationInfo.Entities;
|
||||
|
||||
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
{
|
||||
public class TrainLineSegment
|
||||
{
|
||||
StationDetailInfo _toStation;
|
||||
StationDetailInfo _fromStation;
|
||||
TimeSpan? _elapsedTime;
|
||||
|
||||
public Train Train { get; private set; }
|
||||
|
||||
public TrainStop From { get; private set; }
|
||||
|
||||
public TrainStop To { get; private set; }
|
||||
|
||||
public StationDetailInfo FromStation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_fromStation == null)
|
||||
_fromStation = StationManager.Instance.Storage.Stations.GetValue(From.Code);
|
||||
return _fromStation;
|
||||
}
|
||||
}
|
||||
|
||||
public StationDetailInfo ToStation
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_toStation == null)
|
||||
_toStation = StationManager.Instance.Storage.Stations.GetValue(To.Code);
|
||||
return _toStation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 历时
|
||||
/// </summary>
|
||||
public TimeSpan ElapsedTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_elapsedTime == null)
|
||||
_elapsedTime = To.Arrive - From.Left;
|
||||
return _elapsedTime ?? TimeSpan.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
int? _calculatedMinutesBase;
|
||||
|
||||
/// <summary>
|
||||
/// 进行时间对比的基础分钟数
|
||||
/// </summary>
|
||||
public int CalculatedMinutesBase
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_calculatedMinutesBase == null)
|
||||
{
|
||||
var minutes = ElapsedTime.TotalMinutes;
|
||||
var rate = 1.0;
|
||||
switch (Train.TrainClass)
|
||||
{
|
||||
case 'G':
|
||||
rate = 1.0;
|
||||
break;
|
||||
case 'D':
|
||||
rate = 0.71428;
|
||||
break;
|
||||
case 'Z':
|
||||
rate = 0.45714;
|
||||
break;
|
||||
case 'T':
|
||||
rate = 0.4;
|
||||
break;
|
||||
default:
|
||||
rate = 0.28571;
|
||||
break;
|
||||
}
|
||||
_calculatedMinutesBase = (int)(rate*minutes);
|
||||
}
|
||||
return _calculatedMinutesBase ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建 <see cref="TrainLineSegment" /> 的新实例(TrainLineSegment)
|
||||
/// </summary>
|
||||
/// <param name="train"></param>
|
||||
/// <param name="from"></param>
|
||||
/// <param name="to"></param>
|
||||
public TrainLineSegment(Train train, TrainStop from, TrainStop to)
|
||||
{
|
||||
Train = train;
|
||||
From = from;
|
||||
To = to;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -4,11 +4,14 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using TrainInfomationProviderService.StationInfo;
|
||||
|
||||
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
{
|
||||
public class TrainStop
|
||||
{
|
||||
private string _name;
|
||||
|
||||
[JsonProperty("c")]
|
||||
public string Code { get; set; }
|
||||
|
||||
@ -24,5 +27,34 @@ namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
[JsonProperty("d")]
|
||||
public int Days { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 停靠时间
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public TimeSpan StopTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Arrive == null || Left == null)
|
||||
return TimeSpan.MaxValue;
|
||||
|
||||
return Left.Value - Arrive.Value;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_name) && StationManager.Instance.Storage != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Code))
|
||||
_name = StationManager.Instance.Storage.Stations.GetValue(Code).SelectValue(s => s.Name);
|
||||
else _name = string.Empty;
|
||||
}
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
{
|
||||
public class TrainTransitOnceResult
|
||||
{
|
||||
public TrainLineSegment First { get; private set; }
|
||||
|
||||
public TrainLineSegment Second { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 不推荐车次
|
||||
/// </summary>
|
||||
public bool NotRecommand { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建 <see cref="TrainTransitOnceResult" /> 的新实例(TrainTransitOnceResult)
|
||||
/// </summary>
|
||||
/// <param name="first"></param>
|
||||
/// <param name="second"></param>
|
||||
public TrainTransitOnceResult(TrainLineSegment first, TrainLineSegment second, DateTime date, bool notRecommand=false)
|
||||
{
|
||||
First = first;
|
||||
Second = second;
|
||||
InitTimeInfo(date);
|
||||
NotRecommand = notRecommand;
|
||||
}
|
||||
|
||||
void InitTimeInfo(DateTime date)
|
||||
{
|
||||
FirstTrainLeftDate = date.Add(First.From.Left.Value.AddDays(-First.From.Left.Value.Days));
|
||||
FirstTrainArriveDate = FirstTrainLeftDate.Add(First.ElapsedTime);
|
||||
|
||||
SecondTrainLeftDate = FirstTrainArriveDate.Date.Add(Second.From.Left.Value.AddDays(-Second.From.Left.Value.Days));
|
||||
if (SecondTrainLeftDate < FirstTrainArriveDate)
|
||||
SecondTrainLeftDate = SecondTrainLeftDate.AddDays(1);
|
||||
SecondTrainArriveDate = SecondTrainLeftDate.Add(Second.ElapsedTime);
|
||||
|
||||
WaitElaspsedTime = SecondTrainLeftDate - FirstTrainArriveDate;
|
||||
TotalElapsedTime = SecondTrainArriveDate - FirstTrainLeftDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 前车出发时间
|
||||
/// </summary>
|
||||
public DateTime FirstTrainLeftDate { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前车到达时间
|
||||
/// </summary>
|
||||
public DateTime FirstTrainArriveDate { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 后车出发时间
|
||||
/// </summary>
|
||||
public DateTime SecondTrainLeftDate { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 后车到达时间
|
||||
/// </summary>
|
||||
public DateTime SecondTrainArriveDate { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 前车历时
|
||||
/// </summary>
|
||||
public TimeSpan FirstElapsedTime { get { return First.ElapsedTime; } }
|
||||
|
||||
/// <summary>
|
||||
/// 后车历时
|
||||
/// </summary>
|
||||
public TimeSpan SecondElapsedTime { get { return Second.ElapsedTime; } }
|
||||
|
||||
/// <summary>
|
||||
/// 等待耗时
|
||||
/// </summary>
|
||||
public TimeSpan WaitElaspsedTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总时间
|
||||
/// </summary>
|
||||
public TimeSpan TotalElapsedTime { get; private set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,336 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TrainInfomationProviderService.StationInfo;
|
||||
using TrainInfomationProviderService.StationInfo.Entities;
|
||||
|
||||
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
{
|
||||
public class TrainTransitOnceResultCollection : ICollection<TrainTransitOnceResult>
|
||||
{
|
||||
List<TrainTransitOnceResult> _list = new List<TrainTransitOnceResult>();
|
||||
TrainTransitSearchOptions _options;
|
||||
|
||||
/// <summary>
|
||||
/// 日期
|
||||
/// </summary>
|
||||
public DateTime Date { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 出发城市编码
|
||||
/// </summary>
|
||||
public string FromCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到达城市编码
|
||||
/// </summary>
|
||||
public string ToCode { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 出发城市信息
|
||||
/// </summary>
|
||||
public StationDetailInfo From { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到达城市信息
|
||||
/// </summary>
|
||||
public StationDetailInfo To { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建 <see cref="TrainTransitOnceResultCollection"/> 的新实例(TrainTransitOnceResultCollection)
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="date"></param>
|
||||
/// <param name="fromCode"></param>
|
||||
/// <param name="toCode"></param>
|
||||
public TrainTransitOnceResultCollection(DateTime date, TrainTransitSearchOptions options, string fromCode, string toCode)
|
||||
{
|
||||
ToCode = toCode;
|
||||
FromCode = fromCode;
|
||||
Date = date;
|
||||
_options = options;
|
||||
|
||||
From = StationManager.Instance.Storage.Stations.GetValue(fromCode);
|
||||
To = StationManager.Instance.Storage.Stations.GetValue(toCode);
|
||||
}
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
|
||||
/// <summary>
|
||||
/// 返回一个循环访问集合的枚举器。
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// 可用于循环访问集合的 <see cref="T:System.Collections.Generic.IEnumerator`1"/>。
|
||||
/// </returns>
|
||||
public IEnumerator<TrainTransitOnceResult> GetEnumerator()
|
||||
{
|
||||
return _list.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回一个循环访问集合的枚举数。
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// 一个可用于循环访问集合的 <see cref="T:System.Collections.IEnumerator"/> 对象。
|
||||
/// </returns>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of ICollection<TrainTransitOnceResult>
|
||||
|
||||
/// <summary>
|
||||
/// 将某项添加到 <see cref="T:System.Collections.Generic.ICollection`1"/> 中。
|
||||
/// </summary>
|
||||
/// <param name="item">要添加到 <see cref="T:System.Collections.Generic.ICollection`1"/> 的对象。</param><exception cref="T:System.NotSupportedException"><see cref="T:System.Collections.Generic.ICollection`1"/> 为只读。</exception>
|
||||
public void Add(TrainTransitOnceResult item)
|
||||
{
|
||||
if (item == null || !CheckTransitLineAvailable(item))
|
||||
return;
|
||||
|
||||
_list.Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中移除所有项。
|
||||
/// </summary>
|
||||
/// <exception cref="T:System.NotSupportedException"><see cref="T:System.Collections.Generic.ICollection`1"/> 为只读。</exception>
|
||||
public void Clear()
|
||||
{
|
||||
_list.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确定 <see cref="T:System.Collections.Generic.ICollection`1"/> 是否包含特定值。
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// 如果在 <see cref="T:System.Collections.Generic.ICollection`1"/> 中找到 <paramref name="item"/>,则为 true;否则为 false。
|
||||
/// </returns>
|
||||
/// <param name="item">要在 <see cref="T:System.Collections.Generic.ICollection`1"/> 中定位的对象。</param>
|
||||
public bool Contains(TrainTransitOnceResult item)
|
||||
{
|
||||
return _list.Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从特定的 <see cref="T:System.Array"/> 索引开始,将 <see cref="T:System.Collections.Generic.ICollection`1"/> 的元素复制到一个 <see cref="T:System.Array"/> 中。
|
||||
/// </summary>
|
||||
/// <param name="array">作为从 <see cref="T:System.Collections.Generic.ICollection`1"/> 复制的元素的目标的一维 <see cref="T:System.Array"/>。 <see cref="T:System.Array"/> 必须具有从零开始的索引。</param><param name="arrayIndex"><paramref name="array"/> 中从零开始的索引,从此索引处开始进行复制。</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> 为 null。</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> 小于 0。</exception><exception cref="T:System.ArgumentException">源 <see cref="T:System.Collections.Generic.ICollection`1"/> 中的元素数目大于从 <paramref name="arrayIndex"/> 到目标 <paramref name="array"/> 末尾之间的可用空间。</exception>
|
||||
public void CopyTo(TrainTransitOnceResult[] array, int arrayIndex)
|
||||
{
|
||||
_list.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中移除特定对象的第一个匹配项。
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// 如果已从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中成功移除 <paramref name="item"/>,则为 true;否则为 false。 如果在原始 <see cref="T:System.Collections.Generic.ICollection`1"/> 中没有找到 <paramref name="item"/>,该方法也会返回 false。
|
||||
/// </returns>
|
||||
/// <param name="item">要从 <see cref="T:System.Collections.Generic.ICollection`1"/> 中移除的对象。</param><exception cref="T:System.NotSupportedException"><see cref="T:System.Collections.Generic.ICollection`1"/> 为只读。</exception>
|
||||
public bool Remove(TrainTransitOnceResult item)
|
||||
{
|
||||
return _list.Remove(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 <see cref="T:System.Collections.Generic.ICollection`1"/> 中包含的元素数。
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see cref="T:System.Collections.Generic.ICollection`1"/> 中包含的元素个数。
|
||||
/// </returns>
|
||||
public int Count { get { return _list.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,该值指示 <see cref="T:System.Collections.Generic.ICollection`1"/> 是否为只读。
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// 如果 <see cref="T:System.Collections.Generic.ICollection`1"/> 为只读,则为 true;否则为 false。
|
||||
/// </returns>
|
||||
public bool IsReadOnly { get { return false; } }
|
||||
|
||||
public TrainTransitSearchOptions Options
|
||||
{
|
||||
get { return _options; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 辅助函数
|
||||
|
||||
|
||||
static int GetMinimalSpace(Train train, bool notRecommand)
|
||||
{
|
||||
var extraTime = notRecommand ? 60 : 0;
|
||||
|
||||
switch (train.TrainClass)
|
||||
{
|
||||
case 'C':
|
||||
case 'G':
|
||||
return 30+extraTime;
|
||||
case 'D':
|
||||
return 30 + extraTime;
|
||||
case 'Z':
|
||||
return 60 + extraTime;
|
||||
case 'T':
|
||||
return 60 + extraTime;
|
||||
default:
|
||||
return 60 + extraTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int GetMaxiumSpace(Train train, bool notRecommand)
|
||||
{
|
||||
var extraTime = notRecommand ? 60 : 0;
|
||||
|
||||
switch (train.TrainClass)
|
||||
{
|
||||
case 'C':
|
||||
case 'G':
|
||||
return 150 + extraTime;
|
||||
case 'D':
|
||||
return 150 + extraTime;
|
||||
case 'Z':
|
||||
return 180 + extraTime;
|
||||
case 'T':
|
||||
return 180 + extraTime;
|
||||
default:
|
||||
return 240 + extraTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得比较理想中位时间
|
||||
/// </summary>
|
||||
/// <param name="train"></param>
|
||||
/// <returns></returns>
|
||||
static int GetHighQualityTimeSpace(Train train, bool notRecommand)
|
||||
{
|
||||
var extraTime = notRecommand ? 60 : 0;
|
||||
|
||||
switch (train.TrainClass)
|
||||
{
|
||||
case 'C':
|
||||
case 'G':
|
||||
return 60 + extraTime;
|
||||
case 'D':
|
||||
return 60 + extraTime;
|
||||
case 'Z':
|
||||
return 120 + extraTime;
|
||||
case 'T':
|
||||
return 120 + extraTime;
|
||||
default:
|
||||
return 120 + extraTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 验证车次换乘是否有效
|
||||
|
||||
|
||||
bool CheckTransitLineAvailable(TrainTransitOnceResult item)
|
||||
{
|
||||
//总共时间
|
||||
if (item.First.CalculatedMinutesBase + item.Second.CalculatedMinutesBase > _options.MaxExtraMinutes)
|
||||
//时间过久
|
||||
return false;
|
||||
|
||||
//时间衔接
|
||||
var arriveFirst = Date.Add(item.First.To.Arrive.Value);
|
||||
var leftSecond = arriveFirst.Date.Add(item.Second.From.Left.Value);
|
||||
|
||||
//早于发车
|
||||
if (leftSecond <= arriveFirst)
|
||||
return false;
|
||||
var space = (int)(leftSecond - arriveFirst).TotalMinutes;
|
||||
if (space < GetMinimalSpace(item.First.Train, item.NotRecommand) || space > GetMaxiumSpace(item.Second.Train, item.NotRecommand))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 对列表进行二次优化
|
||||
|
||||
/// <summary>
|
||||
/// 二次优化,排除小站等。
|
||||
/// </summary>
|
||||
internal void SecondaryAnalyze()
|
||||
{
|
||||
//对于前车进行分组优化
|
||||
RemoveSmallStation();
|
||||
//排序
|
||||
ProcessPriority();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除小站
|
||||
/// </summary>
|
||||
void RemoveSmallStation()
|
||||
{
|
||||
var groups = this.GroupBy(s => s.First.Train.Code).Select(s => new { s.Key, Array = s.ToArray() }).ToArray();
|
||||
foreach (var g in groups)
|
||||
{
|
||||
if (g.Array.Length < 2)
|
||||
continue;
|
||||
|
||||
Array.Sort(g.Array, (s1, s2) =>
|
||||
{
|
||||
var st1 = s1.First.To.StopTime.TotalMinutes;
|
||||
var st2 = s2.First.To.StopTime.TotalMinutes;
|
||||
|
||||
if (st1 < st2) return 1;
|
||||
if (st1 > st2) return -1;
|
||||
return 0;
|
||||
});
|
||||
foreach (var line in g.Array.Skip(Options.SameLineMaxKeepStations))
|
||||
{
|
||||
_list.Remove(line);
|
||||
}
|
||||
}
|
||||
|
||||
groups = this.GroupBy(s => s.Second.Train.Code).Select(s => new { s.Key, Array = s.ToArray() }).ToArray();
|
||||
foreach (var g in groups)
|
||||
{
|
||||
if (g.Array.Length < 2)
|
||||
continue;
|
||||
|
||||
Array.Sort(g.Array, (s1, s2) =>
|
||||
{
|
||||
var st1 = s1.Second.From.StopTime.TotalMinutes;
|
||||
var st2 = s2.Second.From.StopTime.TotalMinutes;
|
||||
|
||||
if (st1 < st2) return 1;
|
||||
if (st1 > st2) return -1;
|
||||
return 0;
|
||||
});
|
||||
foreach (var line in g.Array.Skip(Options.SameLineMaxKeepStations))
|
||||
{
|
||||
_list.Remove(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 分组排序
|
||||
|
||||
void ProcessPriority()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TrainInfomationProviderService.TrainInfo.Entities
|
||||
{
|
||||
public class TrainTransitSearchOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 最大允许多出来的时间
|
||||
/// </summary>
|
||||
public int MaxExtraMinutes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 同一个车次最高保持的换乘站数
|
||||
/// </summary>
|
||||
public int SameLineMaxKeepStations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建 <see cref="TrainTransitSearchOptions" /> 的新实例(TrainTransitSearchOptions)
|
||||
/// </summary>
|
||||
public TrainTransitSearchOptions()
|
||||
{
|
||||
SameLineMaxKeepStations = 3;
|
||||
}
|
||||
}
|
||||
}
|
@ -57,10 +57,10 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (RunTimeContext.IsWeb)
|
||||
{
|
||||
return HostingEnvironment.Cache["_12306trains"] as IndexStorage;
|
||||
}
|
||||
//if (RunTimeContext.IsWeb)
|
||||
//{
|
||||
// return HostingEnvironment.Cache["_12306trains"] as IndexStorage;
|
||||
//}
|
||||
return _storage;
|
||||
}
|
||||
}
|
||||
@ -72,55 +72,55 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
_dataFilePath = PathUtility.Combine(RunTimeContext.DataStorageRoot, "trains.json");
|
||||
Trace.TraceInformation("[TAININFOMANGER] 目标缓存文件路径:{0}", _dataFilePath);
|
||||
|
||||
if (RunTimeContext.IsWeb)
|
||||
{
|
||||
Trace.TraceInformation("[TAININFOMANGER] WEB模式");
|
||||
//if (RunTimeContext.IsWeb)
|
||||
//{
|
||||
// Trace.TraceInformation("[TAININFOMANGER] WEB模式");
|
||||
|
||||
InitWeb();
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.TraceInformation("[TAININFOMANGER] 服务模式");
|
||||
InitService();
|
||||
}
|
||||
// InitWeb();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
Trace.TraceInformation("[TAININFOMANGER] 服务模式");
|
||||
InitService();
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
#region web环境
|
||||
|
||||
/// <summary>
|
||||
/// web环境初始化
|
||||
/// </summary>
|
||||
void InitWeb()
|
||||
{
|
||||
Trace.TraceInformation("[TAININFOMANGER] 初始化WEB模式");
|
||||
LoadCache();
|
||||
}
|
||||
///// <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] 缓存加载完成");
|
||||
}
|
||||
//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缓存加入完成");
|
||||
}
|
||||
}
|
||||
// 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
|
||||
@ -130,11 +130,11 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
private Timer _checkStationTimer;
|
||||
private IndexStorage _storage;
|
||||
|
||||
#if DEBUG
|
||||
private bool _ininitalized = true;
|
||||
#else
|
||||
private bool _ininitalized = false;
|
||||
#endif
|
||||
//#if DEBUG
|
||||
// private bool _ininitalized = false;
|
||||
//#else
|
||||
// private bool _ininitalized = false;
|
||||
//#endif
|
||||
|
||||
/// <summary>
|
||||
/// 服务模式初始化
|
||||
@ -152,16 +152,14 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
_storage = new IndexStorage();
|
||||
}
|
||||
var lastestVersion = GetLatestVersionFromWeb();
|
||||
var needUpdate = _storage == null || _storage.Version < lastestVersion;
|
||||
//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;
|
||||
Trace.TraceInformation("[TAININFOMANGER] 正在刷新缓存");
|
||||
RefreshTrainInfo(lastestVersion);
|
||||
Trace.TraceInformation("[TAININFOMANGER] 缓存数据已刷新");
|
||||
|
||||
//_ininitalized = true;
|
||||
_checkStationTimer = new Timer(_ => CheckTrainVersion(), null, new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||
}
|
||||
|
||||
@ -173,6 +171,7 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
{
|
||||
Storage.Version = version;
|
||||
loader.LoadTrainInfo(Storage);
|
||||
Storage.RemoveOutdateStorage();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -190,10 +189,13 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
void CheckTrainVersion()
|
||||
{
|
||||
var lastestVersion = GetLatestVersionFromWeb();
|
||||
if (Storage == null || Storage.Version < lastestVersion)
|
||||
try
|
||||
{
|
||||
RefreshTrainInfo(lastestVersion);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
_checkStationTimer.Change(new TimeSpan(0, 30, 0), Timeout.InfiniteTimeSpan);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using TrainInfomationProviderService.StationInfo;
|
||||
using TrainInfomationProviderService.TrainInfo.Entities;
|
||||
|
||||
namespace TrainInfomationProviderService.TrainInfo
|
||||
@ -12,17 +13,149 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
{
|
||||
public IndexStorage Storage { get; private set; }
|
||||
|
||||
public TrainInfoSearchProvider(IndexStorage storage)
|
||||
public Dictionary<string, HashSet<string>> SameStationInfo { get; set; }
|
||||
|
||||
public TrainInfoSearchProvider()
|
||||
{
|
||||
Trace.TraceInformation("[TRAIN_INFO_SEARCH_PROVIDER] 正在创建车站-车次信息索引对象");
|
||||
Storage = storage;
|
||||
Storage = TrainInfoManager.Instance.Storage;
|
||||
|
||||
foreach (var trainInfoStorage in storage.TrainInfoStorages)
|
||||
foreach (var trainInfoStorage in Storage.TrainInfoStorages)
|
||||
{
|
||||
Trace.TraceInformation("[TRAIN_INFO_SEARCH_PROVIDER] 正在初始化 {0} 车站-车次信息索引对象", trainInfoStorage.Key);
|
||||
trainInfoStorage.Value.InitStationTrainData();
|
||||
}
|
||||
Trace.TraceInformation("[TRAIN_INFO_SEARCH_PROVIDER] 完成创建车站-车次信息索引对象");
|
||||
}
|
||||
|
||||
public IEnumerable<TrainLineSegment> FindDirectTrains(DateTime date, string from, string to)
|
||||
{
|
||||
var infoStorage = Storage.TrainInfoStorages.GetValue(date.ToString("yyyy-MM-dd"));
|
||||
if (infoStorage == null)
|
||||
yield break;
|
||||
|
||||
for (int i = 0; i < infoStorage.Trains.Count; i++)
|
||||
{
|
||||
var train = infoStorage.Trains[i];
|
||||
var stf = FindStop(train, from);
|
||||
if (stf == null)
|
||||
continue;
|
||||
|
||||
var stt = FindStop(train, to);
|
||||
if (stt == null)
|
||||
continue;
|
||||
|
||||
if (stf.Index >= stt.Index)
|
||||
continue;
|
||||
|
||||
yield return new TrainLineSegment(train, stf, stt);
|
||||
}
|
||||
}
|
||||
|
||||
public TrainTransitOnceResultCollection FindOnceTransitTrains(DateTime date, string from, string to, TrainTransitSearchOptions options)
|
||||
{
|
||||
var result = new TrainTransitOnceResultCollection(date, options, from, to);
|
||||
var infoStorage = Storage.TrainInfoStorages.GetValue(date.ToString("yyyy-MM-dd"));
|
||||
if (infoStorage == null)
|
||||
return result;
|
||||
|
||||
//发车经过车站
|
||||
var fromStations = GetSameStations(from);
|
||||
var toStations = GetSameStations(to);
|
||||
var fromTrains = fromStations.Select(s => infoStorage.StationLeftTrainData.GetValue(s)).ExceptNull().SelectMany(s => s).ToArray();
|
||||
var toTrains = toStations.Select(s => infoStorage.StationLeftTrainData.GetValue(s)).ExceptNull().SelectMany(s => s).ToArray();
|
||||
|
||||
foreach (var fromTrain in fromTrains)
|
||||
{
|
||||
var startStop = FindStop(fromTrain, from);
|
||||
foreach (var fstop in fromTrain.TrainStops.SkipWhile(x => startStop != x).Skip(1))
|
||||
{
|
||||
foreach (var toTrain in toTrains)
|
||||
{
|
||||
var toStop = FindStop(toTrain, to);
|
||||
foreach (var tStop in toTrain.TrainStops.TakeWhile(x => toStop != x))
|
||||
{
|
||||
if (fstop.Code == tStop.Code)
|
||||
{
|
||||
//一个中转点
|
||||
var line = new TrainTransitOnceResult(
|
||||
new TrainLineSegment(fromTrain, startStop, fstop),
|
||||
new TrainLineSegment(toTrain, tStop, toStop),
|
||||
date
|
||||
);
|
||||
result.Add(line);
|
||||
}
|
||||
else if (IsStopInclude(fstop.Code, tStop.Code))
|
||||
{
|
||||
//一个中转点
|
||||
var line = new TrainTransitOnceResult(
|
||||
new TrainLineSegment(fromTrain, startStop, fstop),
|
||||
new TrainLineSegment(toTrain, tStop, toStop),
|
||||
date,
|
||||
true
|
||||
);
|
||||
result.Add(line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.SecondaryAnalyze();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HashSet<string> GetSameStations(string code)
|
||||
{
|
||||
var map = SameStationManager.SameStationMap;
|
||||
if (map != null)
|
||||
{
|
||||
var hash = map.GetValue(code);
|
||||
if (hash != null)
|
||||
return hash;
|
||||
}
|
||||
|
||||
return new HashSet<string>() { code };
|
||||
}
|
||||
|
||||
bool IsStopInclude(string code1, string code2)
|
||||
{
|
||||
|
||||
var map = SameStationManager.SameStationMap;
|
||||
if (map == null)
|
||||
return false;
|
||||
|
||||
var set = map.GetValue(code1);
|
||||
|
||||
return set != null && set.Contains(code2);
|
||||
}
|
||||
|
||||
TrainStop FindStop(Train train, string code)
|
||||
{
|
||||
if (train == null || train.TrainStopMap == null)
|
||||
return null;
|
||||
|
||||
var stop = train.TrainStopMap.GetValue(code);
|
||||
if (stop != null)
|
||||
return stop;
|
||||
|
||||
var map = SameStationManager.SameStationMap;
|
||||
if (map == null)
|
||||
return null;
|
||||
|
||||
var hash = map.GetValue(code);
|
||||
if (hash == null)
|
||||
return null;
|
||||
|
||||
foreach (var s in hash)
|
||||
{
|
||||
stop = train.TrainStopMap.GetValue(s);
|
||||
if (stop != null)
|
||||
return stop;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,12 +152,20 @@ namespace TrainInfomationProviderService.TrainInfo
|
||||
curTrainList.AddRange(alltrains);
|
||||
curStorage.Init();
|
||||
}
|
||||
if (alltrains.Count > 0)
|
||||
{
|
||||
curStorage.InitStationTrainData();
|
||||
|
||||
//缓存
|
||||
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] 车次数据缓存成功!");
|
||||
//缓存
|
||||
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] 车次数据缓存成功!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.TraceInformation("[TRAIN_DATA_WEB_PROVIDER] 车次 {0} 数据无变化", date);
|
||||
}
|
||||
|
||||
indexStorage.DateIndices.SafeAdd(date);
|
||||
indexStorage.TrainInfoStorages.AddOrUpdate(date, curStorage);
|
||||
|
@ -64,14 +64,18 @@
|
||||
<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\SameStationManager.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\TrainLineSegment.cs" />
|
||||
<Compile Include="TrainInfo\Entities\TrainStop.cs" />
|
||||
<Compile Include="TrainInfo\Entities\TrainTransitOnceResult.cs" />
|
||||
<Compile Include="TrainInfo\Entities\TrainTransitOnceResultCollection.cs" />
|
||||
<Compile Include="TrainInfo\Entities\TrainTransitSearchOptions.cs" />
|
||||
<Compile Include="TrainInfo\TrainInfoManager.cs" />
|
||||
<Compile Include="TrainInfo\TrainInfoSearchProvider.cs" />
|
||||
<Compile Include="TrainInfo\WebDataProvider.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user