Skip to content
This repository has been archived by the owner on Aug 31, 2020. It is now read-only.

Commit

Permalink
feat: add missing features (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
skyfrk authored Aug 22, 2020
1 parent b9539fd commit e8d958a
Show file tree
Hide file tree
Showing 72 changed files with 1,997 additions and 208 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ jobs:
- name: dotnet publish
working-directory: src/app/TicketStore.Client.App
run: dotnet publish -c Release -r "${{ matrix.target }}" -p:PublishSingleFile=true -p:DebugType=None -o build
- name: upload
uses: actions/upload-artifact@v2
with:
name: TicketStore.Client-${{ matrix.target }}
path: src/app/TicketStore.Client.App/build/*
# - name: upload
# uses: actions/upload-artifact@v2
# with:
# name: TicketStore.Client-${{ matrix.target }}
# path: src/app/TicketStore.Client.App/build/*
10 changes: 5 additions & 5 deletions .github/workflows/ci-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ jobs:
- name: dotnet publish
working-directory: src/app/TicketStore.Server.App
run: dotnet publish -c Release -r "${{ matrix.target }}" -p:PublishSingleFile=true -p:DebugType=None -o build
- name: upload
uses: actions/upload-artifact@v2
with:
name: TicketStore.Server-${{ matrix.target }}
path: src/app/TicketStore.Server.App/build/*
# - name: upload
# uses: actions/upload-artifact@v2
# with:
# name: TicketStore.Server-${{ matrix.target }}
# path: src/app/TicketStore.Server.App/build/*
18 changes: 18 additions & 0 deletions .github/workflows/remove-old-artifacts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: remove-old-artifacts

on:
workflow_dispatch:

jobs:
remove:
name: remove old artifacts
runs-on: ubuntu-18.04
timeout-minutes: 15

steps:
- name: remove
uses: c-hive/gha-remove-artifacts@v1
with:
age: '1 day'
skip-tags: true
skip-recent: 2
19 changes: 19 additions & 0 deletions src/app/TicketStore.Client.App/Command.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace TicketStore.Client.App
{
public enum Command
{
Init,
List,
CreateEvent,
GetSoldTicketCount,
GetAllEvents,
GetEventById,
PurchaseTicket,
GetRemainingBudget,
GetPurchasedTickets
}
}
34 changes: 34 additions & 0 deletions src/app/TicketStore.Client.App/CommandLineOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using CommandLine;
using System;
using System.Collections.Generic;
using System.Text;

namespace TicketStore.Client.App
{
public class CommandLineOptions
{
[Option('v', "verbose", Default = false, Required = false, HelpText = "Set log level to verbose.")]
public bool Verbose { get; }

[Option('h', "host", Default = "localhost:8081", Required = false, HelpText = "The host IP and port of the server.")]
public string Host { get; }

[Option('a', "admin", Default = false, Required = false, HelpText = "Starts the application in administrator mode.")]
public bool Admin { get; }

[Option('c', "command", Required = true, HelpText = "Command to be executed. Run command 'List' for a list of all available commands.")]
public Command Command { get; }

[Option('s',"show-logs", Default = false, Required = false, HelpText = "Shows log messages directly in the console.")]
public bool ShowLogs { get; }

public CommandLineOptions(bool verbose, string host, bool admin, Command command, bool showLogs)
{
Verbose = verbose;
Host = host;
Admin = admin;
Command = command;
ShowLogs = showLogs;
}
}
}
179 changes: 151 additions & 28 deletions src/app/TicketStore.Client.App/Program.cs
Original file line number Diff line number Diff line change
@@ -1,54 +1,177 @@
using Akka.Actor;
using Akka.Configuration;
using CommandLine;
using Serilog;
using Sharprompt;
using Sharprompt.Validations;
using System;
using TicketStore.Client.Logic.Actors;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using TicketStore.Client.Logic;
using TicketStore.Client.Logic.Messages;
using TicketStore.Client.Logic.Util;
using TicketStore.Shared;

namespace TicketStore.Client.App
{
class Program
{
static void Main(string[] args)
{
var logger = new LoggerConfiguration()
.WriteTo.Console()
.MinimumLevel.Information()
.CreateLogger();

Serilog.Log.Logger = logger;

// TODO: use https://github.com/akkadotnet/HOCON
var config = ConfigurationFactory.ParseString(@"
akka {
actor {
provider = remote
Console.OutputEncoding = Encoding.UTF8;

Parser.Default.ParseArguments<CommandLineOptions>(args)
.WithParsed<CommandLineOptions>(RunWithOptions)
.WithNotParsed(HandleParseErrors);
}

static void RunWithOptions(CommandLineOptions opts)
{
if(opts.Command == Command.List)
{
Console.WriteLine("Available commands:");
var commandTypes = Enum.GetValues(typeof(Command)).Cast<Command>();
foreach (var command in commandTypes)
{
Console.WriteLine(Enum.GetName(typeof(Command), command));
}
remote {
dot-netty.tcp {
port = 0
hostname = localhost
Helper.GracefulExitSuccess();
}

var appDataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.DoNotVerify), "TicketStore", "Client");

try
{
Directory.CreateDirectory(appDataDir);
}
catch (IOException)
{
Console.WriteLine($"FATAL Error: Can not create config directory: {appDataDir}");
Helper.GracefulExitError();
}

var akkaConfig = @"
akka {
actor {
provider = remote
}
remote {
dot-netty.tcp {
port = 0
hostname = localhost
}
}
loglevel=INFO,
loggers=[""Akka.Logger.Serilog.SerilogLogger, Akka.Logger.Serilog""]
}
loglevel=INFO,
loggers=[""Akka.Logger.Serilog.SerilogLogger, Akka.Logger.Serilog""]
";

var jsonDataStore = new JsonDataStore(Path.Combine(appDataDir, "config.json"));

var loggerBuilder = new LoggerConfiguration()
.WriteTo.File(Path.Combine(appDataDir, "log.txt"));

if (opts.ShowLogs)
{
loggerBuilder = loggerBuilder.WriteTo.Console();
}

if (opts.Verbose)
{
loggerBuilder = loggerBuilder.MinimumLevel.Verbose();
akkaConfig = akkaConfig.Replace("loglevel=INFO", "loglevel=DEBUG", StringComparison.Ordinal);
} else
{
loggerBuilder = loggerBuilder.MinimumLevel.Information();
}

Serilog.Log.Logger = loggerBuilder.CreateLogger();

using var system = ActorSystem.Create("client", ConfigurationFactory.ParseString(akkaConfig));

var remoteEventActorRef = system.ActorSelection($"akka.tcp://server@{opts.Host}/user/EventActor");
var remoteUserActorRef = system.ActorSelection($"akka.tcp://server@{opts.Host}/user/UserActor");

var clientActorProps = Props.Create<ClientActor>(() => new ClientActor(remoteEventActorRef, remoteUserActorRef, jsonDataStore));
var clientActor = system.ActorOf(clientActorProps, nameof(ClientActor));

Log.Logger.Information("Selected command: {command}", opts.Command);

if (opts.Command != Command.Init)
{
clientActor.Tell(new RestoreStateMessage());
}

if (!opts.Admin && (opts.Command == Command.CreateEvent || opts.Command == Command.GetSoldTicketCount))
{
Log.Logger.Error("This command is only available in admin mode!");
Console.WriteLine("This command is only available in admin mode!");
Helper.GracefulExitError();
}
");

using var system = ActorSystem.Create("Client", config);
switch (opts.Command)
{
case Command.Init:
var userDto = Ask.ForUserDto();
var yearlyBudget = Ask.ForYearlyBudget();
clientActor.Tell(new InitStateMessage(userDto, yearlyBudget));
break;

case Command.CreateEvent:
var eventDto = Ask.ForEventDto();
clientActor.Tell(new CreateEventMessage(eventDto));
break;

var remoteEventActorRef = system.ActorSelection("akka.tcp://Server@localhost:8081/user/EventActor");
var remoteUserActorRef = system.ActorSelection("akka.tcp://Server@localhost:8081/user/UserActor");
case Command.GetSoldTicketCount:
var eventId = Ask.ForEventId();
clientActor.Tell(new GetSoldTicketsMessage(eventId));
break;

// TODO: check if event and user actor are available.
case Command.GetAllEvents:
clientActor.Tell(new GetAllEventsMessage());
break;

var ticketStoreClientActorProps = Props.Create<TicketStoreClientActor>(() => new TicketStoreClientActor(remoteEventActorRef, remoteUserActorRef));
case Command.GetEventById:
var id = Ask.ForEventId();
clientActor.Tell(new GetEventByIdMessage(id));
break;

var ticketStoreClientActor = system.ActorOf(ticketStoreClientActorProps, nameof(TicketStoreClientActor));
case Command.PurchaseTicket:
var eId = Ask.ForEventId();
var ticketCount = Ask.ForTicketCount();
clientActor.Tell(new PurchaseTicketMessage(eId, ticketCount));
break;

// test
ticketStoreClientActor.Tell("test");
case Command.GetRemainingBudget:
clientActor.Tell(new GetRemainingBudgetMessage());
break;

case Command.GetPurchasedTickets:
var sortBy = Ask.ForSortBy();
var orderBy = Ask.ForOrderBy();
clientActor.Tell(new GetPurchasedTicketsMessage(sortBy, orderBy));
break;

default:
Log.Logger.Error("Invalid command.");
Console.WriteLine("Invalid command.");
break;
}

Console.ReadLine();
}

static void HandleParseErrors(IEnumerable<Error> errors)
{
foreach (var error in errors)
{
if (error.StopsProcessing)
{
Serilog.Log.Logger.Error("Parsing error occured: {tag}", error?.Tag);
}
}
}
}
}
6 changes: 6 additions & 0 deletions src/app/TicketStore.Client.App/TicketStore.Client.App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Company>DHBW-VS WI17B Group B4</Company>
<AssemblyTitle>Ticket Store Client</AssemblyTitle>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Akka" Version="1.4.9" />
<PackageReference Include="Akka.Logger.Serilog" Version="1.4.8" />
<PackageReference Include="Akka.Remote" Version="1.4.9" />
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="Sharprompt" Version="2.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\TicketStore.Client.Logic\TicketStore.Client.Logic.csproj" />
<ProjectReference Include="..\TicketStore.Shared\TicketStore.Shared.csproj" />
</ItemGroup>

</Project>
29 changes: 0 additions & 29 deletions src/app/TicketStore.Client.Logic/Actors/TicketStoreClientActor.cs

This file was deleted.

Loading

0 comments on commit e8d958a

Please sign in to comment.