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 }