firefly-compiler 0.5.46 → 0.5.47
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.
- package/core/Buffer.ff +1 -1
- package/experimental/site/.firefly/package.ff +3 -0
- package/experimental/site/ChatRoute.ff +26 -0
- package/experimental/site/Main.ff +40 -0
- package/experimental/site/RouteTools.ff +70 -0
- package/experimental/site/Routes.ff +13 -0
- package/experimental/site2/.firefly/package.ff +3 -0
- package/experimental/site2/ChatRoomRoute.ff +27 -0
- package/experimental/site2/Html.ff +49 -0
- package/experimental/site2/Main.ff +37 -0
- package/experimental/site2/Router.ff +23 -0
- package/output/js/ff/core/Buffer.mjs +2 -2
- package/package.json +1 -1
- package/vscode/package.json +1 -1
- package/webserver/WebRoute.ff +150 -0
package/core/Buffer.ff
CHANGED
|
@@ -193,7 +193,7 @@ fromHex(hex: String): Buffer {
|
|
|
193
193
|
|
|
194
194
|
fromBase64(base64: String): Buffer {
|
|
195
195
|
let binaryString = Js->atob(base64)
|
|
196
|
-
let bytes = Js->Uint8Array->from(binaryString, Js->{char => char->
|
|
196
|
+
let bytes = Js->Uint8Array->from(binaryString, Js->{char => char->charCodeAt(0)})
|
|
197
197
|
Js->DataView->(bytes->buffer)?
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Lux from ff:lux
|
|
2
|
+
import WebServer from ff:webserver
|
|
3
|
+
import RouteTools
|
|
4
|
+
|
|
5
|
+
data Chat(room: String)
|
|
6
|
+
|
|
7
|
+
pageRoute = PageRoute("ChatRoute", "/chat/{roomId}")
|
|
8
|
+
|
|
9
|
+
handle(system: NodeSystem, request: WebRequest[WebResponse], context: Context) {
|
|
10
|
+
let pageData = Chat("42")
|
|
11
|
+
let title = "Chat"
|
|
12
|
+
RouteTools.renderAndServe(system, pageRoute, pageData, title, request, {render(_, pageData)})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
browserMain(system: BrowserSystem) {
|
|
16
|
+
RouteTools.renderToMain(system, {render(_, _)})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
render(lux: Lux, chat: Chat) {
|
|
20
|
+
lux.add("div") {
|
|
21
|
+
lux.add("h1") {
|
|
22
|
+
lux.text("Hello")
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import WebServer from ff:webserver
|
|
2
|
+
import RouteTools
|
|
3
|
+
import Routes
|
|
4
|
+
|
|
5
|
+
nodeMain(system: NodeSystem): Unit {
|
|
6
|
+
let host = system.arguments().grab(0)
|
|
7
|
+
let port = system.arguments().grab(1).grabInt()
|
|
8
|
+
let handlers = RouteTools.checkRoutesAndHandlers(Routes.routes, Routes.handlers())
|
|
9
|
+
system.writeLine("Listening on " + host + ":" + port)
|
|
10
|
+
WebServer.new(system, host, port).listen {request =>
|
|
11
|
+
let path = request.readPath()
|
|
12
|
+
let segments = path.split('/').filter {s => s != "" && s != "." && s != ".."}
|
|
13
|
+
segments.{
|
|
14
|
+
| ["js", ...] =>
|
|
15
|
+
let asset = segments.map {"/" + _}.join()
|
|
16
|
+
request.writeHeader("Content-Type", "text/javascript; charset=UTF-8")
|
|
17
|
+
request.writeStream(system.assets().readStream(asset))
|
|
18
|
+
| _ =>
|
|
19
|
+
// Very sketchy routing
|
|
20
|
+
let routeOption = Routes.routes.find {route =>
|
|
21
|
+
let routeSegments = route.pattern.split('/').filter {s => s != "" && s != "." && s != ".."}
|
|
22
|
+
if(segments.size() != routeSegments.size()) {False} else:
|
|
23
|
+
segments.zip(routeSegments).all {| Pair(s, r) => s == r || r.startsWith("{")}
|
|
24
|
+
}
|
|
25
|
+
routeOption.or {request.writeStatus("404 Not Found")}: route =>
|
|
26
|
+
let context = Context()
|
|
27
|
+
let handle = handlers.grab(route.pattern)
|
|
28
|
+
handle(system, request, context)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
buildMain(system: BuildSystem) {
|
|
34
|
+
mutable assets = AssetSystem.create()
|
|
35
|
+
Routes.routes.each {route =>
|
|
36
|
+
let browser = system.compileForBrowser(route.page + ".ff") // .bundle()
|
|
37
|
+
assets = assets.addAssets("/js/", browser.assets())
|
|
38
|
+
}
|
|
39
|
+
system.setAssets(assets)
|
|
40
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import WebServer from ff:webserver
|
|
2
|
+
import Lux from ff:lux
|
|
3
|
+
|
|
4
|
+
data PageRoute(page: String, pattern: String)
|
|
5
|
+
capability PageHandler(pattern: String, handle: (NodeSystem, WebRequest[WebResponse], Context) => Unit)
|
|
6
|
+
|
|
7
|
+
data Context()
|
|
8
|
+
|
|
9
|
+
serveHtml(
|
|
10
|
+
pageRoute: PageRoute
|
|
11
|
+
title: String
|
|
12
|
+
pageData: Buffer
|
|
13
|
+
contentHtml: String
|
|
14
|
+
styleTags: String
|
|
15
|
+
request: WebRequest[WebResponse]
|
|
16
|
+
): Unit {
|
|
17
|
+
request.writeHeader("Content-Type", "text/html; charset=UTF-8")
|
|
18
|
+
request.writeText("<!doctype html>")
|
|
19
|
+
request.writeText("<html lang='en' style='background-color: #ffffff; color: #333333; width: 100%; height: 100%; color-scheme: light;'>")
|
|
20
|
+
request.writeText("<head>")
|
|
21
|
+
request.writeText("<title>" + title + "</title>")
|
|
22
|
+
request.writeText("<meta name='viewport' content='width=device-width, initial-scale=1.0'>")
|
|
23
|
+
request.writeText("<meta name='theme-color' content='#ecc45e'>")
|
|
24
|
+
request.writeText("<script type='module' src='" + "/js/ff/site/" + pageRoute.page + ".mjs" + "'></script>")
|
|
25
|
+
request.writeText("<script type='text/plain' id='data'>" + pageData.toBase64() + "</script>")
|
|
26
|
+
request.writeText(styleTags)
|
|
27
|
+
request.writeText("</head>")
|
|
28
|
+
request.writeText("<body style='margin: 0; padding: 0; width: 100%; height: 100%; touch-action: manipulation;'>")
|
|
29
|
+
request.writeText("<div id='main'>" + contentHtml + "</div>")
|
|
30
|
+
request.writeText("</body>")
|
|
31
|
+
request.writeText("</html>")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
renderAndServe[T: Serializable](
|
|
35
|
+
system: NodeSystem
|
|
36
|
+
pageRoute: PageRoute
|
|
37
|
+
pageData: T
|
|
38
|
+
title: String
|
|
39
|
+
request: WebRequest[WebResponse]
|
|
40
|
+
render: Lux => Unit
|
|
41
|
+
) {
|
|
42
|
+
let serialized = Serializable.serialize(pageData)
|
|
43
|
+
let htmlAndCss = Lux.renderToString(system, render)
|
|
44
|
+
serveHtml(pageRoute, title, serialized, htmlAndCss.first, htmlAndCss.second, request)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
renderToMain[T: Serializable](system: BrowserSystem, render: (Lux, T) => Unit) {
|
|
48
|
+
let base64 = system.js()->document->getElementById("data")->textContent.grabString()
|
|
49
|
+
let chat = Serializable.deserialize(Buffer.fromBase64(base64))
|
|
50
|
+
Lux.renderById(system, "main") {lux =>
|
|
51
|
+
render(lux, chat)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
checkRoutesAndHandlers(
|
|
56
|
+
routes: List[PageRoute]
|
|
57
|
+
handlers: List[PageHandler]
|
|
58
|
+
): Map[String, (NodeSystem, WebRequest[WebResponse], Context) => Unit] {
|
|
59
|
+
let handlerMap = handlers.map {h => Pair(h.pattern, h.handle)}.toMap()
|
|
60
|
+
routes.each {r =>
|
|
61
|
+
if(!handlerMap.contains(r.pattern)) {
|
|
62
|
+
panic("Missing handler for " + r.pattern)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
let missingPatterns = handlerMap.keys().removeAll(routes.map {_.pattern}.toSet())
|
|
66
|
+
missingPatterns.each {p =>
|
|
67
|
+
panic("Missing route for " + p)
|
|
68
|
+
}
|
|
69
|
+
handlerMap
|
|
70
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import WebServer from ff:webserver
|
|
2
|
+
import RouteTools
|
|
3
|
+
import ChatRoute
|
|
4
|
+
|
|
5
|
+
routes: List[PageRoute] = [
|
|
6
|
+
ChatRoute.pageRoute
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
handlers(): List[PageHandler] {
|
|
10
|
+
[
|
|
11
|
+
PageHandler(ChatRoute.pageRoute.pattern, {ChatRoute.handle(_, _, _)})
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Lux from ff:lux
|
|
2
|
+
import WebServer from ff:webserver
|
|
3
|
+
import Router
|
|
4
|
+
import Html
|
|
5
|
+
|
|
6
|
+
routeModule = SourceLocation.here().module()
|
|
7
|
+
|
|
8
|
+
data Chat(room: String)
|
|
9
|
+
|
|
10
|
+
handle(request: WebRequest[WebResponse], context: RouteContext, roomId: Int) {
|
|
11
|
+
let pageData = Chat("42")
|
|
12
|
+
let title = "Chat"
|
|
13
|
+
Html.renderAndServe(context.system, routeModule, pageData, title, request, {render(_, pageData)})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
browserMain(system: BrowserSystem) {
|
|
17
|
+
Html.renderToMain(system, {render(_, _)})
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
render(lux: Lux, chat: Chat) {
|
|
21
|
+
lux.add("div") {
|
|
22
|
+
lux.add("h1") {
|
|
23
|
+
lux.text("Hello")
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import WebServer from ff:webserver
|
|
2
|
+
import WebRoute from ff:webserver
|
|
3
|
+
import Lux from ff:lux
|
|
4
|
+
|
|
5
|
+
serveHtml(
|
|
6
|
+
moduleName: String
|
|
7
|
+
title: String
|
|
8
|
+
pageData: Buffer
|
|
9
|
+
contentHtml: String
|
|
10
|
+
styleTags: String
|
|
11
|
+
request: WebRequest[WebResponse]
|
|
12
|
+
): Unit {
|
|
13
|
+
request.writeHeader("Content-Type", "text/html; charset=UTF-8")
|
|
14
|
+
request.writeText("<!doctype html>")
|
|
15
|
+
request.writeText("<html lang='en' style='background-color: #ffffff; color: #333333; width: 100%; height: 100%; color-scheme: light;'>")
|
|
16
|
+
request.writeText("<head>")
|
|
17
|
+
request.writeText("<title>" + title + "</title>")
|
|
18
|
+
request.writeText("<meta name='viewport' content='width=device-width, initial-scale=1.0'>")
|
|
19
|
+
request.writeText("<meta name='theme-color' content='#ecc45e'>")
|
|
20
|
+
request.writeText("<script type='module' src='" + "/js/ff/site2/" + moduleName + ".mjs" + "'></script>")
|
|
21
|
+
request.writeText("<script type='text/plain' id='data'>" + pageData.toBase64() + "</script>")
|
|
22
|
+
request.writeText(styleTags)
|
|
23
|
+
request.writeText("</head>")
|
|
24
|
+
request.writeText("<body style='margin: 0; padding: 0; width: 100%; height: 100%; touch-action: manipulation;'>")
|
|
25
|
+
request.writeText("<div id='main'>" + contentHtml + "</div>")
|
|
26
|
+
request.writeText("</body>")
|
|
27
|
+
request.writeText("</html>")
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
renderAndServe[T: Serializable](
|
|
31
|
+
system: NodeSystem
|
|
32
|
+
moduleName: String
|
|
33
|
+
pageData: T
|
|
34
|
+
title: String
|
|
35
|
+
request: WebRequest[WebResponse]
|
|
36
|
+
render: Lux => Unit
|
|
37
|
+
) {
|
|
38
|
+
let serialized = Serializable.serialize(pageData)
|
|
39
|
+
let htmlAndCss = Lux.renderToString(system, render)
|
|
40
|
+
serveHtml(moduleName, title, serialized, htmlAndCss.first, htmlAndCss.second, request)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
renderToMain[T: Serializable](system: BrowserSystem, render: (Lux, T) => Unit) {
|
|
44
|
+
let base64 = system.js()->document->getElementById("data")->textContent.grabString()
|
|
45
|
+
let chat = Serializable.deserialize(Buffer.fromBase64(base64))
|
|
46
|
+
Lux.renderById(system, "main") {lux =>
|
|
47
|
+
render(lux, chat)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import WebServer from ff:webserver
|
|
2
|
+
import WebRoute from ff:webserver
|
|
3
|
+
import Html
|
|
4
|
+
import Router
|
|
5
|
+
|
|
6
|
+
nodeMain(system: NodeSystem): Unit {
|
|
7
|
+
let host = system.arguments().grab(0)
|
|
8
|
+
let port = system.arguments().grab(1).grabInt()
|
|
9
|
+
let context = RouteContext(system)
|
|
10
|
+
let handlers = WebRouteHandler(Array.new())
|
|
11
|
+
Router.handlers(handlers)
|
|
12
|
+
system.writeLine("Listening on " + host + ":" + port)
|
|
13
|
+
WebServer.new(system, host, port).listen {request =>
|
|
14
|
+
let path = request.readPath()
|
|
15
|
+
let segments = path.split('/').filter {s => s != "" && s != "." && s != ".."}
|
|
16
|
+
segments.{
|
|
17
|
+
| ["js", ...] =>
|
|
18
|
+
let asset = segments.map {"/" + _}.join()
|
|
19
|
+
request.writeHeader("Content-Type", "text/javascript; charset=UTF-8")
|
|
20
|
+
request.writeStream(system.assets().readStream(asset))
|
|
21
|
+
| _ =>
|
|
22
|
+
if(!handlers.handle(request, context)) {
|
|
23
|
+
request.writeStatus("404 Not Found")
|
|
24
|
+
}
|
|
25
|
+
Unit
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
buildMain(system: BuildSystem) {
|
|
31
|
+
mutable assets = AssetSystem.create()
|
|
32
|
+
Router.modulesWithBrowserMain.each {moduleName =>
|
|
33
|
+
let browser = system.compileForBrowser(moduleName + ".ff") // .bundle()
|
|
34
|
+
assets = assets.addAssets("/js/", browser.assets())
|
|
35
|
+
}
|
|
36
|
+
system.setAssets(assets)
|
|
37
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import WebServer from ff:webserver
|
|
2
|
+
import WebRoute from ff:webserver
|
|
3
|
+
import ChatRoomRoute
|
|
4
|
+
|
|
5
|
+
chatRoomRoute: WebRoute1[Int] = WebRoute.new1(
|
|
6
|
+
"/chat/{roomId}"
|
|
7
|
+
)
|
|
8
|
+
chatRoomUsersRoute: WebRoute1[Int] = WebRoute.new1(
|
|
9
|
+
"/chat/{roomId}/users"
|
|
10
|
+
)
|
|
11
|
+
chatRoomUserRoute: WebRoute2[Int, Int] = WebRoute.new2(
|
|
12
|
+
"/chat/{roomId}/users/{userId}"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
modulesWithBrowserMain: List[String] = [
|
|
16
|
+
ChatRoomRoute.routeModule
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
handlers(handler: WebRouteHandler[RouteContext]) {
|
|
20
|
+
handler.add1(chatRoomRoute, ChatRoomRoute.handle)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
capability RouteContext(system: NodeSystem)
|
|
@@ -140,7 +140,7 @@ return (new DataView(arrayBuffer_))
|
|
|
140
140
|
export function fromBase64_(base64_) {
|
|
141
141
|
const binaryString_ = atob(base64_);
|
|
142
142
|
const bytes_ = Uint8Array.from(binaryString_, ((char_) => {
|
|
143
|
-
return char_.
|
|
143
|
+
return char_.charCodeAt(0)
|
|
144
144
|
}));
|
|
145
145
|
return (new DataView(bytes_.buffer))
|
|
146
146
|
}
|
|
@@ -186,7 +186,7 @@ return (new DataView(arrayBuffer_))
|
|
|
186
186
|
export async function fromBase64_$(base64_, $task) {
|
|
187
187
|
const binaryString_ = atob(base64_);
|
|
188
188
|
const bytes_ = Uint8Array.from(binaryString_, ((char_) => {
|
|
189
|
-
return char_.
|
|
189
|
+
return char_.charCodeAt(0)
|
|
190
190
|
}));
|
|
191
191
|
return (new DataView(bytes_.buffer))
|
|
192
192
|
}
|
package/package.json
CHANGED
package/vscode/package.json
CHANGED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import WebServer
|
|
2
|
+
|
|
3
|
+
trait P: WebParameter {
|
|
4
|
+
toRouteParameter(text: String): Option[P]
|
|
5
|
+
fromRouteParameter(value: P): String
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
instance String: WebParameter {
|
|
9
|
+
toRouteParameter(text: String): Option[String] {Some(text)} // TODO: Unescape
|
|
10
|
+
fromRouteParameter(value: String): String {value} // TODO: Escape
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
instance Int: WebParameter {
|
|
14
|
+
toRouteParameter(text: String): Option[Int] {text.getInt()}
|
|
15
|
+
fromRouteParameter(value: Int): String {"" + value}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
data WebRoute0(urlPattern: String, segments: List[String])
|
|
19
|
+
data WebRoute1[P1](urlPattern: String, segments: List[String])
|
|
20
|
+
data WebRoute2[P1, P2](urlPattern: String, segments: List[String])
|
|
21
|
+
|
|
22
|
+
new0(urlPattern: String): WebRoute0 {
|
|
23
|
+
WebRoute0(urlPattern, urlPattern.split('/').filter {s => s != ""})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
new1[P1](urlPattern: String): WebRoute1[P1] {
|
|
27
|
+
WebRoute1(urlPattern, urlPattern.split('/').filter {s => s != ""})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
new2[P1, P2](urlPattern: String): WebRoute2[P1, P2] {
|
|
31
|
+
WebRoute2(urlPattern, urlPattern.split('/').filter {s => s != ""})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
extend self: WebRoute0 {
|
|
35
|
+
toUrl(): String {
|
|
36
|
+
self.urlPattern
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
extend self[P1: WebParameter]: WebRoute1[P1] {
|
|
41
|
+
toUrl(p1: P1): String {
|
|
42
|
+
mutable result = ""
|
|
43
|
+
mutable parameter = 1
|
|
44
|
+
self.segments.each {r =>
|
|
45
|
+
result += "/"
|
|
46
|
+
if(r.startsWith("{")) {
|
|
47
|
+
if(parameter == 1) {result += fromRouteParameter(p1)}
|
|
48
|
+
parameter += 1
|
|
49
|
+
} else {
|
|
50
|
+
result += r
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if(self.urlPattern.endsWith("/")) {result += "/"}
|
|
54
|
+
result
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
extend self[P1: WebParameter, P2: WebParameter]: WebRoute2[P1, P2] {
|
|
59
|
+
toUrl(p1: P1, p2: P2): String {
|
|
60
|
+
mutable result = ""
|
|
61
|
+
mutable parameter = 0
|
|
62
|
+
self.segments.each {r =>
|
|
63
|
+
result += "/"
|
|
64
|
+
if(r.startsWith("{")) {
|
|
65
|
+
if(parameter == 1) {result += fromRouteParameter(p1)}
|
|
66
|
+
if(parameter == 2) {result += fromRouteParameter(p2)}
|
|
67
|
+
parameter += 1
|
|
68
|
+
} else {
|
|
69
|
+
result += r
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if(self.urlPattern.endsWith("/")) {result += "/"}
|
|
73
|
+
result
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
capability WebRouteHandler[C](handlers: Array[(WebRequest[WebResponse], List[String], C) => Bool])
|
|
78
|
+
|
|
79
|
+
extend self[C]: WebRouteHandler[C] {
|
|
80
|
+
|
|
81
|
+
add0(route: WebRoute0, handle: (WebRequest[WebResponse], C) => Unit) {
|
|
82
|
+
self.handlers.push {request, segments, context =>
|
|
83
|
+
if(segments != route.segments) {False} else:
|
|
84
|
+
handle(request, context)
|
|
85
|
+
True
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
add1[P1: WebParameter](route: WebRoute1[P1], handle: (WebRequest[WebResponse], C, P1) => Unit) {
|
|
90
|
+
self.handlers.push {request, segments, context =>
|
|
91
|
+
if(segments.size() != route.segments.size()) {False} else:
|
|
92
|
+
let matching = True
|
|
93
|
+
mutable p1 = None
|
|
94
|
+
segments.zip(route.segments).eachWhile {| Pair(s, r) =>
|
|
95
|
+
if(r.startsWith("{")) {
|
|
96
|
+
if(p1.isEmpty()) {
|
|
97
|
+
p1 = toRouteParameter(s)
|
|
98
|
+
!p1.isEmpty()
|
|
99
|
+
} else {
|
|
100
|
+
False
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
r == s
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if(!matching) {False} else:
|
|
107
|
+
handle(request, context, p1.grab())
|
|
108
|
+
True
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
add2[P1: WebParameter, P2: WebParameter](route: WebRoute2[P1, P2], handle: (WebRequest[WebResponse], C, P1, P2) => Unit) {
|
|
113
|
+
self.handlers.push {request, segments, context =>
|
|
114
|
+
if(segments.size() != route.segments.size()) {False} else:
|
|
115
|
+
mutable p1 = None
|
|
116
|
+
mutable p2 = None
|
|
117
|
+
mutable matching = True
|
|
118
|
+
segments.zip(route.segments).eachWhile {| Pair(s, r) =>
|
|
119
|
+
matching = if(r.startsWith("{")) {
|
|
120
|
+
if(p1.isEmpty()) {
|
|
121
|
+
p1 = toRouteParameter(s)
|
|
122
|
+
!p1.isEmpty()
|
|
123
|
+
} elseIf {p2.isEmpty()} {
|
|
124
|
+
p2 = toRouteParameter(s)
|
|
125
|
+
!p2.isEmpty()
|
|
126
|
+
} else {
|
|
127
|
+
False
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
r == s
|
|
131
|
+
}
|
|
132
|
+
matching
|
|
133
|
+
}
|
|
134
|
+
if(!matching) {False} else:
|
|
135
|
+
handle(request, context, p1.grab(), p2.grab())
|
|
136
|
+
True
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
handle(request: WebRequest[WebResponse], context: C): Bool {
|
|
141
|
+
let segments = request.readPath().split('/').filter {s => s != ""}
|
|
142
|
+
mutable handled = False
|
|
143
|
+
self.handlers.eachWhile {| handler =>
|
|
144
|
+
handled = handler(request, segments, context)
|
|
145
|
+
!handled
|
|
146
|
+
}
|
|
147
|
+
handled
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
}
|