1 module handlers.handler;
2 
3 import std.stdio : writeln;
4 import std.socket : Socket, AddressFamily, parseAddress, SocketType, SocketOSException, UnixAddress;
5 import std.json : JSONValue, JSONType;
6 import utils.debugging : debugPrint;
7 
8 public final class MessageHandler
9 {
10 	/* The path to the message handler executable */
11 	private string executablePath;
12 
13 	/* The UNIX domain socket */
14 	private Socket domainSocket;
15 
16 	/* The pluginName/type */
17 	private string pluginName;
18 
19 	/* The UNIX domain socket path */
20 	public string socketPath;
21 
22 	public Socket getSocket()
23 	{
24 		return domainSocket;
25 	}
26 
27 	this(string executablePath, string socketPath, string pluginName)
28 	{
29 		/* Set the plugin name */
30 		this.pluginName = pluginName;
31 
32 		/* Initialize the socket */
33 		//initializeUNIXSocket(socketPath);
34 
35 		/* Set the socket path */
36 		this.socketPath = socketPath;
37 	}
38 
39 	public string getPluginName()
40 	{
41 		return pluginName;
42 	}
43 
44 	public Socket getNewSocket()
45 	{
46 		/* Create the UNIX domain socket */
47 		Socket domainSocket = new Socket(AddressFamily.UNIX, SocketType.STREAM);
48 		
49 		/* Connect to the socket at the socket path */
50 		domainSocket.connect(new UnixAddress(socketPath));
51 
52 		return domainSocket;
53 	}
54 
55 	private void initializeUNIXSocket(string socketPath)
56 	{
57 		/* Create the UNIX domain socket */
58 		domainSocket = new Socket(AddressFamily.UNIX, SocketType.STREAM);
59 
60 		/* Bind it to the socket path */
61 		domainSocket.connect(new UnixAddress(socketPath));
62 	}
63 
64 	private static string[] getAvailableTypes(JSONValue handlerBlock)
65 	{
66 		/* Available types as strings */
67 		string[] availableTypesStrings;
68 		
69 		/* Get the available handlers */
70 		JSONValue availableTypes;
71 		
72 		/* TODO: Bounds check */
73 		availableTypes = handlerBlock["availableTypes"];
74 		
75 		/* Make sure it is an array */
76 		if(availableTypes.type == JSONType.array)
77 		{
78 			/* Get the array of available types */
79 			JSONValue[] availableTypesArray = availableTypes.array;
80 		
81 			for(uint i = 0; i < availableTypesArray.length; i++)
82 			{
83 				/* Make sure that it is a string */
84 				if(availableTypesArray[i].type == JSONType..string)
85 				{
86 					/* Add the type handler to the list of available types */
87 					availableTypesStrings ~= availableTypesArray[i].str;
88 					debugPrint("Module wanted: " ~ availableTypesArray[i].str);
89 				}
90 				else
91 				{
92 					/* TODO: Error handling here */
93 					debugPrint("Available type not of type JSON string");
94 				}
95 			}
96 		}
97 		else
98 		{
99 			/* TODO: Error handling */
100 		}
101 
102 		return availableTypesStrings;
103 	}
104 
105 	private static string[2] getConfigurationArray(string pluginName, JSONValue typeMapBlock)
106 	{
107 		/* The configuration string */
108 		string[2] configurationString;
109 
110 		/* The module block */		
111 		JSONValue moduleBlock;
112 
113 		/* TODO: Bounds check */
114 		moduleBlock = typeMapBlock[pluginName];
115 
116 		/* Module block mst be of tpe JSON object */
117 		if(moduleBlock.type == JSONType.object)
118 		{
119 			/* TODO: Set the executable path */
120 			configurationString[0] = moduleBlock["handlerBinary"].str;
121 
122 			/* TODO: Set the UNIX domain socket path */
123 			configurationString[1] = moduleBlock["unixDomainSocketPath"].str;
124 		}
125 		else
126 		{
127 			/* TODO: Error handling */
128 		}
129 
130 		return configurationString;
131 	}
132 
133 	/* TODO: Implement me */
134 	public static MessageHandler[] constructHandlers(JSONValue handlerBlock)
135 	{
136 		/* List of loaded message handlers */
137 		MessageHandler[] handlers;
138 
139 		/* TODO: Throwing error from inside this function */
140 		string[] availableTypes = getAvailableTypes(handlerBlock);
141 
142 		for(uint i = 0; i < availableTypes.length; i++)
143 		{
144 			/* Load module */
145 			string pluginName = availableTypes[i];
146 			debugPrint("Loading module \"" ~ pluginName ~ "\"...");
147 
148 			try
149 			{
150 				JSONValue typeMap;
151 
152 				/* TODO: Bounds check */
153 				typeMap = handlerBlock["typeMap"];
154 			
155 				string[2] configuration = getConfigurationArray(pluginName, typeMap);
156 				debugPrint("Module executable at: \"" ~ configuration[0] ~ "\"");
157 				debugPrint("Module socket path at: \"" ~ configuration[1] ~ "\"");
158 				MessageHandler constructedMessageHandler = new MessageHandler(configuration[0], configuration[1], pluginName);
159 				handlers ~= constructedMessageHandler;
160 				debugPrint("Module \"" ~ pluginName ~ "\" loaded");
161 			}
162 			catch(SocketOSException exception)
163 			{
164 				debugPrint("Error whilst loading module \"" ~ pluginName ~ "\": " ~ exception.toString());
165 			}
166 		}
167 
168 		return handlers;
169 	}
170 }