1 /*
2  * MsgTrans - Message Transport Framework for DLang. Based on TCP, WebSocket, UDP transmission protocol.
3  *
4  * Copyright (C) 2019 HuntLabs
5  *
6  * Website: https://www.msgtrans.org
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module msgtrans.channel.tcp.TcpDecoder;
13 
14 import msgtrans.PacketParser;
15 import msgtrans.MessageBuffer;
16 
17 import hunt.io.ByteBuffer;
18 import hunt.io.BufferUtils;
19 import hunt.io.channel.Common;
20 import hunt.Exceptions;
21 import hunt.logging.ConsoleLogger;
22 import hunt.net;
23 
24 import std.algorithm;
25 import std.conv;
26 
27 
28 class TcpDecoder : DecoderChain {
29     private enum string PARSER = "PacketParser";
30 
31     /** The default maximum buffer length. Default to 128 chars. */
32     private int bufferLength = 128;
33 
34     /** The default maximum Line length. Default to 1024. */
35     private int maxLineLength = 8*1024;
36 
37 
38     this() {
39         super(null);
40     }
41 
42 
43     /**
44      * @return the allowed maximum size of the line to be decoded.
45      * If the size of the line to be decoded exceeds this value, the
46      * decoder will throw a {@link BufferDataException}.  The default
47      * value is <tt>1024</tt> (1KB).
48      */
49     int getMaxLineLength() {
50         return maxLineLength;
51     }
52 
53     /**
54      * Sets the allowed maximum size of the line to be decoded.
55      * If the size of the line to be decoded exceeds this value, the
56      * decoder will throw a {@link BufferDataException}.  The default
57      * value is <tt>1024</tt> (1KB).
58      *
59      * @param maxLineLength The maximum line length
60      */
61     void setMaxLineLength(int maxLineLength) {
62         if (maxLineLength <= 0) {
63             throw new IllegalArgumentException("maxLineLength (" ~
64                 maxLineLength.to!string() ~ ") should be a positive value");
65         }
66 
67         this.maxLineLength = maxLineLength;
68     }
69 
70     /**
71      * Sets the default buffer size. This buffer is used in the Context
72      * to store the decoded line.
73      *
74      * @param bufferLength The default bufer size
75      */
76     void setBufferLength(int bufferLength) {
77         if (bufferLength <= 0) {
78             throw new IllegalArgumentException("bufferLength (" ~
79                 maxLineLength.to!string() ~ ") should be a positive value");
80 
81         }
82 
83         this.bufferLength = bufferLength;
84     }
85 
86     /**
87      * @return the allowed buffer size used to store the decoded line
88      * in the Context instance.
89      */
90     int getBufferLength() {
91         return bufferLength;
92     }
93 
94     override
95     DataHandleStatus decode(ByteBuffer buf, Connection connection) {
96         version(HUNT_MESSAGE_DEBUG) tracef("connection %d: %s", connection.getId(), buf.toString());
97         PacketParser parser = getParser(connection);
98 
99         MessageBuffer[] msgBuffers = parser.parse(buf);
100         if(msgBuffers is null) {
101             warning("No frame parsed.");
102             return DataHandleStatus.Done;
103         }
104 
105         NetConnectionHandler handler = connection.getHandler();
106         if(handler is null) {
107             warning("No handler found.");
108             return DataHandleStatus.Done;
109         }
110 
111         foreach(MessageBuffer msg; msgBuffers) {
112             handler.messageReceived(connection, msg);
113         }
114 
115 
116         return DataHandleStatus.Done;
117     }
118 
119     private PacketParser getParser(Connection connection) {
120         PacketParser ctx;
121         ctx = cast(PacketParser) connection.getAttribute(PARSER);
122 
123         if (ctx is null) {
124             ctx = new PacketParser(bufferLength);
125             connection.setAttribute(PARSER, ctx);
126         }
127 
128         return ctx;
129     }
130 
131 
132     void dispose(Connection connection) {
133         PacketParser ctx = cast(PacketParser) connection.getAttribute(PARSER);
134 
135         if (ctx !is null) {
136             connection.removeAttribute(PARSER);
137         }
138     }
139 
140 }
141