-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathRender.swift
108 lines (90 loc) · 2.8 KB
/
Render.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//
// Render.swift
// Noze.io
//
// Created by Helge Heß on 6/2/16.
// Copyright © 2016 ZeeZide GmbH. All rights reserved.
//
import fs
import process
import http
import console
public extension ServerResponse {
// TODO: How do we get access to the application?? Need to attach to the
// request? We need to retrieve values.
func render(_ template: String, _ options : Any? = nil) {
let res = self
guard let app = self.app else {
console.error("No app object assigned to response: \(self)")
res.writeHead(500)
res.end()
return
}
let viewEngine = (app.get("view engine") as? String) ?? "mustache"
guard let engine = app.engines[viewEngine] else {
console.error("Did not find view engine: \(viewEngine)")
res.writeHead(500)
res.end()
return
}
let viewsPath = (app.get("views") as? String) ?? process.cwd()
let emptyOpts : [ String : Any ] = [:]
let appViewOptions = app.get("view options") ?? emptyOpts
let viewOptions = options ?? appViewOptions // TODO: merge if possible
lookupTemplate(views: viewsPath, template: template, engine: viewEngine) {
pathOrNot in
guard let path = pathOrNot else {
res.writeHead(404)
res.end()
return
}
engine(path, viewOptions) { ( results: Any?... ) in
let rc = results.count
let v0 = rc > 0 ? results[0] : nil
let v1 = rc > 1 ? results[1] : nil
if let error = v0 {
console.error("template error: \(error)")
res.writeHead(500)
res.end()
return
}
guard let result = v1 else {
console.warn("template returned no content: \(template) \(results)")
res.writeHead(204)
res.end()
return
}
// TBD: maybe support a stream as a result? (result.pipe(res))
let s = (result as? String) ?? "\(result)"
if res.getHeader("Content-Type") == nil {
res.setHeader("Content-Type", "text/html; charset=utf-8")
}
res.writeHead(200)
res.write(s)
res.end()
}
}
}
}
private func lookupTemplate(views p: String, template t: String,
engine e: String,
_ cb: @escaping ( String? ) -> Void)
{
// TODO: try other combos
let fsPath = "\(p)/\(t).\(e)"
fs.stat(fsPath) { err, stat in
guard err == nil && stat != nil else {
console.error("did not find template \(t) at \(fsPath)")
cb(nil)
return
}
guard stat!.isFile() else {
console.error("template path is not a file: \(fsPath)")
cb(nil)
return
}
cb(fsPath)
}
}
// Some protocol is implemented in Foundation, requiring this.
import Foundation