1 /**
2 Copyright: Copyright (c) 2015-2016 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.remotecontrol.plugin;
7 
8 import std.stdio;
9 import std.experimental.logger;
10 import std.traits : Select;
11 
12 import pluginlib;
13 import voxelman.core.events;
14 import voxelman.eventdispatcher.plugin;
15 import voxelman.command.plugin;
16 import voxelman.server.plugin;
17 
18 shared static this()
19 {
20 	pluginRegistry.regClientPlugin(new RemoteControl!true);
21 	pluginRegistry.regServerPlugin(new RemoteControl!false);
22 }
23 
24 final class RemoteControl(bool clientSide) : IPlugin
25 {
26 	alias CommandPlugin = Select!(clientSide, CommandPluginClient, CommandPluginServer);
27 
28 	// IPlugin stuff
29 	mixin IdAndSemverFrom!(voxelman.remotecontrol.plugininfo);
30 	private EventDispatcherPlugin evDispatcher;
31 	private CommandPlugin commandPlugin;
32 	private char[] buf;
33 
34 	override void preInit() {
35 		buf = new char[](2048);
36 	}
37 
38 	override void init(IPluginManager pluginman)
39 	{
40 		evDispatcher = pluginman.getPlugin!EventDispatcherPlugin;
41 		commandPlugin = pluginman.getPlugin!CommandPlugin;
42 		bool enable = true;
43 		static if (!clientSide)
44 		{
45 			ServerPlugin serverPlugin = pluginman.getPlugin!ServerPlugin;
46 			enable = serverPlugin.mode == ServerMode.dedicated;
47 		}
48 
49 		if (enable)
50 			evDispatcher.subscribeToEvent(&onPreUpdateEvent);
51 	}
52 
53 	void onPreUpdateEvent(ref PreUpdateEvent event)
54 	{
55 		try readStdin();
56 		catch (Exception e) { warningf("Exception while reading stdin: %s", e); }
57 	}
58 
59 	void readStdin()
60 	{
61 		if (!stdin.isOpen || stdin.eof || stdin.error) return;
62 
63 		auto size = stdin.size;
64 		if (size > 0 && size != ulong.max)
65 		{
66 			import std.regex : ctRegex, splitter;
67 			import std.algorithm : min;
68 			import std.array : array;
69 
70 			size_t charsToRead = min(size, buf.length);
71 			char[] data = stdin.rawRead(buf[0..charsToRead]);
72 			auto splittedLines = splitter(data, ctRegex!"(\r\n|\r|\n|\v|\f)").array;
73 
74 			while (splittedLines.length > 1)
75 			{
76 				char[] command = splittedLines[0];
77 				splittedLines = splittedLines[1..$];
78 
79 				ExecResult res = commandPlugin.execute(command, ClientId(0));
80 
81 				if (res.status == ExecStatus.notRegistered)
82 				{
83 					warningf("Unknown command '%s'", command);
84 				}
85 				else if (res.status == ExecStatus.error)
86 					warningf("Error executing command '%s': %s", command, res.error);
87 			}
88 
89 			if (splittedLines.length == 1)
90 				stdin.seek(-cast(long)splittedLines[0].length);
91 		}
92 	}
93 }