1 /**
2  * Integration with and wrapper around ae.sys.shutdown
3  * for networked (ae.net.asockets-based) applications.
4  *
5  * Unlike ae.sys.shutdown, the handlers are called from
6  * within the same thread they were registered from -
7  * provided that socketManager.loop() is running in that
8  * thread.
9  *
10  * License:
11  *   This Source Code Form is subject to the terms of
12  *   the Mozilla Public License, v. 2.0. If a copy of
13  *   the MPL was not distributed with this file, You
14  *   can obtain one at http://mozilla.org/MPL/2.0/.
15  *
16  * Authors:
17  *   Vladimir Panteleev <vladimir@thecybershadow.net>
18  */
19 
20 // TODO: Unify addShutdownHandler under a common API.
21 // The host program should decide which shutdown
22 // driver to use.
23 
24 // TODO: Add shuttingDown property
25 
26 module ae.net.shutdown;
27 
28 void addShutdownHandler(void delegate() fn)
29 {
30 	handlers ~= fn;
31 	if (handlers.length == 1) // first
32 		register();
33 }
34 
35 /// Calls all registered handlers.
36 void shutdown()
37 {
38 	foreach (fn; handlers)
39 		fn();
40 }
41 
42 private:
43 
44 static import ae.sys.shutdown;
45 import std.socket : socketPair;
46 import ae.net.asockets;
47 import ae.sys.data;
48 
49 // Per-thread
50 void delegate()[] handlers;
51 
52 final class ShutdownConnection : TcpConnection
53 {
54 	Socket pinger;
55 
56 	this()
57 	{
58 		auto pair = socketPair();
59 		pair[0].blocking = false;
60 		super(pair[0]);
61 		pinger = pair[1];
62 		this.handleReadData = &onReadData;
63 		addShutdownHandler(&onShutdown); // for manual shutdown calls
64 		this.daemon = true;
65 	}
66 
67 	void ping() //@nogc
68 	{
69 		static immutable ubyte[1] data = [42];
70 		pinger.send(data[]);
71 	}
72 
73 	void onShutdown()
74 	{
75 		pinger.close();
76 	}
77 
78 	void onReadData(Data data)
79 	{
80 		shutdown();
81 	}
82 }
83 
84 void register()
85 {
86 	auto socket = new ShutdownConnection();
87 	ae.sys.shutdown.addShutdownHandler(&socket.ping);
88 }