Add custom error handler callback
This commit is contained in:
parent
595872f81c
commit
e739557f8e
3 changed files with 221 additions and 34 deletions
70
server.odin
70
server.odin
|
|
@ -1,12 +1,15 @@
|
|||
package fjord
|
||||
|
||||
import "base:intrinsics"
|
||||
import "base:runtime"
|
||||
import "core:bufio"
|
||||
import "core:bytes"
|
||||
import "core:fmt"
|
||||
import "core:io"
|
||||
import "core:log"
|
||||
import "core:net"
|
||||
import "core:path/slashpath"
|
||||
import "core:reflect"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:sync"
|
||||
|
|
@ -15,7 +18,10 @@ import "core:unicode"
|
|||
|
||||
import http "http"
|
||||
|
||||
Server :: struct($Error_Type: typeid) {
|
||||
Server :: struct(
|
||||
$Error_Type: typeid
|
||||
) where intrinsics.type_is_union(Error_Type)
|
||||
{
|
||||
endpoint: net.Endpoint,
|
||||
not_found_handler: #type proc(
|
||||
request: ^http.Request,
|
||||
|
|
@ -23,6 +29,7 @@ Server :: struct($Error_Type: typeid) {
|
|||
http.Response,
|
||||
Error_Type,
|
||||
),
|
||||
error_handler: #type proc(error: Error_Type) -> http.Response,
|
||||
running: bool,
|
||||
router: Router(Error_Type),
|
||||
thread_pool: thread.Pool,
|
||||
|
|
@ -66,7 +73,7 @@ server_init :: proc(
|
|||
endpoint: net.Endpoint,
|
||||
thread_count: uint,
|
||||
allocator := context.allocator,
|
||||
) {
|
||||
) where intrinsics.type_is_union(Error_Type) {
|
||||
server^ = Server(Error_Type) {
|
||||
endpoint = endpoint,
|
||||
not_found_handler = proc(
|
||||
|
|
@ -83,6 +90,19 @@ server_init :: proc(
|
|||
)
|
||||
return http_response, nil
|
||||
},
|
||||
error_handler = proc(error: Error_Type) -> http.Response {
|
||||
error_string := fmt.tprint(error)
|
||||
body := strings.concatenate(
|
||||
{"<div>Error: ", error_string, "</div>"},
|
||||
context.temp_allocator,
|
||||
)
|
||||
http_response := http.make_response(
|
||||
.BadRequest,
|
||||
transmute([]byte)body,
|
||||
.Html,
|
||||
)
|
||||
return http_response
|
||||
},
|
||||
thread_count = thread_count,
|
||||
running = false,
|
||||
allocator = allocator,
|
||||
|
|
@ -95,7 +115,7 @@ server_init :: proc(
|
|||
|
||||
server_destroy :: proc(server: ^Server($Error_Type)) {
|
||||
if sync.atomic_load(&server.thread_pool.is_running) {
|
||||
thread.pool_join(&server.thread_pool)
|
||||
thread.pool_finish(&server.thread_pool)
|
||||
}
|
||||
|
||||
thread.pool_destroy(&server.thread_pool)
|
||||
|
|
@ -115,6 +135,14 @@ server_set_not_found_handler :: proc(
|
|||
server.not_found_handler = not_found_handler
|
||||
}
|
||||
|
||||
// This is used instead of default server_make param until compiler bug is fixed: https://github.com/odin-lang/Odin/issues/5792
|
||||
server_set_error_handler :: proc(
|
||||
server: ^Server($Error_Type),
|
||||
error_handler: #type proc(error: Error_Type) -> http.Response,
|
||||
) {
|
||||
server.error_handler = error_handler
|
||||
}
|
||||
|
||||
server_add_route :: proc(
|
||||
server: ^Server($Error_Type),
|
||||
method: http.Method,
|
||||
|
|
@ -171,9 +199,9 @@ serve :: proc(server: ^Server($Error_Type), client_socket: net.TCP_Socket) {
|
|||
|
||||
http_response, handler_err := handler(&http_request)
|
||||
|
||||
log.info(handler_err)
|
||||
if handler_err != nil {
|
||||
log.warnf("Handler failed with error: %s", handler_err)
|
||||
return
|
||||
http_response = server.error_handler(handler_err)
|
||||
}
|
||||
|
||||
marshalled_response := http.marshall_response(
|
||||
|
|
@ -183,27 +211,26 @@ serve :: proc(server: ^Server($Error_Type), client_socket: net.TCP_Socket) {
|
|||
net.send_tcp(client_socket, marshalled_response)
|
||||
}
|
||||
|
||||
RequestThreadData :: struct($Error_Type: typeid) {
|
||||
server: ^Server(Error_Type),
|
||||
client_socket: net.TCP_Socket,
|
||||
}
|
||||
|
||||
@(private)
|
||||
request_thread_task :: proc(t: thread.Task) {
|
||||
task_data := cast(^RequestThreadData(any))t.data
|
||||
defer free(task_data, t.allocator)
|
||||
|
||||
serve(task_data.server, task_data.client_socket)
|
||||
|
||||
net.close(task_data.client_socket)
|
||||
// context.temp_allocator is freed automatically on thread death.
|
||||
}
|
||||
|
||||
@(private)
|
||||
spawn_request_thread :: proc(
|
||||
server: ^Server($Error_Type),
|
||||
client_socket: net.TCP_Socket,
|
||||
) {
|
||||
RequestThreadData :: struct($Error_Type: typeid) {
|
||||
server: ^Server(Error_Type),
|
||||
client_socket: net.TCP_Socket,
|
||||
}
|
||||
|
||||
request_thread_task :: proc(t: thread.Task) {
|
||||
task_data := cast(^RequestThreadData(Error_Type))t.data
|
||||
defer free(task_data, t.allocator)
|
||||
|
||||
serve(task_data.server, task_data.client_socket)
|
||||
|
||||
net.close(task_data.client_socket)
|
||||
// context.temp_allocator is freed automatically on thread death.
|
||||
}
|
||||
|
||||
task_data := new(RequestThreadData(Error_Type))
|
||||
task_data^ = RequestThreadData(Error_Type) {
|
||||
server = server,
|
||||
|
|
@ -237,5 +264,4 @@ server_listen_and_serve :: proc(server: ^Server($Error_Type)) {
|
|||
}
|
||||
|
||||
thread.pool_finish(&server.thread_pool)
|
||||
thread.pool_join(&server.thread_pool)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue