-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexplorer.odin
126 lines (98 loc) · 2.51 KB
/
explorer.odin
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package microserv
// generates a file explorer
import "core:fmt"
import "core:log"
import "core:os"
import path "core:path/filepath"
import "core:strings"
// ancient templating technique
Explorer_Head :: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Explorer</title>
<style>
body {
font-family: sans-serif;
background-color: #222;
color: #eee;
}
.path {
font-weight: bold;
margin-bottom: 10px;
color: #fff;
}
.file-list {
list-style: none;
padding: 0;
}
.file-list li {
margin-bottom: 5px;
color: #ddd;
}
</style> </head> <body>
`
//<li><a href="#">file1.txt</a></li>
//<li><a href="#">file2.pdf</a></li>
//<li><a href="#">folder1</a></li>
Explorer_Tail :: `
</ul>
</body>
</html>
`
// only returns the relative path in the serving directory
clean_path :: proc(p: string) -> (out: string, ok := false) {
sane_path := path.clean(p)
sane_base := path.clean(SERV_DIR)
out = strings.trim_left(sane_path, sane_base)
if out == p {
return
}
ok = true
return
}
gen_explorer :: proc(p: string) -> (result: string, ok := false) {
builder := strings.builder_make()
strings.write_string(&builder, Explorer_Head)
handle, err := os.open(p)
defer os.close(handle)
if err != nil {
log.error("failed to open", p)
log.error("reason:", err)
return
}
files, rerr := os.read_dir(handle, 2048)
if rerr != nil {
log.error("failed to read", p)
log.error("reason:", rerr)
return
}
strings.write_string(&builder, "<ul class=\"file-list\">\n")
for file in files {
fname := file.name
fpath := file.name
fpath = path.join([]string{p, file.name})
cpath := clean_path(fpath) or_return
fpath = cpath
if file.is_dir {
fname = fmt.aprint(fname, "/", sep = "")
}
list_item := fmt.aprintf("<li><a href=\"%s\">%s</a></li>", fpath, fname)
strings.write_string(&builder, list_item)
}
strings.write_string(&builder, Explorer_Tail)
result = strings.to_string(builder)
ok = true
return
}
gen_explorer_header :: proc(s: string) -> string {
builder := strings.builder_make()
strings.write_string(&builder, "HTTP/1.1 200 OK\r\n")
strings.write_string(&builder, "Server: MicroServ\r\n")
strings.write_string(&builder, "Content-Type: text/html\r\n")
strings.write_string(&builder, "\r\n")
strings.write_string(&builder, s)
return strings.to_string(builder)
}