コード例 #1
0
        /// <summary>
        /// Maps the given <see cref="IdeaPlugin"/> to a <see cref="Plugin"/>.
        /// </summary>
        /// <param name="this">The IdeaPlugin.</param>
        /// <param name="dbCategory">The plugin category.</param>
        /// <returns>The mapped plugin.</returns>
        public static Plugin ToEntity
        (
            this IdeaPlugin @this,
            PluginCategory dbCategory
        )
        {
            DateTime ParseDateFromMilliseconds(string value)
            {
                var millis = long.Parse(value);

                return(DateTimeOffset.FromUnixTimeMilliseconds(millis).UtcDateTime);
            }

            var result = new Plugin
                         (
                @this.Name,
                dbCategory,
                @this.ID,
                @this.Description,
                @this.Vendor.ToEntity()
                         );

            result.Tags       = @this.Tags?.Split(';').ToList() ?? new List <string>();
            result.Rating     = @this.Rating;
            result.ProjectURL = @this.ProjectURL ?? string.Empty;
            result.UpdatedAt  = ParseDateFromMilliseconds
                                (
                @this.UpdateDate ?? @this.UploadDate ?? throw new InvalidOperationException()
                                );

            return(result);
        }
コード例 #2
0
        public async Task <HttpResponseMessage> DownloadIconAsync
        (
            IdeaPlugin plugin,
            string?theme,
            CancellationToken ct
        )
        {
            var query = HttpUtility.ParseQueryString(string.Empty);

            query[Endpoints.API.Icon.Parameters.PluginID] = plugin.ID;

            if (!(theme is null))
            {
                query[Endpoints.API.Icon.Parameters.Theme] = theme.ToUpperInvariant();
            }

            var uriBuilder = new UriBuilder("https", _baseURL)
            {
                Path  = Endpoints.API.Icon.BasePath,
                Query = query.ToString() ?? string.Empty
            };

            // Resolve moved requests.
            var data = await _httpClient.GetAsync(uriBuilder.Uri, HttpCompletionOption.ResponseHeadersRead, ct);

            while (!data.IsSuccessStatusCode && (data.StatusCode == HttpStatusCode.MovedPermanently || data.StatusCode == HttpStatusCode.Found))
            {
                var newData = await _httpClient.GetAsync(data.Headers.Location, HttpCompletionOption.ResponseHeadersRead, ct);

                data.Dispose();
                data = newData;
            }

            return(data);
        }
コード例 #3
0
ファイル: Program.cs プロジェクト: Nihlus/jetbrains-mirror
        private static async Task <bool> ImportPluginReleaseAsync
        (
            PluginsDatabaseContext db,
            IdeaPlugin pluginRelease
        )
        {
            var dbPlugin = await db.Plugins.FirstOrDefaultAsync(p => p.PluginID == pluginRelease.ID);

            var dbRelease = dbPlugin.Releases.FirstOrDefault(r => r.Version == pluginRelease.Version);

            if (dbRelease is null)
            {
                dbRelease = pluginRelease.ToReleaseEntity(dbPlugin);
                dbPlugin.Releases.Add(dbRelease);
            }
            else
            {
                var newValues = pluginRelease.ToReleaseEntity(dbPlugin);
                newValues.ID = dbRelease.ID;

                var existingEntry = db.Entry(dbRelease);
                existingEntry.CurrentValues.SetValues(newValues);

                if (existingEntry.State == EntityState.Unchanged)
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #4
0
        public static DownloadResult FromError(IdeaPlugin plugin, IResult <DownloadError> result)
        {
            if (result.IsSuccess)
            {
                throw new InvalidOperationException("The original result was successful.");
            }

            return(FromError(plugin, result.Error !.Value, result.ErrorReason));
        }
コード例 #5
0
 public static DownloadResult FromError
 (
     IdeaPlugin plugin,
     DownloadError error,
     string?reason,
     Exception?exception = null
 )
 {
     return(new DownloadResult(plugin, error, reason, exception));
 }
コード例 #6
0
ファイル: Program.cs プロジェクト: Nihlus/jetbrains-mirror
        private static async Task <bool> ImportPluginAsync
        (
            PluginsDatabaseContext db,
            IdeaPlugin plugin,
            IdeaPluginCategory category
        )
        {
            var dbCategory = await db.Categories.FirstOrDefaultAsync(c => c.Name == category.Name);

            if (dbCategory is null)
            {
                return(false);
            }

            var dbPlugin = await db.Plugins.FirstOrDefaultAsync(p => p.PluginID == plugin.ID);

            if (dbPlugin is null)
            {
                dbPlugin = plugin.ToEntity(dbCategory);
                db.Plugins.Add(dbPlugin);
            }
            else
            {
                var newValues = plugin.ToEntity(dbCategory);
                newValues.ID = dbPlugin.ID;

                var existingEntry = db.Entry(dbPlugin);
                existingEntry.CurrentValues.SetValues(newValues);

                if (existingEntry.State == EntityState.Unchanged)
                {
                    return(false);
                }
            }

            return(true);
        }
コード例 #7
0
 /// <summary>
 /// Downloads the given plugin.
 /// </summary>
 /// <param name="plugin">The plugin.</param>
 /// <param name="ct">The cancellation token to use.</param>
 /// <returns>The response from the server.</returns>
 public Task <HttpResponseMessage> DownloadAsync(IdeaPlugin plugin, CancellationToken ct) =>
 DownloadSpecificAsync(plugin.ID, plugin.Version, ct);
コード例 #8
0
ファイル: List.cs プロジェクト: Nihlus/jetbrains-mirror
        /// <summary>
        /// Serves GET requests to this controller.
        /// </summary>
        /// <param name="build">The build to list plugins for.</param>
        /// <returns>The plugins compatible with the given IDE version.</returns>
        public ActionResult <IdeaPluginRepository> Get(string build)
        {
            if (!IDEVersion.TryParse(build, out var ideVersion))
            {
                return(BadRequest());
            }

            var categories     = _database.Categories.ToList();
            var ideaCategories = categories.Select(c => new IdeaPluginCategory(c.Name)).ToList();

            foreach (var category in _database.Categories)
            {
                var ideaCategory = ideaCategories.First(c => c.Name == category.Name);

                foreach (var plugin in category.Plugins)
                {
                    var compatibleRelease = plugin.Releases
                                            .OrderBy(r => r.UploadedAt)
                                            .FirstOrDefault(r => r.CompatibleWith.IsInRange(ideVersion));

                    if (compatibleRelease is null)
                    {
                        continue;
                    }

                    var ideaPlugin = new IdeaPlugin
                                     (
                        plugin.Name,
                        plugin.PluginID,
                        plugin.Description,
                        compatibleRelease.Version,
                        new IdeaVendor
                    {
                        Email = plugin.Vendor.Email,
                        Name  = plugin.Vendor.Name,
                        URL   = plugin.Vendor.URL
                    },
                        new IdeaVersion
                    {
                        UntilBuild = compatibleRelease.CompatibleWith.UntilBuild.IsValid ? compatibleRelease.CompatibleWith.UntilBuild.ToString() : null,
                        SinceBuild = compatibleRelease.CompatibleWith.SinceBuild.IsValid ? compatibleRelease.CompatibleWith.SinceBuild.ToString() : null,
                    },
                        compatibleRelease.ChangeNotes
                                     )
                    {
                        ProjectURL = plugin.ProjectURL,
                        Tags       = plugin.Tags.Aggregate((a, b) => a + ";" + b),
                        Depends    = compatibleRelease.Dependencies,
                        Downloads  = compatibleRelease.Downloads,
                        Size       = compatibleRelease.Size,
                        Rating     = plugin.Rating,
                        UploadDate = (compatibleRelease.UploadedAt.ToFileTimeUtc() / 10000).ToString(),
                        UpdateDate = (plugin.Releases.Select(r => r.UploadedAt).OrderBy(d => d).First().ToFileTimeUtc() / 10000).ToString()
                    };

                    ideaCategory.Plugins.Add(ideaPlugin);
                }
            }

            var ideaRepository = new IdeaPluginRepository();

            ideaRepository.Categories = ideaCategories;

            return(new ActionResult <IdeaPluginRepository>(ideaRepository));
        }
コード例 #9
0
        /// <summary>
        /// Maps the given <see cref="IdeaPlugin"/> to a <see cref="PluginRelease"/>.
        /// </summary>
        /// <param name="this">The IdeaPlugin.</param>
        /// <param name="dbPlugin">The plugin that the release belongs to.</param>
        /// <returns>The mapped release.</returns>
        public static PluginRelease ToReleaseEntity
        (
            this IdeaPlugin @this,
            Plugin dbPlugin
        )
        {
            string?SelectBestSinceValue(IdeaVersion version)
            {
                if (version.SinceBuild is null || version.SinceBuild == "n/a")
                {
                    return(version.Min);
                }

                return(version.SinceBuild);
            }

            string?SelectBestUntilValue(IdeaVersion version)
            {
                if (version.UntilBuild is null || version.UntilBuild == "n/a")
                {
                    return(version.Max);
                }

                return(version.UntilBuild);
            }

            DateTime ParseDateFromMilliseconds(string value)
            {
                var millis = long.Parse(value);

                return(DateTimeOffset.FromUnixTimeMilliseconds(millis).UtcDateTime);
            }

            var        sinceBuildValue = SelectBestSinceValue(@this.IdeaVersion);
            IDEVersion?sinceBuild      = null;

            if (!(sinceBuildValue is null))
            {
                if (!IDEVersion.TryParse(sinceBuildValue, out sinceBuild))
                {
                    throw new InvalidDataException("Bad version string.");
                }
            }

            var        untilBuildValue = SelectBestUntilValue(@this.IdeaVersion);
            IDEVersion?untilBuild      = null;

            if (!(untilBuildValue is null))
            {
                if (!IDEVersion.TryParse(untilBuildValue, out untilBuild))
                {
                    throw new InvalidDataException("Bad version string.");
                }
            }

            var versionRange = new IDEVersionRange
                               (
                sinceBuild ?? IDEVersion.Invalid,
                untilBuild ?? IDEVersion.Invalid
                               );

            // Get the file size and hash
            // TODO: refactor
            var basePath     = Program.Options.InputFolder;
            var pluginFolder = Path.Combine
                               (
                basePath,
                "plugins",
                dbPlugin.Category.Name.GenerateSlug(),
                dbPlugin.Name.GenerateSlug(),
                @this.Version
                               );

            var pluginFile = Directory.EnumerateFiles(pluginFolder).FirstOrDefault();

            if (pluginFile is null)
            {
                throw new FileNotFoundException("Couldn't find the released plugin file. Missing data?");
            }

            string hash;

            using (var md5 = MD5.Create())
            {
                using var file = File.OpenRead(pluginFile);
                var md5Sum = md5.ComputeHash(file);
                hash = BitConverter.ToString(md5Sum).Replace("-", string.Empty).ToLowerInvariant();
            }

            var fileInfo = new FileInfo(pluginFile);
            var size     = fileInfo.Length;

            var result = new PluginRelease
                         (
                dbPlugin,
                @this.ChangeNotes,
                size,
                ParseDateFromMilliseconds
                (
                    @this.UpdateDate ?? @this.UploadDate ?? throw new InvalidOperationException()
                ),
                hash,
                @this.Version,
                versionRange,
                @this.Depends
                         );

            result.Downloads = @this.Downloads;

            return(result);
        }
コード例 #10
0
        private async Task <DownloadResult> DownloadPluginAsync
        (
            string targetDirectory,
            IdeaPlugin plugin,
            CancellationToken ct
        )
        {
            // Try downloading the icon variants
            var iconTargetDirectory = Path.Combine(Program.Options.OutputFolder, "icons");

            await DownloadIconAsync(iconTargetDirectory, plugin, null, ct);
            await DownloadIconAsync(iconTargetDirectory, plugin, "DARCULA", ct);

            // First, let's perform a quick existing file check against the values in the reported plugin
            var sluggedPluginName = plugin.Name.GenerateSlug();
            var version           = plugin.Version;

            var saveDirectory = Path.Combine
                                (
                targetDirectory,
                sluggedPluginName,
                version
                                );

            if (Directory.Exists(saveDirectory))
            {
                var existingFile = Directory.GetFiles(saveDirectory).FirstOrDefault();
                if (!(existingFile is null))
                {
                    if (new FileInfo(existingFile).Length == plugin.Size)
                    {
                        // Looks like we already have this one
                        return(DownloadResult.FromSuccess(plugin, DownloadAction.Skipped));
                    }
                }
            }

            try
            {
                using var data = await _api.DownloadAsync(plugin, ct);

                if (!data.IsSuccessStatusCode)
                {
                    return(DownloadResult.FromError(plugin, DownloadError.Unknown, data.ReasonPhrase));
                }

                string?filename = null;
                if (data.Content.Headers?.ContentDisposition?.FileName is null)
                {
                    // Try an alternate way
                    var alternatePath = data.RequestMessage?.RequestUri?.AbsolutePath;
                    if (!(alternatePath is null))
                    {
                        if (Path.HasExtension(alternatePath))
                        {
                            filename = Path.GetFileName(alternatePath);
                        }
                    }
                }
                else
                {
                    filename = data.Content.Headers.ContentDisposition.FileName;
                }

                if (filename is null)
                {
                    return(DownloadResult.FromError
                           (
                               plugin,
                               DownloadError.Unknown,
                               "Failed to retrieve file information from the download headers."
                           ));
                }

                Directory.CreateDirectory(saveDirectory);

                var savePath = Path.Combine(saveDirectory, filename.Replace("\"", string.Empty));

                if (File.Exists(savePath))
                {
                    var expectedSize = data.Content.Headers?.ContentLength ?? plugin.Size;
                    if (new FileInfo(savePath).Length == expectedSize)
                    {
                        // Looks like we already have this one
                        return(DownloadResult.FromSuccess(plugin, DownloadAction.Skipped));
                    }

                    // It's crap, so delete it and download again
                    File.Delete(savePath);
                }

                // Download to a temporary file first
                var tempFile = Path.GetTempFileName();
                await using (var tempOutput = File.Create(tempFile))
                {
                    await using var contentStream = await data.Content.ReadAsStreamAsync();

                    await contentStream.CopyToAsync(tempOutput, ct);
                }

                // And then move it over to the final save location
                File.Move(tempFile, savePath);

                return(DownloadResult.FromSuccess(plugin, DownloadAction.Downloaded));
            }
            catch (TimeoutException tex)
            {
                return(DownloadResult.FromError(plugin, DownloadError.Timeout, tex.Message));
            }
            catch (Exception ex)
            {
                return(DownloadResult.FromError(plugin, DownloadError.Exception, ex.Message, ex));
            }
        }
コード例 #11
0
 /// <summary>
 /// Creates a successful result.
 /// </summary>
 /// <param name="plugin">The plugin that was successfully downloaded.</param>
 /// <param name="action">The action that was performed.</param>
 /// <returns>The result.</returns>
 public static DownloadResult FromSuccess(IdeaPlugin plugin, DownloadAction action)
 {
     return(new DownloadResult(plugin, action));
 }
コード例 #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DownloadResult"/> class.
 /// </summary>
 /// <param name="plugin">The plugin that was downloaded.</param>
 /// <param name="action">The action that was performed.</param>
 private DownloadResult(IdeaPlugin plugin, DownloadAction action)
 {
     this.Plugin = plugin;
     this.Action = action;
 }
コード例 #13
0
 public static DownloadResult FromError(IdeaPlugin plugin, Exception exception, string reason)
 {
     return(FromError(plugin, DownloadError.Exception, reason, exception));
 }
コード例 #14
0
 public static DownloadResult FromError(IdeaPlugin plugin, Exception exception)
 {
     return(FromError(plugin, DownloadError.Exception, exception.Message, exception));
 }