/// <summary> /// Initialize the provider /// </summary> void IValidator.Init(XmlNode config) { // get the xml node that holds the key (might be empty) XmlNode keyNode = config.SelectSingleNode("key"); // look for key in xml _key = ExtractKeyFromNode(keyNode); // we've tried to find key in "key" nodes, we should have a good key now; check to be sure if (null == _key) { string error = ApplicationUpdateManager.TraceWrite("[KeyValidator.Init]", "RES_CouldNotFindCryptographicKey"); CryptographicException ce = new CryptographicException(error); ExceptionManager.Publish(ce); throw ce; } }
/// <summary> /// Reads the given file and creates a hash code that uses every byte of the file to contribute, then encrypts the resulting hash code using the key /// in the KeyedHashAlgorithm /// </summary> /// <param name="filePath">full path to the file to sign</param> /// <param name="key">the "secret" key used to "sign" the hash</param> /// <returns>a base64-encoded string which is the encrypted signature of the file</returns> string IValidator.Sign(string filePath, string key) { byte[] outSignature = null; FileStream fs = null; try { // using the key (member variable) use hashed-key algorithm to generate // a signature for the file // attempt to open the file with shared read access fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); // create an instance of keyed hash algo--note that the static Create is its own Factory method (sweet) KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(); // feed the hash algo the key kha.Key = Convert.FromBase64String(key); // now hash over entire file, munging with key to give uniqueness that depends on both key and file // for a strong signature. // NOTE: now, the "secret" is the key. Without the "secret", you CANNOT spoof the identity of the file. // the contract between server and client is that the files are what the server promised; the enforcement of that // contract is the cryptographically strong hash, which depends on both key and file identity. // As long as both parties accept the validity of the "secret", they can trust the identity of the file if its signature matches. outSignature = kha.ComputeHash(fs); } catch (Exception e) { ApplicationUpdateManager.TraceWrite(e, "[KeyValidator.Sign]", "RES_EXCEPTION_SigningFile", filePath); throw e; } finally { if (null != fs) { fs.Close(); } } // return the signature return(Convert.ToBase64String(outSignature)); }
public void UserCheckForUpdates() { ApplicationUpdateManager updateManager = services.updateManager; updateManager.CheckForUpdates(OnUserCheckForUpdatesComplete); LoadingTask waitForUpdateCheckTask = new LoadingTask("Checking for updates...", () => { while (updateManager.UpdateCheckInProgress) { ; } }); List <LoadingTask> tasks = new List <LoadingTask>() { waitForUpdateCheckTask }; LoadingTasksManager tasksManager = services.loadingTasksManager; tasksManager.KickTasks(tasks); }
/// <summary> /// Helper function to get the base64-encoded key from the "key" node /// </summary> /// <param name="keyNode">contains the base64 encoded key hash</param> /// <returns>byte array which is the key decoded from base64</returns> private byte[] ExtractKeyFromNode(XmlNode keyNode) { byte[] key = null; // skip out right away if passed a null node if (null == keyNode) { return(null); } try { // we're passed the key node, so just take the innerText and convert to a byte[] from base64 key = Convert.FromBase64String(keyNode.InnerText); } catch (Exception e) { ApplicationUpdateManager.TraceWrite(e, "[KeyValidator.ExtractKeyFromNode]", "RES_CouldNotFindCryptographicKey"); ExceptionManager.Publish(e); throw e; } return(key); }
public async Task TestMultipleUpdates() { IEnumerable <AppIdentity> appsToDeploy = new[] { app1v3, app1v4, app1v5 }; IEnumerable <string> clusters = new[] { "clusterId1" }; IApplicationDeploymentDirectory applicationDeploymentDirectory = new StubIApplicationDeploymentDirectory() .FetchDeployments(() => Task.FromResult(appsToDeploy.Select(identity => new AppDeploymentConfig(identity, clusters)))); string path = Path.GetTempPath(); await applicationPool.AddApplication(new ApplicationStub(app1v1, path)); await applicationPool.AddApplication(new ApplicationStub(app1v2, path)); await applicationPool.AddApplication(new ApplicationStub(app1v3, path)); IUpdateSessionManager updateSessionManagerStub = new StubIUpdateSessionManager() .TryStartUpdateSession(() => Task.FromResult(true)) .EndUpdateSession(() => Task.CompletedTask); const string ClusterId = "clusterId"; const string InstanceId = "instanceId"; ApplicationUpdateManager applicationUpdateManager = new ApplicationUpdateManager(ClusterId, InstanceId, applicationDeploymentDirectory, applicationPool, applicationDownloader, applicationInstaller, deploymentStatusWriterStub, updateSessionManagerStub); await applicationUpdateManager.CheckForUpdates(); Assert.Equal(3, applicationPool.Applications.Count()); Assert.True(applicationPool.HasApplication(app1v3)); Assert.True(applicationPool.HasApplication(app1v4)); Assert.True(applicationPool.HasApplication(app1v5)); Assert.Equal(3, instanceDeploymentStatus.Applications.Count()); VerifyThatDeploymentStatusHasBeenUpdated(instanceDeploymentStatus, app1v3, ClusterId, InstanceId); VerifyThatDeploymentStatusHasBeenUpdated(instanceDeploymentStatus, app1v4, ClusterId, InstanceId); VerifyThatDeploymentStatusHasBeenUpdated(instanceDeploymentStatus, app1v5, ClusterId, InstanceId); }
private void DoStartupJobs() { FilterChecker.CheckInstalledVersions(); Version aParamVersion; // // 6.5.2600.3243 = KB941568, 6.5.2600.3024 = KB927544 // if ( !FilterChecker.CheckFileVersion(Environment.SystemDirectory + "\\quartz.dll", "6.5.2600.3024", out aParamVersion)) { string ErrorMsg = string.Format("Your version {0} of quartz.dll has too many bugs! \nPlease check our Wiki's requirements page.", aParamVersion.ToString()); Log.Info("Util: quartz.dll error - {0}", ErrorMsg); if ( MessageBox.Show(ErrorMsg, "Core directshow component (quartz.dll) is outdated!", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) == DialogResult.OK) { Process.Start(@"http://wiki.team-mediaportal.com/GeneralRequirements"); } } EnableS3Trick(); GUIWindowManager.OnNewAction += new OnActionHandler(OnAction); GUIWindowManager.Receivers += new SendMessageHandler(OnMessage); GUIWindowManager.Callbacks += new GUIWindowManager.OnCallBackHandler(MPProcess); GUIGraphicsContext.CurrentState = GUIGraphicsContext.State.STARTING; Utils.OnStartExternal += new Utils.UtilEventHandler(OnStartExternal); Utils.OnStopExternal += new Utils.UtilEventHandler(OnStopExternal); // load keymapping from keymap.xml ActionTranslator.Load(); //register the playlistplayer for thread messages (like playback stopped,ended) Log.Info("Main: Init playlist player"); g_Player.Factory = new PlayerFactory(); playlistPlayer.Init(); // Only load the USBUIRT device if it has been enabled in the configuration using (Settings xmlreader = new MPSettings()) { bool inputEnabled = xmlreader.GetValueAsBool("USBUIRT", "internal", false); bool outputEnabled = xmlreader.GetValueAsBool("USBUIRT", "external", false); if (inputEnabled || outputEnabled) { Log.Info("Main: Creating the USBUIRT device"); usbuirtdevice = USBUIRT.Create(new USBUIRT.OnRemoteCommand(OnRemoteCommand)); Log.Info("Main: Creating the USBUIRT device done"); } //Load Winlirc if enabled. bool winlircInputEnabled = xmlreader.GetValueAsString("WINLIRC", "enabled", "false") == "true"; if (winlircInputEnabled) { Log.Info("Main: Creating the WINLIRC device"); winlircdevice = new WinLirc(); Log.Info("Main: Creating the WINLIRC device done"); } //Load RedEye if enabled. bool redeyeInputEnabled = xmlreader.GetValueAsString("RedEye", "internal", "false") == "true"; if (redeyeInputEnabled) { Log.Info("Main: Creating the REDEYE device"); redeyedevice = RedEye.Create(new RedEye.OnRemoteCommand(OnRemoteCommand)); Log.Info("Main: Creating the RedEye device done"); } inputEnabled = xmlreader.GetValueAsString("SerialUIR", "internal", "false") == "true"; if (inputEnabled) { Log.Info("Main: Creating the SerialUIR device"); serialuirdevice = SerialUIR.Create(new SerialUIR.OnRemoteCommand(OnRemoteCommand)); Log.Info("Main: Creating the SerialUIR device done"); } } //registers the player for video window size notifications Log.Info("Main: Init players"); g_Player.Init(); GUIGraphicsContext.ActiveForm = Handle; // hook ProcessExit for a chance to clean up when closed peremptorily #if AUTOUPDATE AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); // hook form close to stop updater too this.Closed += new EventHandler(MediaPortal_Closed); #endif XmlDocument doc = new XmlDocument(); try { doc.Load("mediaportal.exe.config"); XmlNode node = doc.SelectSingleNode("/configuration/appStart/ClientApplicationInfo/appFolderName"); if (node != null) { node.InnerText = Directory.GetCurrentDirectory(); } node = doc.SelectSingleNode("/configuration/appUpdater/UpdaterConfiguration/application/client/baseDir"); if (node != null) { node.InnerText = Directory.GetCurrentDirectory(); } node = doc.SelectSingleNode("/configuration/appUpdater/UpdaterConfiguration/application/client/tempDir"); if (node != null) { node.InnerText = Directory.GetCurrentDirectory(); } doc.Save("MediaPortal.exe.config"); } catch (Exception) {} Thumbs.CreateFolders(); try { #if DEBUG #else #if AUTOUPDATE UpdaterConfiguration config = UpdaterConfiguration.Instance; config.Logging.LogPath = Config.Get(Config.Dir.Log) + "updatelog.log"; config.Applications[0].Client.BaseDir = Config.Get(Config.Dir.Base) config.Applications[0].Client.TempDir = Config.Get(Config.Dir.Base) + "temp"; config.Applications[0].Client.XmlFile = Config.Get(Config.Dir.Base) + "MediaPortal.exe.config"; config.Applications[0].Server.ServerManifestFileDestination = Config.Get(Config.Dir.Base) + @"xml\ServerManifest.xml"; try { System.IO.Directory.CreateDirectory(config.Applications[0].Client.BaseDir + @"temp"); System.IO.Directory.CreateDirectory(config.Applications[0].Client.BaseDir + @"xml"); System.IO.Directory.CreateDirectory(config.Applications[0].Client.BaseDir + @"log"); } catch(Exception){} Utils.DeleteFiles(config.Applications[0].Client.BaseDir + "log", "*.log"); ClientApplicationInfo clientInfo = ClientApplicationInfo.Deserialize("MediaPortal.exe.config"); clientInfo.AppFolderName = System.IO.Directory.GetCurrentDirectory(); ClientApplicationInfo.Save("MediaPortal.exe.config",clientInfo.AppFolderName, clientInfo.InstalledVersion); m_strCurrentVersion = clientInfo.InstalledVersion; Text += (" - [v" + m_strCurrentVersion + "]"); // make an Updater for use in-process with us _updater = new ApplicationUpdateManager(); // hook Updater events _updater.DownloadStarted += new UpdaterActionEventHandler(OnUpdaterDownloadStarted); _updater.UpdateAvailable += new UpdaterActionEventHandler(OnUpdaterUpdateAvailable); _updater.DownloadCompleted += new UpdaterActionEventHandler(OnUpdaterDownloadCompleted); // start the updater on a separate thread so that our UI remains responsive _updaterThread = new Thread(new ThreadStart(_updater.StartUpdater)); _updaterThread.Start(); #endif #endif } catch (Exception) {} using (Settings xmlreader = new MPSettings()) { m_iDateLayout = xmlreader.GetValueAsInt("home", "datelayout", 0); } GUIGraphicsContext.ResetLastActivity(); }
public async Task TestMultipleUpdates() { string id1 = "appId1"; var v1 = SemVersion.Parse("1.0.0"); var v2 = SemVersion.Parse("2.0.0"); var v3 = SemVersion.Parse("3.0.0"); var v4 = SemVersion.Parse("4.0.0"); var v5 = SemVersion.Parse("5.0.0"); AppIdentity app1v1 = new AppIdentity(id1, v1); AppIdentity app1v2 = new AppIdentity(id1, v2); AppIdentity app1v3 = new AppIdentity(id1, v3); AppIdentity app1v4 = new AppIdentity(id1, v4); AppIdentity app1v5 = new AppIdentity(id1, v5); IEnumerable <AppIdentity> appsToDeploy = new[] { app1v3, app1v4, app1v5 }; IEnumerable <string> clusters = new[] { "clusterId1" }; IApplicationDeploymentDirectory applicationDeploymentDirectory = new StubIApplicationDeploymentDirectory() .FetchDeployments(() => Task.FromResult(appsToDeploy.Select(identity => new AppDeploymentConfig(identity, clusters)))); IApplicationPool applicationPool = new ApplicationPoolStub(); string path = Path.GetTempPath(); await applicationPool.AddApplication(new ApplicationStub(app1v1, path)); await applicationPool.AddApplication(new ApplicationStub(app1v2, path)); await applicationPool.AddApplication(new ApplicationStub(app1v3, path)); var downloadedApps = new List <AppIdentity>(); IApplicationDownloader applicationDownloader = new StubIApplicationDownloader() .DownloadApplication(appIdentity => { downloadedApps.Add(appIdentity); return(Task.FromResult(true)); } ); var installedApps = new List <AppIdentity>(); var uninstalledApps = new List <AppIdentity>(); string updatedAppId = null; IEnumerable <SemVersion> versionsRemoved = null; IEnumerable <SemVersion> versionsAdded = null; IApplicationInstaller applicationInstaller = new StubIApplicationInstaller() .Install(config => { installedApps.Add(config.AppIdentity); return(Task.FromResult(true)); }) .UnInstall(appIdentity => { uninstalledApps.Add(appIdentity); return(Task.FromResult(true)); }) .Update((applicationsToRemove, applicationsToInstall) => { updatedAppId = applicationsToInstall.First().AppIdentity.Id; versionsRemoved = applicationsToRemove.Select(identity => identity.Version); versionsAdded = applicationsToInstall.Select(config => config.AppIdentity.Version); return(Task.FromResult(true)); } ); ApplicationUpdateManager applicationUpdateManager = new ApplicationUpdateManager("clusterId", applicationDeploymentDirectory, applicationPool, applicationDownloader, applicationInstaller); await applicationUpdateManager.CheckForUpdates(); Assert.Equal(2, downloadedApps.Count); Assert.True(downloadedApps.Contains(app1v4)); Assert.True(downloadedApps.Contains(app1v5)); Assert.False(installedApps.Any()); Assert.False(uninstalledApps.Any()); Assert.Equal(id1, updatedAppId); Assert.Equal(new [] { v1, v2 }, versionsRemoved.ToList()); Assert.Equal(new[] { v4, v5 }, versionsAdded.ToList()); }
public async Task TestMultipleUpdates() { string id1 = "appId1"; var v1 = SemVersion.Parse("1.0.0"); var v2 = SemVersion.Parse("2.0.0"); var v3 = SemVersion.Parse("3.0.0"); var v4 = SemVersion.Parse("4.0.0"); var v5 = SemVersion.Parse("5.0.0"); AppIdentity app1v1 = new AppIdentity(id1, v1); AppIdentity app1v2 = new AppIdentity(id1, v2); AppIdentity app1v3 = new AppIdentity(id1, v3); AppIdentity app1v4 = new AppIdentity(id1, v4); AppIdentity app1v5 = new AppIdentity(id1, v5); IEnumerable <AppIdentity> appsToDeploy = new[] { app1v3, app1v4, app1v5 }; IEnumerable <string> clusters = new[] { "clusterId1" }; IApplicationDeploymentDirectory applicationDeploymentDirectory = new StubIApplicationDeploymentDirectory() .FetchDeployments(() => Task.FromResult(appsToDeploy.Select(identity => new AppDeploymentConfig(identity, clusters)))); IApplicationPool applicationPool = new ApplicationPoolStub(); string path = Path.GetTempPath(); await applicationPool.AddApplication(new ApplicationStub(app1v1, path)); await applicationPool.AddApplication(new ApplicationStub(app1v2, path)); await applicationPool.AddApplication(new ApplicationStub(app1v3, path)); var downloadedApps = new List <AppIdentity>(); IApplicationDownloader applicationDownloader = new StubIApplicationDownloader() .DownloadApplication(appIdentity => { downloadedApps.Add(appIdentity); return(Task.FromResult(true)); } ); IApplicationInstaller applicationInstaller = new StubIApplicationInstaller() .Install(config => { applicationPool.AddApplication(new ApplicationStub(config.AppIdentity, "path")); return(Task.FromResult(true)); }) .UnInstall(appIdentity => { applicationPool.RemoveApplication(appIdentity); return(Task.FromResult(true)); }) .Update((applicationsToRemove, applicationsToInstall) => { foreach (var appIdentity in applicationsToRemove) { applicationPool.RemoveApplication(appIdentity); } foreach (var appInstallConfig in applicationsToInstall) { applicationPool.AddApplication(new ApplicationStub(appInstallConfig.AppIdentity, "path")); } return(Task.FromResult(true)); } ); var instanceDeploymentStatus = new InstanceDeploymentStatus(); IDeploymentStatusWriter deploymentStatusWriterStub = new StubIDeploymentStatusWriter() .PublishInstanceDeploymentStatus((clusterId, instanceId, status) => { instanceDeploymentStatus = status; return(Task.CompletedTask); }); const string ClusterId = "clusterId"; const string InstanceId = "instanceId"; ApplicationUpdateManager applicationUpdateManager = new ApplicationUpdateManager(ClusterId, InstanceId, applicationDeploymentDirectory, applicationPool, applicationDownloader, applicationInstaller, deploymentStatusWriterStub); await applicationUpdateManager.CheckForUpdates(); Assert.Equal(3, applicationPool.Applications.Count()); Assert.True(applicationPool.HasApplication(app1v3)); Assert.True(applicationPool.HasApplication(app1v4)); Assert.True(applicationPool.HasApplication(app1v5)); Assert.Equal(3, instanceDeploymentStatus.Applications.Count()); VerifyThatDeploymentStatusHasBeenUpdated(instanceDeploymentStatus, app1v3, ClusterId, InstanceId); VerifyThatDeploymentStatusHasBeenUpdated(instanceDeploymentStatus, app1v4, ClusterId, InstanceId); VerifyThatDeploymentStatusHasBeenUpdated(instanceDeploymentStatus, app1v5, ClusterId, InstanceId); }
/// <summary> /// Synchronous downloading method using BITS /// </summary> /// <param name="sourceFile">Source file to download</param> /// <param name="destFile">Target file on the local system</param> /// <param name="maxTimeWait">Maximum time to wait for a download</param> void IDownloader.Download(string sourceFile, string destFile, TimeSpan maxTimeWait) { IBackgroundCopyManager backGroundCopyManager = null; IBackgroundCopyJob backGroundCopyJob = null; Guid jobID = Guid.Empty; bool isCompleted = false; bool isSuccessful = false; string cumulativeErrMessage = ""; BG_JOB_STATE state; // to defend against config errors, check to see if the path given is UNC; // if so, throw immediately there's a misconfiguration. Paths to BITS must be HTTP/HTTPS ThrowIfSourceIsUNC(sourceFile); try { // use utility function to create manager, job, get back jobid etc.; uses 'out' semantics CreateCopyJob( out backGroundCopyManager, out backGroundCopyJob, ref jobID, "RES_BITSJobName", "RES_BITSDescription"); // Add the file to the Job List backGroundCopyJob.AddFile(sourceFile, destFile); // Start the Back Ground Copy Job. backGroundCopyJob.Resume(); // set endtime to current tickcount + allowable # milliseconds to wait for job int endTime = Environment.TickCount + (int)maxTimeWait.TotalMilliseconds; #region __While Loop Waits On Single Download__ while (!isCompleted) { backGroundCopyJob.GetState(out state); switch (state) { case BG_JOB_STATE.BG_JOB_STATE_ERROR: { // use utility to: // a) get error info // b) report it // c) cancel and remove copy job HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage); // complete loop, but DON'T say it's successful isCompleted = true; break; } case BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR: { // NOTE: during debugging + test, transient errors resulted in complete job failure about 90% // of the time. Therefore we treat transients just like full errors, and CANCEL the job // use utility to manage error etc. HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage); // stop the loop, set completed to true but not successful isCompleted = true; break; } case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED: { // notify BITS we're happy, remove from queue and transfer ownership to us: backGroundCopyJob.Complete(); // remove job from our collection, we won't need to Cancel() in our Dispose() RemoveCopyJobEntry(jobID); isCompleted = true; isSuccessful = true; break; } default: break; } if (endTime < Environment.TickCount) { HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage); break; } // Avoid 100% CPU utilisation with too tight a loop, let download happen. Thread.Sleep(TIME_WAIT_SYNCH_DOWNLOAD); } #endregion if (!isSuccessful) { // create message + error, package it, publish string error = ApplicationUpdateManager.TraceWrite( "[BITSDownloader.Download]", "RES_MESSAGE_ManifestFileNotDownloaded", sourceFile, cumulativeErrMessage); Exception ex = new Exception(error + Environment.NewLine + cumulativeErrMessage); throw ex; } } catch (ThreadInterruptedException tie) { // if interrupted, clean up job HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage); ApplicationUpdateManager.TraceWrite(tie, "[BITSDownloader.Download]", "RES_TIEInBITS", sourceFile); throw tie; } catch (Exception e) { // if exception, clean up job HandleDownloadErrorCancelJob(backGroundCopyJob, ref cumulativeErrMessage); // then log error string error = ApplicationUpdateManager.TraceWrite( e, "[BITSDownloader.Download]", "RES_MESSAGE_ManifestFileNotDownloaded", sourceFile, cumulativeErrMessage); Exception ex = new Exception(error, e); ExceptionManager.Publish(ex); // throw; allow consuming class to figure out what to do throw ex; } finally { if (null != backGroundCopyJob) { Marshal.ReleaseComObject(backGroundCopyJob); } if (null != backGroundCopyManager) { Marshal.ReleaseComObject(backGroundCopyManager); } } }
/// <summary> /// Internal copy-job factory method. Used to coordinate all aspects of a job set-up, /// which includes creating a copy manager, creating a job within it, setting download /// parameters, and adding the job to our tracking collection for cleanup later /// </summary> /// <param name="copyManager">null reference to copy manager</param> /// <param name="copyJob">null reference to copy job</param> /// <param name="jobID">null reference to job id guid</param> /// <param name="jobNameKey">the key used to look up the job name in the resource file</param> /// <param name="jobDescriptionKey">the key used to look up the job description in the resource file</param> private void CreateCopyJob( out IBackgroundCopyManager copyManager, out IBackgroundCopyJob copyJob, ref Guid jobID, string jobNameKey, string jobDescriptionKey) { string jobName = Resource.ResourceManager[jobNameKey]; string jobDesc = Resource.ResourceManager[jobDescriptionKey]; // wrap in try-finally so we can clean COM objects if unexpected error try { // create the manager copyManager = (IBackgroundCopyManager) new BackgroundCopyManager(); // create the job, set its description, use "out" semantics to get jobid and the actual job object copyManager.CreateJob( jobName, BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, out jobID, out copyJob); // set useful description copyJob.SetDescription(jobDesc); // *** // SET UP BITS JOB SETTINGS--TIMEOUTS/RETRY ETC // SEE THE FOLLOWING REFERENCES: // ** http://msdn.microsoft.com/library/default.asp?url=/library/en-us/bits/bits/ibackgroundcopyjob_setminimumretrydelay.asp?frame=true // ** http://msdn.microsoft.com/library/default.asp?url=/library/en-us/bits/bits/ibackgroundcopyjob_setnoprogresstimeout.asp?frame=true // ** http://msdn.microsoft.com/library/default.asp?url=/library/en-us/bits/bits/bg_job_priority.asp // *** // in constant set to 0; this makes BITS retry as soon as possible after an error copyJob.SetMinimumRetryDelay((uint)BITS_SET_MINIMUM_RETRY_DELAY); // in constant set to 5 seconds; BITS will set job to Error status if exceeded copyJob.SetNoProgressTimeout((uint)BITS_SET_NO_PROGRESS_TIMEOUT); // make this job the highest (but still background) priority-- copyJob.SetPriority(BG_JOB_PRIORITY.BG_JOB_PRIORITY_HIGH); // *** // lock our internal collection of jobs, and add this job--we use this collection in Dispose() // to tell BITS to Cancel() jobs--and remove them from the queue // if we did not do this, BITS would continue for (by default) two weeks to download what we asked! lock (_jobs.SyncRoot) { _jobs.Add(jobID, jobName); } } catch (Exception e) { // bad to catch all exceptions, but OK because we adorn it with necessary additional info then pass it up as innerException string error = ApplicationUpdateManager.TraceWrite(e, "[BITSDownloader.CreateCopyJob]", "RES_EXCEPTION_BITSOtherError", jobID, jobName, jobDesc); // publish Exception newE = new Exception(error, e); ExceptionManager.Publish(newE); // rethrow; throw newE; } }
/// <summary> /// returns a job status enum for a particular job identified by its GUID /// </summary> /// <param name="jobId">a guid for the job requested</param> /// <returns>a JobStatus describing the state of the job</returns> JobStatus IDownloader.GetJobStatus(Guid jobId) { IBackgroundCopyManager backGroundCopyManager = null; IBackgroundCopyJob backGroundCopyJob = null; BG_JOB_STATE state; string errMessage = ""; string jobName = ""; string jobDesc = ""; string error = ""; try { backGroundCopyManager = (IBackgroundCopyManager) new BackgroundCopyManager(); backGroundCopyManager.GetJob(ref jobId, out backGroundCopyJob); // get job name backGroundCopyJob.GetDisplayName(out jobName); // get job desc backGroundCopyJob.GetDescription(out jobDesc); // get job state enum value backGroundCopyJob.GetState(out state); switch (state) { case BG_JOB_STATE.BG_JOB_STATE_ERROR: { // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // return status as error return(JobStatus.Error); } case BG_JOB_STATE.BG_JOB_STATE_TRANSIENT_ERROR: { // NOTE: if transient, just treat as full error. During testing about 90% of transients // resulted in full failure. Cleanup. // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // return status as error return(JobStatus.Error); } case BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED: { // tell BITS to transfer to us and stop thinking about the job backGroundCopyJob.Complete(); // remove job from collection to be Dispose()ed RemoveCopyJobEntry(jobId); return(JobStatus.Ready); } case BG_JOB_STATE.BG_JOB_STATE_CANCELLED: { // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // return status as cancelled return(JobStatus.Cancelled); } default: return(JobStatus.Downloading); } } catch (ThreadInterruptedException tie) { // if interrupted, clean up job HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); ApplicationUpdateManager.TraceWrite(tie, "[BITSDownloader.Download]", "RES_TIEInBITS", "N/A"); throw tie; } catch (Exception e) { // use utility method to handle error: HandleDownloadErrorCancelJob(backGroundCopyJob, ref errMessage); // bad to catch all exceptions, but OK because we adorn it with necessary additional info then pass it up as innerException error = ApplicationUpdateManager.TraceWrite(e, "[BITSDownloader.GetJobStatus]", "RES_EXCEPTION_BITSOtherError", jobId, jobName, jobDesc); // publish Exception newE = new Exception(error, e); ExceptionManager.Publish(newE); // rethrow; throw newE; } finally { if (backGroundCopyManager != null) { Marshal.ReleaseComObject(backGroundCopyManager); } if (backGroundCopyJob != null) { Marshal.ReleaseComObject(backGroundCopyJob); } } }
public async Task TestMultipleUpdates() { string id1 = "appId1"; var v1 = new Version("1.0.0"); var v2 = new Version("2.0.0"); var v3 = new Version("3.0.0"); var v4 = new Version("4.0.0"); var v5 = new Version("5.0.0"); AppIdentity app1v1 = new AppIdentity(id1, v1); AppIdentity app1v2 = new AppIdentity(id1, v2); AppIdentity app1v3 = new AppIdentity(id1, v3); AppIdentity app1v4 = new AppIdentity(id1, v4); AppIdentity app1v5 = new AppIdentity(id1, v5); IEnumerable <AppIdentity> appsToDeploy = new[] { app1v3, app1v4, app1v5 }; IApplicationDeploymentDirectory applicationDeploymentDirectory = new StubIApplicationDeploymentDirectory { FetchDeployments_String = (deploymentId) => Task.FromResult(appsToDeploy) }; IApplicationPool applicationPool = new ApplicationPoolStub(); string path = Path.GetTempPath(); await applicationPool.AddApplication(new ApplicationStub(app1v1, path)); await applicationPool.AddApplication(new ApplicationStub(app1v2, path)); await applicationPool.AddApplication(new ApplicationStub(app1v3, path)); var downloadedApps = new List <AppIdentity>(); IApplicationDownloader applicationDownloader = new StubIApplicationDownloader { DownloadApplication_AppIdentity = (appIdentity) => { downloadedApps.Add(appIdentity); return(Task.FromResult(true)); } }; var installedApps = new List <AppIdentity>(); var uninstalledApps = new List <AppIdentity>(); string updatedAppId = null; IEnumerable <Version> versionsRemoved = null; IEnumerable <Version> versionsAdded = null; IApplicationInstaller applicationInstaller = new StubIApplicationInstaller { Install_AppIdentity = (appIdentity) => { installedApps.Add(appIdentity); return(Task.FromResult(true)); }, UnInstall_AppIdentity = (appIdentity) => { uninstalledApps.Add(appIdentity); return(Task.FromResult(true)); }, Update_String_IEnumerableOfVersion_IEnumerableOfVersion = (appId, versionsToRemove, versionToDeploy) => { updatedAppId = appId; versionsRemoved = versionsToRemove; versionsAdded = versionToDeploy; return(Task.FromResult(true)); } }; ApplicationUpdateManager applicationUpdateManager = new ApplicationUpdateManager("deploymentId", applicationDeploymentDirectory, applicationPool, applicationDownloader, applicationInstaller); await applicationUpdateManager.CheckForUpdates(); Assert.Equal(2, downloadedApps.Count); Assert.True(downloadedApps.Contains(app1v4)); Assert.True(downloadedApps.Contains(app1v5)); Assert.False(installedApps.Any()); Assert.False(uninstalledApps.Any()); Assert.Equal(id1, updatedAppId); Assert.Equal(new [] { v1, v2 }, versionsRemoved.ToList()); Assert.Equal(new[] { v4, v5 }, versionsAdded.ToList()); }