# IServerClient

<Badge tone="type">interface</Badge> <Badge>thread-safe</Badge>

```csharp
namespace AR51.Net;

public interface IServerClient
```

The AR 51 server machines: see their status, launch or quit the AR 51 server program, and start or stop tracking. Use it through [`IAR51Client.Servers`](/docs/sdk-api/csharp-api/classes/iar51client/).

Each machine has two layers: the **server program** (launch, quit, force quit, relaunch) and **tracking** inside it (start, stop). `Servers` follows the system live; all members are safe to use from any thread.

:::tip[How-to]
This page is **reference** (facts only). For a walkthrough with a complete sample, see the [Servers guide](/docs/csharp-api/servers-and-devices/).
:::

## Properties

<div className="apiPropTable apiTable">

| Property | Type | Access | Description |
|---|---|---|---|
| `Servers` | [`IReadOnlyList<ServerInfo>`](#serverinfo) | `get` | The AR 51 server machines currently known, one entry per machine. Empty while not connected. |

</div>

## Method summary

<div className="apiTable">

| Method | Returns | |
|---|---|---|
| [`GetStatusAsync`](#getstatusasync) | [`Task<ServerStatus>`](#serverstatus) |  |
| [`LaunchServerAsync`](#launchserverasync) | [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) |  |
| [`QuitServerAsync`](#quitserverasync) | [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) |  |
| [`ForceQuitServerAsync`](#forcequitserverasync) | [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) |  |
| [`RelaunchServerAsync`](#relaunchserverasync) | [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) |  |
| [`StartTrackingAsync`](#starttrackingasync) | [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) |  |
| [`StopTrackingAsync`](#stoptrackingasync) | [`Task`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task) |  |

</div>

→ Full descriptions in [Method details](#method-details) below.

## Events

Standard .NET events (`EventHandler<T>`): subscribe with `+=`, unsubscribe with `-=`. They are raised on a background thread.

<div className="apiTable">

| Event | Args | Raised when |
|---|---|---|
| `ServersChanged` | [`ServersChangedEventArgs`](#serverschangedeventargs) | Raised when a machine appears in or disappears from `Servers`. Raised on a background thread. |

</div>

<Example>

```csharp
ar51.Servers.ServersChanged += (_, e) =>
{
    foreach (ServerInfo server in e.Added) Console.WriteLine($"+ {server.Name}");
    foreach (ServerInfo server in e.Removed) Console.WriteLine($"- {server.Name}");
};
```

</Example>

## Method details

### GetStatusAsync

<ApiBody kind="method">

```csharp
Task<ServerStatus> GetStatusAsync(ServerInfo server, CancellationToken cancellationToken = default);
```

Gets whether the server program is running on a machine, and whether it is tracking.

<Params>
<Param name="server" type="ServerInfo" typeHref="#serverinfo">The machine, from `Servers`.</Param>
<Param name="cancellationToken" type="CancellationToken" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken">Cancels the request. Optional.</Param>
</Params>

<Returns type="Task<ServerStatus>" typeHref="#serverstatus">The machine's current status.</Returns>

<Throws>
<Throw type="AR51Exception" typeHref="/docs/sdk-api/csharp-api/classes/ar51exception/">The machine could not be reached.</Throw>
</Throws>

<Example>

```csharp
foreach (ServerInfo server in ar51.Servers.Servers)
{
    ServerStatus status = await ar51.Servers.GetStatusAsync(server);
    Console.WriteLine($"{server.Name}: server {status.Server}, tracking {status.Tracking}, version {status.Version ?? "-"}");
}
```

</Example>

</ApiBody>

### LaunchServerAsync

<ApiBody kind="method">

```csharp
Task LaunchServerAsync(ServerInfo server, CancellationToken cancellationToken = default);
```

Launches the AR 51 server program on a machine. Does nothing if it is already running.

<Params>
<Param name="server" type="ServerInfo" typeHref="#serverinfo">The machine, from `Servers`.</Param>
<Param name="cancellationToken" type="CancellationToken" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken">Cancels the request. Optional.</Param>
</Params>

<Returns type="Task" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task">A task that completes when the machine has accepted the request.</Returns>

<Throws>
<Throw type="AR51Exception" typeHref="/docs/sdk-api/csharp-api/classes/ar51exception/">The machine refused ([`AR51ErrorCode.Rejected`](/docs/sdk-api/csharp-api/classes/ar51exception/#ar51errorcode), for example "Restart too soon": try again a few seconds later) or could not be reached.</Throw>
</Throws>

<Example>

```csharp
try
{
    await ar51.Servers.LaunchServerAsync(server);
}
catch (AR51Exception exception) when (exception.ErrorCode == AR51ErrorCode.Rejected)
{
    Console.WriteLine(exception.Message);   // e.g. "Restart too soon": try again a few seconds later
}
```

</Example>

</ApiBody>

### QuitServerAsync

<ApiBody kind="method">

```csharp
Task QuitServerAsync(ServerInfo server, CancellationToken cancellationToken = default);
```

Quits the AR 51 server program on a machine, letting it shut down cleanly. Does nothing if it is not running.

<Params>
<Param name="server" type="ServerInfo" typeHref="#serverinfo">The machine, from `Servers`.</Param>
<Param name="cancellationToken" type="CancellationToken" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken">Cancels the request. Optional.</Param>
</Params>

<Returns type="Task" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task">A task that completes when the machine has accepted the request.</Returns>

<Throws>
<Throw type="AR51Exception" typeHref="/docs/sdk-api/csharp-api/classes/ar51exception/">The machine refused or could not be reached.</Throw>
</Throws>

:::caution[Affects every app using the system]
Tracking runs on the server, so quitting a machine's server program stops it for **every app connected to the AR 51 system**, not just yours.
:::

</ApiBody>

### ForceQuitServerAsync

<ApiBody kind="method">

```csharp
Task ForceQuitServerAsync(ServerInfo server, CancellationToken cancellationToken = default);
```

Ends the AR 51 server program on a machine immediately, without letting it shut down cleanly. Use it when [`QuitServerAsync`](#quitserverasync) does not work.

<Params>
<Param name="server" type="ServerInfo" typeHref="#serverinfo">The machine, from `Servers`.</Param>
<Param name="cancellationToken" type="CancellationToken" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken">Cancels the request. Optional.</Param>
</Params>

<Returns type="Task" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task">A task that completes when the machine has accepted the request.</Returns>

<Throws>
<Throw type="AR51Exception" typeHref="/docs/sdk-api/csharp-api/classes/ar51exception/">The machine refused or could not be reached.</Throw>
</Throws>

:::caution[Affects every app using the system]
Ends the server program without a clean shutdown, for **every app connected to the AR 51 system**. Use it only when [`QuitServerAsync`](#quitserverasync) doesn't work.
:::

</ApiBody>

### RelaunchServerAsync

<ApiBody kind="method">

```csharp
Task RelaunchServerAsync(ServerInfo server, CancellationToken cancellationToken = default);
```

Quits the AR 51 server program on a machine, waits a few seconds, and launches it again.

<Params>
<Param name="server" type="ServerInfo" typeHref="#serverinfo">The machine, from `Servers`.</Param>
<Param name="cancellationToken" type="CancellationToken" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken">Cancels the request. Optional.</Param>
</Params>

<Returns type="Task" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task">A task that completes when the program has been launched again.</Returns>

<Throws>
<Throw type="AR51Exception" typeHref="/docs/sdk-api/csharp-api/classes/ar51exception/">The machine refused or could not be reached.</Throw>
</Throws>

:::caution[Affects every app using the system]
Tracking stops for **every app connected to the AR 51 system** until the program is running again.
:::

</ApiBody>

### StartTrackingAsync

<ApiBody kind="method">

```csharp
Task StartTrackingAsync(ServerInfo server, CancellationToken cancellationToken = default);
```

Starts tracking on a machine. The server program must be running.

<Params>
<Param name="server" type="ServerInfo" typeHref="#serverinfo">The machine, from `Servers`.</Param>
<Param name="cancellationToken" type="CancellationToken" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken">Cancels the request. Optional.</Param>
</Params>

<Returns type="Task" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task">A task that completes when the machine has accepted the request.</Returns>

<Throws>
<Throw type="AR51Exception" typeHref="/docs/sdk-api/csharp-api/classes/ar51exception/">The machine refused or could not be reached.</Throw>
</Throws>

</ApiBody>

### StopTrackingAsync

<ApiBody kind="method">

```csharp
Task StopTrackingAsync(ServerInfo server, CancellationToken cancellationToken = default);
```

Stops tracking on a machine. The server program keeps running.

<Params>
<Param name="server" type="ServerInfo" typeHref="#serverinfo">The machine, from `Servers`.</Param>
<Param name="cancellationToken" type="CancellationToken" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken">Cancels the request. Optional.</Param>
</Params>

<Returns type="Task" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task">A task that completes when the machine has accepted the request.</Returns>

<Throws>
<Throw type="AR51Exception" typeHref="/docs/sdk-api/csharp-api/classes/ar51exception/">The machine refused or could not be reached.</Throw>
</Throws>

:::caution[Affects every app using the system]
Stops tracking on that machine for **every app connected to the AR 51 system**, not just yours.
:::

</ApiBody>

## Related types

Small types used by this interface, documented here.

### ServerInfo

<Badge tone="type">record · sealed</Badge>

```csharp
public sealed record ServerInfo(string Name, string Host, int Port);
```

An AR 51 server machine.

<div className="apiTable">

| Property | Type | Description |
|---|---|---|
| `Name` | `string` | The machine's host name. |
| `Host` | `string` | The machine's IP address. |
| `Port` | `int` | The port of the machine's control service. |

</div>

### ServerStatus

<Badge tone="type">record · sealed</Badge>

```csharp
public sealed record ServerStatus(ServerState Server, TrackingState Tracking, int? ProcessId, TimeSpan? Uptime, string? Version);
```

The status of an AR 51 server machine.

<div className="apiTable">

| Property | Type | Description |
|---|---|---|
| `Server` | [`ServerState`](#serverstate) | Whether the AR 51 server program is running. |
| `Tracking` | [`TrackingState`](#trackingstate) | Whether the program is tracking. |
| `ProcessId` | `int?` | The program's process id, or `null` when it is not running. |
| `Uptime` | [`TimeSpan?`](https://learn.microsoft.com/en-us/dotnet/api/system.timespan) | How long the program has been running, or `null` when it is not running. |
| `Version` | `string?` | The server program's version, for example "3.2.0.9", or `null` when the machine does not report it. |

</div>

### ServerState

<Badge tone="type">enum</Badge>

```csharp
public enum ServerState
```

Whether the AR 51 server program is running on a machine.

<div className="apiTable">

| Value | Meaning |
|---|---|
| `Unknown = 0` | The machine did not say. |
| `NotRunning = 1` | The program is not running. |
| `Running = 2` | The program is running. |

</div>

### TrackingState

<Badge tone="type">enum</Badge>

```csharp
public enum TrackingState
```

Whether the AR 51 server program is tracking.

<div className="apiTable">

| Value | Meaning |
|---|---|
| `Unknown = 0` | The machine did not say. |
| `Idle = 1` | Not tracking. |
| `Running = 2` | Tracking. |

</div>

### ServersChangedEventArgs

<Badge tone="type">class · sealed</Badge>

```csharp
public sealed class ServersChangedEventArgs : EventArgs
```

Data for `IServerClient.ServersChanged`.

<div className="apiPropTable apiTable">

| Property | Type | Access | Description |
|---|---|---|---|
| `Added` | [`IReadOnlyList<ServerInfo>`](#serverinfo) | `get` | Machines that appeared. |
| `Removed` | [`IReadOnlyList<ServerInfo>`](#serverinfo) | `get` | Machines that disappeared. |
| `Servers` | [`IReadOnlyList<ServerInfo>`](#serverinfo) | `get` | Every known machine after the change. |

</div>

<details>
<summary>Constructor</summary>

```csharp
public ServersChangedEventArgs(IReadOnlyList<ServerInfo> added, IReadOnlyList<ServerInfo> removed, IReadOnlyList<ServerInfo> servers);
```

Creates the event data.

</details>

## See also

- [Servers guide](/docs/csharp-api/servers-and-devices/) — walkthrough with a complete, compiled sample
- [Class index](/docs/sdk-api/csharp-api/classes/) — every AR51.Net type
- [Data conventions, threading and errors](/docs/csharp-api/conventions/)
