/// <summary> /// Deletes a package from the folder if it is present. /// </summary> /// <param name="appRef">The package <see cref="AppRef" />.</param> public void Remove(AppRef appRef) { if (isDisposed) { throw new ObjectDisposedException(typeof(AppPackageFolder).Name); } AppPackageInfo info; bool deleted = false; using (TimedLock.Lock(syncLock)) { if (packages.TryGetValue(appRef, out info)) { try { fileWatcher.EnableRaisingEvents = false; File.Delete(info.FullPath); packages.Remove(appRef); deleted = true; } finally { fileWatcher.EnableRaisingEvents = true; } } } if (deleted) { RaiseChangeEvent(); } }
/// <summary> /// Removes a specific application package on an application store. /// </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" /> specifying the package to be removed.</param> public void RemoveRemotePackage(MsgEP storeEP, AppRef appRef) { if (storeEP == null) { storeEP = settings.ClusterEP; } router.Query(storeEP, new AppStoreQuery(AppStoreQuery.RemoveCmd, appRef)); }
/// <summary> /// Returns <c>true</c> if the <see cref="AppRef" /> object passed equals /// this instance. /// </summary> /// <param name="obj">The object to test.</param> /// <returns><c>true</c> if the two objects are equal.</returns> public override bool Equals(object obj) { AppRef appRef = obj as AppRef; if (appRef == null) { return(false); } return(String.Compare(this.uri, appRef.uri, true) == 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)); }
/// <summary> /// Initiates the loading of an application package file into the folder. /// </summary> /// <param name="appRef">The new application package's <see cref="AppRef" />.</param> /// <returns>The fully qualified path to where the new package should be written.</returns> public string BeginTransit(AppRef appRef) { string path; if (isDisposed) { throw new ObjectDisposedException(typeof(AppPackageFolder).Name); } path = transitFolder + appRef.FileName; Helper.CreateFileTree(path); return(path); }
/// <summary> /// Uploads an application package to a remote application store instance. /// </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" /> for the file.</param> /// <param name="path">The path to the application package file.</param> public void UploadPackage(MsgEP storeEP, AppRef appRef, string path) { StreamTransferSession session; if (storeEP == null) { storeEP = settings.ClusterEP; } session = StreamTransferSession.ClientUpload(router, storeEP, path); session.Args = "appref=" + appRef.ToString(); session.Transfer(); }
/// <summary> /// Determines if a specific <see cref="AppPackage" /> is present in the local cache. /// </summary> /// <param name="appRef">The <see cref="AppRef" /> identifing the desired application package.</param> /// <returns><c>true</c> if the application package is present.</returns> /// <exception cref="ObjectDisposedException">Thrown if the cache is not open.</exception> /// <exception cref="InvalidOperationException">Thrown if local package caching is disabled.</exception> public bool IsCached(AppRef appRef) { using (TimedLock.Lock(syncLock)) { VerifyOpen(); VerifyLocal(); if (packageFolder == null) { return(false); } return(packageFolder.GetPackageInfo(appRef) != null); } }
/// <summary> /// Private read constructor. /// </summary> /// <param name="path">The package path on the file system.</param> private AppPackage(string path) { this.path = path; this.readMode = true; this.zipArchive = new ZipFile(path); this.zipOutput = null; this.md5Hash = null; // Load the "Package.ini" file from the archive. if (!ContainsFile("Package.ini")) { throw new FormatException("Application package cannot be opened. Package.ini file is missing."); } StreamReader reader = null; MemoryStream ms; string v; try { ms = new MemoryStream(); CopyFile("Package.ini", ms); ms.Position = 0; reader = new StreamReader(ms); settings = new Config(ConfigPrefix, reader); v = settings.Get("AppRef"); if (v == null) { throw new FormatException("[AppRef] property is missing in the application package metadata."); } else { appRef = new AppRef(v); } } finally { if (reader != null) { reader.Close(); } } }
/// <summary> /// Downloads an application package from a remote application store instance. /// </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" /> for the file.</param> /// <param name="path">The path to the output application package file.</param> public void DownloadPackage(MsgEP storeEP, AppRef appRef, string path) { StreamTransferSession session; AppStoreAck ack; if (storeEP == null) { storeEP = settings.ClusterEP; } ack = (AppStoreAck)router.Query(storeEP, new AppStoreQuery(AppStoreQuery.DownloadCmd, appRef)); storeEP = ack.StoreEP; session = StreamTransferSession.ClientDownload(router, storeEP, path); session.Args = "appref=" + appRef.ToString(); session.Transfer(); }
/// <summary> /// Returns information about a specific application package if it's present /// in the package folder. /// </summary> /// <param name="appRef">The application package <see cref="AppRef" />.</param> /// <returns>The package information or <c>null</c>.</returns> public AppPackageInfo GetPackageInfo(AppRef appRef) { if (isDisposed) { throw new ObjectDisposedException(typeof(AppPackageFolder).Name); } using (TimedLock.Lock(syncLock)) { AppPackageInfo info; if (packages.TryGetValue(appRef, out info)) { return(info); } else { return(null); } } }
/// <summary> /// Returns the requested <see cref="AppPackage" /> from the local cache opened for read access. /// </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> /// <returns>The open <see cref="AppPackage" />.</returns> /// <exception cref="ObjectDisposedException">Thrown if the cache is not open.</exception> /// <remarks> /// <para> /// This method first looks in the local <see cref="AppPackageFolder" /> cache for the /// requested package. If the package is not present locally, then the package will /// be requested from an application store service instance. If the application /// store returns a package, it will be added to the local package folder and /// an open <see cref="AppPackage" /> will be returned. /// </para> /// <note> /// Some care should be taken to ensure that the <see cref="AppPackage" /> /// instances returned are promptly disposed when they are no longer needed. /// </note> /// </remarks> /// <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) { return(GetPackage(storeEP, appRef, true)); }
/// <summary> /// Private create constructor. /// </summary> /// <param name="path">The package path on the file system.</param> /// <param name="appRef">The package's <see cref="AppRef" />.</param> /// <param name="settings">The package metadata settings (or <c>null</c>).</param> /// <remarks> /// <note> /// No <b>Package.ini</b> entry will be created if <paramref name="settings" /> /// is passed as <c>null</c>. /// </note> /// </remarks> private AppPackage(string path, AppRef appRef, ArgCollection settings) { this.path = path; this.readMode = false; this.appRef = appRef; this.zipArchive = null; this.settings = null; this.md5Hash = null; // Create the archive Helper.CreateFileTree(path); if (File.Exists(path)) { File.Delete(path); } zipOutput = new ZipOutputStream(new FileStream(path, FileMode.Create, FileAccess.ReadWrite)); zipOutput.SetLevel(9); if (settings != null) { // Generate the Package.ini file and save it to the archive. StreamWriter writer; MemoryStream ms; ZipEntry entry; DateTime utcNow; utcNow = DateTime.UtcNow; ms = new MemoryStream(); writer = new StreamWriter(ms); try { writer.WriteLine("// Application Package Metadata"); writer.WriteLine("//"); writer.WriteLine("// Generated by: {0} v{1}", Path.GetFileName(Helper.GetAssemblyPath(Assembly.GetExecutingAssembly())), Helper.GetVersion(Assembly.GetExecutingAssembly())); writer.WriteLine("// Create Date: {0}", Helper.ToInternetDate(utcNow)); writer.WriteLine(); writer.WriteLine("#section AppPackage"); writer.WriteLine(); writer.WriteLine(" appref = {0}", appRef.ToString()); foreach (string key in settings) { writer.WriteLine(" {0} = {1}", key, settings[key]); } writer.WriteLine(); writer.WriteLine("#endsection"); writer.WriteLine(); writer.Flush(); entry = new ZipEntry("Package.ini"); entry.DateTime = utcNow; zipOutput.PutNextEntry(entry); zipOutput.Write(ms.GetBuffer(), 0, (int)ms.Length); } finally { writer.Close(); } } }
/// <summary> /// Opens an <see cref="AppPackage" /> for writing, overwritting /// any existing package file. /// </summary> /// <param name="path">File system path to the package.</param> /// <param name="appRef">The package's <see cref="AppRef" />.</param> /// <param name="settings">The fully qualified package metadata settings.</param> /// <remarks> /// <note> /// The standard arguments passed in the <paramref name="settings" /> parameter /// must include the leading <b>"AppPackage.</b> prefix. /// </note> /// </remarks> public static AppPackage Create(string path, AppRef appRef, ArgCollection settings) { return(new AppPackage(path, appRef, settings)); }