예제 #1
0
        /// <summary>
        /// Returns the requested <see cref="AppPackage" /> from the local cache opened for read access,
        /// optionally querying an application store service if the package is not available locally.
        /// </summary>
        /// <param name="storeEP">
        /// The application store endpoint or <c>null</c> to query any
        /// application store instance in the cluster.
        /// </param>
        /// <param name="appRef">The <see cref="AppRef" /> identifing the desired application package.</param>
        /// <param name="queryStore">
        /// Pass <c>true</c> if an application store is to be queried if the package
        /// is not cached locally.
        /// </param>
        /// <returns></returns>
        /// <exception cref="ObjectDisposedException">Thrown if the cache is not open.</exception>
        /// <exception cref="InvalidOperationException">Thrown if local package caching is disabled.</exception>
        /// <exception cref="AppPackageException">Thrown if the package cannot be found.</exception>
        public AppPackage GetPackage(MsgEP storeEP, AppRef appRef, bool queryStore)
        {
            AppPackageInfo info;
            string         transitPath;

            if (storeEP == null)
            {
                storeEP = settings.ClusterEP;
            }

            using (TimedLock.Lock(syncLock))
            {
                VerifyOpen();
                VerifyLocal();

                info = packageFolder.GetPackageInfo(appRef);
                if (info != null)
                {
                    return(AppPackage.Open(info.FullPath));
                }
            }

            // $hack(jeff.lill):
            //
            // The code below isn't strictly threadsafe
            // but should exhibit problems only when
            // closing the client under load so I'm
            // not going to worry about this right now.

            // Download the package from an application store.

            transitPath = packageFolder.BeginTransit(appRef);
            try
            {
                DownloadPackage(null, appRef, transitPath);
                packageFolder.EndTransit(transitPath, true);
            }
            catch
            {
                packageFolder.EndTransit(transitPath, false);
                throw;
            }

            info = packageFolder.GetPackageInfo(appRef);
            if (info == null)
            {
                throw new AppPackageException("Package [{0}] not found.", appRef);
            }

            return(AppPackage.Open(info.FullPath));
        }
예제 #2
0
        /// <summary>
        /// Completes the loading of an application package file.
        /// </summary>
        /// <param name="path">The fully qualified path returned by <see cref="BeginTransit" />.</param>
        /// <param name="commit">
        /// Pass <c>true</c> to commit the package to the folder, <c>false</c> to
        /// delete the transit file without committing it.
        /// </param>
        public void EndTransit(string path, bool commit)
        {
            if (commit)
            {
                AppPackage     package;
                AppPackageInfo info;
                int            size;
                string         destPath;

                using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
                    size = (int)fs.Length;

                using (TimedLock.Lock(syncLock))
                {
                    try
                    {
                        fileWatcher.EnableRaisingEvents = false;

                        destPath = packageFolder + Path.GetFileName(path);
                        if (File.Exists(destPath))
                        {
                            File.Delete(destPath);
                        }

                        File.Move(path, destPath);

                        package = null;

                        try
                        {
                            package = AppPackage.Open(destPath);
                            info    = new AppPackageInfo(package.AppRef, Path.GetFileName(destPath),
                                                         destPath, package.MD5, size, File.GetLastWriteTimeUtc(destPath));
                        }
                        catch
                        {
                            if (package == null)
                            {
                                // The package must be bad so delete it.

                                Helper.DeleteFile(destPath);
                            }

                            throw;
                        }
                        finally
                        {
                            if (package != null)
                            {
                                package.Close();
                            }
                        }

                        packages[info.AppRef] = info;
                    }
                    finally
                    {
                        fileWatcher.EnableRaisingEvents = true;
                    }
                }

                RaiseChangeEvent();
            }
            else
            {
                Helper.DeleteFile(path);
            }
        }
예제 #3
0
        /// <summary>
        /// The actual internal folder scan implementation.
        /// </summary>
        private void InternalScan()
        {
            if (isDisposed)
            {
                return;
            }

            try
            {
                if (Interlocked.Increment(ref scanning) > 1)
                {
                    return;     // Don't allow multiple parallel scans
                }
                Dictionary <AppRef, AppPackageInfo> newPackages = new Dictionary <AppRef, AppPackageInfo>();
                string[] files;

                files = Helper.GetFilesByPattern(packageFolder + "*.zip", SearchOption.TopDirectoryOnly);
                foreach (string file in files)
                {
                    bool isRetry = false;

retry:
                    try
                    {
                        int size;

                        using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
                            size = (int)fs.Length;

                        using (AppPackage package = AppPackage.Open(file))
                            newPackages.Add(package.AppRef, new AppPackageInfo(package.AppRef,
                                                                               Path.GetFileName(file),
                                                                               file,
                                                                               package.MD5,
                                                                               size,
                                                                               File.GetLastWriteTimeUtc(file)));
                    }
                    catch (FileNotFoundException e)
                    {
                        SysLog.LogErrorStackDump("{0}", e.Message);
                    }
                    catch (DirectoryNotFoundException e)
                    {
                        SysLog.LogErrorStackDump("{0}", e.Message);
                    }
                    catch (IOException e)
                    {
                        // I've run into trouble where we've gotten notifications from the
                        // file watcher while a new file is still locked for writing.  In
                        // this situation, I'm going to wait a bit and then retry the
                        // operation once.

                        if (!isRetry)
                        {
                            Thread.Sleep(RetryTime);
                            isRetry = true;
                            goto retry;
                        }

                        SysLog.LogErrorStackDump("{0}", e.Message);
                    }
                    catch (Exception e)
                    {
                        SysLog.LogErrorStackDump("Error [{0}] loading application package [{1}].", e.Message, file);
                    }
                }

                // Determine if there have been any changes to the set of
                // application packages and then update the cached package set
                // and then raise the change event if there were any changes.

                bool changed = false;

                using (TimedLock.Lock(syncLock))
                {
                    foreach (var info in newPackages.Values)
                    {
                        if (!packages.ContainsKey(info.AppRef))
                        {
                            changed = true;
                            break;
                        }
                        else
                        {
                            var orgInfo = packages[info.AppRef];

                            if (info.FileName != orgInfo.FileName ||
                                !Helper.ArrayEquals(info.MD5, orgInfo.MD5))
                            {
                                changed = true;
                                break;
                            }
                        }
                    }

                    if (!changed)
                    {
                        foreach (AppPackageInfo info in packages.Values)
                        {
                            if (!newPackages.ContainsKey(info.AppRef))
                            {
                                changed = true;
                                break;
                            }
                        }
                    }

                    if (changed)
                    {
                        packages = newPackages;
                    }
                }

                if (changed)
                {
                    RaiseChangeEvent();
                }
            }
            finally
            {
                Interlocked.Decrement(ref scanning);
            }
        }