1 module hunt.net.Connection;
2 
3 import hunt.net.AsyncResult;
4 
5 import hunt.io.ByteBuffer;
6 import hunt.collection.Collection;
7 import hunt.io.TcpStream;
8 import hunt.util.Common;
9 
10 import core.time;
11 import std.socket;
12 
13 
14 deprecated("Using Connection instead.")
15 alias TcpSession = Connection;
16 deprecated("Using Connection instead.")
17 alias Session = Connection;
18 
19 // alias NetEventHandler(E) = void delegate(E event);
20 // alias NetEventHandler(T, U) = void delegate(T t, U u);
21 template NetEventHandler(T...) if(T.length > 0)  {
22     alias NetEventHandler = void delegate(T);
23 }
24 
25 alias NetConnectHandler = NetEventHandler!Connection;
26 alias NetMessageHandler = NetEventHandler!(Connection, Object);
27 alias NetExceptionHandler = NetEventHandler!(Connection, Throwable);
28 alias NetErrorHandler = NetEventHandler!(int, Throwable);
29 // alias AsyncConnectHandler = NetEventHandler!(AsyncResult!Connection);
30 // alias AsyncVoidResultHandler = NetEventHandler!(AsyncResult!(Void));
31 
32 enum ConnectionState {
33     Ready,
34     Error,
35     Opening,
36     Opened,
37     Securing,
38     Secured,
39     // Idle,
40     // Active,
41     // Broken,
42     Closing,
43     Closed
44 }
45 
46 /**
47  * <p>
48  *   A handle which represents connection between two end-points regardless of
49  *   transport types.
50  * </p>
51  * <p>
52  *   {@link Connection} provides user-defined attributes.  User-defined attributes
53  *   are application-specific data which are associated with a connection.
54  *   It often contains objects that represents the state of a higher-level protocol
55  *   and becomes a way to exchange data between filters and handlers.
56  * </p>
57  * <h3>Adjusting Transport Type Specific Properties</h3>
58  * <p>
59  *   You can simply downcast the connection to an appropriate subclass.
60  * </p>
61  * <h3>Thread Safety</h3>
62  * <p>
63  *   {@link Connection} is thread-safe.  But please note that performing
64  *   more than one {@link #write(Object)} calls at the same time will
65  *   cause the {@link IoFilter#filterWrite(IoFilter.NextFilter,Connection,WriteRequest)}
66  *   to be executed simultaneously, and therefore you have to make sure the
67  *   {@link IoFilter} implementations you're using are thread-safe, too.
68  * </p>
69  * <h3>Equality of Connections</h3>
70  * TODO : The getId() method is totally wrong. We can't base
71  * a method which is designed to create a unique ID on the hashCode method.
72  * {@link Object#equals(Object)} and {@link Object#hashCode()} shall not be overriden
73  * to the default behavior that is defined in {@link Object}.
74  *
75  * @author <a href="http://mina.apache.org">Apache MINA Project</a>
76  */
77 interface Connection : Closeable {
78 
79     TcpStream getStream();
80 
81     ConnectionState getState();
82     
83     void setState(ConnectionState state);
84 
85     /**
86      * @return the EventHandler which handles this connection.
87      */
88     NetConnectionHandler getHandler();    
89 
90     /**
91      * Returns the value of the user-defined attribute of this connection.
92      *
93      * @param key the key of the attribute
94      * @return <tt>null</tt> if there is no attribute with the specified key
95      */
96     Object getAttribute(string key);
97 
98     /**
99      * Returns the value of user defined attribute associated with the
100      * specified key.  If there's no such attribute, the specified default
101      * value is associated with the specified key, and the default value is
102      * returned.  This method is same with the following code except that the
103      * operation is performed atomically.
104      * <pre>
105      * if (containsAttribute(key)) {
106      *     return getAttribute(key);
107      * } else {
108      *     setAttribute(key, defaultValue);
109      *     return defaultValue;
110      * }
111      * </pre>
112      * 
113      * @param key the key of the attribute we want to retreive
114      * @param defaultValue the default value of the attribute
115      * @return The retrieved attribute or <tt>null</tt> if not found
116      */
117     Object getAttribute(string key, Object defaultValue);
118 
119     /**
120      * Sets a user-defined attribute.
121      *
122      * @param key the key of the attribute
123      * @param value the value of the attribute
124      * @return The old value of the attribute.  <tt>null</tt> if it is new.
125      */
126     Object setAttribute(string key, Object value);
127 
128     /**
129      * Sets a user defined attribute without a value.  This is useful when
130      * you just want to put a 'mark' attribute.  Its value is set to
131      * {@link bool#TRUE}.
132      *
133      * @param key the key of the attribute
134      * @return The old value of the attribute.  <tt>null</tt> if it is new.
135      */
136     Object setAttribute(string key);
137 
138     /**
139      * Sets a user defined attribute if the attribute with the specified key
140      * is not set yet.  This method is same with the following code except
141      * that the operation is performed atomically.
142      * <pre>
143      * if (containsAttribute(key)) {
144      *     return getAttribute(key);
145      * } else {
146      *     return setAttribute(key, value);
147      * }
148      * </pre>
149      * 
150      * @param key The key of the attribute we want to set
151      * @param value The value we want to set
152      * @return The old value of the attribute.  <tt>null</tt> if not found.
153      */
154     Object setAttributeIfAbsent(string key, Object value);
155 
156     /**
157      * Sets a user defined attribute without a value if the attribute with
158      * the specified key is not set yet.  This is useful when you just want to
159      * put a 'mark' attribute.  Its value is set to {@link bool#TRUE}.
160      * This method is same with the following code except that the operation
161      * is performed atomically.
162      * <pre>
163      * if (containsAttribute(key)) {
164      *     return getAttribute(key);  // might not always be bool.TRUE.
165      * } else {
166      *     return setAttribute(key);
167      * }
168      * </pre>
169      * 
170      * @param key The key of the attribute we want to set
171      * @return The old value of the attribute.  <tt>null</tt> if not found.
172      */
173     Object setAttributeIfAbsent(string key);
174 
175     /**
176      * Removes a user-defined attribute with the specified key.
177      *
178      * @param key The key of the attribute we want to remove
179      * @return The old value of the attribute.  <tt>null</tt> if not found.
180      */
181     Object removeAttribute(string key);
182 
183     /**
184      * Removes a user defined attribute with the specified key if the current
185      * attribute value is equal to the specified value.  This method is same
186      * with the following code except that the operation is performed
187      * atomically.
188      * <pre>
189      * if (containsAttribute(key) &amp;&amp; getAttribute(key).equals(value)) {
190      *     removeAttribute(key);
191      *     return true;
192      * } else {
193      *     return false;
194      * }
195      * </pre>
196      * 
197      * @param key The key we want to remove
198      * @param value The value we want to remove
199      * @return <tt>true</tt> if the removal was successful
200      */
201     bool removeAttribute(string key, Object value);
202 
203     /**
204      * Replaces a user defined attribute with the specified key if the
205      * value of the attribute is equals to the specified old value.
206      * This method is same with the following code except that the operation
207      * is performed atomically.
208      * <pre>
209      * if (containsAttribute(key) &amp;&amp; getAttribute(key).equals(oldValue)) {
210      *     setAttribute(key, newValue);
211      *     return true;
212      * } else {
213      *     return false;
214      * }
215      * </pre>
216      * 
217      * @param key The key we want to replace
218      * @param oldValue The previous value
219      * @param newValue The new value
220      * @return <tt>true</tt> if the replacement was successful
221      */
222     bool replaceAttribute(string key, Object oldValue, Object newValue);
223 
224     /**
225      * @param key The key of the attribute we are looking for in the connection 
226      * @return <tt>true</tt> if this connection contains the attribute with
227      * the specified <tt>key</tt>.
228      */
229     bool containsAttribute(string key);
230 
231     /**
232      * @return the set of keys of all user-defined attributes.
233      */
234     string[] getAttributeKeys();
235 
236     void encode(Object message);
237 
238     // void encode(ByteBuffer[] message);
239 
240     // void encode(ByteBufferOutputEntry message);
241 
242     // void notifyMessageReceived(Object message);
243 
244     /**
245      * Writes the specified <code>message</code> to remote peer.  This
246      * operation is asynchronous; {@link IoHandler#messageSent(Connection,Object)}
247      * will be invoked when the message is actually sent to remote peer.
248      * You can also wait for the returned {@link WriteFuture} if you want
249      * to wait for the message actually written.
250      * 
251      * @param message The message to write
252      * @return The associated WriteFuture
253      */
254     void write(Object message); // It's same as void encode(Object message);
255 
256 
257     // void write(OutputEntry<?> entry);
258     // void write(ByteBufferOutputEntry entry);
259 
260     void write(const(ubyte)[] data);
261     void write(string str);
262     void write(ByteBuffer buffer);
263 
264     void write(ByteBuffer byteBuffer, Callback callback);
265 
266     // void write(ByteBuffer[] buffers, Callback callback);
267 
268     // void write(Collection!ByteBuffer buffers, Callback callback);
269 
270     // void write(FileRegion file, Callback callback);
271 
272     int getId();
273 
274 version(HUNT_METRIC) {
275     long getOpenTime();
276 
277     long getCloseTime();
278 
279     long getDuration();
280 
281     long getLastReadTime();
282 
283     long getLastWrittenTime();
284 
285     long getLastActiveTime();
286 
287     size_t getReadBytes();
288 
289     size_t getWrittenBytes();
290 
291     long getIdleTimeout();
292 
293     string toString();
294 }    
295 
296     void close();
297 
298     // void closeNow();
299 
300     void shutdownOutput();
301 
302     void shutdownInput();
303 
304     // bool isOpen();
305 
306     // bool isClosed();
307 
308     /**
309      * @return <tt>true</tt> if this connection is connected with remote peer.
310      */
311     bool isConnected();
312     
313     /**
314      * @return <tt>true</tt> if this connection is active.
315      */
316     bool isActive();
317 
318     /**
319      * @return <tt>true</tt> if and only if this connection is being closed
320      * (but not disconnected yet) or is closed.
321      */
322     bool isClosing();
323     
324     /**
325      * @return <tt>true</tt> if the connection has started and initialized a SslEngine,
326      * <tt>false</tt> if the connection is not yet secured (the handshake is not completed)
327      * or if SSL is not set for this connection, or if SSL is not even an option.
328      */
329     bool isSecured();    
330 
331     bool isShutdownOutput();
332 
333     bool isShutdownInput();
334 
335     bool isWaitingForClose();
336 
337     Address getLocalAddress();
338 
339     Address getRemoteAddress();
340 
341     Duration getMaxIdleTimeout();
342 }
343 
344 
345 deprecated("Using NetConnectionHandler instead.")
346 alias ConnectionEventHandler = NetConnectionHandler;
347 
348 alias ConnectionEventHandlerAdapter = NetConnectionHandlerAdapter;
349 
350 /**
351  * Handles all I/O events on a socket connection.
352  *
353  */
354 abstract class NetConnectionHandler {
355 
356 	void connectionOpened(Connection connection) ;
357 
358 	void connectionClosed(Connection connection) ;
359 
360 	void messageReceived(Connection connection, Object message) ;
361 
362 	void exceptionCaught(Connection connection, Throwable t) ;
363 
364 	void failedOpeningConnection(int connectionId, Throwable t) { }
365 
366 	void failedAcceptingConnection(int connectionId, Throwable t) { }
367 }
368 
369 alias NetConnectionHandlerAdapter = AbstractNetConnectionHandler;
370 
371 /**
372  * 
373  */
374 class AbstractNetConnectionHandler : NetConnectionHandler {
375 
376     private NetConnectHandler _openedHandler;
377     private NetConnectHandler _closedHandler;
378     private NetMessageHandler _messageHandler;
379     private NetExceptionHandler _exceptionHandler;
380     private NetErrorHandler _openFailedHandler;
381     private NetErrorHandler _acceptFailedHandler;
382 
383     this() {
384 
385     }
386 
387     /* ----------------------------- Event Handlers ----------------------------- */
388 
389     ///
390     void onOpened(NetConnectHandler handler) {
391         _openedHandler = handler;
392     }
393 
394     void onClosed(NetConnectHandler handler) {
395         _closedHandler = handler;
396     }
397 
398     void onMessageReceived(NetMessageHandler handler) {
399         _messageHandler = handler;
400     }
401 
402     void onException(NetExceptionHandler handler) {
403         _exceptionHandler = handler;
404     }
405 
406     void onOpenFailed(NetErrorHandler handler) {
407         _openFailedHandler = handler;
408     }
409 
410     /* ------------------------ NetConnectionHandler APIs ----------------------- */
411 
412     ///
413     override void connectionOpened(Connection connection) {
414         if(_openedHandler !is null) 
415             _openedHandler(connection);
416     }
417 
418 	override void connectionClosed(Connection connection) {
419         if(_closedHandler !is null)
420             _closedHandler(connection);
421     }
422 
423 	override void messageReceived(Connection connection, Object message) {
424         if(_messageHandler !is null)
425             _messageHandler(connection, message);
426     }
427 
428 	override void exceptionCaught(Connection connection, Throwable e) {
429         if(_exceptionHandler !is null)
430             _exceptionHandler(connection, e);
431     }
432 
433 	override void failedOpeningConnection(int connectionId, Throwable e) { 
434         if(_openFailedHandler !is null)
435             _openFailedHandler(connectionId, e);
436     }
437 
438 	override void failedAcceptingConnection(int connectionId, Throwable e) { 
439         if(_acceptFailedHandler !is null) 
440             _acceptFailedHandler(connectionId, e);
441     }
442 }