96 lines
2.6 KiB
V
96 lines
2.6 KiB
V
|
module main
|
||
|
|
||
|
import io
|
||
|
import net
|
||
|
import strings
|
||
|
|
||
|
fn (mut vd VDoc) serve_html(out Output) {
|
||
|
cfg := vd.cfg
|
||
|
if out.typ == .html {
|
||
|
vd.render_static_html(true, out)
|
||
|
}
|
||
|
docs := vd.render(out)
|
||
|
dkeys := docs.keys()
|
||
|
if dkeys.len < 1 {
|
||
|
eprintln('no documentation created, the module has no `pub` functions')
|
||
|
exit(1)
|
||
|
}
|
||
|
def_name := docs.keys()[0]
|
||
|
server_url := 'http://localhost:' + cfg.server_port.str()
|
||
|
server := net.listen_tcp(cfg.server_port) or { panic(err) }
|
||
|
println('Serving docs on: $server_url')
|
||
|
if cfg.open_docs {
|
||
|
open_url(server_url)
|
||
|
}
|
||
|
content_type := match out.typ {
|
||
|
.html { 'text/html' }
|
||
|
.markdown { 'text/markdown' }
|
||
|
.json { 'application/json' }
|
||
|
else { 'text/plain' }
|
||
|
}
|
||
|
server_context := VdocHttpServerContext{
|
||
|
docs: docs
|
||
|
content_type: content_type
|
||
|
default_filename: def_name
|
||
|
}
|
||
|
for {
|
||
|
mut conn := server.accept() or {
|
||
|
server.close() or { }
|
||
|
panic(err)
|
||
|
}
|
||
|
handle_http_connection(mut conn, server_context)
|
||
|
conn.close() or { eprintln('error closing the connection: $err') }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct VdocHttpServerContext {
|
||
|
docs map[string]string
|
||
|
content_type string
|
||
|
default_filename string
|
||
|
}
|
||
|
|
||
|
fn handle_http_connection(mut con net.TcpConn, ctx &VdocHttpServerContext) {
|
||
|
mut reader := io.new_buffered_reader(reader: io.make_reader(con))
|
||
|
first_line := reader.read_line() or {
|
||
|
send_http_response(mut con, 501, ctx.content_type, 'bad request')
|
||
|
return
|
||
|
}
|
||
|
request_parts := first_line.split(' ')
|
||
|
if request_parts.len != 3 {
|
||
|
send_http_response(mut con, 501, ctx.content_type, 'bad request')
|
||
|
return
|
||
|
}
|
||
|
urlpath := request_parts[1]
|
||
|
filename := if urlpath == '/' {
|
||
|
ctx.default_filename.trim_left('/')
|
||
|
} else {
|
||
|
urlpath.trim_left('/')
|
||
|
}
|
||
|
if ctx.docs[filename].len == 0 {
|
||
|
send_http_response(mut con, 404, ctx.content_type, 'file not found')
|
||
|
return
|
||
|
}
|
||
|
send_http_response(mut con, 200, ctx.content_type, ctx.docs[filename])
|
||
|
}
|
||
|
|
||
|
fn send_http_response(mut con net.TcpConn, http_code int, content_type string, html string) {
|
||
|
content_length := html.len.str()
|
||
|
shttp_code := http_code.str()
|
||
|
mut http_response := strings.new_builder(20000)
|
||
|
http_response.write('HTTP/1.1 ')
|
||
|
http_response.write(shttp_code)
|
||
|
http_response.write(' OK\r\n')
|
||
|
http_response.write('Server: VDoc\r\n')
|
||
|
http_response.write('Content-Type: ')
|
||
|
http_response.write(content_type)
|
||
|
http_response.write('\r\n')
|
||
|
http_response.write('Content-Length: ')
|
||
|
http_response.write(content_length)
|
||
|
http_response.write('\r\n')
|
||
|
http_response.write('Connection: close\r\n')
|
||
|
http_response.write('\r\n')
|
||
|
http_response.write(html)
|
||
|
sresponse := http_response.str()
|
||
|
con.write_str(sresponse) or { eprintln('error sending http response: $err') }
|
||
|
}
|