1 module hunt.http.routing.impl.AbstractRegexMatcher;
2
3 import hunt.http.routing.Matcher;
4 import hunt.http.routing.Router;
5
6 import hunt.collection;
7 import hunt.Exceptions;
8
9 import hunt.logging;
10
11 import std.conv;
12 import std.regex;
13
14
15 /**
16 *
17 */
18 abstract class AbstractRegexMatcher : Matcher {
19
20 protected Map!(RegexRule, Set!Router) _regexMap;
21
22 protected static class RegexRule {
23 string rule;
24 Regex!char pattern;
25
26 protected this(string rule) {
27 this.rule = rule;
28 pattern = regex(rule);
29 }
30
31 override
32 bool opEquals(Object o) {
33 if (this is o) return true;
34 RegexRule regexRule = cast(RegexRule) o;
35 if(regexRule is null) return false;
36 return rule == regexRule.rule;
37 }
38
39 override
40 size_t toHash() @trusted nothrow {
41 return hashOf(rule);
42 }
43 }
44
45 protected Map!(RegexRule, Set!(Router)) regexMap() {
46 if (_regexMap is null) {
47 _regexMap = new HashMap!(RegexRule, Set!(Router))();
48 }
49 return _regexMap;
50 }
51
52 override
53 void add(string rule, Router router) {
54 // regexMap().computeIfAbsent(new RegexRule(rule), k -> new HashSet<>()).add(router);
55 auto r = new RegexRule(rule);
56 if(regexMap().containsKey(r))
57 {
58 regexMap()[r].add(router);
59 }
60 else
61 {
62 auto hs = new HashSet!(Router)();
63 hs.add(router);
64 regexMap().put(r, hs);
65 }
66 }
67
68 override
69 MatchResult match(string value) {
70 if (_regexMap is null) {
71 return null;
72 }
73
74 Set!Router routers = new HashSet!Router();
75 Map!(Router, Map!(string, string)) parameters = new HashMap!(Router, Map!(string, string))();
76
77 foreach(RegexRule rule, Set!Router routerSet; _regexMap)
78 {
79 // tracef("v=%s, pattern=%s", value, rule.rule);
80 RegexMatch!string m = matchAll(value, rule.pattern);
81
82 if (m.empty)
83 continue;
84
85 routers.addAll(routerSet);
86
87 Map!(string, string) param = new HashMap!(string, string)();
88 foreach(Captures!string item; m)
89 {
90 // tracef("front:%s, length:%d", item.front, item.length);
91 for (size_t i = 1; i <item.length; i++) {
92 // tracef("%d => %s", i, item[i]);
93 param.put("group" ~ i.to!string(), item[i]);
94 }
95 }
96
97 if (!param.isEmpty()) {
98 foreach(router; routerSet)
99 parameters.put(router, param);
100 }
101 }
102 if (routers.isEmpty()) {
103 return null;
104 } else {
105 return new MatchResult(routers, parameters, getMatchType());
106 }
107 }
108
109
110 MatchType getMatchType() { implementationMissing(); return MatchType.PATH; }
111
112 }