wok-server 0.4.13 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/README.en.md +61 -0
  2. package/README.md +44 -29
  3. package/dist/cache/cache.js +98 -98
  4. package/dist/cache/config.js +19 -19
  5. package/dist/cache/index.js +27 -27
  6. package/dist/cache/purge-task.js +46 -46
  7. package/dist/cache/stat.js +47 -47
  8. package/dist/config/convert.js +36 -36
  9. package/dist/config/exception.js +14 -14
  10. package/dist/config/index.js +81 -81
  11. package/dist/http-client/index.js +136 -136
  12. package/dist/i18n/ar.js +17 -17
  13. package/dist/i18n/de.js +17 -17
  14. package/dist/i18n/en-us.js +17 -17
  15. package/dist/i18n/es.js +17 -17
  16. package/dist/i18n/fr.js +17 -17
  17. package/dist/i18n/i18n.js +231 -231
  18. package/dist/i18n/index.js +52 -52
  19. package/dist/i18n/ja.js +17 -17
  20. package/dist/i18n/ko.js +17 -17
  21. package/dist/i18n/msg.js +2 -2
  22. package/dist/i18n/pt.js +17 -17
  23. package/dist/i18n/ru.js +17 -17
  24. package/dist/i18n/tag.js +18 -18
  25. package/dist/i18n/zh-HK.js +17 -17
  26. package/dist/i18n/zh-TW.js +17 -17
  27. package/dist/i18n/zh-cn.js +17 -17
  28. package/dist/index.js +14 -14
  29. package/dist/lock/index.js +114 -114
  30. package/dist/log/config.js +35 -29
  31. package/dist/log/date.js +21 -21
  32. package/dist/log/file.js +198 -72
  33. package/dist/log/index.js +135 -105
  34. package/dist/log/level.js +33 -33
  35. package/dist/log/log.js +56 -0
  36. package/dist/log/store.js +19 -16
  37. package/dist/mongodb/collection.js +2 -2
  38. package/dist/mongodb/config.js +34 -34
  39. package/dist/mongodb/doc.js +2 -2
  40. package/dist/mongodb/exception.js +14 -14
  41. package/dist/mongodb/index.js +58 -58
  42. package/dist/mongodb/manager/base.js +563 -563
  43. package/dist/mongodb/manager/index.js +63 -63
  44. package/dist/mongodb/manager/tx-strict.js +84 -84
  45. package/dist/mongodb/manager/tx.js +30 -30
  46. package/dist/mongodb/migration.js +52 -52
  47. package/dist/mvc/access-log.js +33 -33
  48. package/dist/mvc/config.js +27 -27
  49. package/dist/mvc/exchange.js +113 -113
  50. package/dist/mvc/handler/index.js +7 -6
  51. package/dist/mvc/handler/json.js +65 -65
  52. package/dist/mvc/handler/restful.js +35 -35
  53. package/dist/mvc/handler/sse.js +65 -0
  54. package/dist/mvc/handler/upload.js +31 -31
  55. package/dist/mvc/index.js +50 -50
  56. package/dist/mvc/interceptor.js +2 -2
  57. package/dist/mvc/query.js +43 -43
  58. package/dist/mvc/render/file.js +132 -132
  59. package/dist/mvc/render/html/html.js +90 -90
  60. package/dist/mvc/render/html/index.js +18 -18
  61. package/dist/mvc/render/html/style.js +2 -2
  62. package/dist/mvc/render/index.js +7 -7
  63. package/dist/mvc/render/json.js +26 -26
  64. package/dist/mvc/render/text.js +16 -16
  65. package/dist/mvc/router.js +2 -2
  66. package/dist/mvc/server.js +272 -272
  67. package/dist/mvc/static/header.js +67 -67
  68. package/dist/mvc/static/index.js +6 -6
  69. package/dist/mvc/static/mime-type.js +84 -84
  70. package/dist/mvc/static/server-cache-config.js +66 -66
  71. package/dist/mvc/static/server-cache.js +133 -133
  72. package/dist/mvc/static/static-handler.js +372 -372
  73. package/dist/mysql/config.js +51 -51
  74. package/dist/mysql/exception.js +14 -14
  75. package/dist/mysql/index.js +87 -87
  76. package/dist/mysql/manager/base.js +239 -231
  77. package/dist/mysql/manager/index.js +107 -107
  78. package/dist/mysql/manager/ops/count.js +20 -20
  79. package/dist/mysql/manager/ops/criteria.js +356 -356
  80. package/dist/mysql/manager/ops/delete.js +65 -65
  81. package/dist/mysql/manager/ops/exist.js +26 -26
  82. package/dist/mysql/manager/ops/find.js +169 -130
  83. package/dist/mysql/manager/ops/index.js +14 -14
  84. package/dist/mysql/manager/ops/insert.js +106 -106
  85. package/dist/mysql/manager/ops/modify.js +10 -10
  86. package/dist/mysql/manager/ops/paginate.js +23 -23
  87. package/dist/mysql/manager/ops/query.js +9 -9
  88. package/dist/mysql/manager/ops/update.js +216 -216
  89. package/dist/mysql/manager/ops/utils.js +24 -24
  90. package/dist/mysql/manager/tx-strict.js +103 -100
  91. package/dist/mysql/manager/tx.js +30 -30
  92. package/dist/mysql/manager/utils.js +56 -56
  93. package/dist/mysql/migration.js +136 -136
  94. package/dist/mysql/table-info.js +8 -8
  95. package/dist/task/daily.js +59 -59
  96. package/dist/task/fixed-delay.js +38 -38
  97. package/dist/task/fixed-rate.js +42 -42
  98. package/dist/task/index.js +9 -9
  99. package/dist/task/task.js +56 -56
  100. package/dist/validation/exception.js +36 -36
  101. package/dist/validation/index.js +40 -40
  102. package/dist/validation/validator/array.js +34 -34
  103. package/dist/validation/validator/enum.js +28 -28
  104. package/dist/validation/validator/index.js +14 -14
  105. package/dist/validation/validator/length.js +40 -40
  106. package/dist/validation/validator/max-length.js +35 -35
  107. package/dist/validation/validator/max.js +29 -29
  108. package/dist/validation/validator/min-length.js +33 -33
  109. package/dist/validation/validator/min.js +29 -29
  110. package/dist/validation/validator/not-blank.js +33 -33
  111. package/dist/validation/validator/not-null.js +21 -21
  112. package/dist/validation/validator/plain-obj.js +32 -32
  113. package/dist/validation/validator/regexp.js +34 -34
  114. package/documentation/en/cache.md +56 -0
  115. package/documentation/en/config.md +96 -0
  116. package/documentation/en/engineering.md +256 -0
  117. package/documentation/en/http-client.md +32 -0
  118. package/documentation/en/i18n.md +143 -0
  119. package/documentation/en/index.md +24 -0
  120. package/documentation/en/lock.md +51 -0
  121. package/documentation/en/log.md +109 -0
  122. package/documentation/en/mongodb.md +256 -0
  123. package/documentation/en/mvc.md +688 -0
  124. package/documentation/en/mysql.md +552 -0
  125. package/documentation/en/task.md +45 -0
  126. package/documentation/en/test.md +56 -0
  127. package/documentation/en/validate.md +130 -0
  128. package/documentation/zh-cn/engineering.md +1 -1
  129. package/documentation/zh-cn/log.md +81 -8
  130. package/documentation/zh-cn/mvc.md +66 -24
  131. package/documentation/zh-cn/mysql.md +24 -23
  132. package/documentation/zh-cn/validate.md +2 -2
  133. package/package.json +3 -1
  134. package/skills/wok-server-api-rules/SKILL.md +350 -0
  135. package/skills/wok-server-cache/SKILL.md +216 -0
  136. package/skills/wok-server-config/SKILL.md +200 -0
  137. package/skills/wok-server-getting-started/SKILL.md +123 -0
  138. package/skills/wok-server-getting-started/references/engineering.md +169 -0
  139. package/skills/wok-server-http-client/SKILL.md +164 -0
  140. package/skills/wok-server-i18n/SKILL.md +214 -0
  141. package/skills/wok-server-lock/SKILL.md +144 -0
  142. package/skills/wok-server-log/SKILL.md +218 -0
  143. package/skills/wok-server-mongodb/SKILL.md +235 -0
  144. package/skills/wok-server-mvc/SKILL.md +251 -0
  145. package/skills/wok-server-mvc/references/respond-html.md +157 -0
  146. package/skills/wok-server-mvc/references/sse.md +121 -0
  147. package/skills/wok-server-mvc/references/static-files.md +47 -0
  148. package/skills/wok-server-mvc/references/upload.md +62 -0
  149. package/skills/wok-server-mvc/references/websocket.md +30 -0
  150. package/skills/wok-server-mysql/SKILL.md +315 -0
  151. package/skills/wok-server-mysql/references/multi-datasource.md +76 -0
  152. package/skills/wok-server-mysql/references/version-control.md +22 -0
  153. package/skills/wok-server-task/SKILL.md +158 -0
  154. package/skills/wok-server-validate/SKILL.md +167 -0
  155. package/src/cache/cache.ts +118 -0
  156. package/src/cache/config.ts +53 -0
  157. package/src/cache/index.ts +27 -0
  158. package/src/cache/purge-task.ts +53 -0
  159. package/src/cache/stat.ts +47 -0
  160. package/src/config/convert.ts +27 -0
  161. package/src/config/exception.ts +8 -0
  162. package/src/config/index.ts +92 -0
  163. package/src/http-client/index.ts +202 -0
  164. package/src/i18n/ar.ts +16 -0
  165. package/src/i18n/de.ts +16 -0
  166. package/src/i18n/en-us.ts +16 -0
  167. package/src/i18n/es.ts +16 -0
  168. package/src/i18n/fr.ts +16 -0
  169. package/src/i18n/i18n.ts +230 -0
  170. package/src/i18n/index.ts +50 -0
  171. package/src/i18n/ja.ts +16 -0
  172. package/src/i18n/ko.ts +16 -0
  173. package/src/i18n/msg.ts +50 -0
  174. package/src/i18n/pt.ts +16 -0
  175. package/src/i18n/ru.ts +16 -0
  176. package/src/i18n/tag.ts +18 -0
  177. package/src/i18n/zh-HK.ts +16 -0
  178. package/src/i18n/zh-TW.ts +16 -0
  179. package/src/i18n/zh-cn.ts +16 -0
  180. package/src/index.ts +11 -0
  181. package/src/lock/index.ts +164 -0
  182. package/src/log/config.ts +71 -0
  183. package/src/log/date.ts +19 -0
  184. package/src/log/file.ts +215 -0
  185. package/src/log/index.ts +136 -0
  186. package/src/log/level.ts +29 -0
  187. package/src/log/log.ts +77 -0
  188. package/src/log/store.ts +31 -0
  189. package/src/mongodb/collection.ts +25 -0
  190. package/src/mongodb/config.ts +69 -0
  191. package/src/mongodb/doc.ts +12 -0
  192. package/src/mongodb/exception.ts +8 -0
  193. package/src/mongodb/index.ts +71 -0
  194. package/src/mongodb/manager/base.ts +674 -0
  195. package/src/mongodb/manager/index.ts +80 -0
  196. package/src/mongodb/manager/tx-strict.ts +153 -0
  197. package/src/mongodb/manager/tx.ts +34 -0
  198. package/src/mongodb/migration.ts +66 -0
  199. package/src/mvc/access-log.ts +33 -0
  200. package/src/mvc/config.ts +70 -0
  201. package/src/mvc/exchange.ts +126 -0
  202. package/src/mvc/handler/index.ts +4 -0
  203. package/src/mvc/handler/json.ts +96 -0
  204. package/src/mvc/handler/restful.ts +39 -0
  205. package/src/mvc/handler/sse.ts +90 -0
  206. package/src/mvc/handler/upload.ts +54 -0
  207. package/src/mvc/index.ts +48 -0
  208. package/src/mvc/interceptor.ts +12 -0
  209. package/src/mvc/query.ts +36 -0
  210. package/src/mvc/render/file.ts +148 -0
  211. package/src/mvc/render/html/html.ts +187 -0
  212. package/src/mvc/render/html/index.ts +16 -0
  213. package/src/mvc/render/html/style.ts +1201 -0
  214. package/src/mvc/render/index.ts +4 -0
  215. package/src/mvc/render/json.ts +24 -0
  216. package/src/mvc/render/text.ts +14 -0
  217. package/src/mvc/router.ts +13 -0
  218. package/src/mvc/server.ts +315 -0
  219. package/src/mvc/static/header.ts +86 -0
  220. package/src/mvc/static/index.ts +3 -0
  221. package/src/mvc/static/mime-type.ts +81 -0
  222. package/src/mvc/static/server-cache-config.ts +92 -0
  223. package/src/mvc/static/server-cache.ts +171 -0
  224. package/src/mvc/static/static-handler.ts +445 -0
  225. package/src/mysql/config.ts +130 -0
  226. package/src/mysql/exception.ts +8 -0
  227. package/src/mysql/index.ts +88 -0
  228. package/src/mysql/manager/base.ts +285 -0
  229. package/src/mysql/manager/index.ts +112 -0
  230. package/src/mysql/manager/ops/count.ts +30 -0
  231. package/src/mysql/manager/ops/criteria.ts +412 -0
  232. package/src/mysql/manager/ops/delete.ts +96 -0
  233. package/src/mysql/manager/ops/exist.ts +41 -0
  234. package/src/mysql/manager/ops/find.ts +226 -0
  235. package/src/mysql/manager/ops/index.ts +11 -0
  236. package/src/mysql/manager/ops/insert.ts +120 -0
  237. package/src/mysql/manager/ops/modify.ts +14 -0
  238. package/src/mysql/manager/ops/paginate.ts +60 -0
  239. package/src/mysql/manager/ops/query.ts +13 -0
  240. package/src/mysql/manager/ops/update.ts +294 -0
  241. package/src/mysql/manager/ops/utils.ts +20 -0
  242. package/src/mysql/manager/tx-strict.ts +138 -0
  243. package/src/mysql/manager/tx.ts +31 -0
  244. package/src/mysql/manager/utils.ts +75 -0
  245. package/src/mysql/migration.ts +149 -0
  246. package/src/mysql/table-info.ts +41 -0
  247. package/src/task/daily.ts +70 -0
  248. package/src/task/fixed-delay.ts +45 -0
  249. package/src/task/fixed-rate.ts +49 -0
  250. package/src/task/index.ts +4 -0
  251. package/src/task/task.ts +70 -0
  252. package/src/validation/exception.ts +27 -0
  253. package/src/validation/index.ts +61 -0
  254. package/src/validation/validator/array.ts +32 -0
  255. package/src/validation/validator/enum.ts +25 -0
  256. package/src/validation/validator/index.ts +11 -0
  257. package/src/validation/validator/length.ts +42 -0
  258. package/src/validation/validator/max-length.ts +33 -0
  259. package/src/validation/validator/max.ts +26 -0
  260. package/src/validation/validator/min-length.ts +31 -0
  261. package/src/validation/validator/min.ts +26 -0
  262. package/src/validation/validator/not-blank.ts +31 -0
  263. package/src/validation/validator/not-null.ts +19 -0
  264. package/src/validation/validator/plain-obj.ts +30 -0
  265. package/src/validation/validator/regexp.ts +32 -0
  266. package/types/cache/cache.d.ts +52 -52
  267. package/types/cache/config.d.ts +32 -32
  268. package/types/cache/index.d.ts +2 -2
  269. package/types/cache/purge-task.d.ts +11 -11
  270. package/types/cache/stat.d.ts +26 -26
  271. package/types/config/convert.d.ts +6 -6
  272. package/types/config/exception.d.ts +7 -7
  273. package/types/config/index.d.ts +25 -25
  274. package/types/http-client/index.d.ts +71 -71
  275. package/types/i18n/ar.d.ts +2 -2
  276. package/types/i18n/de.d.ts +2 -2
  277. package/types/i18n/en-us.d.ts +2 -2
  278. package/types/i18n/es.d.ts +2 -2
  279. package/types/i18n/fr.d.ts +2 -2
  280. package/types/i18n/i18n.d.ts +102 -102
  281. package/types/i18n/index.d.ts +9 -9
  282. package/types/i18n/ja.d.ts +2 -2
  283. package/types/i18n/ko.d.ts +2 -2
  284. package/types/i18n/msg.d.ts +50 -50
  285. package/types/i18n/pt.d.ts +2 -2
  286. package/types/i18n/ru.d.ts +2 -2
  287. package/types/i18n/tag.d.ts +11 -11
  288. package/types/i18n/zh-HK.d.ts +2 -2
  289. package/types/i18n/zh-TW.d.ts +2 -2
  290. package/types/i18n/zh-cn.d.ts +2 -2
  291. package/types/index.d.ts +11 -11
  292. package/types/lock/index.d.ts +64 -64
  293. package/types/log/config.d.ts +35 -27
  294. package/types/log/date.d.ts +2 -2
  295. package/types/log/file.d.ts +13 -5
  296. package/types/log/index.d.ts +53 -34
  297. package/types/log/level.d.ts +14 -14
  298. package/types/log/log.d.ts +40 -0
  299. package/types/log/store.d.ts +19 -12
  300. package/types/mongodb/collection.d.ts +25 -25
  301. package/types/mongodb/config.d.ts +45 -45
  302. package/types/mongodb/doc.d.ts +11 -11
  303. package/types/mongodb/exception.d.ts +7 -7
  304. package/types/mongodb/index.d.ts +29 -29
  305. package/types/mongodb/manager/base.d.ts +188 -188
  306. package/types/mongodb/manager/index.d.ts +38 -38
  307. package/types/mongodb/manager/tx-strict.d.ts +41 -41
  308. package/types/mongodb/manager/tx.d.ts +21 -21
  309. package/types/mongodb/migration.d.ts +12 -12
  310. package/types/mvc/access-log.d.ts +7 -7
  311. package/types/mvc/config.d.ts +42 -42
  312. package/types/mvc/exchange.d.ts +72 -72
  313. package/types/mvc/handler/index.d.ts +4 -3
  314. package/types/mvc/handler/json.d.ts +44 -44
  315. package/types/mvc/handler/restful.d.ts +11 -11
  316. package/types/mvc/handler/sse.d.ts +34 -0
  317. package/types/mvc/handler/upload.d.ts +36 -36
  318. package/types/mvc/index.d.ts +22 -22
  319. package/types/mvc/interceptor.d.ts +11 -11
  320. package/types/mvc/query.d.ts +13 -13
  321. package/types/mvc/render/file.d.ts +10 -10
  322. package/types/mvc/render/html/html.d.ts +98 -98
  323. package/types/mvc/render/html/index.d.ts +11 -11
  324. package/types/mvc/render/html/style.d.ts +1201 -1201
  325. package/types/mvc/render/index.d.ts +4 -4
  326. package/types/mvc/render/json.d.ts +17 -17
  327. package/types/mvc/render/text.d.ts +10 -10
  328. package/types/mvc/router.d.ts +11 -11
  329. package/types/mvc/server.d.ts +90 -90
  330. package/types/mvc/static/header.d.ts +27 -27
  331. package/types/mvc/static/index.d.ts +3 -3
  332. package/types/mvc/static/mime-type.d.ts +2 -2
  333. package/types/mvc/static/server-cache-config.d.ts +30 -30
  334. package/types/mvc/static/server-cache.d.ts +76 -76
  335. package/types/mvc/static/static-handler.d.ts +77 -77
  336. package/types/mysql/config.d.ts +90 -90
  337. package/types/mysql/exception.d.ts +7 -7
  338. package/types/mysql/index.d.ts +16 -16
  339. package/types/mysql/manager/base.d.ts +165 -159
  340. package/types/mysql/manager/index.d.ts +36 -36
  341. package/types/mysql/manager/ops/count.d.ts +13 -13
  342. package/types/mysql/manager/ops/criteria.d.ts +134 -134
  343. package/types/mysql/manager/ops/delete.d.ts +46 -46
  344. package/types/mysql/manager/ops/exist.d.ts +6 -6
  345. package/types/mysql/manager/ops/find.d.ts +86 -70
  346. package/types/mysql/manager/ops/index.d.ts +10 -10
  347. package/types/mysql/manager/ops/insert.d.ts +18 -18
  348. package/types/mysql/manager/ops/modify.d.ts +3 -3
  349. package/types/mysql/manager/ops/paginate.d.ts +36 -36
  350. package/types/mysql/manager/ops/query.d.ts +3 -3
  351. package/types/mysql/manager/ops/update.d.ts +76 -76
  352. package/types/mysql/manager/ops/utils.d.ts +5 -5
  353. package/types/mysql/manager/tx-strict.d.ts +36 -35
  354. package/types/mysql/manager/tx.d.ts +15 -15
  355. package/types/mysql/manager/utils.d.ts +17 -17
  356. package/types/mysql/migration.d.ts +8 -8
  357. package/types/mysql/table-info.d.ts +36 -36
  358. package/types/task/daily.d.ts +16 -16
  359. package/types/task/fixed-delay.d.ts +9 -9
  360. package/types/task/fixed-rate.d.ts +9 -9
  361. package/types/task/index.d.ts +4 -4
  362. package/types/task/task.d.ts +34 -34
  363. package/types/validation/exception.d.ts +38 -38
  364. package/types/validation/index.d.ts +32 -32
  365. package/types/validation/validator/array.d.ts +5 -5
  366. package/types/validation/validator/enum.d.ts +8 -8
  367. package/types/validation/validator/index.d.ts +11 -11
  368. package/types/validation/validator/length.d.ts +10 -10
  369. package/types/validation/validator/max-length.d.ts +8 -8
  370. package/types/validation/validator/max.d.ts +7 -7
  371. package/types/validation/validator/min-length.d.ts +6 -6
  372. package/types/validation/validator/min.d.ts +7 -7
  373. package/types/validation/validator/not-blank.d.ts +7 -7
  374. package/types/validation/validator/not-null.d.ts +6 -6
  375. package/types/validation/validator/plain-obj.d.ts +7 -7
  376. package/types/validation/validator/regexp.d.ts +8 -8
@@ -0,0 +1,4 @@
1
+ export * from './text'
2
+ export * from './json'
3
+ export * from './file'
4
+ export * from './html'
@@ -0,0 +1,24 @@
1
+ import { ServerResponse } from 'http'
2
+
3
+ /**
4
+ * 渲染 json 格式数据.
5
+ * @param response 响应信息
6
+ * @param json json对象
7
+ * @param status 状态码,默认 200
8
+ * @returns
9
+ */
10
+ export function renderJson(response: ServerResponse, json: any, status = 200) {
11
+ response.setHeader('content-type', 'application/json; charset=UTF-8')
12
+ response.statusCode = status
13
+ response.end(JSON.stringify(json))
14
+ }
15
+
16
+ /**
17
+ * 渲染错误信息,json 格式
18
+ * @param response
19
+ * @param message
20
+ * @param status
21
+ */
22
+ export function renderError(response: ServerResponse, message: string, status = 400) {
23
+ renderJson(response, { message }, status)
24
+ }
@@ -0,0 +1,14 @@
1
+ import { ServerResponse } from 'http'
2
+
3
+ /**
4
+ * 渲染 json 格式数据.
5
+ * @param response 响应信息
6
+ * @param text 文本
7
+ * @param status 状态码,默认 200
8
+ * @returns
9
+ */
10
+ export function renderText(response: ServerResponse, text: string, status = 200) {
11
+ response.setHeader('content-type', 'text/plain; charset=UTF-8')
12
+ response.statusCode = status
13
+ response.end(text)
14
+ }
@@ -0,0 +1,13 @@
1
+ import { ServerExchange } from './exchange'
2
+
3
+ /**
4
+ * 路由控制器函数.
5
+ */
6
+ export interface RouterHandler {
7
+ (exchange: ServerExchange): Promise<void>
8
+ }
9
+
10
+ /**
11
+ * 路由列表.
12
+ */
13
+ export type Routers = Record<string, RouterHandler>
@@ -0,0 +1,315 @@
1
+ import { readFileSync } from 'fs'
2
+ import { IncomingMessage, Server, ServerResponse, createServer } from 'http'
3
+ import { Server as HttpsServer, createServer as createHttpsServer } from 'https'
4
+ import { Socket } from 'net'
5
+ import { networkInterfaces } from 'os'
6
+ import { isAbsolute, resolve } from 'path'
7
+ import { getLogger } from '../log'
8
+ import { accessLogInterceptor } from './access-log'
9
+ import { WebConfig, getConfig } from './config'
10
+ import { ServerExchange } from './exchange'
11
+ import { Interceptor } from './interceptor'
12
+ import { renderError } from './render'
13
+ import { RouterHandler, Routers } from './router'
14
+ import { ServerStaticRules, StaticHandler } from './static'
15
+ import { notBlank, validate } from '../validation'
16
+
17
+ /**
18
+ * mvc 服务选项
19
+ */
20
+ export interface WokServerOpts {
21
+ /**
22
+ * 路由配置.
23
+ */
24
+ routers: Routers
25
+ /**
26
+ * 拦截器,在路由处理前可以做一些额外操作.
27
+ */
28
+ interceptors?: Interceptor[]
29
+ /**
30
+ * 前置控制器,在服务启动之前,对服务做一些额外的操作。比如可以连接 socket.io 或者一些其它
31
+ * 支持 nodejs 原生 http 服务的组件.
32
+ * @param server
33
+ * @returns
34
+ */
35
+ preHandler?: (server: Server<any>) => Promise<void>
36
+ /**
37
+ * 静态资源配置
38
+ */
39
+ static?: ServerStaticRules
40
+ }
41
+
42
+ function resolvePath(path: string) {
43
+ if (isAbsolute(path)) {
44
+ return path
45
+ }
46
+ return resolve(process.cwd(), path)
47
+ }
48
+
49
+ /**
50
+ * web 服务
51
+ */
52
+ export class WokServer {
53
+ private readonly config: WebConfig
54
+ private readonly server: Server<any> | HttpsServer<any>
55
+ private readonly interceptors: Interceptor[]
56
+ private readonly routers: Routers
57
+ private readonly defaultRouter?: RouterHandler
58
+ private readonly staticHandler?: StaticHandler
59
+
60
+ constructor(private readonly opts: WokServerOpts) {
61
+ this.config = getConfig()
62
+ // https
63
+ let tls:
64
+ | {
65
+ key: Buffer
66
+
67
+ cert: Buffer
68
+ }
69
+ | undefined
70
+ if (this.config.tlsEnable) {
71
+ validate(this.config, {
72
+ tlsCert: [notBlank()],
73
+ tlsKey: [notBlank()]
74
+ })
75
+ tls = {
76
+ cert: readFileSync(resolvePath(this.config.tlsCert)),
77
+ key: readFileSync(resolvePath(this.config.tlsKey))
78
+ }
79
+ }
80
+ // 路由
81
+ this.routers = opts.routers
82
+ this.defaultRouter = this.routers['*']
83
+ // 拦截器
84
+ this.interceptors = []
85
+ if (this.config.accessLog) {
86
+ this.interceptors.push(accessLogInterceptor)
87
+ }
88
+ if (opts.interceptors) {
89
+ this.interceptors.push(...opts.interceptors)
90
+ }
91
+ // 静态处理
92
+ if (opts.static) {
93
+ this.staticHandler = new StaticHandler(opts.static)
94
+ }
95
+ // 主服务
96
+ if (!tls) {
97
+ this.server = createServer((req, res) => {
98
+ res.setHeader('Server', 'Wok Server')
99
+ res.on('error', error => {
100
+ // 如果响应流发生错误,只能把信息记录下来
101
+ getLogger().error(`Response Error:${req.url}`, error)
102
+ })
103
+ this.handleRequest(req, res).catch(error => {
104
+ getLogger().error(`Handle request failed:${req.url}`, error)
105
+ if (!res.writableEnded) {
106
+ // 响应 500
107
+ renderError(res, error.message ? error.message : 'Internal Server Error', 500)
108
+ }
109
+ })
110
+ })
111
+ } else {
112
+ this.server = createHttpsServer(
113
+ {
114
+ key: tls.key,
115
+ cert: tls.cert
116
+ },
117
+ (req, res) => {
118
+ res.setHeader('Server', 'Wok Server')
119
+ res.on('error', error => {
120
+ // 如果响应流发生错误,只能把信息记录下来
121
+ getLogger().error(`Response Error:${req.url}`, error)
122
+ })
123
+ this.handleRequest(req, res).catch(error => {
124
+ getLogger().error(`Handle request failed:${req.url}`, error)
125
+ if (!res.writableEnded) {
126
+ // 响应 500
127
+ renderError(res, error.message ? error.message : 'Internal Server Error', 500)
128
+ }
129
+ })
130
+ }
131
+ )
132
+ }
133
+ this.server.setTimeout(this.config.timeout)
134
+ this.server.on('timeout', (socket: Socket) => {
135
+ socket.end(
136
+ 'HTTP/1.1 408 Timeout\r\ncontent-type: application/json; charset=utf-8\r\n\r\n{"message":"Request timeout"}'
137
+ )
138
+ })
139
+ }
140
+
141
+ /**
142
+ * 处理请求,完成拦截器和路由的流程.
143
+ *
144
+ * @param req
145
+ * @param res
146
+ */
147
+ private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {
148
+ req.socket.remoteAddress
149
+ const { method } = req
150
+ // cros 支持
151
+ res.setHeader('Access-Control-Allow-Origin', this.config.corsAllowOrigin)
152
+ res.setHeader('Access-Control-Allow-Headers', this.config.corsAllowHeaders)
153
+ res.setHeader('Access-Control-Allow-Methods', this.config.corsAllowMethods)
154
+ if (method === 'OPTIONS') {
155
+ res.statusCode = 200
156
+ res.end()
157
+ return
158
+ }
159
+ const exchange = new ServerExchange(req, res)
160
+ // 顺序执行拦截器
161
+ await this.handleInterceptor(0, exchange, req, res)
162
+ }
163
+
164
+ /**
165
+ * 处理拦截器.
166
+ * @param idx 当前要执行的拦截器下标
167
+ * @param exchange 传输对象
168
+ * @param req
169
+ * @param res
170
+ */
171
+ private async handleInterceptor(
172
+ idx: number,
173
+ exchange: ServerExchange,
174
+ req: IncomingMessage,
175
+ res: ServerResponse
176
+ ) {
177
+ const interceptor = this.interceptors[idx]
178
+ // 到最后一个了,那么执行路由处理
179
+ if (!interceptor) {
180
+ await this.handleRouter(exchange)
181
+ return
182
+ }
183
+ await interceptor(exchange, () => this.handleInterceptor(idx + 1, exchange, req, res))
184
+ }
185
+
186
+ /**
187
+ * 处理路由.
188
+ * @param exchange
189
+ * @param routers
190
+ * @param staticSettings
191
+ * @returns
192
+ */
193
+ private async handleRouter(exchange: ServerExchange) {
194
+ const url = exchange.request.url
195
+ if (url === undefined) {
196
+ return
197
+ }
198
+ // 判定路由
199
+ const idx = url.indexOf('?')
200
+ let path = idx === -1 ? url : url.substring(0, idx)
201
+ const router = this.routers[path]
202
+ if (!router) {
203
+ // 路由找不不到,尝试静态文件
204
+ if (this.staticHandler) {
205
+ const method = (exchange.request.method || '').toLowerCase()
206
+ if (method === 'head') {
207
+ if (await this.staticHandler.handleHead(path, exchange.response)) {
208
+ return
209
+ }
210
+ }
211
+ if (method === 'get') {
212
+ if (await this.staticHandler.handleGet(exchange.request, exchange.response, path)) {
213
+ return
214
+ }
215
+ }
216
+ }
217
+ this.respond404(exchange, path)
218
+ return
219
+ }
220
+ // 执行路由
221
+ await router(exchange)
222
+ // 在路由顺利处理的情况下,如果 res 没有 end ,就表示响应没有完成
223
+ // 也就是说路由没有做响应处理,或处理没有完成就结束了,给予错误提示
224
+ if (!exchange.response.writableEnded) {
225
+ throw new Error(`RouterHandler unresponsive, url: ${url}`)
226
+ }
227
+ }
228
+
229
+ /**
230
+ * 404响应
231
+ *
232
+ * @param exchange
233
+ * @param path
234
+ */
235
+ private async respond404(exchange: ServerExchange, path: string) {
236
+ if (this.defaultRouter) {
237
+ await this.defaultRouter(exchange)
238
+ } else {
239
+ exchange.respondErrMsg(`${path} not found`, 404)
240
+ }
241
+ }
242
+
243
+ /**
244
+ * 启动
245
+ */
246
+ async start() {
247
+ if (this.opts.preHandler) {
248
+ await this.opts.preHandler(this.server)
249
+ }
250
+ await new Promise<void>((resolve, reject) => {
251
+ this.server.on('error', e => {
252
+ if ((e as any).code === 'EADDRINUSE') {
253
+ reject(`Port ${this.config.port} is already in use.`)
254
+ } else {
255
+ reject(e)
256
+ }
257
+ })
258
+ this.server.listen(this.config.port, resolve)
259
+ })
260
+ console.log('App running at: ')
261
+ let portOmitted =
262
+ (this.server instanceof HttpsServer && this.config.port === 443) ||
263
+ (this.server instanceof Server && this.config.port === 80)
264
+ this.getIpv4List().forEach(ip => {
265
+ if (portOmitted) {
266
+ console.log(`http://${ip}`)
267
+ } else {
268
+ console.log(`http://${ip}:${this.config.port}`)
269
+ }
270
+ })
271
+ }
272
+
273
+ /**
274
+ * 获取 ipv4 地址列表
275
+ * @returns
276
+ */
277
+ private getIpv4List() {
278
+ const ifs = networkInterfaces()
279
+ const res: string[] = []
280
+ for (const name in ifs) {
281
+ const list = ifs[name]
282
+ if (!list) {
283
+ continue
284
+ }
285
+ res.push(...list.filter(info => info.family === 'IPv4').map(info => info.address))
286
+ }
287
+ return res
288
+ }
289
+ /**
290
+ * 删除服务器端静态资源缓存
291
+ * @param path
292
+ */
293
+ removeServerStaticCache(path: string) {
294
+ if (this.staticHandler) {
295
+ this.staticHandler.removeServerCache(path)
296
+ }
297
+ }
298
+ /**
299
+ * 停止
300
+ */
301
+ async stop() {
302
+ if (!this.server.listening) {
303
+ return
304
+ }
305
+ await new Promise<void>((res, rej) => {
306
+ this.server.close(err => {
307
+ if (err) {
308
+ rej(err)
309
+ } else {
310
+ res()
311
+ }
312
+ })
313
+ })
314
+ }
315
+ }
@@ -0,0 +1,86 @@
1
+ import { IncomingHttpHeaders } from 'http'
2
+ /**
3
+ * 解析 range 消息头,如果解析失败,返回 null
4
+ */
5
+ function parseRange(rangeHeader: string): null | { start: number; end?: number } {
6
+ // 解析,range 示例:bytes=200-1000, 2000-6576, 19000-
7
+ // 多段的情况,暂时不做支持,非常麻烦,段数多还可能会有效率问题
8
+ // 如果不是字节范围不是以字节为单位,暂时也不做支持
9
+ const ranges = rangeHeader.split(',')
10
+ if (!ranges.length) {
11
+ return null
12
+ }
13
+ let range = ranges[0].trim()
14
+ if (!range.startsWith('bytes=')) {
15
+ return null
16
+ }
17
+ range = range.substring(6)
18
+ const strs = range.split('-')
19
+ let start = strs[0] ? parseInt(strs[0], 10) : NaN
20
+ let end = strs[1] ? parseInt(strs[1], 10) : undefined
21
+ return { start, end }
22
+ }
23
+
24
+ /**
25
+ * 静态资源消息头信息
26
+ */
27
+ export interface StaticHeaders {
28
+ /**
29
+ * If-Modified-Since 消息头,测试文件是否在某个时间后修改后
30
+ */
31
+ ifModifiedSince?: Date
32
+ /**
33
+ * 文件部分读取
34
+ */
35
+ range?: { start: number; end?: number }
36
+ /**
37
+ * 是否接受 gzip 压缩,如果支持则压缩后返回
38
+ */
39
+ gzip: boolean
40
+ }
41
+
42
+ /**
43
+ * 解析消息头,返回静态文件处理需要的信息
44
+ * @param headers
45
+ */
46
+ export function parseHeaders(headers: IncomingHttpHeaders) {
47
+ // 是否支持 gzip
48
+ const acceptEncoding = headers['accept-encoding'] as string
49
+ let acceptGzip = false
50
+ if (acceptEncoding) {
51
+ // Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1
52
+ const acceptEncodings = acceptEncoding
53
+ .trim()
54
+ .split(',')
55
+ .map(item => item.trim())
56
+ .map(item => item.split(';')[0])
57
+ if (acceptEncodings.includes('gzip') || acceptEncodings.includes('*')) {
58
+ acceptGzip = true
59
+ }
60
+ }
61
+ let res: StaticHeaders = {
62
+ gzip: acceptGzip
63
+ }
64
+
65
+ // 支持 If-Modified-Since
66
+ // 由于只是简单的文件映射,没有 etag,不能支持 If-None-Match
67
+ const ifModifiedSince = headers['if-modified-since']
68
+ if (ifModifiedSince) {
69
+ const modifiedSince = new Date(ifModifiedSince)
70
+ if (modifiedSince instanceof Date && !isNaN(modifiedSince.getTime())) {
71
+ res.ifModifiedSince = modifiedSince
72
+ }
73
+ }
74
+
75
+ // 支持 Range
76
+ // https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Range
77
+ const rangeHeader = headers['range']
78
+ if (rangeHeader) {
79
+ const rangeRes = parseRange(rangeHeader)
80
+ if (rangeRes) {
81
+ res.range = rangeRes
82
+ }
83
+ }
84
+
85
+ return res
86
+ }
@@ -0,0 +1,3 @@
1
+ export * from './mime-type'
2
+ export * from './header'
3
+ export * from './static-handler'
@@ -0,0 +1,81 @@
1
+ export const MIME_TYPES: Record<string, string> = {
2
+ aac: 'audio/aac',
3
+ abw: 'application/x-abiword',
4
+ arc: 'application/x-freearc',
5
+ avi: 'video/x-msvideo',
6
+ azw: 'application/vnd.amazon.ebook',
7
+ bin: 'application/octet-stream',
8
+ bmp: 'image/bmp',
9
+ bz: 'application/x-bzip',
10
+ bz2: 'application/x-bzip2',
11
+ csh: 'application/x-csh',
12
+ css: 'text/css',
13
+ csv: 'text/csv',
14
+ doc: 'application/msword',
15
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
16
+ eot: 'application/vnd.ms-fontobject',
17
+ epub: 'application/epub+zip',
18
+ gif: 'image/gif',
19
+ htm: 'text/html',
20
+ html: 'text/html',
21
+ ico: 'image/vnd.microsoft.icon',
22
+ ics: 'text/calendar',
23
+ jar: 'application/java-archive',
24
+ jpeg: 'image/jpeg',
25
+ jpg: 'image/jpeg',
26
+ js: 'text/javascript',
27
+ json: 'application/json',
28
+ jsonld: 'application/ld+json',
29
+ mid: 'audio/midi',
30
+ midi: 'audio/midi',
31
+ mjs: 'text/javascript',
32
+ mp3: 'audio/mpeg',
33
+ mpeg: 'video/mpeg',
34
+ mpkg: 'application/vnd.apple.installer+xml',
35
+ odp: 'application/vnd.oasis.opendocument.presentation',
36
+ ods: 'application/vnd.oasis.opendocument.spreadsheet',
37
+ odt: 'application/vnd.oasis.opendocument.text',
38
+ oga: 'audio/ogg',
39
+ ogv: 'video/ogg',
40
+ ogx: 'application/ogg',
41
+ otf: 'font/otf',
42
+ png: 'image/png',
43
+ pdf: 'application/pdf',
44
+ ppt: 'application/vnd.ms-powerpoint',
45
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
46
+ rar: 'application/x-rar-compressed',
47
+ rtf: 'application/rtf',
48
+ sh: 'application/x-sh',
49
+ svg: 'image/svg+xml',
50
+ swf: 'application/x-shockwave-flash',
51
+ tar: 'application/x-tar',
52
+ tif: 'image/tiff',
53
+ tiff: 'image/tiff',
54
+ ttf: 'font/ttf',
55
+ txt: 'text/plain',
56
+ vsd: 'application/vnd.visio',
57
+ wav: 'audio/wav',
58
+ weba: 'audio/webm',
59
+ webm: 'video/webm',
60
+ webp: 'image/webp',
61
+ woff: 'font/woff',
62
+ woff2: 'font/woff2',
63
+ xhtml: 'application/xhtml+xml',
64
+ xls: 'application/vnd.ms-excel',
65
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
66
+ xml: 'application/xml',
67
+ xul: 'application/vnd.mozilla.xul+xml',
68
+ zip: 'application/zip',
69
+ '3gp': 'video/3gpp',
70
+ '3g2': 'video/3gpp2',
71
+ '7z': 'application/x-7z-compressed'
72
+ }
73
+
74
+ export function decideContentType(fileName: string): string | undefined {
75
+ const idx = fileName.lastIndexOf('.')
76
+ if (idx === -1) {
77
+ return undefined
78
+ }
79
+ const suffix = fileName.substring(idx + 1)
80
+ return MIME_TYPES[suffix]
81
+ }
@@ -0,0 +1,92 @@
1
+ import { generateConfig } from '../../config'
2
+ import { PropValidator, max, min, notNull } from '../../validation'
3
+
4
+ /**
5
+ * 服务器缓存配置
6
+ * Server Cache Configuration
7
+ */
8
+ export interface ServerCacheConfig {
9
+ /**
10
+ * Enable or disable caching,default is false (disabled)
11
+ */
12
+ enable: boolean
13
+ /**
14
+ * The maximum age of the cache in seconds
15
+ */
16
+ maxAge: number
17
+ /**
18
+ * The maximum size of the cache in bytes
19
+ * or a string representing a number followed by a unit of measure (e.g. 100k, 10m, 1g)
20
+ */
21
+ maxSize: number | string
22
+ /**
23
+ * The maximum size of a file in the cache in bytes
24
+ * or a string representing a number followed by a unit of measure (e.g. 100k, 10m, 1g)
25
+ */
26
+ maxFileSize: number | string
27
+ }
28
+
29
+ export function parseSize(size: number | string): number {
30
+ if (typeof size === 'number') {
31
+ return size
32
+ }
33
+ const match = size.match(/^(\d+)([kmg]?)$/i)
34
+ if (!match) {
35
+ throw new Error(`Invalid size: ${size}`)
36
+ }
37
+ const [, num, unit] = match
38
+ let sizeNum = parseInt(num, 10)
39
+ switch (unit.toLowerCase()) {
40
+ case 'k':
41
+ sizeNum *= 1024
42
+ break
43
+ case 'm':
44
+ sizeNum *= 1024 * 1024
45
+ break
46
+ case 'g':
47
+ sizeNum *= 1024 * 1024 * 1024
48
+ break
49
+ default:
50
+ break
51
+ }
52
+ return sizeNum
53
+ }
54
+
55
+ function validateSize(max: number | string): PropValidator<number | string> {
56
+ const maxNum = parseSize(max)
57
+ const validator = 'size'
58
+ return val => {
59
+ if (val === null || val === undefined) {
60
+ return { ok: true }
61
+ }
62
+ const sizeNum = typeof val === 'number' ? val : parseSize(val)
63
+ if (sizeNum < 1) {
64
+ return { ok: false, validator, message: `size must greater than 1` }
65
+ }
66
+ if (sizeNum > maxNum) {
67
+ return { ok: false, validator, message: `size must less than ${max}` }
68
+ }
69
+ return { ok: true }
70
+ }
71
+ }
72
+ /**
73
+ * 获取缓存的配置信息
74
+ * @returns
75
+ */
76
+ export function getConfig() {
77
+ return generateConfig<ServerCacheConfig>(
78
+ {
79
+ enable: false,
80
+ maxAge: 600,
81
+ maxSize: '100m',
82
+ maxFileSize: '10m'
83
+ },
84
+ 'SERVER_STATIC_CACHE',
85
+ {
86
+ enable: [notNull()],
87
+ maxAge: [notNull(), min(1), max(31536000)],
88
+ maxSize: [notNull(), validateSize('1024g')],
89
+ maxFileSize: [notNull(), validateSize('1g')]
90
+ }
91
+ )
92
+ }