# How UpdateService Checks for and Applies Core Updates in v2rayN

> Discover how v2rayN's UpdateService checks for and applies core updates by interacting with the GitHub API and downloading specific binaries for installation.

- Repository: [2dust/v2rayN](https://github.com/2dust/v2rayN)
- Tags: internals
- Published: 2026-02-27

---

**The `UpdateService` class orchestrates core updates by comparing local and remote versions via the GitHub API, downloading the correct architecture-specific binary to a temporary location, and notifying the UI through callback delegates for final installation.**

The v2rayN proxy client relies on external core binaries such as Xray, v2fly, and sing-box to handle network traffic. The `UpdateService` class located in [`v2rayN/ServiceLib/Services/UpdateService.cs`](https://github.com/2dust/v2rayN/blob/main/v2rayN/ServiceLib/Services/UpdateService.cs) automates the entire core-update workflow, from version detection to file retrieval, while delegating the final extraction and service restart to the UI layer via asynchronous callbacks.

## The Core Update Workflow

### Initializing the Download Service and Callbacks

The public entry point `CheckUpdateCore` begins by instantiating a `DownloadService` and registering event handlers for `UpdateCompleted` and `Error` (lines 56‑75). These handlers invoke the injected `updateFunc` callback to stream progress messages back to the caller. The method immediately signals the start of the operation by calling `UpdateFunc` with the localized "Start Updating" message (line 82).

### Fetching Remote Version Information

The `CheckUpdateAsync` method (lines 13‑30) coordinates version detection by first invoking `GetRemoteVersion`. This helper uses `DownloadService.TryDownloadString` to query the GitHub API, following the `latest` redirect for stable releases or parsing the releases endpoint for pre-releases (lines 32‑61). The result is the tag name of the newest available core version.

### Resolving the Correct Download URL

Once the remote version is known, `ParseDownloadUrl` (lines 16‑70) determines whether an update is required. It executes the local binary via `GetCoreVersion` (passing the core’s `VersionArg`) to parse the currently installed version. Using `GetUrlFromCore`, it constructs the platform-specific download URL by evaluating `Utils.IsWindows`, `IsLinux`, or `IsMacOS` combined with `RuntimeInformation.ProcessArchitecture`. If the remote version is less than or equal to the local version, the method returns a failure result; otherwise, it populates `result.Url` (lines 62‑65).

### Downloading and Reporting Progress

When `CheckUpdateAsync` returns a valid URL, `CheckUpdateCore` generates a temporary file path via `Utils.GetTempPath` and initiates the download through `downloadHandle.DownloadFileAsync(url, fileName, true, _timeout)` (line 92). Upon completion, the `UpdateCompleted` event fires, invoking `UpdateFunc(true, fileName)` to hand the archive path to the UI for extraction (lines 58‑71). Errors are reported via `UpdateFunc(false, message)`.

## Key Implementation Details

### Architecture-Aware Asset Resolution

Actual download URLs are not hardcoded in `UpdateService`. Instead, `CoreInfoManager` provides `CoreInfo` objects containing per-core metadata, including download URL templates for each supported platform. The `GetUrlFromCore` helper selects the correct GitHub release asset based on the runtime operating system and CPU architecture, ensuring Windows users receive `.zip` archives while Linux and macOS users get the appropriate binaries.

### Version Comparison Logic

The service prevents unnecessary downloads by executing a direct comparison in `ParseDownloadUrl`. After normalizing version strings from the local binary output and the remote GitHub tag, the logic skips the download if `curVersion >= version`, immediately notifying the UI that the core is already up-to-date.

## Using UpdateService in Practice

Instantiate the service with a callback delegate and check for a stable release:

```csharp
// UI-side: define a simple progress callback
Func<bool, string, Task> updateCallback = async (notify, msg) =>
{
    // `notify == true` means the file path is ready
    if (notify)
        Console.WriteLine($"Core archive ready: {msg}");
    else
        Console.WriteLine(msg);
};

// Create the service (pass the global Config instance)
var updater = new UpdateService(Config.Instance, updateCallback);

// Request an update for the V2Ray core (stable release)
await updater.CheckUpdateCore(ECoreType.v2fly, preRelease: false);

```

Process multiple core types sequentially:

```csharp
foreach (var core in new[] { ECoreType.v2fly, ECoreType.mihomo, ECoreType.sing_box })
{
    await updater.CheckUpdateCore(core, preRelease: false);
}

```

Integrate with UI progress indicators:

```csharp
Func<bool, string, Task> uiProgress = async (notify, msg) =>
{
    if (notify)
        progressBar.Value = 100;                 // download finished
    else
        statusLabel.Content = msg;                // status text updates
};
var updater = new UpdateService(Config.Instance, uiProgress);
await updater.CheckUpdateCore(ECoreType.Xray, preRelease: true);

```

## Summary

- **UpdateService.cs** serves as the central coordinator for core updates, implementing the `CheckUpdateCore` public API that drives the entire workflow.
- The service uses **DownloadService** for HTTP operations, including `TryDownloadString` for API queries and `DownloadFileAsync` for binary retrieval.
- **Architecture awareness** is built into `GetUrlFromCore`, which selects the correct GitHub release asset based on the current OS and CPU architecture.
- **Version comparison** happens in `ParseDownloadUrl` by executing the local binary to get its version and comparing against the GitHub tag, skipping downloads when the local core is current.
- **Callback-driven design** allows the UI to receive real-time status updates and the final temporary file path without `UpdateService` handling extraction or service restarts directly.

## Frequently Asked Questions

### Where does UpdateService download the core binaries from?

UpdateService queries GitHub Releases for each core type. It uses the GitHub API to fetch tag names for pre-releases or follows the `latest` redirect for stable builds, then constructs download URLs pointing to the release assets hosted on GitHub.

### How does UpdateService determine if an update is actually needed?

The service executes the current local binary with its version argument via `GetCoreVersion` to obtain the installed version string. It compares this against the remote version tag in `ParseDownloadUrl`. If the remote version is not greater than the local version, the update is skipped and the UI is notified that the core is already up-to-date.

### What happens after the core archive is downloaded?

UpdateService does not handle extraction or installation internally. Instead, it invokes the `UpdateFunc` callback with `notify: true` and the temporary file path. The UI layer (typically the main window) receives this path, extracts the archive, replaces the old binaries, and restarts the service if necessary.

### Does UpdateService support updating multiple core types simultaneously?

While `CheckUpdateCore` processes one core type per call, the service instance can be reused. You can loop through multiple `ECoreType` values (such as v2fly, Xray, and sing-box) and call `CheckUpdateCore` for each, using the same callback delegate to handle progress for all operations.