Skip to content

Commit 9a1d223

Browse files
committed
Node.Cli: initial commit of cli, about 95% complete (issue #2)
1 parent 4e43064 commit 9a1d223

11 files changed

Lines changed: 351 additions & 93 deletions

File tree

Synapse.NodeService.HttpClient/NodeServiceHttpApiClient.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using Synapse.Core;
55
using Synapse.Common.WebApi;
6+
using System.Collections.Generic;
67

78
namespace Synapse.Services
89
{
@@ -38,14 +39,14 @@ public async Task CancelPlanAsync(long planInstanceId)
3839
}
3940

4041

41-
public void Drainstop()
42+
public void Drainstop(bool shutdown)
4243
{
43-
DrainstopAsync().Wait();
44+
DrainstopAsync( shutdown ).Wait();
4445
}
4546

46-
public async Task DrainstopAsync()
47+
public async Task DrainstopAsync(bool shutdown)
4748
{
48-
string requestUri = $"{_rootPath}/drainstop/?action=stop";
49+
string requestUri = $"{_rootPath}/drainstop/?action=stop&shutdown={shutdown}";
4950
await GetAsync( requestUri );
5051
}
5152

@@ -59,5 +60,29 @@ public async Task UndrainstopAsync()
5960
string requestUri = $"{_rootPath}/drainstop/?action=unstop";
6061
await GetAsync( requestUri );
6162
}
63+
64+
public bool GetIsDrainstopComplete() { return GetIsDrainstopCompleteAsync().Result; }
65+
66+
public async Task<bool> GetIsDrainstopCompleteAsync()
67+
{
68+
string requestUri = $"{_rootPath}/drainstop/?action=status";
69+
return await GetAsync<bool>( requestUri );
70+
}
71+
72+
public int GetCurrentQueueDepth() { return GetCurrentQueueDepthAsync().Result; }
73+
74+
public async Task<int> GetCurrentQueueDepthAsync()
75+
{
76+
string requestUri = $"{_rootPath}/drainstop/?action=depth";
77+
return await GetAsync<int>( requestUri );
78+
}
79+
80+
public List<string> GetCurrentQueueItems() { return GetCurrentQueueItemsAsync().Result; }
81+
82+
public async Task<List<string>> GetCurrentQueueItemsAsync()
83+
{
84+
string requestUri = $"{_rootPath}/drainstop/?action=list";
85+
return await GetAsync<List<string>>( requestUri );
86+
}
6287
}
6388
}

Synapse.NodeService.HttpClient/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion( "0.0.0.5" )]
36-
[assembly: AssemblyFileVersion( "0.0.0.5" )]
35+
[assembly: AssemblyVersion( "0.1.0.0" )]
36+
[assembly: AssemblyFileVersion( "0.1.0.0" )]

Synapse.NodeService.cli/App.config

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,74 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<configuration>
3-
<startup>
4-
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
5-
</startup>
3+
<configSections>
4+
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler"/>
5+
</configSections>
6+
<system.serviceModel>
7+
<services>
8+
<service behaviorConfiguration="SynapseServiceBehavior" name="Synapse.Services.SynapseNodeServer">
9+
<host>
10+
<baseAddresses>
11+
<add baseAddress="http://localhost:8000/synapse/node"/>
12+
</baseAddresses>
13+
</host>
14+
<!-- this endpoint is exposed at the base address: http://localhost:8000/synapse/node -->
15+
<endpoint address="" binding="webHttpBinding" contract="Synapse.Core.Runtime.ISynapseNodeServer" behaviorConfiguration="web"/>
16+
<!-- this endpoint is exposed at: http://localhost:8000/synapse/node/ws -->
17+
<endpoint address="ws" binding="wsHttpBinding" contract="Synapse.Core.Runtime.ISynapseNodeServer"/>
18+
<!-- this endpoint is exposed at: http://localhost:8000/synapse/node/mex -->
19+
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
20+
</service>
21+
</services>
22+
<behaviors>
23+
<serviceBehaviors>
24+
<behavior name="SynapseServiceBehavior">
25+
<serviceMetadata httpGetEnabled="true"/>
26+
<serviceDebug includeExceptionDetailInFaults="True"/>
27+
</behavior>
28+
</serviceBehaviors>
29+
<endpointBehaviors>
30+
<behavior name="web">
31+
<webHttp helpEnabled="true" defaultOutgoingResponseFormat="Json" automaticFormatSelectionEnabled="true"/>
32+
</behavior>
33+
</endpointBehaviors>
34+
</behaviors>
35+
</system.serviceModel>
36+
<startup>
37+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
38+
</startup>
39+
<log4net>
40+
<appender name="SynapseNodeConsole" type="log4net.Appender.ColoredConsoleAppender">
41+
<layout type="log4net.Layout.PatternLayout">
42+
<conversionPattern value="%d{ISO8601}|%-5p|(%t)|%m%n"/>
43+
</layout>
44+
<filter type="log4net.Filter.LoggerMatchFilter">
45+
<loggerToMatch value="SynapseNodeServer" />
46+
</filter>
47+
<filter type="log4net.Filter.DenyAllFilter" />
48+
<mapping>
49+
<level value="DEBUG" />
50+
<foreColor value="White" />
51+
</mapping>
52+
<mapping>
53+
<level value="INFO" />
54+
<foreColor value="White, HighIntensity" />
55+
</mapping>
56+
<mapping>
57+
<level value="WARN" />
58+
<foreColor value="Yellow, HighIntensity" />
59+
</mapping>
60+
<mapping>
61+
<level value="ERROR" />
62+
<foreColor value="Red, HighIntensity" />
63+
</mapping>
64+
<mapping>
65+
<level value="FATAL" />
66+
<foreColor value="Purple, HighIntensity" />
67+
</mapping>
68+
</appender>
69+
<root>
70+
<level value="DEBUG"/>
71+
<appender-ref ref="SynapseNodeConsole"/>
72+
</root>
73+
</log4net>
674
</configuration>

Synapse.NodeService.cli/Program.cs

Lines changed: 163 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,65 +5,179 @@
55
using Synapse.Core;
66
using Synapse.Services;
77

8-
namespace Synapse.Services.NodeService.cli
8+
namespace Synapse.Services.NodeService.Cli
99
{
10-
class Program
10+
class Program : Synapse.Common.CmdLine.HttpApiCliBase
1111
{
1212
static void Main(string[] args)
1313
{
14-
string url = "http://localhost:8000/synapse/node";
15-
if( args.Length > 0 )
16-
url = args[0];
17-
18-
NodeServiceHttpApiClient winClient = new NodeServiceHttpApiClient( url );
19-
20-
string __root = @"C:\Devo\synapse\synapse.core.net\Synapse.UnitTests";
21-
string __plansRoot = $@"{__root}\Plans";
22-
string plan0Name = "planScheduler.yaml";
23-
string plan1Name = "planScheduler.yaml";
24-
string plan2Name = "planScheduler.yaml";
25-
string plan3Name = "planScheduler.yaml";
26-
27-
Plan plan00 = Plan.FromYaml( $"{__plansRoot}\\{plan0Name}" );
28-
Plan plan01 = Plan.FromYaml( $"{__plansRoot}\\{plan1Name}" );
29-
Plan plan02 = Plan.FromYaml( $"{__plansRoot}\\{plan2Name}" );
30-
Plan plan03 = Plan.FromYaml( $"{__plansRoot}\\{plan3Name}" );
31-
Plan plan04 = Plan.FromYaml( $"{__plansRoot}\\{plan0Name}" );
32-
Plan plan05 = Plan.FromYaml( $"{__plansRoot}\\{plan1Name}" );
33-
Plan plan06 = Plan.FromYaml( $"{__plansRoot}\\{plan2Name}" );
34-
Plan plan07 = Plan.FromYaml( $"{__plansRoot}\\{plan3Name}" );
35-
36-
List<Plan> plans = new List<Plan>();
37-
plans.Add( plan00 );
38-
plans.Add( plan01 );
39-
plans.Add( plan02 );
40-
plans.Add( plan03 );
41-
plans.Add( plan04 );
42-
plans.Add( plan05 );
43-
plans.Add( plan06 );
44-
plans.Add( plan07 );
45-
46-
int count = 3;
47-
if( args.Length > 1 )
48-
count = int.Parse( args[1] );
49-
50-
int instanceId = 0;
51-
try
14+
if( args.Length > 0 && (args[0].ToLower() == "interactive" || args[0].ToLower() == "i") )
5215
{
53-
Parallel.For( 0, count, ctr =>
16+
Program p = new Program()
5417
{
55-
winClient.StartPlan( instanceId++, false, plan00 );
56-
} );
18+
IsInteractive = true,
19+
};
20+
if( args.Length > 1 )
21+
{
22+
string[] s = args[1].Split( new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries );
23+
if( s.Length == 2 )
24+
p.BaseUrl = s[1];
25+
}
26+
27+
string input = Console.ReadLine();
28+
while( input.ToLower() != "exit" )
29+
{
30+
p.ProcessArgs( input.Split( ' ' ) );
31+
input = Console.ReadLine();
32+
}
33+
}
34+
else
35+
{
36+
new Program().ProcessArgs( args );
37+
}
38+
}
39+
40+
41+
Dictionary<string, string> _methods = new Dictionary<string, string>();
42+
string _service = "service";
43+
44+
public Program()
45+
{
46+
_methods.Add( "start", "StartPlan" );
47+
_methods.Add( "s", "StartPlan" );
48+
_methods.Add( "cancel", "CancelPlan" );
49+
_methods.Add( "c", "CancelPlan" );
50+
_methods.Add( "drainstop", "Drainstop" );
51+
_methods.Add( "dst", "Drainstop" );
52+
_methods.Add( "undrainstop", "Undrainstop" );
53+
_methods.Add( "ust", "Undrainstop" );
54+
_methods.Add( "DrainStatus", "GetIsDrainstopComplete" );
55+
_methods.Add( "dss", "GetIsDrainstopComplete" );
56+
_methods.Add( "QueueDepth", "GetCurrentQueueDepth" );
57+
_methods.Add( "qd", "GetCurrentQueueDepth" );
58+
_methods.Add( "QueueItems", "GetCurrentQueueItems" );
59+
_methods.Add( "qi", "GetCurrentQueueItems" );
60+
61+
SynapseNodeConfig config = SynapseNodeConfig.Deserialze();
62+
BaseUrl = $"http://localhost:{config.WebApiPort}/synapse/node";
63+
}
64+
65+
public bool IsInteractive { get; set; }
66+
public string BaseUrl { get; set; }
67+
68+
void ProcessArgs(string[] args)
69+
{
70+
if( args.Length == 0 )
71+
{
72+
WriteHelpAndExit();
5773
}
58-
catch( Exception ex )
74+
else
5975
{
60-
Console.WriteLine( Synapse.Common.WebApi.Utilities.UnwindException( ex ) );
76+
string arg0 = args[0].ToLower();
77+
78+
if( _methods.ContainsKey( arg0 ) )
79+
{
80+
if( args.Length > 1 )
81+
{
82+
bool error = false;
83+
Dictionary<string, string> parms = ParseCmdLine( args, 1, ref error, suppressErrorMessages: true );
84+
if( parms.ContainsKey( "url" ) )
85+
BaseUrl = parms["url"];
86+
}
87+
Console.WriteLine( $"Calling {_methods[arg0]} on {BaseUrl}" );
88+
RunMethod( new NodeServiceHttpApiClient( BaseUrl ), _methods[arg0], args );
89+
}
90+
else if( arg0.StartsWith( _service ) )
91+
RunServiceAction( args );
92+
else
93+
WriteHelpAndExit( "Unknown action." );
6194
}
95+
}
96+
97+
98+
protected virtual void RunServiceAction(string[] args)
99+
{
100+
if( args.Length < 2 )
101+
WriteHelpAndExit( "Not enough arguments specified." );
102+
103+
string option = args[1].ToLower();
104+
105+
switch( option )
106+
{
107+
case "run":
108+
{
109+
SynapseNodeService.RunConsole();
110+
break;
111+
}
112+
case "install":
113+
{
114+
string message = string.Empty;
115+
if( !InstallUtility.InstallService( install: true, message: out message ) )
116+
Console.WriteLine( message );
117+
break;
118+
}
119+
case "uninstall":
120+
{
121+
string message = string.Empty;
122+
if( !InstallUtility.InstallService( install: false, message: out message ) )
123+
Console.WriteLine( message );
124+
break;
125+
}
126+
default:
127+
{
128+
WriteHelpAndExit( "Unknown service action." );
129+
break;
130+
}
131+
}
132+
}
133+
134+
135+
#region Help
136+
protected override void WriteHelpAndExit(string errorMessage = null)
137+
{
138+
bool haveError = !string.IsNullOrWhiteSpace( errorMessage );
139+
140+
ConsoleColor defaultColor = Console.ForegroundColor;
141+
142+
Console_WriteLine( $"synapse.node.cli.exe, Version: {typeof( Program ).Assembly.GetName().Version}\r\n", ConsoleColor.Green );
143+
Console.WriteLine( "Syntax:" );
144+
Console_WriteLine( " synapse.node.cli.exe service {0}command{1} | {0}httpAction parm:value{1} |", ConsoleColor.Cyan, "{", "}" );
145+
Console.WriteLine( " interactive|i [url:http://{1}host:port{2}/synapse/node]\r\n", "", "{", "}" );
146+
Console_WriteLine( " interactive{0,-2}Run this CLI in interactive mode. Optionally specify URL.", ConsoleColor.Green, "" );
147+
Console.WriteLine( "{0,-15}All commands below work in standard or interactive modes.\r\n", "" );
148+
Console.WriteLine( " service{0,-6}Install/Uninstall the Windows Service, or Run the Service", "" );
149+
Console.WriteLine( "{0,-15}as a cmdline-hosted daemon.", "" );
150+
Console.WriteLine( "{0,-15}- Commands: install|uninstall|run", "" );
151+
Console.WriteLine( "{0,-15}- Example: synapse.node.cli service run\r\n", "" );
152+
Console.WriteLine( " httpAction{0,-3}Execute a command, optionally include URL", "" );
153+
Console.WriteLine( "{0,-15}Parm help: synapse.node.cli {1}httpAction{2} help.", "", "{", "}" );
154+
Console.WriteLine( "{0,-15}URL: url:http://{1}host:port{2}/synapse/node\r\n", "", "{", "}" );
155+
Console.WriteLine( " - httpActions:", "" );
156+
Console.WriteLine( " - Start|s Start a new Plan Instance.", "" );
157+
Console.WriteLine( " - Cancel|c Cancel a Plan Instance.", "" );
158+
Console.WriteLine( " - Drainstop|dst Prevents the node from receiving incoming requests;", "" );
159+
Console.WriteLine( " allows existing threads to complete. Optionally stops", "" );
160+
Console.WriteLine( " the Service when queue is fully drained.", "" );
161+
Console.WriteLine( " - DrainStatus|dss Returns true/false on whether queue is fully drained.", "" );
162+
Console.WriteLine( " - QueueDepth|qd Returns the number of items remaining in the queue.", "" );
163+
Console.WriteLine( " - QueueItems|qi Returns the list of items remaining in the queue.", "" );
164+
Console.WriteLine( " - Undrainstop|ust Resumes normal request processing.\r\n", "" );
165+
Console.WriteLine( " Examples:", "" );
166+
Console.WriteLine( " synapse.node.cli l url:http://somehost/synapse/node", "" );
167+
Console.WriteLine( " synapse.node.cli li help", "" );
168+
Console.WriteLine( " synapse.node.cli li planName:foo url:http://somehost/synapse/node", "" );
169+
Console.WriteLine( " synapse.node.cli li planName:foo", "" );
170+
Console.WriteLine( " synapse.node.cli i url:http://somehost/synapse/node", "" );
171+
Console.WriteLine( " synapse.node.cli i", "" );
172+
173+
if( haveError )
174+
Console_WriteLine( $"\r\n\r\n*** Last error:\r\n{errorMessage}\r\n", ConsoleColor.Red );
175+
176+
Console.ForegroundColor = defaultColor;
62177

63-
//Parallel.ForEach( plans, plan =>
64-
//{
65-
// winClient.StartPlan( instanceId++, false, plan );
66-
//} );
178+
if( !IsInteractive )
179+
Environment.Exit( haveError ? 1 : 0 );
67180
}
181+
#endregion
68182
}
69183
}

Synapse.NodeService.cli/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
3434
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion( "0.0.0.5" )]
36-
[assembly: AssemblyFileVersion( "0.0.0.5" )]
35+
[assembly: AssemblyVersion( "0.1.0.0" )]
36+
[assembly: AssemblyFileVersion( "0.1.0.0" )]

0 commit comments

Comments
 (0)