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 module ae.net.shutdown;
21 
22 void addShutdownHandler(void delegate() fn)
23 {
24 	handlers ~= fn;
25 	if (handlers.length == 1) // first
26 		register();
27 }
28 
29 /// Calls all registered handlers.
30 void shutdown()
31 {
32 	foreach (fn; handlers)
33 		fn();
34 }
35 
36 private:
37 
38 static import ae.sys.shutdown;
39 import std.socket : socketPair;
40 import ae.net.asockets;
41 import ae.sys.data;
42 
43 // Per-thread
44 void delegate()[] handlers;
45 
46 final class ShutdownConnection : TcpConnection
47 {
48 	Socket pinger;
49 
50 	this()
51 	{
52 		auto pair = socketPair();
53 		pair[0].blocking = false;
54 		super(pair[0]);
55 		pinger = pair[1];
56 		this.handleReadData = &onReadData;
57 		addShutdownHandler(&onShutdown); // for manual shutdown calls
58 		this.daemon = true;
59 	}
60 
61 	void ping()
62 	{
63 		ubyte[] data = [42];
64 		pinger.send(data);
65 	}
66 
67 	void onShutdown()
68 	{
69 		pinger.close();
70 	}
71 
72 	void onReadData(Data data)
73 	{
74 		shutdown();
75 	}
76 }
77 
78 void register()
79 {
80 	auto socket = new ShutdownConnection();
81 	ae.sys.shutdown.addShutdownHandler(&socket.ping);
82 }