
header "sys" as sys

use core
use net
use fs
use thread

fn handler_default(req: Request) Response {
    return Response.html("Hello world!")
}
fn fast_handler_default(req: Context, res: ResponseWriter) {
    res.respond(200, "text/html", "Hello world!")
}

+ class Server {
    ~ host: String
    ~ port: u16
    socket: net:SocketTCP
    max_connections: uint
    connections: uint (0)
    handler: fn(Request)(Response) (handler_default)
    + fast_handler: ?fn(Context, ResponseWriter)()
    -[ns+] static_dirs: Array[String] (.{})
    -[ns+] active_body_size: uint (0)
    max_request_header_size: uint (8 * 1024) // 8 KB
    max_request_body_size: uint (32 * 1024 * 1024) // 32 MB
    max_server_wide_body_size: uint (2 * 1024 .@cast(uint)) // 2 GB
    + show_info: bool (false)

    + static fn new(host: String, port: u16, handler: fn(Request)(Response)) Server !socket_init_error !socket_bind_error {

        let max_connections : uint = 10000
        let socket = net:Socket.new_tcp(host, port) ! {
            throw socket_init_error
        }
        socket.bind() ! {
            throw socket_bind_error
        }

        return Server{
            host: host,
            port: port,
            socket: socket,
            max_connections: max_connections,
            handler: handler,
        }
    }

    + fn start(worker_count: i32 (8)) void {

        // SIGPIPE
        core:signal_ignore(13)

        if worker_count < 1 {
            worker_count = 1
        }
        if worker_count > 128 {
            worker_count = 128
        }

        if this.show_info {
            println("[+] Running http server on port " + this.port)
            println("[+] Worker count: " + worker_count)
        }

        worker_count--
        while worker_count > 0 {
            thread:Thread.start(fn() {
                worker(this)
            }) ! {
                println("[+] Failed to start worked number: " + worker_count)
            }
            worker_count--
        }

        worker(this)
    }

    + fn add_static_dir(path: String) !notfound {
        let full = fs:resolve(path)
        if !fs:is_dir(path) : throw notfound
        if this.show_info : println("[+] Add static dir: " + full)
        this.static_dirs.append(full)
    }
}

