Skip to content
This repository was archived by the owner on Jul 10, 2025. It is now read-only.

Commit c1509d8

Browse files
committed
Upgrade to Grain 0.4 (w/ comment questions)
1 parent af3d878 commit c1509d8

File tree

5 files changed

+241
-155
lines changed

5 files changed

+241
-155
lines changed

fileserver.gr

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,59 +8,83 @@ import String from "string"
88
import Mediatype from "./lib/mediatype"
99
import Stringutil from "./lib/stringutil"
1010

11-
let serve = (abs_path) => {
12-
// Trim the leading /
13-
let path = String.slice(1, String.length(abs_path), abs_path)
14-
File.fdWrite(File.stderr, "Fileserver: Loading file ")
15-
File.fdWrite(File.stderr, path)
16-
File.fdWrite(File.stderr, "\n")
11+
let internalError = () => {
12+
// Is stdout correct here?
13+
let result = File.fdWrite(File.stdout, "Status: 500\n\nInternal Server Error")
14+
match (result) {
15+
Err(err) => {
16+
// TODO: What do you do on a write error?
17+
void
18+
},
19+
Ok(_nBytes) => void,
20+
}
21+
}
1722

18-
// Open file
19-
// TODO: This throws an error when something goes wrong.
20-
// But Grain 0.3 does not have a try/catch yet.
21-
// When we figure out how, we need to catch the error here
22-
// and do a 404 or 500.
23-
let input = File.pathOpen(
24-
File.pwdfd,
25-
[],
26-
path,
27-
[],
28-
[File.FdRead],
29-
[],
30-
[],
31-
)
23+
let notFound = () => {
24+
let result = File.fdWrite(File.stdout, "Status: 404\n\nNot Found")
25+
match (result) {
26+
Err(err) => {
27+
// TODO: What do you do on a write error?
28+
void
29+
},
30+
Ok(_nBytes) => void,
31+
}
32+
}
3233

33-
File.fdWrite(File.stdout, "Content-Type: ")
34-
File.fdWrite(File.stdout, Mediatype.guess(path))
35-
File.fdWrite(File.stdout, "\n\n")
36-
37-
// Pipe output to STDOUT
38-
let rec pipe = (in, out) => {
39-
let (d, len) = File.fdRead(in, 1024)
40-
File.fdWrite(out, d)
41-
if (len > 0) {
42-
pipe(in, out)
43-
}
44-
}
45-
pipe(input, File.stdout)
46-
File.fdClose(input)
34+
// Pipe output to STDOUT
35+
let rec pipe = (in, out) => {
36+
let res = File.fdRead(in, 1024)
37+
match (res) {
38+
Err(err) => {
39+
// TODO: What to do on a read error?
40+
void
41+
},
42+
Ok((d, len)) => {
43+
// TODO: What should happen if this Result is an error
44+
File.fdWrite(out, d)
45+
if (len > 0) {
46+
pipe(in, out)
47+
}
48+
},
49+
}
4750
}
4851

49-
let guestpath = (env) => {
52+
let serve = abs_path => {
53+
// Trim the leading /
54+
let path = String.slice(1, String.length(abs_path), abs_path)
55+
// TODO: What should happen if any of these Results are an error
56+
File.fdWrite(File.stderr, "Fileserver: Loading file ")
57+
File.fdWrite(File.stderr, path)
58+
File.fdWrite(File.stderr, "\n")
5059

51-
// Backward compat for an older version of Wagi that had PATH_INFO wrong.
52-
// X_RELATIVE_PATH was removed before Wagi 0.4
53-
match (Map.get("X_RELATIVE_PATH", env)) {
54-
Some(p) => String.concat("/", p),
55-
None => {
56-
Option.unwrap(Map.get("PATH_INFO", env))
57-
}
58-
}
59-
60+
// Open file
61+
let result = File.pathOpen(File.pwdfd, [], path, [], [File.FdRead], [], [])
62+
63+
match (result) {
64+
Err(_err) => notFound(),
65+
Ok(input) => {
66+
// TODO: What should happen if any of these Results are an error
67+
File.fdWrite(File.stdout, "Content-Type: ")
68+
File.fdWrite(File.stdout, Mediatype.guess(path))
69+
File.fdWrite(File.stdout, "\n\n")
70+
71+
pipe(input, File.stdout)
72+
// TODO: What should happen if this Result is an error
73+
File.fdClose(input)
74+
void
75+
},
76+
}
6077
}
6178

62-
let notFound = () => {
63-
File.fdWrite(File.stdout, "Status: 404\n\nNot Found")
79+
let guestpath = env => {
80+
// Backward compat for an older version of Wagi that had PATH_INFO wrong.
81+
// X_RELATIVE_PATH was removed before Wagi 0.4
82+
match (Map.get("X_RELATIVE_PATH", env)) {
83+
Some(p) => String.concat("/", p),
84+
None => {
85+
Option.unwrap(Map.get("PATH_INFO", env))
86+
},
87+
}
6488
}
6589

6690
let kv = Env.envMap()

lib/env.gr

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,44 @@ import Array from "array"
44
import String from "string"
55
import Option from "option"
66

7-
// Split an environment variable at the first equals sign.
8-
// @param item: An environment variable pair, separated by an equals sign (=).
9-
// @return (String, String) A tuple key/value pair.
10-
export let splitEnvVar = (item) => {
11-
let offsetOpt = String.indexOf("=", item)
7+
/**
8+
* Split an environment variable at the first equals sign.
9+
*
10+
* @param item: An environment variable pair, separated by an equals sign (=).
11+
* @returns A tuple key/value pair.
12+
*/
13+
export let splitEnvVar = item => {
14+
let offsetOpt = String.indexOf("=", item)
1215

13-
// For now, fail if the env var is malformed.
14-
let offset = Option.unwrap(offsetOpt)
16+
// For now, fail if the env var is malformed.
17+
let offset = Option.unwrap(offsetOpt)
1518

16-
let key = String.slice(0, offset, item)
17-
let val = String.slice(offset+1, String.length(item), item)
18-
(key, val)
19+
let key = String.slice(0, offset, item)
20+
let val = String.slice(offset + 1, String.length(item), item)
21+
(key, val)
1922
}
2023

21-
// Get the environment variables as a Map<String, String>
22-
//
23-
// @return Map<String, String> A map of all environment variables.
24-
export let envMap = () => {
25-
let parsed = Map.make()
26-
let env = Process.env()
27-
let pairs = Array.map(splitEnvVar,env)
24+
/**
25+
* Get the environment variables as a Map<String, String>
26+
*
27+
* @returns A map of all environment variables.
28+
*/
29+
export let envMap = () => {
30+
let parsed = Map.make()
31+
let env = Process.env()
32+
match (env) {
33+
Err(err) => parsed,
34+
Ok(env) => {
35+
let pairs = Array.map(splitEnvVar, env)
2836

29-
Array.forEach((item) => {
30-
let (k, v) = item
31-
Map.set(k, v, parsed)
32-
}, pairs)
33-
parsed
37+
Array.forEach(
38+
item => {
39+
let (k, v) = item
40+
Map.set(k, v, parsed)
41+
},
42+
pairs,
43+
)
44+
parsed
45+
},
46+
}
3447
}
35-
36-

lib/mediatype.gr

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import String from "string"
22
import Array from "array"
33
import Option from "option"
44
import Map from "map"
5-
import {lastIndexOf, reverse} from "./lib/stringutil"
5+
import { lastIndexOf, reverse } from "./stringutil"
66

77
export let default_mt = "application/octet-stream"
88

@@ -82,18 +82,30 @@ Map.set("7z", "application/x-7z-compressed", mediatypes)
8282
Map.set("azw", "application/vnd.amazon.ebook", mediatypes)
8383
Map.set("bin", "application/octet-stream", mediatypes)
8484
Map.set("doc", "application/msword", mediatypes)
85-
Map.set("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", mediatypes)
85+
Map.set(
86+
"docx",
87+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
88+
mediatypes,
89+
)
8690
Map.set("epub", "application/epub+zip", mediatypes)
8791
Map.set("odp", "application/vnd.oasis.opendocument.presentation", mediatypes)
8892
Map.set("ods", "application/vnd.oasis.opendocument.spreadsheet", mediatypes)
8993
Map.set("odt", "application/vnd.oasis.opendocument.text", mediatypes)
9094
Map.set("pdf", "application/pdf", mediatypes)
9195
Map.set("ppt", "application/vnd.ms-powerpoint", mediatypes)
92-
Map.set("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation", mediatypes)
96+
Map.set(
97+
"pptx",
98+
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
99+
mediatypes,
100+
)
93101
Map.set("rtf", "application/rtf", mediatypes)
94102
Map.set("vsd", "application/vnd.visio", mediatypes)
95103
Map.set("xls", "application/vnd.ms-excel", mediatypes)
96-
Map.set("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", mediatypes)
104+
Map.set(
105+
"xlsx",
106+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
107+
mediatypes,
108+
)
97109

98110
// Fonts
99111
Map.set("eot", "application/vnd.ms-fontobject", mediatypes)
@@ -102,19 +114,21 @@ Map.set("ttf", "font/ttf", mediatypes)
102114
Map.set("woff", "font/woff", mediatypes)
103115
Map.set("woff2", "font/woff2", mediatypes)
104116

105-
// Guess the media type of this file
106-
//
107-
// Per recommendation, if no media type is found for an extension,
108-
// this returns `application/octet-stream`.
109-
//
110-
// @param filename: The name of the file
111-
// @returns String a media type
117+
/**
118+
* Guess the media type of this file
119+
*
120+
* Per recommendation, if no media type is found for an extension,
121+
* this returns `application/octet-stream`.
122+
*
123+
* @param filename: The name of the file
124+
* @returns A media type
125+
*/
112126
export let guess = (filename: String) => {
113-
match (lastIndexOf(".", filename)) {
114-
Some(extOffset) => {
115-
let ext = String.slice(extOffset + 1, String.length(filename), filename)
116-
Option.unwrapWithDefault(default_mt, Map.get(ext, mediatypes))
117-
},
118-
None => default_mt
119-
}
127+
match (lastIndexOf(".", filename)) {
128+
Some(extOffset) => {
129+
let ext = String.slice(extOffset + 1, String.length(filename), filename)
130+
Option.unwrapWithDefault(default_mt, Map.get(ext, mediatypes))
131+
},
132+
None => default_mt,
133+
}
120134
}

lib/stringutil.gr

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,50 @@
11
import String from "string"
22
import Array from "array"
33

4-
// Return a String that is the reverse of the given String.
5-
//
6-
// @param str: The string to reverse.
7-
// @return String A reversed version of the given string
4+
/**
5+
* Return a String that is the reverse of the given String.
6+
*
7+
* @param str: The string to reverse.
8+
* @returns A reversed version of the given string
9+
*/
810
export let reverse = (str: String) => {
9-
let chars = String.explode(str)
10-
let clen = Array.length(chars)
11-
let rev = Array.init(clen, (index) => {
12-
let last = clen - index - 1
13-
chars[last]
14-
})
15-
String.implode(rev)
11+
let chars = String.explode(str)
12+
let rev = Array.reverse(chars)
13+
String.implode(rev)
1614
}
1715

18-
// Get the index of the last appearance of needle in the haystack.
19-
//
20-
// For a multi-character needle, this will return the end of that sequence,
21-
// not the beginning (as indexOf does).
22-
//
23-
// @param needle: The string to search for
24-
// @param haystack: The string to be searched
25-
// @return Option<Number> The offset, if found, or a number
16+
/**
17+
* Get the index of the last appearance of needle in the haystack.
18+
*
19+
* For a multi-character needle, this will return the end of that sequence,
20+
* not the beginning (as indexOf does).
21+
*
22+
* @param needle: The string to search for
23+
* @param haystack: The string to be searched
24+
* @returns The offset, if found, or a number
25+
*/
2626
export let lastIndexOf = (needle: String, haystack: String) => {
27-
let rev = reverse(haystack)
28-
let revNeedle = reverse(needle)
29-
let nlen = String.length(needle)
30-
let i = String.indexOf(revNeedle, rev)
31-
match (i) {
32-
Some(offset) => Some(String.length(haystack) - 1 - offset),
33-
None => None,
34-
}
27+
let rev = reverse(haystack)
28+
let revNeedle = reverse(needle)
29+
let nlen = String.length(needle)
30+
let i = String.indexOf(revNeedle, rev)
31+
match (i) {
32+
Some(offset) => Some(((String.length(haystack)) - 1) - offset),
33+
None => None,
34+
}
3535
}
3636

3737
export let afterLast = (needle: String, haystack: String) => {
38-
match (lastIndexOf(needle, haystack)) {
39-
Some(index) => String.slice(index + 1, String.length(haystack), haystack),
40-
None => haystack
41-
}
38+
match (lastIndexOf(needle, haystack)) {
39+
Some(index) => String.slice(index + 1, String.length(haystack), haystack),
40+
None => haystack,
41+
}
4242
}
4343

4444
export let beforeLast = (needle: String, haystack: String) => {
45-
let nlen = String.length(needle)
46-
match (lastIndexOf(needle, haystack)) {
47-
Some(index) => String.slice(0, index + 1 - nlen, haystack),
48-
None => haystack
49-
}
45+
let nlen = String.length(needle)
46+
match (lastIndexOf(needle, haystack)) {
47+
Some(index) => String.slice(0, (index + 1) - nlen, haystack),
48+
None => haystack,
49+
}
5050
}

0 commit comments

Comments
 (0)