コード例 #1
0
 /// <summary>
 /// Used to delete a directory and all its contents.
 /// </summary>
 /// <param name="path">full path to directory</param>
 public static void DeleteDirectory(string path)
 {
     if (Directory.Exists(path))
     {
         try
         {
             Directory.Delete(path, true);
         }
         catch (UnauthorizedAccessException uae)
         {
             string error = ApplicationUpdateManager.TraceWrite(uae, "[FileUtility.DeleteDirectory]", "RES_EXCEPTION_UnauthorizedAccessDirectory", path, uae.Message);
             ExceptionManager.Publish(uae);
             //  throw, this is serious enough to halt:
             throw uae;
         }
     }
 }
コード例 #2
0
        private static void Init()
        {
            #region Get the configuration instance
            try
            {
                if (null == _configuration)
                {
                    _configuration = (UpdaterConfiguration)ConfigurationSettings.GetConfig("appUpdater");
                }
            }
            catch (ApplicationUpdaterException aex)
            {
                string error = ApplicationUpdateManager.TraceWrite(aex, "[UpdaterConfiguration.cctor]", "RES_UnableToLoadConfiguration", AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

                ApplicationUpdaterException theException = new ApplicationUpdaterException(error, aex);

                ExceptionManager.Publish(theException);
                throw theException;
            }
            catch (ConfigurationException configEx)
            {
                string error = ApplicationUpdateManager.TraceWrite(configEx, "[UpdaterConfiguration.cctor]", "RES_UnableToLoadConfiguration", AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

                ConfigurationException plusConfEx = new ConfigurationException(error, configEx);

                ExceptionManager.Publish(plusConfEx);
                throw plusConfEx;
            }
            catch (Exception exception)
            {
                //  for general exception, just publish and throw no more is reasonable to add
                ExceptionManager.Publish(exception);
                throw exception;
            }
            if (_configuration == null)
            {
                string error = ApplicationUpdateManager.TraceWrite("[UpdaterConfiguration.cctor]", "RES_UnableToLoadConfiguration", AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

                ApplicationUpdaterException theException = new ApplicationUpdaterException(error);
                ExceptionManager.Publish(theException);
                throw theException;
            }
            #endregion
        }
コード例 #3
0
        /// <summary>
        /// Returns an object instantiated by the Activator, using fully-qualified asm/type supplied.
        /// Permits construction arguments to be supplied which it passes to the object's constructor on instantiation.
        /// </summary>
        /// <param name="assemblyName">fully-qualified assembly name</param>
        /// <param name="typeName">the type name</param>
        /// <param name="constructorArguments">constructor arguments for type to be created</param>
        /// <returns>instance of requested assembly/type typed as System.Object</returns>
        public static object Create(string assemblyName, string typeName, object[] constructorArguments)
        {
            Assembly assemblyInstance = null;
            Type     typeInstance     = null;

            try
            {
                //  use full asm name to get assembly instance
                assemblyInstance = Assembly.Load(assemblyName.Trim());
            }
            catch (Exception e)
            {
                string error = ApplicationUpdateManager.TraceWrite("[GenericFactory.Create]", "RES_EXCEPTION_CantLoadAssembly", assemblyName, typeName);

                TypeLoadException tle = new TypeLoadException(error, e);
                ExceptionManager.Publish(tle);
                throw tle;
            }

            try
            {
                //  use type name to get type from asm; note we WANT case specificity
                typeInstance = assemblyInstance.GetType(typeName.Trim(), true, false);

                //  now attempt to actually create an instance, passing constructor args if available
                if (constructorArguments != null)
                {
                    return(Activator.CreateInstance(typeInstance, constructorArguments));
                }
                else
                {
                    return(Activator.CreateInstance(typeInstance));
                }
            }
            catch (Exception e)
            {
                string error = ApplicationUpdateManager.TraceWrite("[GenericFactory.Create]", "RES_EXCEPTION_CantCreateInstanceUsingActivate", assemblyName, typeName);

                TypeLoadException tle = new TypeLoadException(error, e);
                ExceptionManager.Publish(tle);
                throw tle;
            }
        }
コード例 #4
0
        /// <summary>
        /// This method compares the recently downloaded file with the client version.
        /// If the server version is greater compared with the client version, the
        /// return value is <c>true</c>.
        /// </summary>
        /// <returns>true if client version older than server</returns>
        private bool IsClientUpdateNeeded()
        {
            ClientApplicationInfo clientInfo = null;

            //  get client info from its config file
            clientInfo = ClientApplicationInfo.Deserialize(_application.Client.XmlFile);

            ApplicationUpdateManager.TraceWrite("[DownloaderManager.ClientMustBeUpdated]", "RES_MESSAGE_ClientServerVersionCheck", _application.Name, clientInfo.InstalledVersion, _server.AvailableVersion);

            // get both versions, return comparison
            Version clientVersion = null;

            clientVersion = new Version(clientInfo.InstalledVersion);

            Version serverVersion = null;

            serverVersion = new Version(_server.AvailableVersion);

            return(serverVersion > clientVersion);
        }
コード例 #5
0
        /// <summary>
        /// Internal helper, stops the specified DownloadManager by application name
        /// </summary>
        private void StopUpdaterHelper(string appName)
        {
            bool isGoodStop = false;

            //  unpackage objects from holder
            DownloaderManager dnldMgr    = ((DnldMgrHolder)_dnldHolders[appName]).dnldMgr;
            Thread            dnldThread = ((DnldMgrHolder)_dnldHolders[appName]).dnldThread;

            //  signal downloaderMgr it's time to stop, chance to exit gracefully:
            if (null != dnldMgr)
            {
                dnldMgr.MustStopUpdating.Set();
            }

            //  check if the thread is event started
            if ((null != dnldThread) && (System.Threading.ThreadState.Unstarted != dnldThread.ThreadState))
            {
                //  wait to join for reasonable timeout
                isGoodStop = dnldThread.Join(TIMEOUT_THREAD_JOIN);
            }
            else
            {
                isGoodStop = true;
            }

            //  if it's not a clean join, then interrupt thread
            if (!isGoodStop)
            {
                dnldThread.Interrupt();
                //  log problem
                ApplicationUpdateManager.TraceWrite("[ApplicationUpdateManager.StopUpdater]", "RES_StopUpdaterInterruptThread", dnldThread.Name);
            }


            //  announce we are stopping:
            ApplicationUpdateManager.TraceWrite(
                "[ApplicationUpdateManager.StopUpdater]",
                "RESX_MESSAGE_UpdaterStopped",
                dnldMgr.ApplicationName,
                DateTime.Now.ToString(Resource.ResourceManager["RESX_DateTimeToStringFormat"], CultureInfo.CurrentCulture));
        }
コード例 #6
0
        /// <summary>
        /// Updater start method
        /// </summary>
        /// <remarks>
        /// This method iterates through the applications to update, and starts each on its own thread
        /// </remarks>
        public void StartUpdater()
        {
            //  lock the holder collection while we iterate through it
            lock (_dnldHolders.SyncRoot)
            {
                //  cycle through collection of holders, starting each thread
                foreach (DictionaryEntry de in _dnldHolders)
                {
                    DnldMgrHolder holder = (DnldMgrHolder)de.Value;
                    //  start the thread
                    holder.dnldThread.Start();

                    //  announce we have started:
                    ApplicationUpdateManager.TraceWrite(
                        "[ApplicationUpdateManager.StartUpdater]",
                        "RESX_MESSAGE_UpdaterStarted",
                        holder.dnldMgr.ApplicationName,
                        DateTime.Now.ToString(Resource.ResourceManager["RESX_DateTimeToStringFormat"], CultureInfo.CurrentCulture));
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Utility method that splits a full type name (assembly + type) into the constituent five parts, trims those parts, and throws an error if there are not exactly five members.
        /// </summary>
        /// <param name="fullType">the assembly + type names, fully qualified</param>
        /// <param name="typeName">the type name, full</param>
        /// <param name="assemblyName">they fully-qualified assembly name including name, version, culture, and public key token</param>
        private static void SplitType(string fullType, out string typeName, out string assemblyName)
        {
            string[] parts = fullType.Split(COMMA_DELIMITER.ToCharArray());

            // ms--most common source of errors is bad configuration, especially of the assembly+type definitions in config files.
            //  Assert() here so we can be alerted during debugging.
            Debug.Assert(5 == parts.Length, "in GenericFactory.SplitType, passed fullType = " + fullType + " and it would not split 5 ways.");

            if (5 != parts.Length)
            {
                //  pad parts to satisfy error message--not best, but makes clearer errors:
                string[] errorParts = new string[] { "<undefined>", "<undefined>", "<undefined>", "<undefined>", "<undefined>" };
                for (int i = 0; i < 5; i++)
                {
                    if (i < parts.Length)
                    {
                        errorParts[i] = parts[i];
                    }
                }
                string error = ApplicationUpdateManager.TraceWrite("[GenericFactory.SplitType]", "RES_EXCEPTION_BadTypeArgumentInFactory", errorParts);

                //  publish this exception
                ArgumentException ae = new ArgumentException(error, "fullType");
                ExceptionManager.Publish(ae);
                throw ae;
            }
            else
            {
                //  package type name:
                typeName = parts[0].Trim();
                //  package fully-qualified assembly name separated by commas
                assemblyName = String.Concat(parts[1].Trim() + COMMA_DELIMITER,
                                             parts[2].Trim() + COMMA_DELIMITER,
                                             parts[3].Trim() + COMMA_DELIMITER,
                                             parts[4].Trim());
                //  return
                return;
            }
        }
コード例 #8
0
        /// <summary>
        /// Uses a file path to load an assembly.  Then instantiates the requested type by searching interfaces.
        /// Returns an object instantiated by the Activator, using fully-qualified combined assembly-type  supplied.
        /// Assembly parameter example: "Microsoft.ApplicationBlocks.ApplicationUpdater,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"
        /// Type parameter example: "Microsoft.ApplicationBlocks.ApplicationUpdater.Validators.RSAValidator"
        /// </summary>
        /// <param name="filePath">full path to assembly</param>
        /// <param name="interfaceToActivate">the Type representing the interface to activate</param>
        /// <returns></returns>
        public static object Create(string filePath, Type interfaceToActivate)
        {
            Assembly asm          = null;
            Type     typeInstance = null;

            Type[] types = null;
            Object obj   = null;

            try
            {
                asm   = Assembly.LoadFrom(filePath);
                types = asm.GetTypes();
                //  walk through all types in assembly, find the one that IS IPP and use its info
                foreach (Type type in types)
                {
                    //  search for interface by string name in this type
                    typeInstance = type.GetInterface(interfaceToActivate.FullName, false);
                    //  if we find the interface, return the type that implements it
                    if (null != typeInstance)
                    {
                        //  we found the first instance of the given interface
                        //  THERE MAY BE MORE but this is a convenience method.
                        typeInstance = type;
                        break;
                    }
                }
                obj = asm.CreateInstance(typeInstance.FullName);
            }
            catch (Exception e)
            {
                string error = ApplicationUpdateManager.TraceWrite("[GenericFactory.Create]", "RES_EXCEPTION_CantCreateInstanceFromFilePath", filePath, interfaceToActivate);

                TypeLoadException tle = new TypeLoadException(error, e);
                ExceptionManager.Publish(tle);
                throw tle;
            }

            return(obj);
        }
コード例 #9
0
        /// <summary>
        /// This method helps restart the app.  It expects a DnldMgrHolder to be packaged in the object argument; it unpacks this holder
        /// and starts the downloadermanager it contains on the thread it contains
        /// </summary>
        /// <param name="state">an object wrapper around a DnldMgrHolder</param>
        private void RestartUpdaterHelper(object state)
        {
            DnldMgrHolder holder;

            //  extract our holder from the callback's object passed in here as "state"
            holder = (DnldMgrHolder)state;

            //  dispose the timer
            if (null != holder.restartTimer)
            {
                holder.restartTimer.Dispose();
            }

            //  start it
            holder.dnldThread.Start();
            //  log restart
            ApplicationUpdateManager.TraceWrite(
                "[ApplicationUpdateManager.RestartUpdater]",
                "RES_RestartedUpdater",
                holder.dnldMgr.ApplicationName,
                DateTime.Now.ToString(Resource.ResourceManager["RESX_DateTimeToStringFormat"], CultureInfo.CurrentCulture));
        }
コード例 #10
0
        /// <summary>
        /// Wraps the stopping of the IPP thread; this thread ventures outside and does work through IPP.Run(), may take a while;
        /// we may need to reign it in, so stopping + error collection code here.
        /// Common errors in IPP thread:  TheadInterruptedException + TAE, or frank Exception if those not properly handled.
        /// </summary>
        private void StopPostProcessorThread()
        {
            string threadName = "";

            try
            {
                //  join/interrupt the IPOstProcessor thread; it should catch internally and know to Dispose() NOW!
                if (null != _ippThread)
                {
                    //  cache name here
                    threadName = _ippThread.Name;

                    //  NOTE: if you need to do very long-running work, such as large installs or extensive file manipulation, it
                    //  is HIGHLY RECOMMENDED you merely use the IPP Run() method __to spawn a separate process__,
                    //  and in turn do all that long-running work in _that_ process, returning our IPP thread as soon as new Process launches.
                    //  Then you're not at the mercy of Updater's lifetime to complete potentially sensitive work!

                    //  give it a chance, if it's completed it should Join() otherwise Interrupt() it
                    //  Interrupt will only wake it if it's WaitSleepJoin; it will not help if the thread is in unmanaged code
                    if (!_ippThread.Join(MILLISECOND_WAIT_TIMEOUT_IPP))
                    {
                        _ippThread.Interrupt();
                    }
                    //  give another chance to clean up, then abort to prevent having it hang around
                    if (!_ippThread.Join(MILLISECOND_WAIT_TIMEOUT_IPP))
                    {
                        _ippThread.Abort();
                    }
                }
            }
            catch (Exception e)
            {
                ApplicationUpdateManager.TraceWrite(e, "[DownloaderManager.StopPostProcessorThread]", "RES_EXCEPTION_StoppingIPP", threadName, e.Message);
                ExceptionManager.Publish(e);
                //  SWALLOW this exception, because we WANT other applications to continue downloading.  Just exit quietly after logging the problem.
                //  downloads should not stop because of IPP errors.
            }
        }
コード例 #11
0
        internal static string TraceWrite(Exception e, string location, string messageKey, params object[] args)
        {
            string message = "";
            //  get recursive error dump string
            StringBuilder sb = new StringBuilder(5000);

            ApplicationUpdateManager.RecurseErrorStack(e, ref sb);
            string error = sb.ToString();

            if (null != messageKey && null != args)
            {
                message = FormatMessage(messageKey, args);
            }
            Trace.WriteLine("");
            Trace.WriteLine(location + " : ");
            Trace.Indent();
            Trace.WriteLine(message);
            Trace.WriteLine(error);
            Trace.WriteLine("");
            Trace.Unindent();

            return(message);
        }
コード例 #12
0
        /// <summary>
        /// Uses an XML file as source of data.  Populate a ClientApplicationInfo object and return it.
        /// </summary>
        /// <param name="filePath">The XML file path</param>
        /// <returns></returns>
        public static ClientApplicationInfo Deserialize(string filePath)
        {
            // Cannot use xml-deserialization here
            ApplicationUpdateManager.TraceWrite("[ClientApplicationInfo.Deserialize]", "RES_MESSAGE_DeserializingClientApplicationInfo", filePath);

            //  create xml doc
            XmlDocument           doc           = new XmlDocument();
            XmlNode               node          = null;
            ClientApplicationInfo clientAppInfo = new ClientApplicationInfo();

            try
            {
                //  load it
                doc.Load(filePath);
                //  select the sub-node we want:
                //  NOTE that we are using a regular app.config, specifically AppStart.exe.config;
                //  SO we can't just treat it like a regular xml-deserialization because the serializer doesn't like the extra
                //  nodes.  Therefore just walk the XML to get values for class

                node = doc.SelectSingleNode("configuration/appStart/ClientApplicationInfo");

                //  set values
                clientAppInfo.AppFolderName    = node.SelectSingleNode("appFolderName").InnerText;
                clientAppInfo.AppExeName       = node.SelectSingleNode("appExeName").InnerText;
                clientAppInfo.InstalledVersion = node.SelectSingleNode("installedVersion").InnerText;
            }
            catch (Exception e)
            {
                string error = ApplicationUpdateManager.TraceWrite(e, "[ClientApplicationInfo.Deserialize]", "RES_EXCEPTION_CouldNotDeserializeClientApplicationInfo", e.Message, filePath);

                ExceptionManager.Publish(e);
                throw e;
            }
            //  return it
            return(clientAppInfo);
        }
コード例 #13
0
        /// <summary>
        /// Deserializes the configuration in an XML file
        /// </summary>
        /// <param name="filePath">The XML file path</param>
        /// <returns>ServerApplicationInfo object</returns>
        public static ServerApplicationInfo Deserialize(string filePath)
        {
            ServerApplicationInfo serverInfo  = null;
            XmlSerializer         _serializer = new XmlSerializer(typeof(ServerApplicationInfo));

            ApplicationUpdateManager.TraceWrite("[ServerApplicationInfo.Deserialize]", "RES_MESSAGE_DeserializeServerApplicationInfo", filePath);

            try
            {
                using (FileStream fs = new FileStream(filePath, FileMode.Open))
                {
                    serverInfo = (ServerApplicationInfo)_serializer.Deserialize(new XmlTextReader(fs));
                }
                //  return it
                return(serverInfo);
            }
            catch (Exception e)
            {
                ApplicationUpdateManager.TraceWrite(e, "[ServerApplicationInfo.Deserialize]", "RES_EXCEPTION_CouldNotDeserializeServerApplicationInfo", e.Message, filePath);

                ExceptionManager.Publish(e);
                throw e;
            }
        }
コード例 #14
0
        /// <summary>
        /// Using manifest information in node @"<postProcessor type='' assembly=''></postProcessor>",
        /// this instantiates the object.  The object MUST implement IPostProcessor interface.  That interface
        /// has a single method "void Run()"
        /// The object is used to do post-update actions such as run custom installers, make event logs, clean up
        /// old installs, etc.
        ///
        ///   NOTE:
        /// The PostProcessor runs from a thread _spawned by this thread_, and under _THIS_ security context.
        /// Therefore if AppUpdater
        /// is running as a high-privilege user, the PostProcessor can do quite a bit...BE CAREFUL.
        /// ALSO note that _we are using a separate thread_, so PostProcessor does NOT block this thread.
        /// </summary>
        private void RunPostProcessor()
        {
            IPostProcessor ipp           = null;
            object         postProcessor = null;

            //  FIRST, check if PostProcessor config node is null
            if (null == _server.PostProcessor)
            {
                return;
            }

            //  we must run IPP _from the new version directory_, not the temp dir...temp dir is gone/going away;
            //  use Path.Combine serially to ensure correct pathing.
            string ippPath = Path.Combine(Path.Combine(_application.Client.BaseDir, _server.AvailableVersion), _server.PostProcessor.Name);

            //  check if file actually exists:
            if (!File.Exists(ippPath))
            {
                return;
            }

            //  swallow all post-processor errors but log them
            try
            {
                //  instantiate IPP using GenericFactory
                postProcessor = GenericFactory.Create(ippPath, typeof(IPostProcessor));
                //  check if it's right interface so we can fail very quietly here
                if (postProcessor is IPostProcessor)
                {
                    ipp = postProcessor as IPostProcessor;
                    //***    THREADING    ***
                    //  here we create our member thread, and tell it to Run() IPP
                    //  this way we are not blocked here, IPP may be very long-running if it
                    //  does un-installers, works with files, etc...
                    //    NOTE
                    //  1)  we are not attempting to clean up this thread, catch exceptions, etc. for it; Run() must do that
                    //  2)  IF the IPP needs to Dispose(), it must do so internally when it unwinds its stack--
                    //		so when Run() is complete, call Dispose() internally
                    //	 3)  the IPP should be aware that the parent app might shut down ungracefully--SO it should sink the
                    //		ProcessExit event and do cleanup
                    //	 4)  in case it is Abort()'ed or Interrupt()'ed, it should catch both those exceptions and clean up.
                    //
                    _ippThread      = new Thread(new ThreadStart(ipp.Run));
                    _ippThread.Name = "IPostProcessor_Thread_" + _application.Name;
                    _ippThread.Start();
                }
                else
                {
                    ApplicationUpdateManager.TraceWrite("[DownloaderManager.RunPostProcessor]", "RES_MESSAGE_IPPWouldNotCast", ippPath, postProcessor.GetType());
                }
            }
            catch (ThreadInterruptedException tie)
            {
                ApplicationUpdateManager.TraceWrite(tie, "[DownloaderManager.RunPostProcessor]", "RES_EXCEPTION_ThreadInterruptedException", Thread.CurrentThread.Name);
                throw tie;
            }
            catch (Exception e)
            {
                ApplicationUpdateManager.TraceWrite(e, "[DownloaderManager.RunPostProcessor]", "RES_EXCEPTION_RunningIPP", _server.PostProcessor.Name, _server.PostProcessor.Type, _server.PostProcessor.Assembly);
                ExceptionManager.Publish(e);
            }
            return;
        }
コード例 #15
0
        /// <summary>
        /// Default constructor
        /// </summary>
        public ApplicationUpdateManager()
        {
            DnldMgrHolder holder;

            //  initialize the hybriddict we're using to hold DnldMgrHolder structs
            _dnldHolders = new HybridDictionary();

            #region Configuration Testing

            //  attempt to load configuration first.  If there is an error, throw here and go no further--config is essential
            try
            {
                UpdaterConfiguration config = UpdaterConfiguration.Instance;
            }
            catch (Exception e)
            {
                //  throw right away after logging, we cannot continue
                ExceptionManager.Publish(e);
                throw e;
            }
            #endregion

            #region Set Up File-Based Logging

            SetupLogging();

            #endregion

            #region Create Managers, Create Validator + Downloader, Construct Managers with their respective objects (downloader + validator)

            //  iterate through applications array (which in turn uses config to get this info)
            //  at each application, create a new DownloaderManager + its objects + attendant thread
            foreach (ApplicationConfiguration application in UpdaterConfiguration.Instance.Applications)
            {
                //  use helper function to create + package a complete DnldMgrHolder + the inner DownloaderManager and all its parts
                holder = SetupDownloadManager(application);
                //  check if app of this name exists already; CANNOT HAVE two apps of same name being updated
                if (_dnldHolders.Contains(application.Name))
                {
                    string error = ApplicationUpdateManager.TraceWrite("[ApplicationUpdateManager.ctor]", "RES_EXCEPTION_DuplicateApplicationName", application.Name);
                    ConfigurationException configE = new ConfigurationException(error);
                    ExceptionManager.Publish(configE);
                    throw configE;
                }
                //  add the holder to the hashtable for starting later
                _dnldHolders.Add(application.Name, holder);
            }

            #endregion

            #region Hook ProcessExit

            //  wrap in try in case security not allowing us to hook this, log and continue it's not crucial
            try
            {
                //  hook the AppDomain.ProcessExit event so that we can gracefully interrupt threads and clean up if
                //  process is killed
                AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
            }
            catch (SecurityException se)
            {
                //  log and continue
                ApplicationUpdateManager.TraceWrite(se, "[ApplicationUpdateManager.CTOR]", "RES_EXCEPTION_ConfigCantLoadInAUConstructor");
                ExceptionManager.Publish(se);
            }

            #endregion
        }
コード例 #16
0
        /// <summary>
        /// Checks job status; if job is NOT downloading, returns immediately--these status
        /// settings indicate the job is "in process"
        /// Then queries IDownloader instance for job status.  If job is "Ready", set job status
        /// to "validating" and initiates validation.  For all other status, sets job status
        /// to returned status and returns from function.
        /// </summary>
        private void CheckDownloadCompleteOrError()
        {
            //  check if the job status is anything BUT downloading.  If it's error, cancelled, validating, or ready, we don't
            //  need to query downloader.  In fact doing so will cause an exception in downloader, since it is not downloading it anymore.
            if (JobStatus.Downloading != _dnldJob.Status)
            {
                return;
            }

            //  wrapped in try-catch because it might take a while to poll, and if we're interrupted we need to handle properly
            //  also crucial to log failures of downloader here...
            try
            {
                switch (_downloader.GetJobStatus(_dnldJob.JobId))
                {
                //  check if job is ready from downloader; if so, set status to ready in table and signal Validator
                case JobStatus.Ready:
                {
                    //  if job ready, annotate in the DownloadJobStatusEntry status field, make it "Validating"
                    _dnldJob.Status = JobStatus.Validating;

                    //*  TELL THE VALIDATOR TO GET WORKING ON THIS DOWNLOAD
                    ValidateFilesAndCleanup();

                    //*  NOTIFY LISTENERS THAT DOWNLOAD IS COMPLETE
                    this.OnDownloadCompleted();

                    //*  WRITE TO TRACE DNLD COMPLETE
                    ApplicationUpdateManager.TraceWrite("[DownloaderManager.CheckDownloadCompleteOrError]", "RES_MESSAGE_DownloadComplete", _guidEndDnld0, _guidEndDnld1, _guidEndDnld2, _guidEndDnld3, _guidEndDnld4);

                    break;
                }

                //  check if job errored; if so, set error to true and leave.
                case JobStatus.Error:
                {
                    _dnldJob.Status = JobStatus.Error;
                    break;
                }

                case JobStatus.Cancelled:
                {
                    _dnldJob.Status = JobStatus.Cancelled;
                    break;
                }

                case JobStatus.Downloading:
                {
                    _dnldJob.Status = JobStatus.Downloading;
                    break;
                }

                default:
                {
                    break;
                }
                }
            }
            //  don't swallow TIE's, rethrow
            catch (ThreadInterruptedException tie)
            {
                throw tie;
            }
            catch (Exception e)
            {
                string error = ApplicationUpdateManager.TraceWrite(e, "[DownloaderManager.CheckDownloadCompleteOrError]", "RES_ErrorDownloadingJob", _application.Name, e.Message);
                ExceptionManager.Publish(new ApplicationUpdaterException(error, e));
            }
        }
コード例 #17
0
        private void SetupLogging()
        {
            if (null != UpdaterConfiguration.Instance.Logging)
            {
                FileStream fs = null;

                //  create time-based log file name
                //  get the dir path for the log file
                string path = UpdaterConfiguration.Instance.Logging.LogPath;

                //  if no path return
                if (path.Length > 0)
                {
                    path = Path.GetDirectoryName(UpdaterConfiguration.Instance.Logging.LogPath);
                }
                else
                {
                    return;
                }

                //  first, see if dir specified exists:
                if (!Directory.Exists(path))
                {
                    string error = ApplicationUpdateManager.TraceWrite("[ApplicationUpdateManager.SetupLogging]", "RES_MESSAGE_UpdaterLogDirectoryNotFound", path);
                    ExceptionManager.Publish(new ConfigurationException(error));
                    return;
                }

                //  strip off all except actual file name
                string logName = Path.GetFileNameWithoutExtension(UpdaterConfiguration.Instance.Logging.LogPath);

                //  append the month-day-year-hour-minute-second for uniqueness
                logName =
                    logName +
                    "_" +
                    DateTime.Now.ToString(Resource.ResourceManager["RESX_DateTimeToStringFormatLogFile"], CultureInfo.CurrentCulture) +
                    ".log";

                //  recombine path
                logName = Path.Combine(path, logName);

                //  attempt to create the file with the given path
                try
                {
                    fs = File.Create(logName);
                }
                catch (Exception ex)
                {
                    //  if we can't trace, and move along--logging not worth pitching the whole update
                    string error = ApplicationUpdateManager.TraceWrite(ex, "[ApplicationUpdateManager.SetupLogging]", "RES_MESSAGE_UpdaterLogCannotBeWritten", logName);
                    ExceptionManager.Publish(new ConfigurationException(error, ex));
                    return;
                }
                finally
                {
                    if (null != fs)
                    {
                        fs.Close();
                    }
                }

                //  add this log file to trace listeners
                Trace.Listeners.Add(new TextWriterTraceListener(logName));

                //  set up trace to auto-flush
                Trace.AutoFlush = true;
            }
        }
コード例 #18
0
        /// <summary>
        /// This figures out how many milliseconds to wait--or, if using ExtendedFormat, queries the helper to find if time has elapsed.  If time
        /// has elapsed, it returns (true if the MRE is set, signalling that ApplicationUpdaterManager has signalled to stop)
        /// allowing a new download cycle to begin.  Otherwise, it loops internally, polling the IDownloader for job status.
        ///
        /// </summary>
        /// <returns>true if we were interrupted (The MustStopUpdating event is signaled)</returns>
        private bool IsPollerIntervalElapsed()
        {
            double mSecToWaitTotal    = 0;
            double mSecWaitedSoFar    = 0;
            double pollingInterval    = 0;
            bool   isMustStopSignaled = false;
            bool   isWaitTimeElapsed  = false;

            //  check if polling type is extended-format; if so don't try parsing an int from it
            if (PollingType.ExtendedFormat != UpdaterConfiguration.Instance.Polling.Type)
            {
                pollingInterval = double.Parse(UpdaterConfiguration.Instance.Polling.Value, CultureInfo.CurrentCulture);
            }

            mSecToWaitTotal = GetPollingIntervalMilliseconds(pollingInterval, UpdaterConfiguration.Instance.Polling.Type);

            //    NOTE:  slightly tricky loop here.
            //  it must satisfy three requirements:
            //		1)  we must remain responsive to UpdaterManager in this loop while polling our IDownloader for job status
            //		2)  we must wait a certain time to poll for a new download
            //		3)  we must poll the downloader for completed jobs, and go to validation when job available
            //	so, we:
            //		a)  cache the tickcount when we started all this (in RunDownloader) for reference
            //		b)  check if UpdateManager has told us to stop (isMustStopSignaled)
            //		c)  poll the downloader
            //		d)  if we're using extended format wait, check if THAT has elapsed
            //		e)  finally get the total loop time by subtracting current tickcount from the cached one;
            //			if we have run out of time or isMustStop is signaled, we leave the loop.
            //		f)  if there was a major error in downloader, exit
            //		g)  if time waited seems very long (> 2* poll time) then download is taking too long,
            //			assume failure and exit...UNLESS we are using extended time, in which case we just wait
            //

            while ((!isWaitTimeElapsed) || (JobStatus.Downloading == _dnldJob.Status))
            {
                //  query downloader for job status; it will put status in _dnldJob.Status
                CheckDownloadCompleteOrError();

                //  if using Extended Format poll type--check if that helper class tells us we've waited long enough.
                if (PollingType.ExtendedFormat == UpdaterConfiguration.Instance.Polling.Type)
                {
                    if (ExtendedFormatHelper.IsExtendedExpired(UpdaterConfiguration.Instance.Polling.Value, _lastUpdate, DateTime.Now))
                    {
                        _lastUpdate       = DateTime.Now;
                        isWaitTimeElapsed = true;
                    }
                }                  // IF

                //  calculate the total waited time based on TickCount since started this method
                //  ADD the poll wait time, since we will pass it again before leaving this loop
                mSecWaitedSoFar = ((Environment.TickCount - _tickCountAtStart) + MILLISECOND_WAIT_POLL_LOOP);

                //  check if allowable time has elapsed, if so set flag isWaitTimeElapsed so main can continue
                if (mSecWaitedSoFar > mSecToWaitTotal)
                {
                    isWaitTimeElapsed = true;
                }

                //  NOTE:  JUST IN CASE, we do sanity check here:  if we have been waiting for a download for > 2
                //  polling intervals, then FORCE EXIT, something must be wrong
                //  if using extended format, don't do this check
                if (mSecWaitedSoFar > (2 * mSecToWaitTotal) && !(PollingType.ExtendedFormat == UpdaterConfiguration.Instance.Polling.Type))
                {
                    //  if we've waited this long, the job is hung and we need to recycle--throw
                    string    error = ApplicationUpdateManager.TraceWrite("[DownloaderManager.IsPollerIntervalElapsed]", "RES_EXCEPTION_WaitedMoreThanTwicePollPeriod", mSecWaitedSoFar, _dnldJob.ApplicationName);
                    Exception ex    = new Exception(error);
                    throw ex;
                }

                //  do a fixed wait on MustStopUpdating, 5 seconds acc. to constant in declarations...
                isMustStopSignaled = _mustStopUpdating.WaitOne(MILLISECOND_WAIT_POLL_LOOP, false);

                //  if MustStop has been signalled, we must leave the loop regardless
                if (isMustStopSignaled)
                {
                    break;
                }
            }

            //  finally return isEventSignaled to inform caller of whether we were told to stop during the wait
            return(isMustStopSignaled);
        }
コード例 #19
0
        /// <summary>
        ///  Determine the files to be downloaded and call the IDownloader to perform the job
        /// </summary>
        /// <returns>the job id guid</returns>
        private Guid DownloadApplicationFiles()
        {
            string fullSourcePath      = "";
            string fullDestinationPath = "";

            //Get the location of files on server
            string sourceLocation = _server.UpdateLocation;

            //  ensure terminal slash
            sourceLocation = FileUtility.AppendSlashURLorUNC(sourceLocation);

            //Get the base dir where to copy files
            string baseDir = _application.Client.TempDir;

            ApplicationUpdateManager.TraceWrite("[DownloaderManager.DownloadApplicationFiles]", "RES_MESSAGE_DownloadingAppFiles", _application.Name, _application.Client.TempDir);

            //Prepare remote and local URLs

            ArrayList sourceFiles = new ArrayList();
            ArrayList targetFiles = new ArrayList();

            try
            {
                foreach (FileConfig file in _server.Files)
                {
                    //  set full source/destination paths complete with filename:
                    fullSourcePath      = sourceLocation + file.Name;
                    fullDestinationPath = baseDir + file.UNCName;

                    ApplicationUpdateManager.TraceWrite(
                        "[DownloaderManager.DownloadApplicationFiles]", "RES_MESSAGE_SettingUpFileForDownload",
                        fullSourcePath, fullDestinationPath);

                    //  add the source to our source arraylist
                    sourceFiles.Add(fullSourcePath);

                    //  add the destination to our destination arraylist
                    targetFiles.Add(fullDestinationPath);

                    //  ensure that the local target directory exists
                    //  use utility function to extract root path from given file path--
                    //  thus "C:\foo\file.txt" returns "C:\foo\"
                    if (!Directory.Exists(FileUtility.GetRootDirectoryFromFilePath(fullDestinationPath)))
                    {
                        Directory.CreateDirectory(FileUtility.GetRootDirectoryFromFilePath(fullDestinationPath));
                    }
                }
            }            // TRY
            catch (ThreadInterruptedException tie)
            {
                //  rethrow don't swallow tie, need to clean up
                throw tie;
            }
            catch (Exception e)
            {
                string error = ApplicationUpdateManager.TraceWrite(
                    e,
                    "[DownloaderManager.DownloadApplicationFiles]",
                    "RES_EXCEPTION_SettingUpDownloadDirectories", fullSourcePath, fullDestinationPath);

                //  wrap exception in our exception and publish; then throw the raw exception up
                ExceptionManager.Publish(
                    new ApplicationUpdaterException(Resource.ResourceManager["RES_EXCEPTION_SettingUpDownloadDirectories"], e));
                throw e;
            }

            try
            {
                //  send this "job", both source and destination arraylists (as arrays) to the downloader
                return(_downloader.BeginDownload(
                           (string[])sourceFiles.ToArray(typeof(string)),
                           (string[])targetFiles.ToArray(typeof(string))));
            }
            //  don't swallow tie
            //  thread must interrupt gracefully.
            catch (ThreadInterruptedException tie)
            {
                throw tie;
            }
            catch (Exception e)
            {
                ApplicationUpdateManager.TraceWrite(
                    e,
                    "[DownloaderManager.DownloadApplicationFiles]",
                    "RES_EXCEPTION_UsingDownloader",
                    _downloader.GetType().FullName,
                    _downloader.GetType().AssemblyQualifiedName);

                throw e;
            }
        }
コード例 #20
0
        private void BeginFileDownloads()
        {
            bool isUpdateNeeded     = false;
            bool isMustStopSignaled = false;

            try
            {
                //Compare metadata server file
                isUpdateNeeded = IsClientUpdateNeeded();

                if (isUpdateNeeded)
                {
                    //  fire event to notify "UpdateAvailable"
                    //  NOTE:  IF APPLICATION BLOCKS THIS THREAD AND CALLS StopUpdater(), that means this update is being
                    //  aborted.  Handle gracefully.
                    OnUpdateAvailable(  );

                    //  !!!!  CHECK if the MRE "MustStopUpdating" is signaled, exit if so; we've been told to stop politely,
                    //  don't make us Interrupt()
                    isMustStopSignaled = _mustStopUpdating.WaitOne(MILLISECOND_WAIT_TIMEOUT, false);
                    if (isMustStopSignaled)
                    {
                        return;
                    }

                    ApplicationUpdateManager.TraceWrite("[DownloaderManager.BeginFileDownloads]", "RES_MESSAGE_FilesMustBeUpdated", _application.Name);

                    //  **
                    //              downloader, "DOWNLOAD ALL THESE FILES"--ASYNCH
                    //  **
                    //  Get Job GUID from downloader
                    //  put job GUID in our jobstatus object
                    _dnldJob.JobId = DownloadApplicationFiles(  );
                    //  set job status to downloading
                    _dnldJob.Status = JobStatus.Downloading;


                    //  **
                    //    FIRE THE DOWNLOADSTARTED EVENT
                    //  **
                    OnDownloadStarted(  );


                    ApplicationUpdateManager.TraceWrite("[DownloaderManager.BeginFileDownloads]", "RES_MESSAGE_DnldJobStatusUpdated", _dnldJob.JobId, _application.Name);
                }
                else
                {
                    ApplicationUpdateManager.TraceWrite("[DownloaderManager.BeginFileDownloads]", "RES_MESSAGE_NoNewVersionOnServer", _application.Name);

                    //  we have compared versions.  We have found we have most up-to-date.  Now delete ServerManifest locally
                    RemoveManifestAndTempFiles();

                    //  set job status to Validating to "dequeue" it
                    _dnldJob.Status = JobStatus.Validating;
                }
            }
            //  do not swallow TIE's, throw them
            catch (ThreadInterruptedException tie)
            {
                throw tie;
            }
            catch (Exception e)
            {
                ApplicationUpdateManager.TraceWrite(e, "[DownloaderManager.BeginFileDownloads]", "RES_GeneralUpdaterError", _application.Name);
                ExceptionManager.Publish(new Exception(Resource.ResourceManager["RES_GeneralUpdaterError", _application.Name], e));
            }
        }
コード例 #21
0
        /// <summary>
        /// Download the metadata from the server using the synchronous method
        /// from the IDownloader interface.
        /// </summary>
        /// <returns>true if the manifest downloaded and exists as a file at the correct path</returns>
        private bool IsServerManifestDownloaded()
        {
            bool isManifestValid   = false;
            bool isManifestPresent = false;

            ApplicationUpdateManager.TraceWrite(
                "[DownloaderManager.IsServerManifestDownloaded]",
                "RES_MESSAGE_DownloadManifestStarted",
                _application.Name,
                DateTime.Now.ToString(Resource.ResourceManager["RESX_DateTimeToStringFormat"], CultureInfo.CurrentCulture));

            ApplicationUpdateManager.TraceWrite(
                "[DownloaderManager.IsServerManifestDownloaded]",
                "RES_MESSAGE_SourceFileName",
                _application.Server.ServerManifestFile);

            ApplicationUpdateManager.TraceWrite(
                "[DownloaderManager.IsServerManifestDownloaded]",
                "RES_MESSAGE_DestFileName",
                _application.Server.ServerManifestFileDestination);


            //  wrap; we don't want to fall through if synch download of manifest fails, we want to wait for next poll time
            try
            {
                //Get the server metadata file (server manifest, commonly called "ServerConfig.xml")
                _downloader.Download(
                    _application.Server.ServerManifestFile,
                    _application.Server.ServerManifestFileDestination,
                    TimeSpan.FromMilliseconds(_application.Server.MaxWaitXmlFile));

                // **
                // ***  HERE WE POPULATE OUR _server OBJECT TO ENCAPSULATE MANIFEST INFO  ***
                // **
                //  load the _server (ServerApplicationInfo) object w/ manifest data--THIS IS THE ONLY PLACE WE NEED POPULATE THIS
                _server = ServerApplicationInfo.Deserialize(_application.Server.ServerManifestFileDestination);
            }
            catch (Exception e)
            {
                //  if exception during manifest download, log it but swallow here;
                //  we don't want to drop out of main loop and end up restarting, we want to wait full interval
                string    message = ApplicationUpdateManager.TraceWrite(e, "[DownloaderManager.IsServerManifestDownloaded]", "RES_EXCEPTION_MetadataCantBeDownloadedOrNotValid", _application.Name);
                Exception ex      = new Exception(message, e);
                ExceptionManager.Publish(ex);

                //  return false to alert that manifest download NOT successful
                return(false);
            }


            //  **    FIRE MANIFEST DOWNLOADED EVENT    **
            ApplicationUpdateManager.TraceWrite("[DownloaderManager.IsServerManifestDownloaded]", "RES_MESSAGE_DownloadManifestCompleted", _application.Server.ServerManifestFileDestination);
            this.OnServerManifestDownloaded(  );

            //  **
            //  **    VALIDATE MANIFEST FILE    **
            //  **
            isManifestValid = ValidateManifestFile();

            //  check if it's still present
            isManifestPresent = File.Exists(_application.Server.ServerManifestFileDestination);


            return(isManifestPresent && isManifestValid);
        }
コード例 #22
0
        ///**
        ///***    MAIN METHOD
        ///**
        /// <summary>
        /// This is the main method.
        /// </summary>
        /// <remarks>This method does the following tasks:<list>
        /// <item>1. Get the server metadata information</item>
        /// <item>2. Compare server version with client versoins</item>
        /// <item>3. Start the download process if some local files are old.</item>
        /// </list></remarks>
        public void RunDownloader()
        {
            bool isManifestDownloadSuccess = false;
            bool isEventSignaled           = false;

            //  wrap whole loop in try--we need to catch ThreadInterruptedException and cleanup downloader
            try
            {
                #region While-Loop with Polling Wait and Inner Try-Catch
                while (true)
                {
                    ApplicationUpdateManager.TraceWrite("[DownloaderManager.RunDownloader]", "RES_MESSAGE_CheckingOnUpdates", _application.Name);

                    //  set the job status to Ready, we want to start fresh--
                    //  on previous passes it may have been set to Validating, but if we are back here in loop we have
                    //  completed one full polling pass
                    _dnldJob.Status = JobStatus.Ready;

                    //  set the member tickcount so we have timestamp for loop's start
                    _tickCountAtStart = Environment.TickCount;

                    //  get the Manifest from server
                    isManifestDownloadSuccess = IsServerManifestDownloaded();

                    if (isManifestDownloadSuccess)
                    {
                        BeginFileDownloads();
                    }

                    //  now go to the main polling loop, which waits the full pollingInterval.
                    //  during the wait loop it checks download job status
                    isEventSignaled = IsPollerIntervalElapsed();

                    //  check if we've been signaled
                    if (isEventSignaled)
                    {
                        break;
                    }
                }          //  WHILE
                #endregion
            }              //  TRY

            //  if ThreadInterruptedException, we are being told to stop.  Publish, clean up, and leave (see finally)
            catch (ThreadInterruptedException tie)
            {
                ApplicationUpdateManager.TraceWrite(tie, "[DownloaderManager.RunDownloader]", "RES_EXCEPTION_ThreadInterruptedException", Thread.CurrentThread.Name);
                ExceptionManager.Publish(tie);

                //  OK to swallow this one, we KNOW who did it to us--the ApplicationUpdateManager--and we
                //  just go to Finally now; clean up and unwind stack.  Then AUManager (AU==gold) will Join() us gracefully.
            }
            catch (Exception e)
            {
                ApplicationUpdateManager.TraceWrite(e, "[DownloaderManager.RunDownloader]");

                ExceptionManager.Publish(e);
                //  SWALLOW this exception, because we want this application to keep trying to update;
                //  error may be transient...try restarting via BadExitCallback

                //  AND LASTLY:  use the "BadExit" callback to notify UpdaterManager something rotten has happened;
                //  it's up to Updater to figure out what to do but in current implementation Updater simply waits a while then restarts this update
                _badExitCbk(_application.Name);
            }
            finally
            {
                //  let downloader clean up
                _downloader.Dispose();
                //  let validator clean up
                _validator.Dispose();
                //  delete temp files + manifest
                RemoveManifestAndTempFiles();
                //  stop the IPP thread
                StopPostProcessorThread();
            }              //  FINALLY
        }