@@ -35,15 +35,31 @@ import
35
35
std/ macros,
36
36
std/ tables,
37
37
std/ strformat,
38
+ std/ strutils,
38
39
std/ base64,
39
- ../ core/ constants
40
+ std/ httpcore,
41
+ ../ core/ constants,
42
+ ../ private/ macro_utils,
43
+ ./ routing
40
44
41
45
42
46
export base64
43
47
44
48
45
49
type
46
- DecoratorImpl * = proc (httpMethods: seq [string ], routePath: string , statementList: NimNode , arguments: seq [NimNode ])
50
+ DecoratorImpl * = proc (
51
+ httpMethods: seq [string ],
52
+ routePath: string ,
53
+ statementList: NimNode ,
54
+ arguments: seq [NimNode ]
55
+ )
56
+ CachedResult * = object
57
+ data* : string
58
+ headers* : HttpHeaders
59
+ statusCode* : HttpCode
60
+ CachedRoute * = object
61
+ create_at* : float
62
+ res* : CachedResult
47
63
48
64
49
65
var decorators* {.compileTime .} = newTable [string , DecoratorImpl ]()
@@ -74,6 +90,9 @@ macro decorator*(name, body: untyped): untyped =
74
90
75
91
76
92
when enableDefaultDecorators:
93
+ var cachedRoutes* {.threadvar .}: Table [string , CachedRoute ]
94
+ cachedRoutes = initTable [string , CachedRoute ]()
95
+
77
96
proc authBasicDecoratorImpl (httpMethods: seq [string ], routePath: string , statementList: NimNode , arguments: seq [NimNode ]) =
78
97
statementList.insert (0 , parseStmt """
79
98
var (username, password) = ("", "")
@@ -123,8 +142,87 @@ var userAgent = navigator.userAgent
123
142
)
124
143
125
144
145
+ proc cachedDecoratorImpl (httpMethods: seq [string ], routePath: string , statementList: NimNode , arguments: seq [NimNode ]) =
146
+ let
147
+ route = handleRoute (routePath)
148
+ purePath = route.purePath.replace ('{' , '_' ).replace ('}' , '_' )
149
+
150
+ let expiresIn =
151
+ if arguments.len == 1 :
152
+ arguments[0 ]
153
+ else :
154
+ newLit (60 )
155
+
156
+ var routeKey = fmt" { purePath} :pp("
157
+ for i in route.pathParams:
158
+ routeKey &= i.name & " ={" & i.name & " }"
159
+ routeKey &= " )"
160
+ echo routeKey
161
+
162
+ let
163
+ queryStmt = newStmtList ()
164
+ queryArrStmt = newStmtList ()
165
+
166
+ if statementList.isIdentUsed (ident " query" ):
167
+ var usages = statementList.getIdentUses (ident " query" )
168
+ for i in usages:
169
+ if i.kind == nnkInfix and i[0 ] == ident " ?" and i[1 ] == ident " query" and i[2 ].kind == nnkIdent:
170
+ queryStmt.add parseStmt (fmt""" routeKey &= "{ i[2 ]} " & "=" & query.getOrDefault("{ i[2 ]} ", "") """ )
171
+ elif i.kind == nnkBracketExpr and i[0 ] == ident " query" and i[1 ].kind == nnkStrLit:
172
+ queryStmt.add parseStmt (fmt""" routeKey &= "{ i[1 ].strVal} " & "=" & query.getOrDefault("{ i[1 ].strVal} ", "") """ )
173
+ elif i.kind == nnkBracketExpr and i[0 ] == ident " query" :
174
+ queryStmt.add parseStmt (fmt""" routeKey &= { i[1 ].toStrLit} & "=" & query.getOrDefault({ i[1 ].toStrLit} , "") """ )
175
+ else :
176
+ discard
177
+ # echo i.treeRepr
178
+ if statementList.isIdentUsed (ident " queryArr" ):
179
+ var usages = statementList.getIdentUses (ident " queryArr" )
180
+ for i in usages:
181
+ if i.kind == nnkInfix and i[0 ] == ident " ?" and i[1 ] == ident " queryArr" and i[2 ].kind == nnkIdent:
182
+ queryStmt.add parseStmt (fmt""" routeKey &= "{ i[2 ]} " & "=" & $queryArr.getOrDefault("{ i[2 ]} ", "") """ )
183
+ elif i.kind == nnkBracketExpr and i[0 ] == ident " queryArr" and i[1 ].kind == nnkStrLit:
184
+ queryStmt.add parseStmt (fmt""" routeKey &= "{ i[1 ].strVal} " & "=" & $queryArr.getOrDefault("{ i[1 ].strVal} ", "") """ )
185
+ elif i.kind == nnkBracketExpr and i[0 ] == ident " queryArr" :
186
+ queryStmt.add parseStmt (fmt""" routeKey &= { i[1 ].toStrLit} & "=" & $queryArr.getOrDefault({ i[1 ].toStrLit} , "") """ )
187
+ else :
188
+ discard
189
+ # echo i.treeRepr
190
+
191
+ let cachedRoutesResult = newNimNode (nnkDotExpr).add (
192
+ newNimNode (nnkBracketExpr).add (ident " cachedRoutes" , ident " routeKey" ), ident " res"
193
+ )
194
+ let cachedRoutesCreateAt = newNimNode (nnkDotExpr).add (
195
+ newNimNode (nnkBracketExpr).add (ident " cachedRoutes" , ident " routeKey" ), ident " create_at"
196
+ )
197
+
198
+ statementList.insert (0 , newStmtList (
199
+ newVarStmt (ident " routeKey" , newCall (" fmt" , newLit (fmt" { routeKey} " ))),
200
+ queryStmt,
201
+ queryArrStmt,
202
+ newConstStmt (ident " thisRouteCanBeCached" , newLit (true )),
203
+ newNimNode (nnkIfStmt).add (newNimNode (nnkElifBranch).add (
204
+ newCall (" hasKey" , ident " cachedRoutes" , ident " routeKey" ),
205
+ newNimNode (nnkIfStmt).add (newNimNode (nnkElifBranch).add (
206
+ newCall (" <" , newCall (" -" , newCall (" cpuTime" ), cachedRoutesCreateAt), expiresIn),
207
+ newStmtList (
208
+ newConstStmt (ident " thisIsCachedResponse" , newLit (true )),
209
+ newCall (
210
+ " answer" ,
211
+ ident " req" ,
212
+ newNimNode (nnkDotExpr).add (cachedRoutesResult, ident " data" ),
213
+ newNimNode (nnkDotExpr).add (cachedRoutesResult, ident " statusCode" ),
214
+ newNimNode (nnkDotExpr).add (cachedRoutesResult, ident " headers" ),
215
+ ),
216
+ newNimNode (nnkBreakStmt).add (ident " __handleRequestBlock" )
217
+ )
218
+ )),
219
+ )),
220
+ ))
221
+
222
+
126
223
static :
127
224
regDecorator (" AuthBasic" , authBasicDecoratorImpl)
128
225
regDecorator (" AuthBearerJWT" , authBearerJwtDecoratorImpl)
129
226
regDecorator (" AuthJWT" , authJwtDecoratorImpl)
130
227
regDecorator (" GetUserAgent" , getUserAgentDecoratorImpl)
228
+ regDecorator (" Cached" , cachedDecoratorImpl)
0 commit comments