1 module hio.common;
2 
3 import std.exception;
4 import std.conv;
5 import core.stdc.string: strerror;
6 import std.experimental.logger;
7 
8 import core.sys.posix.sys.socket;
9 import core.stdc.string;
10 import core.stdc.errno;
11 import core.sys.posix.unistd;
12 
13 auto s_strerror(T)(T e) @trusted {
14     return to!string(strerror(e));
15 }
16 
17 SocketPair makeSocketPair() @safe {
18     import core.sys.posix.fcntl;
19     int[2] pair;
20     auto r = (() @trusted => socketpair(AF_UNIX, SOCK_DGRAM, 0, pair))();
21     if ( r == -1 ) {
22         throw new Exception(s_strerror(errno()));
23     }
24     auto flags = (() @trusted => fcntl(pair[0], F_GETFL, 0) | O_NONBLOCK)();
25     (() @trusted => fcntl(pair[0], F_SETFL, flags))();
26     flags = (() @trusted => fcntl(pair[1], F_GETFL, 0) | O_NONBLOCK)();
27     (() @trusted => fcntl(pair[1], F_SETFL, flags))();
28     SocketPair result;
29     result._pair = pair;
30     return result;
31 }
32 
33 
34 struct SocketPair {
35     int[2]  _pair = [-1, -1];
36     ~this() @safe {
37         (() @trusted => close())();
38     }
39     public void close() {
40         if ( _pair[0] >= 0 ) {
41             core.sys.posix.unistd.close(_pair[0]);
42         }
43         if ( _pair[1] >= 0 ) {
44             core.sys.posix.unistd.close(_pair[1]);
45         }
46         _pair = [-1, -1];
47     }
48     auto opIndex(size_t i) const {
49         return _pair[i];
50     }
51     auto read(uint i, size_t len) @safe
52     {
53         enforce!Exception(i <= 1, "Index in socketpair must be 0 or 1");
54         if ( len <= 0 ) {
55             throw new Exception("read length must be > 0");
56         }
57         ubyte[] b = new ubyte[](len);
58         auto s = (() @trusted => core.sys.posix.unistd.read(_pair[i], b.ptr, len))();
59         enforce!Exception(s > 0, "failed to read from socketpair");
60         return b;
61     }
62     auto write(uint i, ubyte[] b) @safe {
63         return (() @trusted => core.sys.posix.unistd.write(_pair[i], b.ptr, b.length))();
64     }
65 }
66 
67 
68 //class NotificationChannel {
69 //    import  containers;
70 
71 //    private enum NotificationType {Signal, Broadcast}
72 //
73 //    private NotificationType _type = NotificationType.Signal;
74 //
75 //    private SList!(void delegate() @safe) _subscribers;
76 //
77 //    SocketPair  _pipe;
78 //
79 //    auto readEnd() const @safe @nogc {
80 //        return _pipe[0];
81 //    }
82 //
83 //    auto writeEnd() const @safe @nogc {
84 //        return _pipe[1];
85 //    }
86 //
87 //    void handler() @safe {
88 //        with (NotificationType) final switch(_type) {
89 //        case Signal:
90 //            auto s = _subscribers.front;
91 //            s();
92 //            break;
93 //        case Broadcast:
94 //            foreach(s; _subscribers) {
95 //                s();
96 //            }
97 //            break;
98 //        }
99 //    }
100 //
101 //    this() @safe {
102 //        _pipe = makeSocketPair();
103 //    }
104 //    shared this() @safe {
105 //        //_pipe = makeSocketPair();
106 //    }
107 //    void subscribe(void delegate() @safe h) @safe {
108 //        _subscribers ~= h;
109 //    }
110 //    void unsubscribe(void delegate() @safe h) @safe {
111 //        _subscribers.remove(h);
112 //    }
113 //
114 //    auto signal() @property @safe @nogc {
115 //        _type = NotificationType.Signal;
116 //        ubyte[1] b = [0];
117 //        auto s = _pipe.write(1, b);
118 //        return this;
119 //    }
120 //    auto broadcast() @property @safe @nogc {
121 //        _type = NotificationType.Broadcast;
122 //        ubyte[1] b = [0];
123 //        auto s = _pipe.write(1, b);
124 //        return this;
125 //    }
126 //}
127