using System; using System.Collections.Generic; using System.Linq; using System.Text; using ScrewTurn.Wiki.PluginFramework; using System.Net; using System.IO; namespace ScrewTurn.Wiki { /// /// Handles the updating of providers. /// public class ProviderUpdater { private List visitedUrls; private ISettingsStorageProviderV30 settingsProvider; private List providers; private Dictionary fileNamesForProviders; /// /// Initializes a new instance of the class. /// /// The settings storage provider. /// A provider->file dictionary. /// The providers to update. public ProviderUpdater(ISettingsStorageProviderV30 settingsProvider, Dictionary fileNamesForProviders, params IProviderV30[][] providers) { if(settingsProvider == null) throw new ArgumentNullException("settingsProvider"); if(fileNamesForProviders == null) throw new ArgumentNullException("fileNamesForProviders"); if(providers == null) throw new ArgumentNullException("providers"); if(providers.Length == 0) throw new ArgumentException("Providers cannot be empty", "providers"); this.settingsProvider = settingsProvider; this.fileNamesForProviders = fileNamesForProviders; this.providers = new List(20); foreach(IProviderV30[] group in providers) { this.providers.AddRange(group); } visitedUrls = new List(10); } /// /// Updates all the providers. /// /// The number of updated DLLs. public int UpdateAll() { Log.LogEntry("Starting automatic providers update", EntryType.General, Log.SystemUsername); int updatedDlls = 0; foreach(IProviderV30 prov in providers) { if(string.IsNullOrEmpty(prov.Information.UpdateUrl)) continue; string newVersion; string newDllUrl; UpdateStatus status = Tools.GetUpdateStatus(prov.Information.UpdateUrl, prov.Information.Version, out newVersion, out newDllUrl); if(status == UpdateStatus.NewVersionFound && !string.IsNullOrEmpty(newDllUrl)) { // Update is possible // Case insensitive check if(!visitedUrls.Contains(newDllUrl.ToLowerInvariant())) { string dllName = null; if(!fileNamesForProviders.TryGetValue(prov.GetType().FullName, out dllName)) { Log.LogEntry("Could not determine DLL name for provider " + prov.GetType().FullName, EntryType.Error, Log.SystemUsername); continue; } // Download DLL and install if(DownloadAndUpdateDll(prov, newDllUrl, dllName)) { visitedUrls.Add(newDllUrl.ToLowerInvariant()); updatedDlls++; } } else { // Skip DLL (already updated) Log.LogEntry("Skipping provider " + prov.GetType().FullName + ": DLL already updated", EntryType.General, Log.SystemUsername); } } } Log.LogEntry("Automatic providers update completed: updated " + updatedDlls.ToString() + " DLLs", EntryType.General, Log.SystemUsername); return updatedDlls; } /// /// Downloads and updates a DLL. /// /// The provider. /// The URL of the new DLL. /// The file name of the DLL. private bool DownloadAndUpdateDll(IProviderV30 provider, string url, string filename) { try { HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); if(response.StatusCode != HttpStatusCode.OK) { Log.LogEntry("Update failed for provider " + provider.GetType().FullName + ": Status Code=" + response.StatusCode.ToString(), EntryType.Error, Log.SystemUsername); response.Close(); return false; } BinaryReader reader = new BinaryReader(response.GetResponseStream()); byte[] content = reader.ReadBytes((int)response.ContentLength); reader.Close(); bool done = settingsProvider.StorePluginAssembly(filename, content); if(done) Log.LogEntry("Provider " + provider.GetType().FullName + " updated", EntryType.General, Log.SystemUsername); else Log.LogEntry("Update failed for provider " + provider.GetType().FullName + ": could not store assembly", EntryType.Error, Log.SystemUsername); return done; } catch(Exception ex) { Log.LogEntry("Update failed for provider " + provider.GetType().FullName + ": " + ex.ToString(), EntryType.Error, Log.SystemUsername); return false; } } } }