diff --git a/Masa.Framework.sln.DotSettings b/Masa.Framework.sln.DotSettings
index 1e0e7b13e..38420906f 100644
--- a/Masa.Framework.sln.DotSettings
+++ b/Masa.Framework.sln.DotSettings
@@ -1,5 +1,6 @@
True
+ True
True
True
True
\ No newline at end of file
diff --git a/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Constant.cs b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/DaprStarterConstant.cs
similarity index 73%
rename from src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Constant.cs
rename to src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/DaprStarterConstant.cs
index e32be40df..8225a0d9b 100644
--- a/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Constant.cs
+++ b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/DaprStarterConstant.cs
@@ -3,11 +3,15 @@
namespace Masa.BuildingBlocks.Development.DaprStarter;
-public static class Constant
+public static class DaprStarterConstant
{
public const string DEFAULT_APPID_DELIMITER = "-";
- public const string DEFAULT_FILE_NAME = "dapr";
+ public const string DEFAULT_DAPR_FILE_NAME = "dapr";
+
+ public const string DEFAULT_FILE_NAME = "daprd";
+
+ public const string DEFAULT_PROCESS_NAME = "dapr-starter";
public const string DEFAULT_ARGUMENT_PREFIX = "--";
diff --git a/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/IDaprProcess.cs b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/IDaprProcess.cs
index db173dd12..d8f39e0e3 100644
--- a/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/IDaprProcess.cs
+++ b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/IDaprProcess.cs
@@ -3,6 +3,9 @@
namespace Masa.BuildingBlocks.Development.DaprStarter;
+///
+/// Manage dapr sidecar start or stop
+///
public interface IDaprProcess : IDisposable
{
void Start();
diff --git a/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Options/DaprOptions.cs b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Options/DaprOptions.cs
index 387ed3720..0646e883d 100644
--- a/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Options/DaprOptions.cs
+++ b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Options/DaprOptions.cs
@@ -5,18 +5,19 @@
namespace Masa.BuildingBlocks.Development.DaprStarter;
+#pragma warning disable S3236
///
/// dapr startup configuration information
/// When the specified attribute is configured as null, the default value of the parameter is subject to the default value of dapr of the current version
///
-public class DaprOptions
+public class DaprOptions : DaprOptionsBase
{
///
/// The id for your application, used for service discovery
///
public string? AppId { get; set; }
- private string _appIdDelimiter = Constant.DEFAULT_APPID_DELIMITER;
+ private string _appIdDelimiter = DaprStarterConstant.DEFAULT_APPID_DELIMITER;
///
/// Separator used to splice AppId and AppIdSuffix
@@ -58,76 +59,31 @@ public string? AppIdSuffix
///
public bool DisableAppIdSuffix { get; set; }
- private int? _maxConcurrency;
+ private int? _maxConcurrency = -1;
///
/// The concurrency level of the application, otherwise is unlimited
- /// Must be greater than 0
+ /// Must be greater than or equal -1
///
- public int? MaxConcurrency
+ public override int? MaxConcurrency
{
get => _maxConcurrency;
set
{
if (value != null)
- MasaArgumentException.ThrowIfLessThanOrEqual(value.Value, (ushort)0, nameof(MaxConcurrency));
+ MasaArgumentException.ThrowIfLessThan(value.Value, -1, nameof(MaxConcurrency));
_maxConcurrency = value;
}
}
- private ushort? _appPort;
-
- ///
- /// The port your application is listening on
- /// Required. Must be between 0-65535
- ///
- public ushort? AppPort
- {
- get => _appPort;
- set
- {
- if (value != null)
- MasaArgumentException.ThrowIfLessThanOrEqual(value.Value, (ushort)0, nameof(AppPort));
-
- _appPort = value;
- }
- }
-
- ///
- /// The protocol (gRPC or HTTP) Dapr uses to talk to the application. Valid values are: http or grpc
- ///
- public Protocol? AppProtocol { get; set; }
-
- ///
- /// Enable https when Dapr invokes the application
- /// default: null (don't use https)
- ///
- public bool? EnableSsl { get; set; }
-
- ///
- /// Dapr configuration file
- /// default:
- /// Linux & Mac: $HOME/.dapr/config.yaml
- /// Windows: %USERPROFILE%\.dapr\config.yaml
- ///
- public string? Config { get; set; }
-
- ///
- /// The path for components directory
- /// default:
- /// Linux & Mac: $HOME/.dapr/components
- /// Windows: %USERPROFILE%\.dapr\components
- ///
- public string? ComponentPath { get; set; }
-
private ushort? _daprGrpcPort;
///
/// The gRPC port for Dapr to listen on
/// Must be greater than 0
///
- public ushort? DaprGrpcPort
+ public override ushort? DaprGrpcPort
{
get => _daprGrpcPort;
set
@@ -145,7 +101,7 @@ public ushort? DaprGrpcPort
/// The HTTP port for Dapr to listen on
/// Must be greater than 0
///
- public ushort? DaprHttpPort
+ public override ushort? DaprHttpPort
{
get => _daprHttpPort;
set
@@ -157,39 +113,13 @@ public ushort? DaprHttpPort
}
}
- ///
- /// Enable pprof profiling via an HTTP endpoint
- ///
- public bool? EnableProfiling { get; set; }
-
- ///
- /// The image to build the code in. Input is: repository/image
- ///
- public string? Image { get; set; }
-
- ///
- /// The log verbosity. Valid values are: debug, info, warn, error, fatal, or panic
- /// default: info
- ///
- public LogLevel? LogLevel { get; set; }
-
- ///
- /// default: localhost
- ///
- public string? PlacementHostAddress { get; set; }
-
- ///
- /// Address for the Sentry CA service
- ///
- public string? SentryAddress { get; set; }
-
private ushort? _metricsPort;
///
/// The port that Dapr sends its metrics information to
/// Must be greater than 0
///
- public ushort? MetricsPort
+ public override ushort? MetricsPort
{
get => _metricsPort;
set
@@ -207,7 +137,7 @@ public ushort? MetricsPort
/// The port for the profile server to listen on
/// Must be greater than 0
///
- public ushort? ProfilePort
+ public override ushort? ProfilePort
{
get => _profilePort;
set
@@ -219,39 +149,32 @@ public ushort? ProfilePort
}
}
- ///
- /// Path to a unix domain socket dir mount. If specified
- /// communication with the Dapr sidecar uses unix domain sockets for lower latency and greater throughput when compared to using TCP ports
- /// Not available on Windows OS
- ///
- public string? UnixDomainSocket { get; set; }
-
- private int? _daprMaxRequestSize;
+ private int? _daprHttpMaxRequestSize;
///
/// Max size of request body in MB.
/// Must be greater than 0
///
- public int? DaprMaxRequestSize
+ public int? DaprHttpMaxRequestSize
{
- get => _daprMaxRequestSize;
+ get => _daprHttpMaxRequestSize;
set
{
if (value != null)
- MasaArgumentException.ThrowIfLessThanOrEqual(value.Value, (ushort)0, nameof(DaprMaxRequestSize));
+ MasaArgumentException.ThrowIfLessThanOrEqual(value.Value, (ushort)0, nameof(DaprHttpMaxRequestSize));
- _daprMaxRequestSize = value;
+ _daprHttpMaxRequestSize = value;
}
}
- private int _heartBeatInterval = Constant.DEFAULT_HEARTBEAT_INTERVAL;
+ private int _heartBeatInterval = DaprStarterConstant.DEFAULT_HEARTBEAT_INTERVAL;
///
/// Heartbeat detection interval, used to detect dapr status
/// default: 5000 ms
/// Must be greater than 0
///
- public int HeartBeatInterval
+ public override int HeartBeatInterval
{
get => _heartBeatInterval;
set
@@ -262,16 +185,59 @@ public int HeartBeatInterval
}
}
+ public string PlacementHostAddress { get; set; }
+
///
/// Start the heartbeat check to ensure that the dapr program is active.
/// When the heartbeat check is turned off, dapr will not start automatically after it exits abnormally.
///
- public bool EnableHeartBeat { get; set; } = true;
+ public override bool EnableHeartBeat { get; set; } = true;
- public bool CreateNoWindow { get; set; } = true;
+ public override bool CreateNoWindow { get; set; } = true;
+
+ ///
+ /// Allowed HTTP origins (default "*")
+ ///
+ public string AllowedOrigins { get; set; }
+
+ ///
+ /// Address for a Dapr control plane
+ ///
+ public string ControlPlaneAddress { get; set; }
+
+ ///
+ /// Increasing max size of read buffer in KB to handle sending multi-KB headers (default 4)
+ ///
+ public int? DaprHttpReadBufferSize { get; set; }
+
+ ///
+ /// gRPC port for the Dapr Internal API to listen on.
+ ///
+ public int? DaprInternalGrpcPort { get; set; }
+
+ ///
+ /// Enable API logging for API calls
+ ///
+ public bool? EnableApiLogging { get; set; }
+
+ ///
+ /// Enable prometheus metric (default true)
+ ///
+ public bool? EnableMetrics { get; set; }
+
+ ///
+ /// Runtime mode for Dapr (default "standalone")
+ ///
+ public string Mode { get; set; }
+
+ ///
+ /// Extended parameters, used to supplement unsupported parameters
+ ///
+ public string ExtendedParameter { get; set; }
public bool IsIncompleteAppId()
{
return !DisableAppIdSuffix && (AppIdSuffix == null || AppIdSuffix.Trim() != string.Empty);
}
}
+#pragma warning restore S3236
diff --git a/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Options/DaprOptionsBase.cs b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Options/DaprOptionsBase.cs
new file mode 100644
index 000000000..530bb9b57
--- /dev/null
+++ b/src/BuildingBlocks/Development/Masa.BuildingBlocks.Development.DaprStarter/Options/DaprOptionsBase.cs
@@ -0,0 +1,125 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+// ReSharper disable once CheckNamespace
+
+namespace Masa.BuildingBlocks.Development.DaprStarter;
+
+#pragma warning disable S3236
+public abstract class DaprOptionsBase
+{
+ private ushort? _appPort;
+
+ ///
+ /// The port your application is listening on
+ /// Required. Must be between 0-65535
+ ///
+ public ushort? AppPort
+ {
+ get => _appPort;
+ set
+ {
+ if (value != null)
+ MasaArgumentException.ThrowIfLessThanOrEqual(value.Value, (ushort)0, nameof(AppPort));
+
+ _appPort = value;
+ }
+ }
+
+ ///
+ /// The protocol (gRPC or HTTP) Dapr uses to talk to the application. Valid values are: http or grpc
+ /// default: HTTP
+ ///
+ public Protocol? AppProtocol { get; protected set; } = Protocol.Http;
+
+ ///
+ /// Enable https when Dapr invokes the application
+ /// Sets the URI scheme of the app to https and attempts an SSL connection
+ ///
+ public bool? EnableSsl { get; set; }
+
+ ///
+ /// The gRPC port for Dapr to listen on
+ ///
+ // ReSharper disable once InconsistentNaming
+ public virtual ushort? DaprGrpcPort { get; set; }
+
+ ///
+ /// The HTTP port for Dapr to listen on
+ ///
+ public virtual ushort? DaprHttpPort { get; set; }
+
+ public virtual bool EnableHeartBeat { get; set; }
+
+ public virtual int HeartBeatInterval { get; set; }
+
+ public virtual bool CreateNoWindow { get; set; }
+
+ ///
+ /// The concurrency level of the application, otherwise is unlimited
+ ///
+ public virtual int? MaxConcurrency { get; set; }
+
+ ///
+ /// Dapr configuration file
+ /// default: config.yaml
+ /// The actual components-path is equal to Path.Combine(options.RootPath, options.Config)
+ ///
+ public string Config { get; set; }
+
+ ///
+ /// The path for components directory
+ /// default: components
+ /// The actual components-path is equal to Path.Combine(options.RootPath, options.ComponentPath)
+ ///
+ public string ComponentPath { get; set; }
+
+ ///
+ /// The root address of dapr configuration
+ /// daprd, dapr runtime required component configuration path
+ /// default:Linux/Mac: $HOME/.dapr/
+ /// Windows: %USERPROFILE%\.dapr\
+ ///
+ public string RootPath { get; set; }
+
+ ///
+ /// The path to the dapr directory
+ /// defdult: Linux/Mac: /usr/local/bin
+ /// Windows: C:\dapr
+ ///
+ public string DaprRootPath { get; set; }
+
+ ///
+ /// Enable pprof profiling via an HTTP endpoint
+ ///
+ public bool? EnableProfiling { get; set; }
+
+ ///
+ /// The log verbosity. Valid values are: debug, info, warn, error, fatal, or panic
+ /// default: info
+ ///
+ public LogLevel? LogLevel { get; set; }
+
+ ///
+ /// Address for the Sentry CA service
+ ///
+ public string? SentryAddress { get; set; }
+
+ ///
+ /// The port that Dapr sends its metrics information to
+ ///
+ public virtual ushort? MetricsPort { get; set; }
+
+ ///
+ /// The port for the profile server to listen on
+ ///
+ public virtual ushort? ProfilePort { get; set; }
+
+ ///
+ /// Path to a unix domain socket dir mount. If specified
+ /// communication with the Dapr sidecar uses unix domain sockets for lower latency and greater throughput when compared to using TCP ports
+ /// Not available on Windows OS
+ ///
+ public string? UnixDomainSocket { get; set; }
+}
+#pragma warning restore S3236
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DaprBackgroundService.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DaprBackgroundService.cs
index 62cfab234..b57edc807 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DaprBackgroundService.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DaprBackgroundService.cs
@@ -11,18 +11,21 @@ public class DaprBackgroundService : BackgroundService
private readonly DaprOptions _options;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly ILogger? _logger;
+ private readonly IServiceProvider _serviceProvider;
public DaprBackgroundService(
IAppPortProvider appPortProvider,
IDaprProcess daprProcess,
IOptionsMonitor options,
IHostApplicationLifetime hostApplicationLifetime,
+ IServiceProvider serviceProvider,
ILogger? logger)
{
_appPortProvider = appPortProvider;
_daprProcess = daprProcess;
_options = options.CurrentValue;
_hostApplicationLifetime = hostApplicationLifetime;
+ _serviceProvider = serviceProvider;
_logger = logger;
}
@@ -41,21 +44,36 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger?.LogInformation("{Name} is Starting ...", nameof(DaprBackgroundService));
- CheckCompletionAppPort(_options);
+ CheckCompletionAppPortAndEnableSSl(_options);
+ PortUtils.CheckCompletionPort(_options, _serviceProvider);
_daprProcess.Start();
}
}
- private void CheckCompletionAppPort(DaprOptions daprOptions)
+ private void CheckCompletionAppPortAndEnableSSl(DaprOptions daprOptions)
{
- if (daprOptions.AppPort == null)
+ if (daprOptions.AppPort == null || daprOptions.EnableSsl == null)
{
- CompletionAppPort(daprOptions);
+ if (daprOptions.EnableSsl == null && daprOptions.AppPort != null)
+ {
+ daprOptions.EnableSsl = _appPortProvider.GetEnableSsl(daprOptions.AppPort.Value);
+ }
+ else
+ {
+ CompletionAppPortAndEnableSSl(daprOptions);
+ }
+ }
+ else
+ {
+ if (daprOptions.EnableSsl != _appPortProvider.GetEnableSsl(daprOptions.AppPort.Value))
+ {
+ throw new UserFriendlyException($"The current AppPort: {daprOptions.AppPort.Value} is not an {(daprOptions.EnableSsl is true ? "Https" : "Http")} port, Dapr failed to start");
+ }
}
}
- private void CompletionAppPort(DaprOptions daprOptions)
+ private void CompletionAppPortAndEnableSSl(DaprOptions daprOptions)
{
var item = _appPortProvider.GetAppPort(daprOptions.EnableSsl);
if (daprOptions.EnableSsl == null)
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DefaultAppPortProvider.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DefaultAppPortProvider.cs
index fcc04b556..6eace1372 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DefaultAppPortProvider.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DefaultAppPortProvider.cs
@@ -9,7 +9,36 @@ public class DefaultAppPortProvider : IAppPortProvider
public DefaultAppPortProvider(IServer server) => _server = server;
+ public bool GetEnableSsl(ushort appPort)
+ {
+ var ports = GetPorts();
+ if (ports.Any(p => p.Port == appPort))
+ {
+ var port = ports.First(p => p.Port == appPort);
+ return port.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase);
+ }
+
+ throw new UserFriendlyException($"The current port {appPort} is unavailable, Dapr failed to start");
+ }
+
public (bool EnableSsl, ushort AppPort) GetAppPort(bool? enableSsl)
+ {
+ var ports = GetPorts();
+
+ if (ports.Count == 1)
+ {
+ return new(ports[0].Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase), (ushort)ports[0].Item2);
+ }
+
+ if (enableSsl is false && ports.Any(p => p.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)))
+ {
+ return new(false, GetAppPort(ports, false));
+ }
+
+ return new(true, GetAppPort(ports, true));
+ }
+
+ private List<(string Scheme, int Port)> GetPorts()
{
var addresses = _server.Features.Get()?.Addresses;
if (addresses is { IsReadOnly: false, Count: 0 })
@@ -19,19 +48,9 @@ public class DefaultAppPortProvider : IAppPortProvider
.Select(address => new Uri(address))
.Where(address
=> address.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)
- || address.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
+ || address.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
.Select(address => new ValueTuple(address.Scheme, address.Port)).ToList();
-
- if (ports.Count == 1)
- {
- return new(ports[0].Item1.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase), (ushort)ports[0].Item2);
- }
-
- if (enableSsl is true && ports.Any(p => p.Item1.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)))
- {
- return new(true, GetAppPort(ports, true));
- }
- return new(false, GetAppPort(ports, false));
+ return ports;
}
public static ushort GetAppPort(List> ports, bool enableSsl)
@@ -43,6 +62,7 @@ public static ushort GetAppPort(List> ports, bool enable
.Select(p => (ushort)p.Item2)
.FirstOrDefault();
}
+
return ports
.Where(p => p.Item1.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
.Select(p => (ushort)p.Item2)
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DefaultAvailabilityPortProvider.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DefaultAvailabilityPortProvider.cs
new file mode 100644
index 000000000..87b3a2bc9
--- /dev/null
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/DefaultAvailabilityPortProvider.cs
@@ -0,0 +1,41 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.Development.DaprStarter.AspNetCore;
+
+[ExcludeFromCodeCoverage]
+public class DefaultAvailabilityPortProvider : IAvailabilityPortProvider
+{
+ private readonly ILogger? _logger;
+
+ public DefaultAvailabilityPortProvider(ILogger? logger = null)
+ {
+ _logger = logger;
+ }
+
+ public ushort? GetAvailablePort(ushort startingPort, IEnumerable? reservedPorts = null)
+ {
+ MasaArgumentException.ThrowIfGreaterThan(startingPort, ushort.MaxValue);
+ try
+ {
+ var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
+
+ var connectionsEndpoints = ipGlobalProperties.GetActiveTcpConnections().Select(c => c.LocalEndPoint);
+ var ports = connectionsEndpoints.Concat(ipGlobalProperties.GetActiveTcpListeners())
+ .Concat(ipGlobalProperties.GetActiveUdpListeners())
+ .Select(point => point.Port)
+ .ToList();
+ if (reservedPorts != null)
+ {
+ ports.AddRange(reservedPorts);
+ }
+
+ return (ushort)Enumerable.Range(startingPort, ushort.MaxValue - startingPort + 1).Except(ports).FirstOrDefault();
+ }
+ catch (Exception ex)
+ {
+ _logger?.LogWarning(ex, "Failed to get available ports, startingPort: {StartingPort}", startingPort);
+ return null;
+ }
+ }
+}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/IAppPortProvider.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/IAppPortProvider.cs
index c2490405b..fe5e8b9db 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/IAppPortProvider.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/IAppPortProvider.cs
@@ -5,5 +5,7 @@ namespace Masa.Contrib.Development.DaprStarter.AspNetCore;
public interface IAppPortProvider
{
+ bool GetEnableSsl(ushort appPort);
+
(bool EnableSsl, ushort AppPort) GetAppPort(bool? enableSsl);
}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/IAvailabilityPortProvider.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/IAvailabilityPortProvider.cs
new file mode 100644
index 000000000..99428c9e5
--- /dev/null
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/IAvailabilityPortProvider.cs
@@ -0,0 +1,9 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+namespace Masa.Contrib.Development.DaprStarter.AspNetCore;
+
+public interface IAvailabilityPortProvider
+{
+ ushort? GetAvailablePort(ushort startingPort, IEnumerable? reservedPorts = null);
+}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/Internal/PortUtils.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/Internal/PortUtils.cs
new file mode 100644
index 000000000..ae0502df1
--- /dev/null
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/Internal/PortUtils.cs
@@ -0,0 +1,57 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+// ReSharper disable once CheckNamespace
+
+namespace Masa.Contrib.Development.DaprStarter.AspNetCore;
+
+internal static class PortUtils
+{
+ public static void CheckCompletionPort(DaprOptions daprOptions, IServiceProvider serviceProvider)
+ {
+ var daprEnvironmentProvider = serviceProvider.GetRequiredService();
+
+ daprOptions.DaprHttpPort ??= daprEnvironmentProvider.GetHttpPort();
+ daprOptions.DaprGrpcPort ??= daprEnvironmentProvider.GetGrpcPort();
+
+ var reservedPorts = new List();
+ AddReservedPorts(daprOptions.DaprHttpPort);
+ AddReservedPorts(daprOptions.DaprGrpcPort);
+ AddReservedPorts(daprOptions.MetricsPort);
+ AddReservedPorts(daprOptions.ProfilePort);
+ AddReservedPorts(daprOptions.AppPort);
+
+ var availabilityPortProvider = serviceProvider.GetRequiredService();
+
+ daprEnvironmentProvider.TrySetHttpPort(GetPortAndAddReservedPortsByAvailability(daprOptions.DaprHttpPort, 3500));
+ daprEnvironmentProvider.TrySetGrpcPort(GetPortAndAddReservedPortsByAvailability(daprOptions.DaprGrpcPort, 5001));
+ daprEnvironmentProvider.TrySetMetricsPort(GetPortAndAddReservedPortsByAvailability(daprOptions.MetricsPort, 9090));
+
+ // Environment variables need to be improved
+ bool IsAvailablePort([NotNullWhen(true)] ushort? port)
+ {
+ return port is > 0;
+ }
+
+ void AddReservedPorts(ushort? port)
+ {
+ if (port is > 0) reservedPorts.Add(port.Value);
+ }
+
+ ushort? GetPortAndAddReservedPortsByAvailability(ushort? port, ushort startingPort)
+ {
+ ushort? portByAvailability;
+ if (IsAvailablePort(port))
+ {
+ portByAvailability = port.Value;
+ }
+ else
+ {
+ portByAvailability = availabilityPortProvider.GetAvailablePort(startingPort, reservedPorts);
+ if (portByAvailability != null) reservedPorts.Add(portByAvailability.Value);
+ }
+
+ return portByAvailability;
+ }
+ }
+}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/ServiceCollectionExtensions.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/ServiceCollectionExtensions.cs
index bf279c6f2..77ddbe16f 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/ServiceCollectionExtensions.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/ServiceCollectionExtensions.cs
@@ -49,15 +49,16 @@ private static IServiceCollection AddDaprStarter(this IServiceCollection service
services.AddSingleton();
services.TryAddSingleton();
+ services.TryAddSingleton();
action.Invoke();
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetRequiredService>();
- var daprEnvironmentProvider = serviceProvider.GetRequiredService();
- daprEnvironmentProvider.CompleteDaprEnvironment(options.CurrentValue.DaprHttpPort, options.CurrentValue.DaprGrpcPort);
if (isDelay) return services.AddHostedService();
+ PortUtils.CheckCompletionPort(options.CurrentValue, serviceProvider);
+
ArgumentNullException.ThrowIfNull(options.CurrentValue.AppPort);
var daprProcess = serviceProvider.GetRequiredService();
daprProcess.Start();
@@ -65,8 +66,9 @@ private static IServiceCollection AddDaprStarter(this IServiceCollection service
}
+
+
private sealed class DaprService
{
-
}
}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/_Imports.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/_Imports.cs
index fc7e9a731..8b11e86ae 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/_Imports.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter.AspNetCore/_Imports.cs
@@ -2,13 +2,14 @@
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
global using Masa.BuildingBlocks.Development.DaprStarter;
-global using Masa.Contrib.Development.DaprStarter;
global using Masa.Contrib.Development.DaprStarter.AspNetCore;
global using Microsoft.AspNetCore.Hosting.Server;
global using Microsoft.AspNetCore.Hosting.Server.Features;
global using Microsoft.Extensions.Configuration;
+global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging;
global using Microsoft.Extensions.Options;
global using System.Diagnostics.CodeAnalysis;
+global using System.Net.NetworkInformation;
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/CommandLineBuilder.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/CommandLineBuilder.cs
index 80704841f..a05d2157b 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/CommandLineBuilder.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/CommandLineBuilder.cs
@@ -15,11 +15,11 @@ public CommandLineBuilder(string prefix)
Arguments = new();
}
- public CommandLineBuilder Add(string name, string value, bool isSkip = false)
+ public CommandLineBuilder Add(string name, Func valueFunc, bool isSkip = false)
{
if (!isSkip)
{
- Arguments.Add($"{Prefix}{name} {value}");
+ Arguments.Add($"{Prefix}{name} {valueFunc.Invoke()}");
}
return this;
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprEnvironmentProvider.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprEnvironmentProvider.cs
index bb1d11e7a..68042bc56 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprEnvironmentProvider.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprEnvironmentProvider.cs
@@ -9,10 +9,14 @@ public class DaprEnvironmentProvider : IDaprEnvironmentProvider
private const string HTTP_PORT = "DAPR_HTTP_PORT";
+ private const string METRICS_PORT = "DAPR_METRICS_PORT";
+
public ushort? GetHttpPort() => GetEnvironmentVariable(HTTP_PORT);
public ushort? GetGrpcPort() => GetEnvironmentVariable(GRPC_PORT);
+ public ushort? GetMetricsPort() => GetEnvironmentVariable(METRICS_PORT);
+
private static ushort? GetEnvironmentVariable(string environment)
{
if (ushort.TryParse(Environment.GetEnvironmentVariable(environment), out ushort port))
@@ -25,33 +29,32 @@ public bool TrySetHttpPort(ushort? httpPort)
{
if (httpPort is > 0)
{
- SetHttpPort(httpPort.Value);
+ Environment.SetEnvironmentVariable(HTTP_PORT, httpPort.Value.ToString());
return true;
}
+
return false;
}
- // ReSharper disable once InconsistentNaming
public bool TrySetGrpcPort(ushort? grpcPort)
{
if (grpcPort is > 0)
{
- SetGrpcPort(grpcPort.Value);
+ Environment.SetEnvironmentVariable(GRPC_PORT, grpcPort.Value.ToString());
return true;
}
+
return false;
}
- public void SetHttpPort(ushort httpPort) => Environment.SetEnvironmentVariable(HTTP_PORT, httpPort.ToString());
-
- // ReSharper disable once InconsistentNaming
- public void SetGrpcPort(ushort grpcPort) => Environment.SetEnvironmentVariable(GRPC_PORT, grpcPort.ToString());
-
- // ReSharper disable once InconsistentNaming
- public void CompleteDaprEnvironment(ushort? httpPort, ushort? grpcPort)
+ public bool TrySetMetricsPort(ushort? metricsPort)
{
- if (grpcPort is > 0) SetGrpcPort(grpcPort.Value);
+ if (metricsPort is > 0)
+ {
+ Environment.SetEnvironmentVariable(METRICS_PORT, metricsPort.Value.ToString());
+ return true;
+ }
- if (httpPort is > 0) SetHttpPort(httpPort.Value);
+ return false;
}
}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcess.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcess.cs
index b4f6c9871..ae8028868 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcess.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcess.cs
@@ -8,62 +8,67 @@ public class DaprProcess : DaprProcessBase, IDaprProcess
{
private readonly object _lock = new();
- private readonly IDaprProvider _daprProvider;
+ private readonly IDaprProcessProvider _daprProcessProvider;
private readonly IProcessProvider _processProvider;
private readonly ILogger? _logger;
- private readonly IOptionsMonitor _daprOptions;
private DaprProcessStatus Status { get; set; }
- private System.Timers.Timer? _heartBeatTimer;
- private Process? _process;
- private int _retryTime;
///
- /// record whether dapr is initialized for the first time
+ /// A sidecar that is terminated by the user or the system can only be started by start
///
- private bool _isFirst = true;
+ private bool _isStopByManually;
+
+ private System.Timers.Timer? _heartBeatTimer;
+ private Process? _process;
+ private int _retryTime;
public DaprProcess(
- IDaprProvider daprProvider,
+ IDaprProcessProvider daprProcessProvider,
IProcessProvider processProvider,
IOptionsMonitor daprOptions,
IDaprEnvironmentProvider daprEnvironmentProvider,
- ILogger? logger = null,
- IOptions? masaAppConfigureOptions = null) : base(daprEnvironmentProvider, masaAppConfigureOptions)
+ IDaprProvider daprProvide,
+ ILogger? logger = null)
+ : base(daprEnvironmentProvider, daprProvide, daprOptions)
{
- _daprProvider = daprProvider;
+ _daprProcessProvider = daprProcessProvider;
_processProvider = processProvider;
_logger = logger;
- _daprOptions = daprOptions;
daprOptions.OnChange(Refresh);
}
public void Start()
{
+ if (Status == DaprProcessStatus.Started)
+ {
+ _logger?.LogInformation("The sidecar has been successfully started. If you want to restart, please stop and start again");
+ return;
+ }
+
lock (_lock)
{
- var options = ConvertToDaprCoreOptions(_daprOptions.CurrentValue);
+ _isStopByManually = false;
+ var sidecarOptions = ConvertToSidecarOptions(DaprOptions.CurrentValue);
- StartCore(options);
+ StartCore(sidecarOptions);
}
}
- private void StartCore(DaprCoreOptions options)
+ private void StartCore(SidecarOptions options)
{
UpdateStatus(DaprProcessStatus.Starting);
var commandLineBuilder = CreateCommandLineBuilder(options);
- StopCore(SuccessDaprOptions);
-
- if (_isFirst)
- {
- CompleteDaprEnvironment(options.DaprHttpPort, options.DaprGrpcPort);
- }
- _process = _daprProvider.DaprStart(
+ _process = _daprProcessProvider.DaprStart(
+ GetDefaultSidecarFileName(),
commandLineBuilder.ToString(),
options.CreateNoWindow,
(_, args) =>
{
- if (_isFirst) CheckAndCompleteDaprEnvironment(args.Data);
+ if (args.Data == null)
+ return;
+
+ if (IsFirst) CheckAndCompleteDaprEnvironment(args.Data);
}, () => UpdateStatus(DaprProcessStatus.Stopped));
_retryTime = 0;
@@ -81,96 +86,123 @@ private void StartCore(DaprCoreOptions options)
{
_heartBeatTimer?.Start();
}
- }
- public void CompleteDaprEnvironment(ushort? httpPort, ushort? grpcPort)
- {
- var setHttpPortResult = DaprEnvironmentProvider.TrySetHttpPort(httpPort);
- if (setHttpPortResult)
- {
- SuccessDaprOptions!.TrySetHttpPort(httpPort);
- _logger?.LogInformation("Update Dapr environment variables, DaprHttpPort: {HttpPort}", httpPort);
- }
+ // Register the child process to the job object to ensure that the child process terminates when the parent process terminates
+ // Windows only
- var setGrpcPortResult = DaprEnvironmentProvider.TrySetGrpcPort(grpcPort);
- if (setGrpcPortResult)
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
- SuccessDaprOptions!.TrySetGrpcPort(grpcPort);
- _logger?.LogInformation("Update Dapr environment variables, DAPR_GRPC_PORT: {grpcPort}", grpcPort);
+ //Only supported on windows
+ return;
}
-
- if (setHttpPortResult && setGrpcPortResult) _isFirst = false;
+ ChildProcessTracker.AddProcess(_process);
}
- public void CheckAndCompleteDaprEnvironment(string? data)
+ private void CheckAndCompleteDaprEnvironment(string data)
{
- if (data == null)
- return;
-
var httpPort = GetHttpPort(data);
- var grpcPort = GetgRPCPort(data);
+ var grpcPort = GetGrpcPort(data);
- CompleteDaprEnvironment(httpPort, grpcPort);
+ SuccessDaprOptions!.TrySetHttpPort(httpPort);
+ SuccessDaprOptions!.TrySetGrpcPort(grpcPort);
+ CompleteDaprEnvironment();
}
- public void Stop()
+ private void CompleteDaprEnvironment()
{
- lock (_lock)
+ if (SuccessDaprOptions!.DaprHttpPort is > 0 && SuccessDaprOptions!.DaprGrpcPort is > 0)
{
- StopCore(SuccessDaprOptions);
- _heartBeatTimer?.Stop();
+ DaprEnvironmentProvider.TrySetHttpPort(SuccessDaprOptions.DaprHttpPort);
+ DaprEnvironmentProvider.TrySetGrpcPort(SuccessDaprOptions.DaprGrpcPort);
+ IsFirst = false;
+ _retryTime = 0;
+ UpdateStatus(DaprProcessStatus.Started);
}
}
- private void StopCore(DaprCoreOptions? options)
+ ///
+ /// Only stop sidecars started by the current program
+ ///
+ public void Stop()
{
- if (options != null)
+ lock (_lock)
{
- // In https mode, the dapr process cannot be stopped by dapr stop
- if (options.EnableSsl is true)
- {
- _process?.Kill();
- }
- else
+ switch (Status)
{
- _daprProvider.DaprStop(options.AppId);
+ case DaprProcessStatus.Stopped:
+ _logger?.LogDebug("dapr sidecar stopped, do not repeat stop");
+ return;
+ case DaprProcessStatus.Stopping:
+ _logger?.LogDebug("dapr sidecar is stopping, do not repeat, please wait...");
+ return;
+ default:
+ if (SuccessDaprOptions == null)
+ {
+ _logger?.LogDebug("There is no dapr sidecar successfully launched by the current program");
+ return;
+ }
+
+ UpdateStatus(DaprProcessStatus.Stopping);
+ StopCore();
+ _heartBeatTimer?.Stop();
+ _isStopByManually = true;
+ return;
}
+ }
+ }
- if (options.DaprHttpPort != null)
- CheckPortAndKill(options.DaprHttpPort.Value);
- if (options.DaprGrpcPort != null)
- CheckPortAndKill(options.DaprGrpcPort.Value);
+ private void StopCore()
+ {
+ // In https mode, the dapr process cannot be stopped by dapr stop
+ _process?.Kill();
+ if (SuccessDaprOptions!.EnableSsl is not true)
+ {
+ _daprProcessProvider.DaprStop(GetDefaultDaprFileName(), SuccessDaprOptions.AppId);
}
+
+ if (SuccessDaprOptions.DaprHttpPort != null)
+ CheckPortAndKill(SuccessDaprOptions.DaprHttpPort.Value);
+ if (SuccessDaprOptions.DaprGrpcPort != null)
+ CheckPortAndKill(SuccessDaprOptions.DaprGrpcPort.Value);
+
+ UpdateStatus(DaprProcessStatus.Stopped);
}
///
/// Refresh the dapr configuration, the source dapr process will be killed and the new dapr process will be restarted
///
///
- public void Refresh(DaprOptions options)
+ private void Refresh(DaprOptions options)
{
lock (_lock)
{
- _logger?.LogDebug("Dapr configuration refresh, Dapr AppId is {AppId}, please wait...", SuccessDaprOptions!.AppId);
+ if (_isStopByManually)
+ {
+ _logger?.LogDebug("configuration update, you need to start dapr through Start (Restart is not supported due to manual stop of sidecar)");
+ return;
+ }
+ var sidecarOptionsByRefresh = ConvertToSidecarOptions(options);
if (SuccessDaprOptions != null)
{
- options.AppPort = SuccessDaprOptions.AppPort;
- options.EnableSsl = SuccessDaprOptions.EnableSsl;
- options.DaprHttpPort = SuccessDaprOptions.DaprHttpPort;
- options.DaprGrpcPort = SuccessDaprOptions.DaprGrpcPort;
+ sidecarOptionsByRefresh.AppPort ??= SuccessDaprOptions.AppPort;
+ sidecarOptionsByRefresh.EnableSsl ??= SuccessDaprOptions.EnableSsl;
+ sidecarOptionsByRefresh.DaprHttpPort ??= SuccessDaprOptions.DaprHttpPort;
+ sidecarOptionsByRefresh.DaprGrpcPort ??= SuccessDaprOptions.DaprGrpcPort;
+
+ if (sidecarOptionsByRefresh.Equals(SuccessDaprOptions))
+ {
+ return;
+ }
UpdateStatus(DaprProcessStatus.Restarting);
- _logger?.LogDebug(
- "Dapr configuration refresh, Dapr AppId is {AppId}, closing dapr, please wait...",
- SuccessDaprOptions!.AppId);
- StopCore(SuccessDaprOptions);
+ StopCore();
}
- _isFirst = true;
+ IsFirst = true;
SuccessDaprOptions = null;
- _logger?.LogDebug("Dapr configuration refresh, Dapr AppId is {AppId}, restarting dapr, please wait...", options.AppId);
- StartCore(ConvertToDaprCoreOptions(options));
+ _logger?.LogDebug("Dapr sidecar configuration updated, Dapr AppId is {AppId}, restarting dapr, please wait...", options.AppId);
+ StartCore(sidecarOptionsByRefresh);
}
}
@@ -186,7 +218,7 @@ private void CheckPortAndKill(ushort port)
port,
pId,
process.Name,
- Constant.DEFAULT_FILE_NAME);
+ DaprStarterConstant.DEFAULT_PROCESS_NAME);
process.Kill();
}
}
@@ -196,45 +228,53 @@ private void HeartBeat()
{
lock (_lock)
{
- if (SuccessDaprOptions!.EnableSsl is true)
- {
- _logger?.LogDebug("The dapr status cannot be monitored in https mode, the check has been skipped");
+ if (SuccessDaprOptions == null)
return;
+
+ var daprList = _daprProcessProvider.GetDaprList(GetDefaultDaprFileName(), SuccessDaprOptions.AppId, out bool isException);
+ if (daprList.Count > 1)
+ {
+ _logger?.LogDebug("dapr sidecar appears more than 1 same appid, this may cause error");
}
- if (!_daprProvider.IsExist(SuccessDaprOptions!.AppId))
+ if (!daprList.Any())
{
- if (Status == DaprProcessStatus.Started || Status == DaprProcessStatus.Stopped)
- {
- _logger?.LogWarning("Dapr stopped, restarting, please wait...");
- StartCore(SuccessDaprOptions);
- }
- else if (Status == DaprProcessStatus.Starting)
+ if(isException)
+ return;
+
+ switch (Status)
{
- if (_retryTime < Constant.DEFAULT_RETRY_TIME)
- {
+ case DaprProcessStatus.Started:
+ _logger?.LogWarning("Dapr sidecar terminated abnormally, restarting, please wait...");
+ StartCore(SuccessDaprOptions);
+ break;
+ case DaprProcessStatus.Starting when _retryTime < DaprStarterConstant.DEFAULT_RETRY_TIME:
_retryTime++;
_logger?.LogDebug("Dapr is not started: The {Retries}th heartbeat check. AppId is {AppId}",
_retryTime,
SuccessDaprOptions.AppId);
- }
- else
- {
+ break;
+ case DaprProcessStatus.Starting:
_logger?.LogWarning(
"Dapr is not started: The {Retries}th heartbeat check. Dapr stopped, restarting, please wait...",
_retryTime + 1);
StartCore(SuccessDaprOptions);
- }
- }
- else
- {
- _logger?.LogWarning("Dapr is restarting, the current state is {State}, please wait...", Status);
+ break;
+ case DaprProcessStatus.Restarting:
+ _logger?.LogWarning("Dapr is restarting, the current state is {State}, please wait...", Status);
+ break;
}
}
else
{
- _retryTime = 0;
- UpdateStatus(DaprProcessStatus.Started);
+ if (Status == DaprProcessStatus.Starting)
+ {
+ // Execute only when getting HttpPort, gRPCPort exception
+ var daprSidecar = daprList.First();
+ SuccessDaprOptions.TrySetHttpPort(daprSidecar.HttpPort);
+ SuccessDaprOptions.TrySetGrpcPort(daprSidecar.GrpcPort);
+ UpdateStatus(DaprProcessStatus.Started);
+ }
}
}
}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcessBase.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcessBase.cs
index df1caef81..0e0c21fba 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcessBase.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProcessBase.cs
@@ -6,112 +6,203 @@ namespace Masa.Contrib.Development.DaprStarter;
[ExcludeFromCodeCoverage]
public abstract class DaprProcessBase
{
- private readonly IOptions? _masaAppConfigureOptions;
-
protected IDaprEnvironmentProvider DaprEnvironmentProvider { get; }
- ///
- /// Use after getting dapr AppId and global AppId fails
- ///
- private static readonly string DefaultAppId = (Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly()).GetName().Name!.Replace(
- ".",
- Constant.DEFAULT_APPID_DELIMITER);
+ private readonly IDaprProvider _daprProvider;
- private const string HTTP_PORT_PATTERN = @"HTTP Port: ([0-9]+)";
- private const string GRPC_PORT_PATTERN = @"gRPC Port: ([0-9]+)";
+ private static readonly string[] HttpPortPatterns = { "http server is running on port ([0-9]+)" };
+ private static readonly string[] GrpcPortPatterns = { "API gRPC server is running on port ([0-9]+)" };
+ private static readonly string UserFilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
- internal DaprCoreOptions? SuccessDaprOptions;
+ internal SidecarOptions? SuccessDaprOptions;
+ protected readonly IOptionsMonitor DaprOptions;
+ private static string? _defaultDaprFileName;
+ private static string? _defaultSidecarFileName;
+
+ ///
+ /// record whether dapr is initialized for the first time
+ ///
+ protected bool IsFirst = true;
- protected DaprProcessBase(IDaprEnvironmentProvider daprEnvironmentProvider, IOptions? masaAppConfigureOptions)
+ protected DaprProcessBase(
+ IDaprEnvironmentProvider daprEnvironmentProvider,
+ IDaprProvider daprProvider,
+ IOptionsMonitor daprOptions)
{
DaprEnvironmentProvider = daprEnvironmentProvider;
- _masaAppConfigureOptions = masaAppConfigureOptions;
+ _daprProvider = daprProvider;
+ DaprOptions = daprOptions;
}
- internal DaprCoreOptions ConvertToDaprCoreOptions(DaprOptions options)
+ internal SidecarOptions ConvertToSidecarOptions(DaprOptions options)
{
- var appId = options.AppId;
- if (appId.IsNullOrWhiteSpace())
- appId = _masaAppConfigureOptions?.Value.AppId;
- if (appId.IsNullOrWhiteSpace())
- appId = DefaultAppId;
- if (options.IsIncompleteAppId())
- appId = $"{appId}{options.AppIdDelimiter}{options.AppIdSuffix ?? NetworkUtils.GetPhysicalAddress()}";
- DaprCoreOptions
- dataOptions = new(
- appId!,
- options.AppPort ?? throw new ArgumentNullException(nameof(options), $"{options.AppPort} must be greater than 0"),
- options.AppProtocol,
- options.EnableSsl,
- options.DaprGrpcPort ?? DaprEnvironmentProvider.GetGrpcPort(),
- options.DaprHttpPort ?? DaprEnvironmentProvider.GetHttpPort(),
- options.EnableHeartBeat)
- {
- HeartBeatInterval = options.HeartBeatInterval,
- CreateNoWindow = options.CreateNoWindow,
- MaxConcurrency = options.MaxConcurrency,
- Config = options.Config,
- ComponentPath = options.ComponentPath,
- EnableProfiling = options.EnableProfiling,
- Image = options.Image,
- LogLevel = options.LogLevel,
- PlacementHostAddress = options.PlacementHostAddress,
- SentryAddress = options.PlacementHostAddress,
- MetricsPort = options.MetricsPort,
- ProfilePort = options.ProfilePort,
- UnixDomainSocket = options.UnixDomainSocket,
- DaprMaxRequestSize = options.DaprMaxRequestSize
- };
- return dataOptions;
+ var sidecarOptions = new SidecarOptions(
+ _daprProvider.CompletionAppId(options.AppId),
+ options.AppPort,
+ options.AppProtocol,
+ options.EnableSsl)
+ {
+ EnableHeartBeat = options.EnableHeartBeat,
+ HeartBeatInterval = options.HeartBeatInterval,
+ CreateNoWindow = options.CreateNoWindow,
+ MaxConcurrency = options.MaxConcurrency,
+ Config = options.Config,
+ ComponentPath = options.ComponentPath,
+ EnableProfiling = options.EnableProfiling,
+ LogLevel = options.LogLevel,
+ SentryAddress = options.SentryAddress,
+ MetricsPort = options.MetricsPort,
+ ProfilePort = options.ProfilePort,
+ UnixDomainSocket = options.UnixDomainSocket,
+ DaprHttpMaxRequestSize = options.DaprHttpMaxRequestSize,
+ PlacementHostAddress = options.PlacementHostAddress,
+ AllowedOrigins = options.AllowedOrigins,
+ ControlPlaneAddress = options.ControlPlaneAddress,
+ DaprHttpReadBufferSize = options.DaprHttpReadBufferSize,
+ DaprInternalGrpcPort = options.DaprInternalGrpcPort,
+ EnableApiLogging = options.EnableApiLogging,
+ EnableMetrics = options.EnableMetrics,
+ Mode = options.Mode,
+ RootPath = options.RootPath,
+ DaprRootPath = options.DaprRootPath,
+ ExtendedParameter = options.ExtendedParameter
+ };
+ sidecarOptions.TrySetHttpPort(options.DaprHttpPort ?? DaprEnvironmentProvider.GetHttpPort());
+ sidecarOptions.TrySetGrpcPort(options.DaprGrpcPort ?? DaprEnvironmentProvider.GetGrpcPort());
+ sidecarOptions.TrySetMetricsPort(options.MetricsPort ?? DaprEnvironmentProvider.GetMetricsPort());
+
+ if (sidecarOptions.EnableDefaultPlacementHostAddress && sidecarOptions.PlacementHostAddress.IsNullOrWhiteSpace())
+ {
+ var port = Environment.OSVersion.Platform == PlatformID.Win32NT ? 6050 : 50005;
+ sidecarOptions.PlacementHostAddress = $"127.0.0.1:{port}";
+ }
+
+ if (sidecarOptions.RootPath.IsNullOrWhiteSpace())
+ {
+ sidecarOptions.RootPath = Path.Combine(UserFilePath, ".dapr");
+ }
+
+ if (sidecarOptions.DaprRootPath.IsNullOrWhiteSpace())
+ {
+ sidecarOptions.DaprRootPath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\dapr" : "/usr/local/bin";
+ }
+
+ if (sidecarOptions.ComponentPath.IsNullOrWhiteSpace())
+ {
+ sidecarOptions.ComponentPath = "components";
+ }
+
+ if (sidecarOptions.Config.IsNullOrWhiteSpace())
+ {
+ sidecarOptions.Config = "config.yaml";
+ }
+
+ return sidecarOptions;
}
- internal CommandLineBuilder CreateCommandLineBuilder(DaprCoreOptions options)
+ internal CommandLineBuilder CreateCommandLineBuilder(SidecarOptions options)
{
- var commandLineBuilder = new CommandLineBuilder(Constant.DEFAULT_ARGUMENT_PREFIX);
+ var commandLineBuilder = new CommandLineBuilder(DaprStarterConstant.DEFAULT_ARGUMENT_PREFIX);
commandLineBuilder
- .Add("app-id", options.AppId)
- .Add("app-port", options.AppPort.ToString())
- .Add("app-protocol", options.AppProtocol?.ToString().ToLower() ?? string.Empty, options.AppProtocol == null)
- .Add("app-ssl", "", options.EnableSsl != true)
- .Add("components-path", options.ComponentPath ?? string.Empty, options.ComponentPath == null)
- .Add("app-max-concurrency", options.MaxConcurrency?.ToString() ?? string.Empty, options.MaxConcurrency == null)
- .Add("config", options.Config ?? string.Empty, options.Config == null)
- .Add("dapr-grpc-port", options.DaprGrpcPort?.ToString() ?? string.Empty, !(options.DaprGrpcPort > 0))
- .Add("dapr-http-port", options.DaprHttpPort?.ToString() ?? string.Empty, !(options.DaprHttpPort > 0))
- .Add("enable-profiling", options.EnableProfiling?.ToString().ToLower() ?? string.Empty, options.EnableProfiling == null)
- .Add("image", options.Image ?? string.Empty, options.Image == null)
- .Add("log-level", options.LogLevel?.ToString().ToLower() ?? string.Empty, options.LogLevel == null)
- .Add("placement-host-address", options.PlacementHostAddress ?? string.Empty, options.PlacementHostAddress == null)
- .Add("sentry-address", options.SentryAddress ?? string.Empty, options.SentryAddress == null)
- .Add("metrics-port", options.MetricsPort?.ToString() ?? string.Empty, options.MetricsPort == null)
- .Add("profile-port", options.ProfilePort?.ToString() ?? string.Empty, options.ProfilePort == null)
- .Add("unix-domain-socket", options.UnixDomainSocket ?? string.Empty, options.UnixDomainSocket == null)
- .Add("dapr-http-max-request-size", options.DaprMaxRequestSize?.ToString() ?? string.Empty, options.DaprMaxRequestSize == null);
-
- SuccessDaprOptions ??= options;
+ .Add("app-id", () => options.AppId)
+ .Add("app-port", () => options.GetAppPort().ToString())
+ .Add("app-protocol", () => options.AppProtocol!.Value.ToString().ToLower(), options.AppProtocol == null)
+ .Add("app-ssl", () => "", options.EnableSsl != true)
+ .Add("components-path", () => Path.Combine(options.RootPath, options.ComponentPath))
+ .Add("app-max-concurrency", () => options.MaxConcurrency!.Value.ToString(), options.MaxConcurrency == null)
+ .Add("config", () => Path.Combine(options.RootPath, options.Config))
+ .Add("dapr-grpc-port", () => options.DaprGrpcPort!.Value.ToString(), !(options.DaprGrpcPort > 0))
+ .Add("dapr-http-port", () => options.DaprHttpPort!.Value.ToString(), !(options.DaprHttpPort > 0))
+ .Add("enable-profiling", () => options.EnableProfiling!.Value.ToString().ToLower(), options.EnableProfiling == null)
+ .Add("log-level", () => options.LogLevel!.Value.ToString().ToLower(), options.LogLevel == null)
+ .Add("sentry-address", () => options.SentryAddress!, options.SentryAddress == null)
+ .Add("metrics-port", () => options.MetricsPort!.Value.ToString(), options.MetricsPort == null)
+ .Add("profile-port", () => options.ProfilePort!.Value.ToString(), options.ProfilePort == null)
+ .Add("unix-domain-socket", () => options.UnixDomainSocket!, options.UnixDomainSocket == null)
+ .Add("dapr-http-max-request-size", () => options.DaprHttpMaxRequestSize!.Value.ToString(),
+ options.DaprHttpMaxRequestSize == null)
+ .Add("placement-host-address", () => options.PlacementHostAddress, options.PlacementHostAddress.IsNullOrWhiteSpace())
+ .Add("allowed-origins", () => options.AllowedOrigins, options.AllowedOrigins.IsNullOrWhiteSpace())
+ .Add("control-plane-address", () => options.ControlPlaneAddress, options.ControlPlaneAddress.IsNullOrWhiteSpace())
+ .Add("dapr-http-read-buffer-size", () => options.DaprHttpReadBufferSize!.Value.ToString(),
+ options.DaprHttpReadBufferSize == null)
+ .Add("dapr-internal-grpc-port", () => options.DaprInternalGrpcPort!.Value.ToString(), options.DaprInternalGrpcPort == null)
+ .Add("enable-api-logging", () => "", options.EnableApiLogging is not true)
+ .Add("enable-metrics", () => "", options.EnableMetrics is not true)
+ .Add("mode", () => options.Mode, options.Mode.IsNullOrWhiteSpace())
+ .Add(options.ExtendedParameter, () => "", options.ExtendedParameter.IsNullOrWhiteSpace());
+
+ if (!IsFirst)
+ return commandLineBuilder;
+
+ SetDefaultFileName(options.DaprRootPath, options.RootPath);
+ SuccessDaprOptions = options;
+
return commandLineBuilder;
}
-#pragma warning disable S6444
- protected static ushort GetHttpPort(string data)
+
+ #region GetHttpPort、GetGrpcPort
+
+ ///
+ /// Get the HttpPort according to the output, but it is unreliable
+ /// After the prompt information output by dapr is adjusted, it may cause the failure to obtain the port
+ ///
+ ///
+ ///
+ protected static ushort? GetHttpPort(string data)
{
- ushort httpPort = 0;
- var httpPortMatch = Regex.Matches(data, HTTP_PORT_PATTERN);
- if (httpPortMatch.Count > 0)
+ foreach (var pattern in HttpPortPatterns)
{
- httpPort = ushort.Parse(httpPortMatch[0].Groups[1].ToString());
+ var port = GetPort(data, pattern);
+ if (port is > 0)
+ return port;
}
- return httpPort;
+
+ return null;
}
- protected static ushort GetgRPCPort(string data)
+ static ushort? GetPort(string data, string pattern)
{
- ushort grpcPort = 0;
- var gRPCPortMatch = Regex.Matches(data, GRPC_PORT_PATTERN);
- if (gRPCPortMatch.Count > 0)
+ ushort? port = null;
+ var regex = new Regex(pattern, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1));
+ var match = regex.Matches(data);
+ if (match.Count > 0)
{
- grpcPort = ushort.Parse(gRPCPortMatch[0].Groups[1].ToString());
+ port = ushort.Parse(match[0].Groups[1].ToString());
}
- return grpcPort;
+
+ return port;
+ }
+
+ ///
+ /// Get the gRpcPort according to the output, but it is unreliable
+ /// After the prompt information output by dapr is adjusted, it may cause the failure to obtain the port
+ ///
+ ///
+ ///
+ protected static ushort? GetGrpcPort(string data)
+ {
+ foreach (var pattern in GrpcPortPatterns)
+ {
+ var port = GetPort(data, pattern);
+ if (port is > 0)
+ return port;
+ }
+
+ return null;
+ }
+
+ #endregion
+
+ static string GetFileName(string fileName) => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"{fileName}.exe" : fileName;
+
+ protected static string GetDefaultDaprFileName() => _defaultDaprFileName!;
+
+ protected static string GetDefaultSidecarFileName() => _defaultSidecarFileName!;
+
+ private static void SetDefaultFileName(string daprRootPath, string sidecarRootPath)
+ {
+ _defaultDaprFileName = Path.Combine(daprRootPath, GetFileName(DaprStarterConstant.DEFAULT_DAPR_FILE_NAME));
+ _defaultSidecarFileName = Path.Combine(sidecarRootPath, "bin", GetFileName(DaprStarterConstant.DEFAULT_FILE_NAME));
}
-#pragma warning restore S6444
}
diff --git a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProvider.cs b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProvider.cs
index 7faa4fc44..41fd540e4 100644
--- a/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProvider.cs
+++ b/src/Contrib/Development/Masa.Contrib.Development.DaprStarter/DaprProvider.cs
@@ -4,25 +4,24 @@
namespace Masa.Contrib.Development.DaprStarter;
[ExcludeFromCodeCoverage]
-public class DaprProvider : IDaprProvider
+public class DaprProcessProvider : IDaprProcessProvider
{
- private readonly ILoggerFactory? _loggerFactory;
- private readonly ILogger? _logger;
+ private readonly ILogger? _logger;
- public DaprProvider(ILoggerFactory? loggerFactory)
+ public DaprProcessProvider(ILogger? logger = null)
{
- _loggerFactory = loggerFactory;
- _logger = loggerFactory?.CreateLogger();
+ _logger = logger;
}
- public List GetDaprList(string appId)
+ public List GetDaprList(string fileName, string appId, out bool isException)
{
- var processUtils = new ProcessUtils(_loggerFactory);
+ isException = false;
+ var processUtils = new ProcessUtils(_logger);
processUtils.Exit += delegate
{
- _logger?.LogDebug("{Name} process has exited", Constant.DEFAULT_FILE_NAME);
+ _logger?.LogDebug("{Name} process has exited, appid: {AppId}", DaprStarterConstant.DEFAULT_PROCESS_NAME, appId);
};
- processUtils.Run(Constant.DEFAULT_FILE_NAME, "list -o json", out string response, true, true);
+ processUtils.Run(fileName, "list -o json", out string response, true, true);
List daprList = new();
try
{
@@ -45,18 +44,21 @@ public List GetDaprList(string appId)
}
catch (Exception exception)
{
+ isException = true;
_logger?.LogWarning(exception, "----- Error getting list of running dapr, response message is {Response}", response);
return new List();
}
+
return daprList.Where(dapr => dapr.AppId == appId).ToList();
}
- public Process DaprStart(string arguments,
+ public Process DaprStart(string fileName,
+ string arguments,
bool createNoWindow,
Action