1 module hunt.http.codec.websocket.stream.ExtensionNegotiator;
2 
3 import hunt.http.codec.http.model.HttpHeader;
4 import hunt.http.codec.http.model.MetaData;
5 import hunt.http.codec.websocket.model.Extension;
6 import hunt.http.codec.websocket.model.ExtensionConfig;
7 import hunt.http.codec.websocket.model.IncomingFrames;
8 import hunt.http.codec.websocket.model.OutgoingFrames;
9 import hunt.http.codec.websocket.model.extension.AbstractExtension;
10 import hunt.http.codec.websocket.model.extension.ExtensionFactory;
11 import hunt.http.codec.websocket.model.extension.WebSocketExtensionFactory;
12 
13 import hunt.container;
14 
15 import hunt.http.codec.websocket.model.ExtensionConfig;
16 
17 import hunt.container;
18 import hunt.lang.exception;
19 
20 import std.algorithm;
21 import std.array;
22 import std.container.array;
23 import std.range;
24 
25 /**
26  * 
27  */
28 class ExtensionNegotiator {
29 
30     private ExtensionFactory factory;
31     private IncomingFrames nextIncomingFrames;
32     private OutgoingFrames nextOutgoingFrames;
33     private IncomingFrames incomingFrames;
34     private OutgoingFrames outgoingFrames;
35 
36     this() {
37         this(new WebSocketExtensionFactory());
38     }
39 
40     this(ExtensionFactory factory) {
41         this.factory = factory;
42     }
43 
44     ExtensionFactory getFactory() {
45         return factory;
46     }
47 
48     void setFactory(ExtensionFactory factory) {
49         this.factory = factory;
50     }
51 
52     ExtensionConfig[] negotiate(MetaData metaData) {
53         InputRange!string fieldValues = metaData.getFields().getValues(HttpHeader.SEC_WEBSOCKET_EXTENSIONS.asString());
54 
55         Array!(ExtensionConfig) configList = ExtensionConfig.parseEnum(fieldValues);
56         auto r = configList[].filter!(c => factory.isAvailable(c.getName()));
57 
58         return r.array;
59         // return parseEnum(metaData.getFields().getValues(HttpHeader.SEC_WEBSOCKET_EXTENSIONS.asString()))
60         //         .stream().filter(c -> factory.isAvailable(c.getName()))
61         //         .collect(Collectors.toList());
62     }
63 
64     Extension[] parse(MetaData metaData) {
65         assert(nextIncomingFrames !is null, "The next incoming frames MUST be not null");
66         assert(nextOutgoingFrames !is null, "The next outgoing frames MUST be not null");
67 
68         Extension[] extensions = _parse(metaData);
69         if (!extensions.empty) {
70             size_t len = extensions.length;
71             for (size_t i = 0; i < len; i++) {
72                 size_t next = i + 1;
73                 if (next < len - 1) {
74                     extensions[i].setNextIncomingFrames(extensions[next]);
75                 } else {
76                     extensions[i].setNextIncomingFrames(nextIncomingFrames);
77                 }
78             }
79             incomingFrames = extensions[0];
80 
81             for (size_t i = len - 1; i >= 0; i--) {
82                 size_t next = i - 1;
83                 if (next > 0) {
84                     extensions[i].setNextOutgoingFrames(extensions[next]);
85                 } else {
86                     extensions[i].setNextOutgoingFrames(nextOutgoingFrames);
87                 }
88             }
89             outgoingFrames = extensions[len - 1];
90             return extensions;
91         } else {
92             incomingFrames = nextIncomingFrames;
93             outgoingFrames = nextOutgoingFrames;
94             return [];
95         }
96     }
97 
98     protected Extension[] _parse(MetaData metaData) {
99 
100         InputRange!string fieldValues = metaData.getFields().getValues(HttpHeader.SEC_WEBSOCKET_EXTENSIONS.asString());
101         Array!(ExtensionConfig) configList = ExtensionConfig.parseEnum(fieldValues);
102         auto r = configList[].filter!(c => factory.isAvailable(c.getName()))
103             .map!(delegate Extension (ExtensionConfig c) {
104                 Extension e = factory.newInstance(c);
105                 AbstractExtension abstractExtension = cast(AbstractExtension) e;
106                 if (abstractExtension !is null) 
107                     abstractExtension.setConfig(c);
108                 return e;
109             });
110 
111         return r.array;
112     }
113 
114     IncomingFrames getNextIncomingFrames() {
115         return nextIncomingFrames;
116     }
117 
118     void setNextIncomingFrames(IncomingFrames nextIncomingFrames) {
119         this.nextIncomingFrames = nextIncomingFrames;
120     }
121 
122     OutgoingFrames getNextOutgoingFrames() {
123         return nextOutgoingFrames;
124     }
125 
126     void setNextOutgoingFrames(OutgoingFrames nextOutgoingFrames) {
127         this.nextOutgoingFrames = nextOutgoingFrames;
128     }
129 
130     IncomingFrames getIncomingFrames() {
131         return incomingFrames;
132     }
133 
134     OutgoingFrames getOutgoingFrames() {
135         return outgoingFrames;
136     }
137 
138 }