/*
+------------------------------------------------------------------+
| Author: Ivan Murzak (https://github.com/IvanMurzak) |
| Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) |
| Copyright (c) 2025 Ivan Murzak |
| Licensed under the Apache License, Version 2.0. |
| See the LICENSE file in the project root for more information. |
+------------------------------------------------------------------+
*/
#nullable enable
using System;
using System.IO;
using System.Net.Http;
using UnityEngine;
namespace com.IvanMurzak.Unity.MCP.Editor.DependencyResolver
{
///
/// Downloads .nupkg files from the NuGet v3 flat container API.
/// Uses the flat container URL pattern:
/// https://api.nuget.org/v3-flatcontainer/{id}/{version}/{id}.{version}.nupkg
///
static class NuGetDownloader
{
const string Tag = NuGetConfig.LogTag;
static readonly HttpClient httpClient = CreateHttpClient();
static HttpClient CreateHttpClient()
{
var handler = new HttpClientHandler
{
AutomaticDecompression = System.Net.DecompressionMethods.GZip
| System.Net.DecompressionMethods.Deflate
};
var client = new HttpClient(handler);
client.DefaultRequestHeaders.Add("User-Agent", "Unity-MCP-NuGetResolver");
client.Timeout = TimeSpan.FromMinutes(5);
return client;
}
///
/// Downloads a .nupkg file to the cache. Returns the cached file path.
/// If the file is already cached, returns immediately without downloading.
///
public static string Download(NuGetPackage package)
{
NuGetCache.EnsureCacheDirectory();
var cachedPath = NuGetCache.GetCachedPath(package);
if (File.Exists(cachedPath))
return cachedPath;
var url = package.DownloadUrl;
Debug.Log($"{Tag} Downloading {package.Id} {package.Version} from {url}");
try
{
using (var response = httpClient.GetAsync(url).GetAwaiter().GetResult())
{
response.EnsureSuccessStatusCode();
using (var stream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
using (var fileStream = File.Create(cachedPath))
{
stream.CopyTo(fileStream);
}
}
Debug.Log($"{Tag} Downloaded {package.Id} {package.Version} ({new FileInfo(cachedPath).Length / 1024} KB)");
}
catch (Exception ex)
{
Debug.LogError($"{Tag} Failed to download {package}: {ex.Message}");
if (File.Exists(cachedPath))
File.Delete(cachedPath);
throw;
}
return cachedPath;
}
}
}