Files
jellyfin-ha-src/Emby.Server.Implementations/Session/RemoteSessionController.cs
T
unkin-agent 00d0765152
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/push/ci Pipeline failed
feat(session): share the session directory between instances
Publish every session to valkey with the instance holding it, and route a
command for a non-local session to its owner over a per-instance pub/sub
channel. Entries expire, so a dead instance leaves the directory.
2026-09-24 22:48:48 +10:00

66 lines
2.2 KiB
C#

using System;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Session;
namespace Emby.Server.Implementations.Session;
/// <summary>
/// Stands in for the websocket of a session another instance holds: messages are forwarded to that
/// instance, which writes them to the connection it owns.
/// </summary>
public sealed class RemoteSessionController : ISessionController
{
private readonly IPodMessageBus _bus;
private readonly string _ownerPod;
private readonly string _sessionId;
/// <summary>
/// Initializes a new instance of the <see cref="RemoteSessionController"/> class.
/// </summary>
/// <param name="bus">The cross-instance bus.</param>
/// <param name="ownerPod">The instance holding the connection.</param>
/// <param name="sessionId">The session identifier.</param>
/// <param name="isSessionActive">Whether the owner reported the session as active.</param>
/// <param name="supportsMediaControl">Whether the owner reported the session as controllable.</param>
public RemoteSessionController(IPodMessageBus bus, string ownerPod, string sessionId, bool isSessionActive, bool supportsMediaControl)
{
_bus = bus;
_ownerPod = ownerPod;
_sessionId = sessionId;
IsSessionActive = isSessionActive;
SupportsMediaControl = supportsMediaControl;
}
/// <inheritdoc />
public bool IsSessionActive { get; }
/// <inheritdoc />
public bool SupportsMediaControl { get; }
/// <inheritdoc />
public Task SendMessage<T>(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken)
{
var routed = new RoutedSessionMessage
{
SessionId = _sessionId,
MessageType = name,
MessageId = messageId,
Data = JsonSerializer.Serialize(data, JsonDefaults.Options)
};
_bus.Publish(
_ownerPod,
new PodMessage
{
Kind = RoutedSessionMessage.Kind,
Payload = JsonSerializer.Serialize(routed, JsonDefaults.Options)
});
return Task.CompletedTask;
}
}