private async Task <bool> ProcessPackage(UserInfo userInfo, string feedName, PackageName packageName, PackageState packageState, PackageState damagedPackageState, Func <IPackageStorageItem, Task <IPackageStorageItem> > tryWithPackageItemBefore, Func <IPackageStorageItem, ZipPackage, Task> tryWithPackage, Func <IPackageStorageItem, Task> tryWithPackageItemAfter)
        {
            var feed        = storage.GetFeed(feedName);
            var packageItem = feed.GetPackage(null, packageState, packageName);
            var traceName   = packageItem.ToString();

            try
            {
                packageItem = await tryWithPackageItemBefore(packageItem);

                if (packageItem == null)
                {
                    throw new Exception(string.Format("Missing package {0}", traceName));
                }

                using (var packageStream = await packageItem.Get())
                {
                    if (packageStream == null)
                    {
                        throw new Exception(string.Format("Missing package data {0}", traceName));
                    }

                    var package = new ZipPackage(packageStream);
                    await tryWithPackage(packageItem, package);
                }

                await tryWithPackageItemAfter(packageItem);

                return(true);
            }
            catch (Exception e)
            {
                support.TrackException(e, new { packageName });
                Trace.TraceError("Unexpected error while processing package {0}:\n{1}", traceName, e);
                notifier.Damaged(userInfo, packageName).Wait();

                if (packageItem != null)
                {
                    packageItem.Move(damagedPackageState, packageName).Wait();
                }

                return(false);
            }
        }