Skip to content

Commit

Permalink
Merge pull request #9 from mbican/development
Browse files Browse the repository at this point in the history
release 0.1.0
  • Loading branch information
mbican authored Jan 26, 2019
2 parents cd128f3 + 0ef065f commit 886d930
Show file tree
Hide file tree
Showing 19 changed files with 550 additions and 55 deletions.
20 changes: 20 additions & 0 deletions CronHosts.ConsoleApp/CronHosts.ConsoleApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<NullableContextOptions>enable</NullableContextOptions>
<Version>0.1.0</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="commandlineparser" Version="2.4.3" />
<PackageReference Include="EfautValueObject" Version="0.5.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CronHosts.Domain\CronHosts.Domain.csproj" />
</ItemGroup>
</Project>
157 changes: 157 additions & 0 deletions CronHosts.ConsoleApp/CronHostsProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using CommandLine;
using CronHosts.Domain;
using Efaut;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace CronHosts.ConsoleApp
{
public class CronHostsProgram: IProgram
{
#region Dependencies

#nullable disable

public Lazy<Parser> ParserLazy { get; set; }
protected Parser Parser => ParserLazy?.Value;

public Lazy<Random> RandomLazy { get; set; }
protected Random Random => RandomLazy?.Value;

public Lazy<IDomain> DomainLazy { get; set; }
protected IDomain Domain => DomainLazy?.Value;

public Lazy<IDateTimeService> DateTimeServiceLazy { get; set; }
protected IDateTimeService DateTimeService => DateTimeServiceLazy?.Value;

#nullable restore

#endregion Dependencies

public sealed class Arguments: ValueObject
{
[Value(0)]
public string? File { get; }

public Arguments(string? file)
{
File = file;
}
}

public enum ExitCode: int
{
Success = 0,
ArgumentError = 1,
UnknownError = 1000,
}

public async Task<int> Run(string[] args)
{
var parserResult = Parser.ParseArguments<Arguments>(args);
if (parserResult is Parsed<Arguments> parsed)
{
var arguments = parsed.Value;
await DoRun(arguments);
return (int)ExitCode.Success;
}
else if (parserResult is NotParsed<Arguments> notParsed)
{
var errors = notParsed.Errors;
return (int)ExitCode.ArgumentError;
}
else
{
return (int)ExitCode.UnknownError;
}
}

protected async Task DoRun(Arguments arguments)
{
// if file name has been provided
if (arguments.File == null)
{ // use standard input
using (var input = Console.OpenStandardInput())
using (var reader = new StreamReader(input))
using (var output = Console.OpenStandardOutput())
using (var writer = new StreamWriter(output))
await Domain.Execute(reader, writer, DateTimeService.GetUtcNow());
}
else
{ // use file
var existingFile = arguments.File;
// create name for a temp file
var random = Random.Next();
var tempFile = $"{existingFile}_{random:x8}.tmp";
// create name for a backup file
var bakFile = $"{existingFile}_{random:x8}.bak";
try
{
// copy existingFile to tempFile so it has original metadata
File.Copy(existingFile, tempFile);
// open existing file for reading
using (var reader = new StreamReader(existingFile, true))
// open temp file for writing
using (var writer = new StreamWriter(tempFile))
// execute cronhosts processes existing file into temp file
await Domain.Execute(reader, writer, DateTimeService.GetUtcNow());
// swap completed temp file for existing file while renaming existing file to bakFile in case of something goes wrong
File.Replace(tempFile, existingFile, bakFile);
// after successful swap delete the original file renamed to bakFile
File.Delete(bakFile);
}
catch
{ // in case of an error
// try restore original file from back up
try { File.Move(bakFile, existingFile); } catch { }
try
{
// if original file exists
if (File.Exists(existingFile))
// delete temp file
File.Delete(tempFile);
else
// otherwise rename tempFile to original file
File.Move(tempFile, existingFile);
}
catch { }
throw;
}
}
}

public static IReadOnlyDictionary<ExitCode, string> ErrorMessages = new Dictionary<ExitCode, string>
{
[ExitCode.Success] = "Success",
[ExitCode.ArgumentError] = "ArgumentError",
[ExitCode.UnknownError] = "UnknownError",
};

public class CronHostsFatalException: ApplicationException
{
public ExitCode ExitCode { get; protected set; }

public CronHostsFatalException(ExitCode exitCode) : base(ErrorMessages[exitCode])
{
ExitCode = exitCode;
}

public CronHostsFatalException(ExitCode exitCode, string message) : base(message)
{
ExitCode = exitCode;
}

public CronHostsFatalException(ExitCode exitCode, Exception innerExcpetion) : base(ErrorMessages[exitCode], innerExcpetion)
{
ExitCode = exitCode;
}

public CronHostsFatalException(ExitCode exitCode, string message, Exception innerExcpetion) : base(message, innerExcpetion)
{
ExitCode = exitCode;
}
}
}
}
14 changes: 14 additions & 0 deletions CronHosts.ConsoleApp/DateTimeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace CronHosts.ConsoleApp
{
public class DateTimeService: IDateTimeService
{
public DateTime GetUtcNow()
{
return DateTime.UtcNow;
}
}
}
11 changes: 11 additions & 0 deletions CronHosts.ConsoleApp/IDateTimeService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace CronHosts.ConsoleApp
{
public interface IDateTimeService
{
DateTime GetUtcNow();
}
}
12 changes: 12 additions & 0 deletions CronHosts.ConsoleApp/IProgram.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace CronHosts.ConsoleApp
{
public interface IProgram
{
Task<int> Run(string[] args);
}
}
17 changes: 17 additions & 0 deletions CronHosts.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Autofac;
using System.Threading.Tasks;

namespace CronHosts.ConsoleApp
{
public static class Program
{
private static IContainer Container { get; set; }

public static async Task<int> Main(string[] args)
{
using (Container = Startup.Build())
using (var scope = Container.BeginLifetimeScope("program"))
return await scope.Resolve<IProgram>().Run(args);
}
}
}
24 changes: 24 additions & 0 deletions CronHosts.ConsoleApp/Startup.Autofac.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using Autofac;
using CommandLine;
using CronHosts.Domain;

namespace CronHosts.ConsoleApp
{
public static partial class Startup
{
public static void ConfigureAutofac(ContainerBuilder builder)
{
Domain.Startup.ConfigureAutofac(builder);

builder.RegisterType<CronHostsProgram>().As<IProgram>().PropertiesAutowired().InstancePerLifetimeScope();

builder.RegisterType<DateTimeService>().As<IDateTimeService>().PropertiesAutowired().InstancePerLifetimeScope();

builder.RegisterType<Random>().AsSelf().InstancePerLifetimeScope();
builder.Register(a => new Parser(ConfigureParser)).AsSelf().InstancePerLifetimeScope();
}
}
}
15 changes: 15 additions & 0 deletions CronHosts.ConsoleApp/Startup.Parser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using CommandLine;
using System;
using System.Collections.Generic;
using System.Text;

namespace CronHosts.ConsoleApp
{
public static partial class Startup
{
public static void ConfigureParser(ParserSettings settings)
{
settings.HelpWriter = Console.Error;
}
}
}
4 changes: 2 additions & 2 deletions CronHosts/Startup.cs → CronHosts.ConsoleApp/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
using System.Text;
using Autofac;

namespace CronHosts
namespace CronHosts.ConsoleApp
{
public static partial class Startup
{
public static IContainer Configure()
public static IContainer Build()
{
var builder = new ContainerBuilder();
ConfigureAutofac(builder);
Expand Down
16 changes: 16 additions & 0 deletions CronHosts.Domain/CronHosts.Domain.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<LangVersion>8.0</LangVersion>
<NullableContextOptions>enable</NullableContextOptions>
<ApplicationIcon />
<StartupObject />
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac" Version="4.8.1" />
<PackageReference Include="Shuttle.Core.Cron" Version="10.0.6" />
</ItemGroup>
</Project>
Loading

0 comments on commit 886d930

Please sign in to comment.