1+ using Microsoft . Extensions . Logging ;
2+ using Surging . Core . CPlatform . Address ;
3+ using Surging . Core . CPlatform . Mqtt ;
4+ using Surging . Core . CPlatform . Mqtt . Implementation ;
5+ using Surging . Core . CPlatform . Serialization ;
6+ using System ;
7+ using System . Collections . Generic ;
8+ using System . IO ;
9+ using System . Linq ;
10+ using System . Text ;
11+ using System . Threading . Tasks ;
12+
13+ namespace Surging . Core . CPlatform . Routing . Implementation
14+ {
15+ public class SharedFileMqttServiceRouteManager : MqttServiceRouteManagerBase , IDisposable
16+ {
17+ #region Field
18+
19+ private readonly string _filePath ;
20+ private readonly ISerializer < string > _serializer ;
21+ private readonly IMqttServiceFactory _mqttServiceFactory ;
22+ private readonly ILogger < SharedFileMqttServiceRouteManager > _logger ;
23+ private MqttServiceRoute [ ] _routes ;
24+ private readonly FileSystemWatcher _fileSystemWatcher ;
25+
26+ #endregion Field
27+
28+ #region Constructor
29+
30+ public SharedFileMqttServiceRouteManager ( string filePath , ISerializer < string > serializer ,
31+ IMqttServiceFactory mqttServiceFactory , ILogger < SharedFileMqttServiceRouteManager > logger ) : base ( serializer )
32+ {
33+ _filePath = filePath ;
34+ _serializer = serializer ;
35+ _mqttServiceFactory = mqttServiceFactory ;
36+ _logger = logger ;
37+
38+ var directoryName = Path . GetDirectoryName ( filePath ) ;
39+ if ( ! Directory . Exists ( directoryName ) )
40+ Directory . CreateDirectory ( directoryName ) ;
41+ if ( ! File . Exists ( filePath ) ) File . Create ( filePath ) . Close ( ) ;
42+ _fileSystemWatcher = new FileSystemWatcher ( directoryName , Path . GetFileName ( filePath ) ) ;
43+
44+ _fileSystemWatcher . Changed += _fileSystemWatcher_Changed ;
45+ _fileSystemWatcher . Created += _fileSystemWatcher_Changed ;
46+ _fileSystemWatcher . Deleted += _fileSystemWatcher_Changed ;
47+ _fileSystemWatcher . Renamed += _fileSystemWatcher_Changed ;
48+ _fileSystemWatcher . IncludeSubdirectories = false ;
49+ _fileSystemWatcher . EnableRaisingEvents = true ;
50+ }
51+
52+ #endregion Constructor
53+
54+ #region Implementation of IDisposable
55+
56+ /// <summary>
57+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
58+ /// </summary>
59+ public void Dispose ( )
60+ {
61+ _fileSystemWatcher ? . Dispose ( ) ;
62+ }
63+
64+ #endregion Implementation of IDisposable
65+
66+ #region Overrides of ServiceRouteManagerBase
67+
68+ /// <summary>
69+ /// 获取所有可用的服务路由信息。
70+ /// </summary>
71+ /// <returns>服务路由集合。</returns>
72+ public override async Task < IEnumerable < MqttServiceRoute > > GetRoutesAsync ( )
73+ {
74+ if ( _routes == null )
75+ await EntryRoutes ( _filePath ) ;
76+ return _routes ;
77+ }
78+
79+
80+ /// <summary>
81+ /// 清空所有的服务路由。
82+ /// </summary>
83+ /// <returns>一个任务。</returns>
84+ public override Task ClearAsync ( )
85+ {
86+ if ( File . Exists ( _filePath ) )
87+ File . Delete ( _filePath ) ;
88+ return Task . FromResult ( 0 ) ;
89+ }
90+
91+ /// <summary>
92+ /// 设置服务路由。
93+ /// </summary>
94+ /// <param name="routes">服务路由集合。</param>
95+ /// <returns>一个任务。</returns>
96+ protected override async Task SetRoutesAsync ( IEnumerable < MqttServiceDescriptor > routes )
97+ {
98+ using ( var fileStream = new FileStream ( _filePath , FileMode . OpenOrCreate , FileAccess . Write , FileShare . None ) )
99+ {
100+ fileStream . SetLength ( 0 ) ;
101+ using ( var writer = new StreamWriter ( fileStream , Encoding . UTF8 ) )
102+ {
103+ await writer . WriteAsync ( _serializer . Serialize ( routes ) ) ;
104+ }
105+ }
106+ }
107+
108+ public override async Task RemveAddressAsync ( IEnumerable < AddressModel > Address )
109+ {
110+ var routes = await GetRoutesAsync ( ) ;
111+ foreach ( var route in routes )
112+ {
113+ route . MqttEndpoint = route . MqttEndpoint . Except ( Address ) ;
114+ }
115+ await base . SetRoutesAsync ( routes ) ;
116+ }
117+
118+ #endregion Overrides of ServiceRouteManagerBase
119+
120+ #region Private Method
121+
122+ private async Task < IEnumerable < MqttServiceRoute > > GetRoutes ( string file )
123+ {
124+ MqttServiceRoute [ ] routes ;
125+ if ( File . Exists ( file ) )
126+ {
127+ if ( _logger . IsEnabled ( LogLevel . Debug ) )
128+ _logger . LogDebug ( $ "准备从文件:{ file } 中获取服务路由。") ;
129+ string content ;
130+ while ( true )
131+ {
132+ try
133+ {
134+ using (
135+ var fileStream = new FileStream ( file , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) )
136+ {
137+ var reader = new StreamReader ( fileStream , Encoding . UTF8 ) ;
138+ content = await reader . ReadToEndAsync ( ) ;
139+ }
140+ break ;
141+ }
142+ catch ( IOException )
143+ {
144+ }
145+ }
146+ try
147+ {
148+ var serializer = _serializer ;
149+ routes =
150+ ( await
151+ _mqttServiceFactory . CreateMqttServiceRoutesAsync (
152+ serializer . Deserialize < string , MqttServiceDescriptor [ ] > ( content ) ) ) . ToArray ( ) ;
153+ if ( _logger . IsEnabled ( LogLevel . Information ) )
154+ _logger . LogInformation (
155+ $ "成功获取到以下路由信息:{ string . Join ( "," , routes . Select ( i => i . MqttDescriptor . Topic ) ) } 。") ;
156+ }
157+ catch ( Exception exception )
158+ {
159+ if ( _logger . IsEnabled ( LogLevel . Error ) )
160+ _logger . LogError ( exception , "获取路由信息时发生了错误。" ) ;
161+ routes = new MqttServiceRoute [ 0 ] ;
162+ }
163+ }
164+ else
165+ {
166+ if ( _logger . IsEnabled ( LogLevel . Warning ) )
167+ _logger . LogWarning ( $ "无法获取路由信息,因为文件:{ file } 不存在。") ;
168+ routes = new MqttServiceRoute [ 0 ] ;
169+ }
170+ return routes ;
171+ }
172+
173+ private async Task EntryRoutes ( string file )
174+ {
175+ var oldRoutes = _routes ? . ToArray ( ) ;
176+ var newRoutes = ( await GetRoutes ( file ) ) . ToArray ( ) ;
177+ _routes = newRoutes ;
178+ if ( oldRoutes == null )
179+ {
180+ //触发服务路由创建事件。
181+ OnCreated ( newRoutes . Select ( route => new MqttServiceRouteEventArgs ( route ) ) . ToArray ( ) ) ;
182+ }
183+ else
184+ {
185+ //旧的服务Id集合。
186+ var oldServiceIds = oldRoutes . Select ( i => i . MqttDescriptor . Topic ) . ToArray ( ) ;
187+ //新的服务Id集合。
188+ var newServiceIds = newRoutes . Select ( i => i . MqttDescriptor . Topic ) . ToArray ( ) ;
189+
190+ //被删除的服务Id集合
191+ var removeServiceIds = oldServiceIds . Except ( newServiceIds ) . ToArray ( ) ;
192+ //新增的服务Id集合。
193+ var addServiceIds = newServiceIds . Except ( oldServiceIds ) . ToArray ( ) ;
194+ //可能被修改的服务Id集合。
195+ var mayModifyServiceIds = newServiceIds . Except ( removeServiceIds ) . ToArray ( ) ;
196+
197+ //触发服务路由创建事件。
198+ OnCreated (
199+ newRoutes . Where ( i => addServiceIds . Contains ( i . MqttDescriptor . Topic ) )
200+ . Select ( route => new MqttServiceRouteEventArgs ( route ) )
201+ . ToArray ( ) ) ;
202+
203+ //触发服务路由删除事件。
204+ OnRemoved (
205+ oldRoutes . Where ( i => removeServiceIds . Contains ( i . MqttDescriptor . Topic ) )
206+ . Select ( route => new MqttServiceRouteEventArgs ( route ) )
207+ . ToArray ( ) ) ;
208+
209+ //触发服务路由变更事件。
210+ var currentMayModifyRoutes =
211+ newRoutes . Where ( i => mayModifyServiceIds . Contains ( i . MqttDescriptor . Topic ) ) . ToArray ( ) ;
212+ var oldMayModifyRoutes =
213+ oldRoutes . Where ( i => mayModifyServiceIds . Contains ( i . MqttDescriptor . Topic ) ) . ToArray ( ) ;
214+
215+ foreach ( var oldMayModifyRoute in oldMayModifyRoutes )
216+ {
217+ if ( ! currentMayModifyRoutes . Contains ( oldMayModifyRoute ) )
218+ OnChanged (
219+ new MqttServiceRouteChangedEventArgs (
220+ currentMayModifyRoutes . First (
221+ i => i . MqttDescriptor . Topic == oldMayModifyRoute . MqttDescriptor . Topic ) ,
222+ oldMayModifyRoute ) ) ;
223+ }
224+ }
225+ }
226+
227+ private async void _fileSystemWatcher_Changed ( object sender , FileSystemEventArgs e )
228+ {
229+ if ( _logger . IsEnabled ( LogLevel . Information ) )
230+ _logger . LogInformation ( $ "文件{ _filePath } 发生了变更,将重新获取路由信息。") ;
231+
232+ if ( e . ChangeType == WatcherChangeTypes . Changed )
233+ {
234+ string content ;
235+ try
236+ {
237+ content = File . ReadAllText ( _filePath , Encoding . UTF8 ) ;
238+ }
239+ catch ( IOException ) //还没有操作完,忽略本次修改
240+ {
241+ return ;
242+ }
243+ if ( ! string . IsNullOrWhiteSpace ( content ) )
244+ {
245+ await EntryRoutes ( _filePath ) ;
246+ }
247+ else
248+ {
249+ return ;
250+ }
251+ }
252+
253+ await EntryRoutes ( _filePath ) ;
254+ }
255+
256+ public override async Task RemoveByTopicAsync ( string topic , IEnumerable < AddressModel > endpoint )
257+ {
258+ var routes = await GetRoutesAsync ( ) ;
259+ try
260+ {
261+ var route = routes . Where ( p => p . MqttDescriptor . Topic == topic ) . SingleOrDefault ( ) ;
262+ if ( route != null )
263+ {
264+ route . MqttEndpoint = route . MqttEndpoint . Except ( endpoint ) ;
265+ await base . SetRoutesAsync ( new MqttServiceRoute [ ] { route } ) ;
266+ }
267+ }
268+ catch ( Exception ex )
269+ {
270+ throw ex ;
271+ }
272+ }
273+
274+
275+
276+ #endregion Private Method
277+ }
278+ }
0 commit comments