Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: publish logs #10

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/ATech.Ring.DotNet.Cli/Abstractions/Runnable.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Queil.Ring.Protocol.Events;

namespace ATech.Ring.DotNet.Cli.Abstractions;

using System;
Expand Down Expand Up @@ -61,6 +63,11 @@ protected virtual async Task RecoverAsync(TContext ctx, CancellationToken token)
await _fsm.FireAsync(Trigger.Start);
}

protected virtual void PublishLogs(string line)
{
Sender.Enqueue(Message.RunnableLogs(new RunnableLogLine { RunnableId = UniqueId, Line = line }));
}

private async Task<Fsm> InitFsm(CancellationToken token)
{
_fsm.Configure(State.Zero)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ protected override async Task<AspNetCoreContext> InitAsync(CancellationToken tok

protected override async Task StartAsync(AspNetCoreContext ctx, CancellationToken token)
{
var info = await Dotnet.RunAsync(ctx, token, ctx.Urls);
var info = await Dotnet.RunAsync(ctx, ctx.Urls, PublishLogs, token);
ctx.ProcessId = info.Pid;
ctx.Output = info.Output;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected override async Task<TContext> InitAsync(CancellationToken token)

protected override async Task StartAsync(TContext ctx, CancellationToken token)
{
var info = await Dotnet.RunAsync(ctx, token);
var info = await Dotnet.RunAsync(ctx, logger: PublishLogs, token:token);
ctx.ProcessId = info.Pid;
ctx.Output = info.Output;
}
Expand Down
7 changes: 4 additions & 3 deletions src/ATech.Ring.DotNet.Cli/Runnables/Proc/ProcRunnable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class ProcRunnable : ProcessRunnable<ProcContext, Queil.Ring.Configuratio
private readonly ProcessRunner _runner;

public ProcRunnable(Queil.Ring.Configuration.Runnables.Proc config,
ILogger<ProcessRunnable<ProcContext, Queil.Ring.Configuration.Runnables.Proc>> logger,
ILogger<ProcessRunnable<ProcContext, Queil.Ring.Configuration.Runnables.Proc>> logger,
ISender sender,
ProcessRunner runner) : base(config, logger, sender)
{
Expand All @@ -31,7 +31,8 @@ public ProcRunnable(Queil.Ring.Configuration.Runnables.Proc config,

protected override async Task StartAsync(ProcContext ctx, CancellationToken token)
{
var info = await _runner.RunProcessAsync(Config.WorkingDir, Config.Env, Config.Args, token);
var info = await _runner.RunProcessAsync(workingDir: Config.WorkingDir, onData: PublishLogs , envVars: Config.Env, args: Config.Args,
token: token);
ctx.ProcessId = info.Pid;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public class NetExeRunnable : CsProjRunnable<NetExeContext, NetExeConfig>

public NetExeRunnable(
NetExeConfig config,
ProcessRunner processRunner,
ILogger<NetExeRunnable> logger,
ProcessRunner processRunner,
ILogger<NetExeRunnable> logger,
ISender sender) : base(config, logger, sender)
{
_processRunner = processRunner;
Expand All @@ -41,8 +41,8 @@ protected override NetExeContext CreateContext()
protected override async Task StartAsync(NetExeContext ctx, CancellationToken token)
{
_processRunner.Command = ctx.EntryAssemblyPath;
var result = await _processRunner.RunProcessAsync(Config.Args, token);
var result = await _processRunner.RunProcessAsync(args: Config.Args, onData: PublishLogs, token: token);
ctx.ProcessId = result.Pid;
ctx.Output = result.Output;
}
}
}
2 changes: 1 addition & 1 deletion src/ATech.Ring.DotNet.Cli/Tools/DockerCompose.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public async Task<ExecutionInfo> PullAsync(string composeFilePath, CancellationT

public async Task<ExecutionInfo> UpAsync(string composeFilePath, CancellationToken token)
{
return await this.RunProcessAsync(new object[] { "-f", $"\"{composeFilePath}\"", "up", "--force-recreate" }, token);
return await this.RunProcessAsync(args: new object[] { "-f", $"\"{composeFilePath}\"", "up", "--force-recreate" }, token: token);
}

public async Task<ExecutionInfo> DownAsync(string composeFilePath, CancellationToken token)
Expand Down
6 changes: 3 additions & 3 deletions src/ATech.Ring.DotNet.Cli/Tools/DotnetCliBundle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ public DotnetCliBundle(ProcessRunner processRunner, ILogger<DotnetCliBundle> log
Logger = logger;
}

public async Task<ExecutionInfo> RunAsync(DotnetContext ctx, CancellationToken token, string[]? urls = null)
public async Task<ExecutionInfo> RunAsync(DotnetContext ctx, string[]? urls = null, Action<string>? logger=null, CancellationToken token=default)
{
HandleUrls();
if (File.Exists(ctx.ExePath))
{
_processRunner.Command = ctx.ExePath;
return await _processRunner.RunProcessAsync(ctx.WorkingDir, DefaultEnvVars, null, token);
return await _processRunner.RunProcessAsync(ctx.WorkingDir, DefaultEnvVars, onData: logger, token:token);
}
if (File.Exists(ctx.EntryAssemblyPath))
{
// Using dotnet exec here because dotnet run spawns subprocesses and killing it doesn't actually kill them
return await this.RunProcessAsync(ctx.WorkingDir, DefaultEnvVars, new object[] { "exec", $"\"{ctx.EntryAssemblyPath}\"" }, token);
return await this.RunProcessAsync(ctx.WorkingDir, DefaultEnvVars, new object[] { "exec", $"\"{ctx.EntryAssemblyPath}\"" }, token:token);
}
throw new InvalidOperationException($"Neither Exe path nor Dll path specified. {ctx.CsProjPath}");

Expand Down
17 changes: 6 additions & 11 deletions src/ATech.Ring.DotNet.Cli/Tools/ToolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,9 @@ public static Task<ExecutionInfo> RunProcessWaitAsync(this ITool tool, Cancellat
public static Task<ExecutionInfo> RunProcessWaitAsync(this ITool tool, object[] args, CancellationToken token)
=> tool.RunProcessCoreAsync(args: args, wait: true, token: token);

public static Task<ExecutionInfo> RunProcessAsync(this ITool tool, object[] args, CancellationToken token)
=> tool.RunProcessCoreAsync(args, token: token);

public static Task<ExecutionInfo> RunProcessAsync(this ITool tool, string workingDirectory,
IDictionary<string, string>? envVars, object[]? args, CancellationToken token)
=> tool.RunProcessCoreAsync(args, envVars: envVars, workingDirectory: workingDirectory, captureStdOut: false,
token: token);

public static Task<ExecutionInfo> RunProcessAsync(this ITool tool, Action<string> onErrorData,
IDictionary<string, string>? envVars, object[]? args, CancellationToken token)
=> tool.RunProcessCoreAsync(args: args, onErrorData: onErrorData, envVars: envVars, token: token);
public static Task<ExecutionInfo> RunProcessAsync(this ITool tool, string? workingDir = null,
IDictionary<string, string>? envVars = null, object[]? args = null, Action<string>? onData = null, Action<string>? onErrorData =null, CancellationToken token=default)
=> tool.RunProcessCoreAsync(workingDirectory: workingDir, args: args, onErrorData: onErrorData, onData: onData, envVars: envVars, token: token);

//TODO: this should be configurable
private static readonly string[] FailureWords = { "err", "error", "fail" };
Expand All @@ -72,6 +64,7 @@ private static async Task<ExecutionInfo> RunProcessCoreAsync(this ITool tool,
string? workingDirectory = null,
IDictionary<string, string>? envVars = null,
Action<string>? onErrorData = null,
Action<string>? onData = null,
bool captureStdOut = true,
CancellationToken token = default)
{
Expand All @@ -86,6 +79,8 @@ private static async Task<ExecutionInfo> RunProcessCoreAsync(this ITool tool,
void OnData(object _, DataReceivedEventArgs line)
{
if (line.Data == null) return;
onData?.Invoke(line.Data);

if (captureStdOut) sb.AppendLine(line.Data);

if (FailureWords.Any(x => line.Data.Contains(x, StringComparison.OrdinalIgnoreCase)))
Expand Down
14 changes: 9 additions & 5 deletions src/ATech.Ring.DotNet.Cli/Tools/Windows/IISExpressExe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,25 @@ namespace ATech.Ring.DotNet.Cli.Tools.Windows;

public class IISExpressExe : ITool
{
public string Command { get; set; } = "C:\\Program Files\\IIS Express\\iisexpress.exe";
public string Command { get; set; } = @"C:\Program Files\IIS Express\iisexpress.exe";
public string[] DefaultArgs { get; set; } = Array.Empty<string>();
public ILogger<ITool> Logger { get; }
public IISExpressExe(ILogger<IISExpressExe> logger) => Logger = logger;

private void OnError(string error)
{
if (error == null) return;
var message = error.StartsWith("Failed to register URL") ? $"The port might be used another process. Try 'netstat -na -o' or if ports are reserved 'netsh interface ipv4 show excludedportrange protocol=tcp'). Original error: {error}" : $"IISExpress failed. Original error: {error}";
var message = error.StartsWith("Failed to register URL")
? $"The port might be used another process. Try 'netstat -na -o' or if ports are reserved 'netsh interface ipv4 show excludedportrange protocol=tcp'). Original error: {error}"
: $"IISExpress failed. Original error: {error}";

Logger.LogError(message);
}

public async Task<ExecutionInfo> StartWebsite(string configPath, CancellationToken token, IDictionary<string,string>? envVars = null)
public async Task<ExecutionInfo> StartWebsite(string configPath, CancellationToken token,
IDictionary<string, string>? envVars = null)
{
return await this.RunProcessAsync(OnError, envVars, new object[] { $"/config:\"{configPath}\"", $"/siteid:1" }, token);
return await this.RunProcessAsync(envVars: envVars,
args: new object[] { $"/config:\"{configPath}\"", $"/siteid:1" }, onErrorData: OnError, token: token);
}
}
}
29 changes: 27 additions & 2 deletions src/ATech.Ring.DotNet.Cli/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,21 @@
"Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.9"
}
},
"MessagePack": {
"type": "Transitive",
"resolved": "2.5.140",
"contentHash": "nkIsgy8BkIfv40bSz9XZb4q//scI1PF3AYeB5X66nSlIhBIqbdpLz8Qk3gHvnjV3RZglQLO/ityK3eNfLii2NA==",
"dependencies": {
"MessagePack.Annotations": "2.5.140",
"Microsoft.NET.StringTools": "17.6.3",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"MessagePack.Annotations": {
"type": "Transitive",
"resolved": "2.5.140",
"contentHash": "JE3vwluOrsJ4t3hnfXzIxJUh6lhx6M/KR8Sark/HOUw1DJ5UKu5JsAnnuaQngg6poFkRx1lzHSLTkxHNJO7+uQ=="
},
"Microsoft.AspNetCore.Connections.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
Expand Down Expand Up @@ -504,6 +519,15 @@
"System.Buffers": "4.5.0"
}
},
"Microsoft.NET.StringTools": {
"type": "Transitive",
"resolved": "17.6.3",
"contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA==",
"dependencies": {
"System.Memory": "4.5.5",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"Microsoft.NETCore.Platforms": {
"type": "Transitive",
"resolved": "1.1.0",
Expand Down Expand Up @@ -651,8 +675,8 @@
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "sDJYJpGtTgx+23Ayu5euxG5mAXWdkDb4+b0rD0Cab0M1oQS9H0HXGPriKcqpXuiJDTV7fTp/d+fMDJmnr6sNvA=="
"resolved": "4.5.5",
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw=="
},
"System.Net.WebSockets.WebSocketProtocol": {
"type": "Transitive",
Expand Down Expand Up @@ -814,6 +838,7 @@
"queil.ring.protocol": {
"type": "Project",
"dependencies": {
"MessagePack": "[2.5.140, )",
"System.Text.Json": "[6.*, )",
"System.Threading.Channels": "[6.*, )"
}
Expand Down
30 changes: 30 additions & 0 deletions src/Queil.Ring.Client.FSharp/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,40 @@
"resolved": "6.0.7",
"contentHash": "e6wGrq5smV3Yk2fBE/Y0nBG5oFyF59k5Je0a0QDydUpg6liyaafGjD3xvutciKepCP2knspZ/sWViC/F1OyyQQ=="
},
"MessagePack": {
"type": "Transitive",
"resolved": "2.5.140",
"contentHash": "nkIsgy8BkIfv40bSz9XZb4q//scI1PF3AYeB5X66nSlIhBIqbdpLz8Qk3gHvnjV3RZglQLO/ityK3eNfLii2NA==",
"dependencies": {
"MessagePack.Annotations": "2.5.140",
"Microsoft.NET.StringTools": "17.6.3",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"MessagePack.Annotations": {
"type": "Transitive",
"resolved": "2.5.140",
"contentHash": "JE3vwluOrsJ4t3hnfXzIxJUh6lhx6M/KR8Sark/HOUw1DJ5UKu5JsAnnuaQngg6poFkRx1lzHSLTkxHNJO7+uQ=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ=="
},
"Microsoft.NET.StringTools": {
"type": "Transitive",
"resolved": "17.6.3",
"contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA==",
"dependencies": {
"System.Memory": "4.5.5",
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.5",
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
Expand Down Expand Up @@ -53,6 +82,7 @@
"queil.ring.protocol": {
"type": "Project",
"dependencies": {
"MessagePack": "[2.5.140, )",
"System.Text.Json": "[6.*, )",
"System.Threading.Channels": "[6.*, )"
}
Expand Down
15 changes: 15 additions & 0 deletions src/Queil.Ring.Protocol/Events/RunnableLogLine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using MessagePack;

namespace Queil.Ring.Protocol.Events;

[MessagePackObject]
public class RunnableLogLine
{
[property: Key(0)]public string RunnableId { get; set; } = null!;
[property: Key(1)]public string Line { get; set; } = null!;

public ReadOnlySpan<byte> Serialize() => MessagePackSerializer.Serialize(this);
public static RunnableLogLine Deserialize(ReadOnlySpan<byte> bytes) =>
MessagePackSerializer.Deserialize<RunnableLogLine>(bytes.ToArray().AsMemory());
}
8 changes: 4 additions & 4 deletions src/Queil.Ring.Protocol/Events/WorkspaceInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((WorkspaceInfo)obj);
return obj.GetType() == GetType() && Equals((WorkspaceInfo)obj);
}

public override int GetHashCode() => HashCode.Combine(Path, Runnables, Flavours, CurrentFlavour, ServerState, WorkspaceState);
public static WorkspaceInfo Empty { get; } = new(string.Empty, Array.Empty<RunnableInfo>(), Array.Empty<string>(), string.Empty, ServerState.IDLE, WorkspaceState.NONE);
public ReadOnlySpan<byte> Serialize() => JsonSerializer.SerializeToUtf8Bytes(this, SerializerOptions.Value);

public static WorkspaceInfo? Deserialize(ReadOnlySpan<byte> bytes) => JsonSerializer.Deserialize<WorkspaceInfo>(bytes, SerializerOptions.Value);

private static readonly Lazy<JsonSerializerOptions> SerializerOptions = new(() =>
{
var options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());
return options;
});
}
}
3 changes: 2 additions & 1 deletion src/Queil.Ring.Protocol/Message.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public enum M : byte
RUNNABLE_UNRECOVERABLE = 16,
RUNNABLE_RECOVERING = 17,
RUNNABLE_DESTROYED = 18,

RUNNABLE_LOGS = 28,
WORKSPACE_DEGRADED = 19,
WORKSPACE_HEALTHY = 20,
WORKSPACE_STOPPED = 21,
Expand Down Expand Up @@ -104,6 +104,7 @@ public override string ToString()
public static Message RunnableRecovering(ReadOnlySpan<char> id) => new(M.RUNNABLE_RECOVERING, id);
public static Message RunnableStopped(ReadOnlySpan<char> id) => new(M.RUNNABLE_STOPPED, id);
public static Message RunnableDestroyed(ReadOnlySpan<char> id) => new(M.RUNNABLE_DESTROYED, id);
public static Message RunnableLogs(RunnableLogLine line) => new(M.RUNNABLE_LOGS, line.Serialize());
public static Message ServerIdle() => new(M.SERVER_IDLE);
public static Message ServerLoaded(ReadOnlySpan<char> workspacePath) => new(M.SERVER_LOADED, workspacePath);
public static Message ServerRunning(ReadOnlySpan<char> workspacePath) => new(M.SERVER_RUNNING, workspacePath);
Expand Down
1 change: 1 addition & 0 deletions src/Queil.Ring.Protocol/Queil.Ring.Protocol.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="MessagePack" Version="2.5.140" />
<PackageReference Include="System.Text.Json" Version="6.*" />
<PackageReference Include="System.Threading.Channels" Version="6.*" />
</ItemGroup>
Expand Down
Loading