feat(batch23): implement route protocol and info/perms foundation
This commit is contained in:
171
dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.Routes.cs
Normal file
171
dotnet/src/ZB.MOM.NatsNet.Server/ClientConnection.Routes.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
// Copyright 2012-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using ZB.MOM.NatsNet.Server.Auth;
|
||||
using ZB.MOM.NatsNet.Server.Internal;
|
||||
using ZB.MOM.NatsNet.Server.Protocol;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server;
|
||||
|
||||
public sealed partial class ClientConnection
|
||||
{
|
||||
internal void RemoveReplySub(Subscription? sub)
|
||||
{
|
||||
if (sub?.Sid is not { Length: > 0 } sid || Server is not NatsServer server)
|
||||
return;
|
||||
|
||||
var sidText = Encoding.ASCII.GetString(sid);
|
||||
var sep = sidText.IndexOf(' ');
|
||||
if (sep <= 0)
|
||||
return;
|
||||
|
||||
var accountName = sidText[..sep];
|
||||
var (account, _) = server.LookupAccount(accountName);
|
||||
account?.Sublist?.Remove(sub);
|
||||
|
||||
lock (_mu)
|
||||
{
|
||||
Subs.Remove(sidText);
|
||||
}
|
||||
}
|
||||
|
||||
internal Exception? ProcessAccountSub(byte[] arg)
|
||||
{
|
||||
_ = arg;
|
||||
// Gateway account-sub propagation is owned by gateway sessions.
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void ProcessAccountUnsub(byte[] arg)
|
||||
{
|
||||
_ = arg;
|
||||
// Gateway account-unsub propagation is owned by gateway sessions.
|
||||
}
|
||||
|
||||
internal Exception? ProcessRoutedOriginClusterMsgArgs(byte[] arg) =>
|
||||
ProtocolParser.ProcessRoutedOriginClusterMsgArgs(ParseCtx, arg);
|
||||
|
||||
internal Exception? ProcessRoutedHeaderMsgArgs(byte[] arg) =>
|
||||
ProtocolParser.ProcessRoutedHeaderMsgArgs(ParseCtx, arg);
|
||||
|
||||
internal Exception? ProcessRoutedMsgArgs(byte[] arg) =>
|
||||
ProtocolParser.ProcessRoutedMsgArgs(ParseCtx, arg);
|
||||
|
||||
internal void ProcessInboundRoutedMsg(byte[] msg)
|
||||
{
|
||||
_in.Msgs++;
|
||||
_in.Bytes += Math.Max(0, msg.Length - 2);
|
||||
|
||||
if (Opts.Verbose)
|
||||
SendOK();
|
||||
|
||||
var pa = ParseCtx.Pa;
|
||||
if (pa.Subject is null)
|
||||
return;
|
||||
|
||||
var (acc, result) = GetAccAndResultFromCache();
|
||||
if (acc is null)
|
||||
return;
|
||||
|
||||
if ((result?.PSubs.Count ?? 0) + (result?.QSubs.Count ?? 0) > 0)
|
||||
ProcessMsgResults(acc, result, msg, null, pa.Subject, pa.Reply, PmrFlags.None);
|
||||
}
|
||||
|
||||
internal Exception? SendRouteConnect(string clusterName, bool tlsRequired)
|
||||
{
|
||||
var user = string.Empty;
|
||||
var pass = string.Empty;
|
||||
var routeUrl = Route?.Url;
|
||||
if (routeUrl is not null && !string.IsNullOrEmpty(routeUrl.UserInfo))
|
||||
{
|
||||
var userInfo = routeUrl.UserInfo.Split(':', 2);
|
||||
user = userInfo[0];
|
||||
if (userInfo.Length > 1)
|
||||
pass = userInfo[1];
|
||||
}
|
||||
|
||||
if (Server is not NatsServer server)
|
||||
return new InvalidOperationException("route server unavailable");
|
||||
|
||||
var connect = new ConnectInfo
|
||||
{
|
||||
Echo = true,
|
||||
Verbose = false,
|
||||
Pedantic = false,
|
||||
User = user,
|
||||
Pass = pass,
|
||||
Tls = tlsRequired,
|
||||
Name = server.ID(),
|
||||
Headers = server.SupportsHeaders(),
|
||||
Cluster = clusterName,
|
||||
Dynamic = server.IsClusterNameDynamic(),
|
||||
Lnoc = true,
|
||||
};
|
||||
|
||||
var payload = JsonSerializer.Serialize(connect);
|
||||
EnqueueProto(Encoding.ASCII.GetBytes($"CONNECT {payload}\r\n"));
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void ProcessRouteInfo(ServerInfo info)
|
||||
{
|
||||
if (Server is not NatsServer server)
|
||||
return;
|
||||
|
||||
lock (_mu)
|
||||
{
|
||||
Route ??= new Route();
|
||||
|
||||
if (Flags.IsSet(ClientFlags.InfoReceived))
|
||||
{
|
||||
Opts.Import = info.Import;
|
||||
Opts.Export = info.Export;
|
||||
}
|
||||
|
||||
Route.RemoteId = info.Id;
|
||||
Route.RemoteName = info.Name;
|
||||
Route.AuthRequired = info.AuthRequired;
|
||||
Route.TlsRequired = info.TlsRequired;
|
||||
Route.GatewayUrl = info.GatewayUrl ?? string.Empty;
|
||||
Route.Lnoc = info.Lnoc;
|
||||
Route.Lnocu = info.Lnocu;
|
||||
Route.JetStream = info.JetStream;
|
||||
Route.ConnectUrls = info.ClientConnectUrls?.ToList() ?? [];
|
||||
Route.WsConnUrls = info.WsConnectUrls?.ToList() ?? [];
|
||||
Route.LeafnodeUrl = info.LeafNodeUrls is { Length: 1 } leaf ? leaf[0] : string.Empty;
|
||||
Route.Hash = NatsServer.GetHash(info.Name);
|
||||
Route.IdHash = NatsServer.GetHash(info.Id);
|
||||
|
||||
Opts.Protocol = info.Proto;
|
||||
Headers = server.SupportsHeaders() && info.Headers;
|
||||
Flags |= ClientFlags.InfoReceived;
|
||||
}
|
||||
|
||||
if (NatsServer.NeedsCompression(server.GetOpts().Cluster.Compression.Mode))
|
||||
_ = server.NegotiateRouteCompression(this, Route?.DidSolicit == true, Route?.AccName is { Length: > 0 } an ? Encoding.ASCII.GetString(an) : string.Empty, info.Compression ?? string.Empty, server.GetOpts());
|
||||
|
||||
server.UpdateRemoteRoutePerms(this, info);
|
||||
}
|
||||
|
||||
internal bool CanImport(string subject) => PubAllowedFullCheck(subject, fullCheck: false, hasLock: true);
|
||||
|
||||
internal bool CanExport(string subject) => CanSubscribe(subject);
|
||||
|
||||
internal void SetRoutePermissions(RoutePermissions? perms)
|
||||
{
|
||||
if (perms is null)
|
||||
{
|
||||
Perms = null;
|
||||
MPerms = null;
|
||||
return;
|
||||
}
|
||||
|
||||
SetPermissions(new Permissions
|
||||
{
|
||||
Publish = perms.Import?.Clone(),
|
||||
Subscribe = perms.Export?.Clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user