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