1 module hunt.http.codec.http.encode.DataGenerator;
2 
3 import hunt.http.codec.http.encode.HeaderGenerator;
4 
5 import hunt.http.codec.http.frame.DataFrame;
6 import hunt.http.codec.http.frame.Flags;
7 import hunt.http.codec.http.frame.Frame;
8 import hunt.http.codec.http.frame.FrameType;
9 
10 import hunt.collection;
11 import hunt.Exceptions;
12 
13 import std.algorithm;
14 import std.conv;
15 import std.typecons;
16 
17 
18 /**
19 */
20 class DataGenerator {
21 	private HeaderGenerator headerGenerator;
22 
23 	this(HeaderGenerator headerGenerator) {
24 		this.headerGenerator = headerGenerator;
25 	}
26 
27 	Tuple!(int, List!(ByteBuffer))   generate(DataFrame frame, int maxLength) {
28 		return generateData(frame.getStreamId(), frame.getData(), frame.isEndStream(), maxLength);
29 	}
30 
31 	Tuple!(int, List!(ByteBuffer)) generateData(int streamId, ByteBuffer data, bool last, int maxLength) {
32 		if (streamId < 0)
33 			throw new IllegalArgumentException("Invalid stream id: " ~ streamId.to!string);
34 
35 		List!ByteBuffer list = new LinkedList!(ByteBuffer)();
36 
37 		int dataLength = data.remaining();
38 		int maxFrameSize = headerGenerator.getMaxFrameSize();
39 		int length = std.algorithm.min(dataLength, std.algorithm.min(maxFrameSize, maxLength));
40 		if (length == dataLength) {
41 			generateFrame(streamId, data, last, list);
42 		} else {
43 			int limit = data.limit();
44 			int newLimit = data.position() + length;
45 			data.limit(newLimit);
46 			ByteBuffer slice = data.slice();
47 			data.position(newLimit);
48 			data.limit(limit);
49 			generateFrame(streamId, slice, false, list);
50 		}
51 		return tuple(length + Frame.HEADER_LENGTH, list);
52 	}
53 
54 	private void generateFrame(int streamId, ByteBuffer data, bool last, List!ByteBuffer list) {
55 		int length = data.remaining();
56 
57 		int flags = Flags.NONE;
58 		if (last)
59 			flags |= Flags.END_STREAM;
60 
61 		ByteBuffer header = headerGenerator.generate(FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags,
62 				streamId);
63 
64 		BufferUtils.flipToFlush(header, 0);
65 		list.add(header);
66 
67 		if (data.remaining() > 0)
68 			list.add(data);
69 	}
70 
71 }