Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Aaronontheweb/full-sample
adds a full working sample of a custom command
- Loading branch information
Showing
11 changed files
with
572 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
############################################################################### | ||
# Set default behavior to automatically normalize line endings. | ||
############################################################################### | ||
* text=auto | ||
|
||
############################################################################### | ||
# Set default behavior for command prompt diff. | ||
# | ||
# This is need for earlier builds of msysgit that does not have it on by | ||
# default for csharp files. | ||
# Note: This is only used by command line | ||
############################################################################### | ||
#*.cs diff=csharp | ||
|
||
############################################################################### | ||
# Set the merge driver for project and solution files | ||
# | ||
# Merging from the command prompt will add diff markers to the files if there | ||
# are conflicts (Merging from VS is not affected by the settings below, in VS | ||
# the diff markers are never inserted). Diff markers may cause the following | ||
# file extensions to fail to load in VS. An alternative would be to treat | ||
# these files as binary and thus will always conflict and require user | ||
# intervention with every merge. To do so, just uncomment the entries below | ||
############################################################################### | ||
#*.sln merge=binary | ||
#*.csproj merge=binary | ||
#*.vbproj merge=binary | ||
#*.vcxproj merge=binary | ||
#*.vcproj merge=binary | ||
#*.dbproj merge=binary | ||
#*.fsproj merge=binary | ||
#*.lsproj merge=binary | ||
#*.wixproj merge=binary | ||
#*.modelproj merge=binary | ||
#*.sqlproj merge=binary | ||
#*.wwaproj merge=binary | ||
|
||
############################################################################### | ||
# behavior for image files | ||
# | ||
# image files are treated as binary by default. | ||
############################################################################### | ||
#*.jpg binary | ||
#*.png binary | ||
#*.gif binary | ||
|
||
############################################################################### | ||
# diff behavior for common document formats | ||
# | ||
# Convert binary document formats to text before diffing them. This feature | ||
# is only available from the command line. Turn it on by uncommenting the | ||
# entries below. | ||
############################################################################### | ||
#*.doc diff=astextplain | ||
#*.DOC diff=astextplain | ||
#*.docx diff=astextplain | ||
#*.DOCX diff=astextplain | ||
#*.dot diff=astextplain | ||
#*.DOT diff=astextplain | ||
#*.pdf diff=astextplain | ||
#*.PDF diff=astextplain | ||
#*.rtf diff=astextplain | ||
#*.RTF diff=astextplain |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 15 | ||
VisualStudioVersion = 15.0.26403.7 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Petabridge.Cmd.QuickStart", "Petabridge.Cmd.QuickStart\Petabridge.Cmd.QuickStart.csproj", "{31FD95DB-EFC4-435A-87F1-40D2AAAB1AE5}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{31FD95DB-EFC4-435A-87F1-40D2AAAB1AE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{31FD95DB-EFC4-435A-87F1-40D2AAAB1AE5}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{31FD95DB-EFC4-435A-87F1-40D2AAAB1AE5}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{31FD95DB-EFC4-435A-87F1-40D2AAAB1AE5}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
EndGlobal |
20 changes: 20 additions & 0 deletions
20
Petabridge.Cmd.QuickStart/Petabridge.Cmd.QuickStart/App.config
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
|
||
<configuration> | ||
<configSections> | ||
<section name="akka" type="Akka.Configuration.Hocon.AkkaConfigurationSection, Akka" /> | ||
</configSections> | ||
<startup> | ||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> | ||
</startup> | ||
<akka> | ||
<hocon> | ||
<![CDATA[ | ||
petabridge.cmd{ | ||
# disable logging palettes on startup | ||
log-palettes-on-startup = off | ||
} | ||
]]> | ||
</hocon> | ||
</akka> | ||
</configuration> |
99 changes: 99 additions & 0 deletions
99
Petabridge.Cmd.QuickStart/Petabridge.Cmd.QuickStart/MessageMemorizerActor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="MessageMemorizerActor.cs" company="Petabridge, LLC"> | ||
// Copyright (C) 2017 - 2017 Petabridge, LLC <https://petabridge.com> | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Akka.Actor; | ||
|
||
namespace Petabridge.Cmd.QuickStart | ||
{ | ||
/// <summary> | ||
/// Actor responsible for memorizing messages that will be saved on the server. | ||
/// </summary> | ||
public class MessageMemorizerActor : ReceiveActor | ||
{ | ||
private readonly SortedSet<Message> _messages = new SortedSet<Message>(); | ||
|
||
public MessageMemorizerActor() | ||
{ | ||
Receive<Message>(m => | ||
{ | ||
_messages.Add(m); | ||
Sender.Tell(CommandResponse.Empty); | ||
}); | ||
|
||
Receive<FetchMessages>(f => f.Since == null, f => // all messages | ||
{ | ||
foreach (var msg in _messages) | ||
Sender.Tell(new CommandResponse(msg.ToString(), false)); | ||
// by setting final:false we signal to client that more responses are coming | ||
Sender.Tell(CommandResponse.Empty); // tells the client not to expect any more responses (final == true) | ||
}); | ||
|
||
Receive<FetchMessages>(f => | ||
{ | ||
var acceptableTime = DateTime.UtcNow - f.Since; | ||
var matchingMessages = | ||
_messages.Where(x => x.TimeStamp >= acceptableTime).OrderBy(x => x.TimeStamp).ToList(); | ||
foreach (var msg in matchingMessages) | ||
Sender.Tell(new CommandResponse(msg.ToString(), false)); | ||
// by setting final:false we signal to client that more responses are coming | ||
Sender.Tell(CommandResponse.Empty); // tells the client not to expect any more responses (final == true) | ||
}); | ||
|
||
Receive<PurgeMessages>(_ => | ||
{ | ||
_messages.Clear(); | ||
Sender.Tell(CommandResponse.Empty); | ||
}); | ||
} | ||
|
||
public class Message : IComparable<Message> | ||
{ | ||
public Message(string msg, DateTime timeStamp, string ip) | ||
{ | ||
Msg = msg; | ||
TimeStamp = timeStamp; | ||
Ip = ip; | ||
} | ||
|
||
public DateTime TimeStamp { get; } | ||
public string Msg { get; } | ||
public string Ip { get; } | ||
|
||
public int CompareTo(Message other) | ||
{ | ||
if (ReferenceEquals(this, other)) return 0; | ||
if (ReferenceEquals(null, other)) return 1; | ||
return TimeStamp.CompareTo(other.TimeStamp); | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return $"[{Ip}][{TimeStamp.ToShortTimeString()}]: {Msg}"; | ||
} | ||
} | ||
|
||
public class FetchMessages | ||
{ | ||
public FetchMessages(TimeSpan? since = null) | ||
{ | ||
Since = since; | ||
} | ||
|
||
public TimeSpan? Since { get; } | ||
} | ||
|
||
public class PurgeMessages | ||
{ | ||
public static readonly PurgeMessages Instance = new PurgeMessages(); | ||
|
||
private PurgeMessages() | ||
{ | ||
} | ||
} | ||
} | ||
} |
121 changes: 121 additions & 0 deletions
121
Petabridge.Cmd.QuickStart/Petabridge.Cmd.QuickStart/MsgCommandHandlerActor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
using System.Threading.Tasks; | ||
using Akka.Actor; | ||
using Akka.Configuration; | ||
using Petabridge.Cmd.Host; | ||
|
||
namespace Petabridge.Cmd.QuickStart | ||
{ | ||
/// <summary> | ||
/// Actor responsible for handling all <see cref="Command"/>s defined inside <see cref="MsgCommands.Palette"/> | ||
/// </summary> | ||
public class MsgCommandHandlerActor : CommandHandlerActor | ||
{ | ||
private readonly IActorRef _messageMemorizer; | ||
private static readonly Regex TimeRegex = new Regex(@"^(?<value>([0-9]+(\.[0-9]+)?))\s*(?<unit>(ms|s|h|m|d))$", RegexOptions.Compiled); | ||
|
||
public MsgCommandHandlerActor(IActorRef messageMemorizer) : base(MsgCommands.Palette) | ||
{ | ||
_messageMemorizer = messageMemorizer; | ||
Receive<Command>(c => c.Name.Equals(MsgCommands.CheckMessages.Name), command => ExecuteCommand(command, HandleFetch)); | ||
Receive<Command>(c => c.Name.Equals(MsgCommands.Write.Name), command => ExecuteCommand(command, HandleWrite)); | ||
Receive<Command>(c => c.Name.Equals(MsgCommands.Echo.Name), command => ExecuteCommand(command, HandleEcho)); | ||
Receive<Command>(c => c.Name.Equals(MsgCommands.Purge.Name), command => ExecuteCommand(command, HandlePurge)); | ||
} | ||
|
||
public void HandlePurge(Command purge) | ||
{ | ||
_messageMemorizer.Tell(MessageMemorizerActor.PurgeMessages.Instance, Sender); | ||
} | ||
|
||
public void HandleWrite(Command write) | ||
{ | ||
var msg = | ||
write.Arguments.SingleOrDefault( | ||
x => MsgCommands.Write.ArgumentsByName["message"].Switch.Contains(x.Item1))? | ||
.Item2; | ||
|
||
_messageMemorizer.Tell(new MessageMemorizerActor.Message(msg, DateTime.UtcNow, Sender.Path.Name), Sender); | ||
} | ||
|
||
public void HandleEcho(Command echo) | ||
{ | ||
var msg = | ||
echo.Arguments.SingleOrDefault( | ||
x => MsgCommands.Echo.ArgumentsByName["message"].Switch.Contains(x.Item1))? | ||
.Item2; | ||
|
||
Sender.Tell(new CommandResponse(new MessageMemorizerActor.Message(msg, DateTime.UtcNow, Sender.Path.Name).ToString())); // will echo what was written on commandline | ||
} | ||
|
||
public void HandleFetch(Command fetch) | ||
{ | ||
// check if we have a timeframe for the message specified | ||
// what this code does: scans the set of arguments in `fetch` to see | ||
// if any of the switches for the `since` argument have been used, and if | ||
// so return the value for that argument. Otherwise, return null. | ||
var containsTimeframe = | ||
fetch.Arguments.SingleOrDefault( | ||
x => MsgCommands.CheckMessages.ArgumentsByName["since"].Switch.Contains(x.Item1))?.Item2; | ||
|
||
if (containsTimeframe == null) | ||
{ | ||
_messageMemorizer.Tell(new MessageMemorizerActor.FetchMessages(), Sender); // preserve sender so client gets replies directly | ||
return; | ||
} | ||
|
||
// using regular expression to extract the time format | ||
var m = TimeRegex.Match(containsTimeframe); | ||
if (!m.Success) | ||
{ | ||
Sender.Tell(new ErroredCommandResponse($"Unable to extract time format from {containsTimeframe}. Should be in format of [value][ms|s|m|h|d] for milliseconds, seconds, minutes, hours, or days respectively.")); | ||
return; | ||
} | ||
|
||
|
||
try | ||
{ | ||
var unit = m.Groups["unit"].Value; | ||
var value = Int32.Parse(m.Groups["value"].Value); | ||
|
||
if (value < 0) | ||
{ | ||
Sender.Tell(new ErroredCommandResponse($"Need to pass in positive time value for `since` argument. Instead, received [{value} {unit}]")); | ||
return; | ||
} | ||
|
||
TimeSpan time = TimeSpan.Zero; | ||
switch (unit) | ||
{ | ||
case "ms": | ||
time = TimeSpan.FromMilliseconds(value); | ||
break; | ||
case "s": | ||
time = TimeSpan.FromSeconds(value); | ||
break; | ||
case "m": | ||
time = TimeSpan.FromMinutes(value); | ||
break; | ||
case "h": | ||
time = TimeSpan.FromHours(value); | ||
break; | ||
case "d": | ||
time = TimeSpan.FromDays(value); | ||
break; | ||
} | ||
|
||
// make sure the original sender is passed along so reply goes to client | ||
_messageMemorizer.Tell(new MessageMemorizerActor.FetchMessages(time), Sender); | ||
|
||
} | ||
catch (Exception ex) | ||
{ | ||
Sender.Tell(new ErroredCommandResponse($"Error occurred while processing command: {ex.Message}")); | ||
} | ||
} | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
Petabridge.Cmd.QuickStart/Petabridge.Cmd.QuickStart/MsgCommandPaletteHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="MsgCommandPaletteHandler.cs" company="Petabridge, LLC"> | ||
// Copyright (C) 2017 - 2017 Petabridge, LLC <https://petabridge.com> | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
using Akka.Actor; | ||
using Petabridge.Cmd.Host; | ||
|
||
namespace Petabridge.Cmd.QuickStart | ||
{ | ||
/// <summary> | ||
/// Gets registered with <see cref="PetabridgeCmd" /> in order to enable the server to begin processing | ||
/// <see cref="MsgCommands.Palette" /> using the <see cref="MsgCommandHandlerActor" /> and the | ||
/// <see cref="MessageMemorizerActor" />. | ||
/// </summary> | ||
public class MsgCommandPaletteHandler : CommandPaletteHandler | ||
{ | ||
private Props _underlyingProps; | ||
|
||
public MsgCommandPaletteHandler() | ||
: base(MsgCommands.Palette) // registers the command palette with this handler. | ||
{ | ||
} | ||
|
||
public override Props HandlerProps => _underlyingProps; | ||
|
||
/* | ||
* Overriding this method gives us the ability to do things like create the MessageMemorizerActor before HandlerProps gets used | ||
*/ | ||
|
||
public override void OnRegister(PetabridgeCmd plugin) | ||
{ | ||
var memorizer = plugin.Sys.ActorOf(Props.Create(() => new MessageMemorizerActor()), "pbm-msg-memorizier"); | ||
|
||
// will be used to create a new MsgCommandHandlerActor instance per connection | ||
_underlyingProps = Props.Create(() => new MsgCommandHandlerActor(memorizer)); | ||
base.OnRegister(plugin); | ||
} | ||
} | ||
} |
Oops, something went wrong.