@@ -90,25 +90,73 @@ private async Task RunWebSocketsAsync(CancellationToken cancellationToken)
9090 PropertyNameCaseInsensitive = true
9191 } ) ;
9292
93- string remoteStoragePath = Mapping . GetAbsoluteUri ( webSocketMessage . ItemPath ) ;
94-
95- // Just in case there is more than one WebSockets server/virtual folder that
96- // is sending notifications (like with webdavserver.net, webdavserver.com),
97- // here we filter notifications that come from a different server/virtual folder.
98- if ( remoteStoragePath . StartsWith ( Program . Settings . WebDAVServerUrl , StringComparison . InvariantCultureIgnoreCase ) )
93+ // Because of the on-demand loading, item or its parent may not exists or be offline.
94+ // We can ignore notifiction in this case and avoid many requests to the remote storage.
95+ if ( ShouldUpdate ( webSocketMessage ) )
9996 {
100- Logger . LogDebug ( $ "EventType: { webSocketMessage . EventType } ", webSocketMessage . ItemPath , webSocketMessage . TargetPath ) ;
10197 await ProcessAsync ( ) ;
10298 }
10399 }
104100 }
105101
102+ /// <summary>
103+ /// Verifies that the item exists in the user file system and should be updated.
104+ /// </summary>
105+ /// <param name="webSocketMessage">Information about change in the remote storage.</param>
106+ /// <returns>True if the item exists and should be updated. False otherwise.</returns>
107+ private bool ShouldUpdate ( WebSocketMessage webSocketMessage )
108+ {
109+ string remoteStoragePath = Mapping . GetAbsoluteUri ( webSocketMessage . ItemPath ) ;
110+
111+ // Just in case there is more than one WebSockets server/virtual folder that
112+ // is sending notifications (like with webdavserver.net, webdavserver.com),
113+ // here we filter notifications that come from a different server/virtual folder.
114+ if ( remoteStoragePath . StartsWith ( Program . Settings . WebDAVServerUrl , StringComparison . InvariantCultureIgnoreCase ) )
115+ {
116+ Logger . LogDebug ( $ "EventType: { webSocketMessage . EventType } ", webSocketMessage . ItemPath , webSocketMessage . TargetPath ) ;
117+
118+ string userFileSystemPath = Mapping . ReverseMapPath ( remoteStoragePath ) ;
119+ switch ( webSocketMessage . EventType )
120+ {
121+ case "created" :
122+ case "deleted" :
123+ // Verify that parent folder exists and is not offline.
124+ string userFileSystemParentPath = Path . GetDirectoryName ( userFileSystemPath ) ;
125+ return Directory . Exists ( userFileSystemParentPath )
126+ && ! new DirectoryInfo ( userFileSystemParentPath ) . Attributes . HasFlag ( FileAttributes . Offline ) ;
127+
128+ case "moved" :
129+ // Verify that source exists OR target folder exists and is not offline.
130+ if ( File . Exists ( userFileSystemPath ) )
131+ {
132+ return true ;
133+ }
134+ else
135+ {
136+ string remoteStorageNewPath = Mapping . GetAbsoluteUri ( webSocketMessage . TargetPath ) ;
137+ string userFileSystemNewPath = Mapping . ReverseMapPath ( remoteStorageNewPath ) ;
138+ string userFileSystemNewParentPath = Path . GetDirectoryName ( userFileSystemNewPath ) ;
139+ return Directory . Exists ( userFileSystemNewParentPath )
140+ && ! new DirectoryInfo ( userFileSystemNewParentPath ) . Attributes . HasFlag ( FileAttributes . Offline ) ;
141+ }
142+
143+ case "updated" :
144+ default :
145+ // Any other notifications.
146+ return File . Exists ( userFileSystemPath ) ;
147+ }
148+ }
149+
150+ return false ;
151+ }
152+
106153 /// <summary>
107154 /// Starts monitoring changes in the remote storage.
108155 /// </summary>
109156 /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
110157 public async Task StartAsync ( CancellationToken cancellationToken = default )
111158 {
159+ Logger . LogDebug ( "Starting" , webSocketServerUrl ) ;
112160 await Task . Factory . StartNew (
113161 async ( ) =>
114162 {
@@ -123,21 +171,19 @@ await Task.Factory.StartNew(
123171 {
124172 repeat = false ;
125173
126- Logger . LogDebug ( "Starting" , webSocketServerUrl ) ;
127-
128174 // Configure web sockets and connect to the server.
129175 clientWebSocket . Options . KeepAliveInterval = TimeSpan . FromSeconds ( 10 ) ;
130176 clientWebSocket . Options . Credentials = Engine . Credentials ;
131177 clientWebSocket . Options . Cookies = new CookieContainer ( ) ;
132178 clientWebSocket . Options . Cookies . Add ( Engine . Cookies ) ;
133179 clientWebSocket . Options . SetRequestHeader ( "InstanceId" , Engine . InstanceId . ToString ( ) ) ;
134180 await clientWebSocket . ConnectAsync ( new Uri ( webSocketServerUrl ) , cancellationToken ) ;
135- Logger . LogDebug ( "Connected" , webSocketServerUrl ) ;
181+ Logger . LogMessage ( "Connected" , webSocketServerUrl ) ;
136182
137183 // After esteblishing connection with a server we must get all changes from the remote storage.
138184 // This is required on Engine start, server recovery, network recovery, etc.
139185 Logger . LogDebug ( "Getting all changes from server" , webSocketServerUrl ) ;
140- await ProcessAsync ( ) ;
186+ await ProcessAsync ( Logger ) ;
141187
142188 Logger . LogMessage ( "Started" , webSocketServerUrl ) ;
143189
@@ -193,20 +239,27 @@ public async Task StopAsync()
193239 /// web sockets should not stop processing changes.
194240 /// To stop processing changes that are already received the Engine must be stopped.
195241 /// </remarks>
196- private async Task ProcessAsync ( )
242+ private async Task ProcessAsync ( ILogger logger = null )
197243 {
198244 try
199245 {
200- await Engine . ServerNotifications ( Engine . Path , Logger )
201- . ProcessChangesAsync ( async ( metadata , userFileSystemPath ) =>
202- await Engine . Placeholders . GetItem ( userFileSystemPath ) . SavePropertiesAsync ( metadata as FileSystemItemMetadataExt , Logger ) ) ;
246+ await Engine . ServerNotifications ( Engine . Path , logger ) . ProcessChangesAsync ( SavePropertiesAsync ) ;
203247 }
204248 catch ( Exception ex )
205249 {
206250 Logger . LogError ( "Failed to process changes" , Engine . Path , null , ex ) ;
207251 }
208252 }
209253
254+ private async Task SavePropertiesAsync ( IFileSystemItemMetadata metadata , string userFileSystemPath )
255+ {
256+ if ( Engine . Placeholders . TryGetItem ( userFileSystemPath , out PlaceholderItem placeholderItem ) )
257+ {
258+ await placeholderItem . SavePropertiesAsync ( metadata as FileSystemItemMetadataExt ) ;
259+ }
260+ }
261+
262+
210263 private bool disposedValue = false ; // To detect redundant calls
211264
212265 protected virtual void Dispose ( bool disposing )
0 commit comments