1 /*******************************************************************************
2 
3     Utility for handling requests via a unix socket.
4 
5     Commands can be registered to the registry and when the command is received
6     the provided delegate will be called. Any provided arguments will be split
7     by the space character and provided as an array.
8 
9     Copyright:
10         Copyright (c) 2009-2018 dunnhumby Germany GmbH.
11         All rights reserved.
12 
13     License:
14         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
15         Alternatively, this file may be distributed under the terms of the Tango
16         3-Clause BSD License (see LICENSE_BSD.txt for details).
17 
18 *******************************************************************************/
19 
20 module ocean.net.server.unix.CommandRegistry;
21 
22 import ocean.meta.types.Qualifiers;
23 
24 /// ditto
25 public class CommandsRegistry
26 {
27     import ocean.core.array.Mutation: filterInPlace;
28     import ocean.core.array.Transformation: split;
29     import ocean.core.Buffer;
30     import ocean.core.Enforce;
31     import ocean.core.Verify;
32     import ocean.text.convert.Integer;
33     import ocean.io.device.IODevice;
34 
35     /// Alias for our interactive handler delegate.
36     public alias void delegate ( cstring[],
37             void delegate (cstring),
38             void delegate (ref mstring) ) InteractiveHandler;
39 
40     /// Alias for our non-interactive handler delegate.
41     public alias void delegate ( cstring[],
42             void delegate (cstring) ) Handler;
43 
44     /// Alias for the type of handler delegate which accepts
45     /// the socket instance for direct control over it
46     public alias void delegate ( cstring[], void delegate (cstring),
47             void delegate (ref mstring), IODevice socket ) RawSocketHandler;
48 
49     /// Our registered map of interactive handlers by command.
50     private InteractiveHandler[istring] interactive_handlers;
51 
52     /// Our registered map of handlers by command.
53     private Handler[istring] handlers;
54 
55     /// Registered map of handlers that accept socket by command.
56     private RawSocketHandler[istring] handlers_ex;
57 
58     /// Stores the command arguments split by " ";
59     private cstring[] args_buf;
60 
61     /***************************************************************************
62 
63         Receives all commands from the socket and splits the command by " ".
64         If a matching command is registered then the command will be called with
65         the remaining arguments. This method will be called by the
66         UnixSocketListener whenever a command is received.
67 
68         Params:
69             command = The command received by the unix socket.
70             args = The arguments provided with the command.
71             send_response = Delegate to call with response string.
72             wait_reply = Delegate to call to obtain the reply from the user
73             socket = connected socket stream
74 
75     ***************************************************************************/
76 
77     public void handle ( cstring command, cstring args,
78                  scope void delegate (cstring) send_response,
79                  scope void delegate (ref mstring buf) wait_reply,
80                  IODevice socket )
81     {
82         scope predicate = (cstring v) { return !v.length; };
83 
84         // escape the command, remove empty elements.
85         scope arguments_split = () {
86             split(args, " ", this.args_buf);
87             return this.args_buf[0..filterInPlace(this.args_buf[], predicate)];
88         };
89 
90         if (auto handler = command in this.interactive_handlers)
91         {
92             auto arguments = arguments_split();
93             (*handler)(arguments, send_response, wait_reply);
94         }
95         else if (auto handler = command in this.handlers)
96         {
97             auto arguments = arguments_split();
98             (*handler)(arguments, send_response);
99         }
100         else if (auto handler = command in handlers_ex)
101         {
102             auto arguments = arguments_split();
103             (*handler)(arguments, send_response, wait_reply, socket);
104         }
105         else
106         {
107             send_response("Command not found\n");
108         }
109     }
110 
111     /***************************************************************************
112 
113         Register a command and interactive handler to the unix listener.
114 
115         Params:
116             command = The command to listen for in the socket listener.
117             handler = The interactive handler to call when command is received.
118 
119     ***************************************************************************/
120 
121     public void addHandler ( istring command,
122         scope InteractiveHandler handler )
123     {
124         this.interactive_handlers[command] = handler;
125     }
126 
127     /***************************************************************************
128 
129         Register a command and a handler the registry.
130 
131         Params:
132             command = The command name
133             handler = The handler to call when command is received.
134 
135     ***************************************************************************/
136 
137     public void addHandler ( istring command, scope Handler handler )
138     {
139         this.handlers[command] = handler;
140     }
141 
142     /***************************************************************************
143 
144         Registers a command and the raw socket handler with the registry
145 
146         Params:
147             command = The command name
148             handler = The handler to call when command is received.
149 
150     ***************************************************************************/
151 
152     public void addHandler ( istring command, scope RawSocketHandler handler )
153     {
154         this.handlers_ex[command] = handler;
155     }
156 
157     /***************************************************************************
158 
159         Register a command and handler to the unix listener.
160 
161         Params:
162             command = The command name of the command to remove from the registry
163 
164     ***************************************************************************/
165 
166     public void removeHandler ( istring command )
167     {
168         this.handlers.remove(command);
169         this.interactive_handlers.remove(command);
170         this.handlers_ex.remove(command);
171     }
172 }