-
Notifications
You must be signed in to change notification settings - Fork 686
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* update v * v: pure V server * doc * doc * remove binary * manualfree * manualfree * changes after code review * fix: router problem removing Router. It also, make everything faster * remove until find a better solution * remove gitignore * update doc * update V version * fix: wrong http_ok_response * ops
- Loading branch information
Showing
12 changed files
with
615 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[*] | ||
charset = utf-8 | ||
end_of_line = lf | ||
insert_final_newline = true | ||
trim_trailing_whitespace = true | ||
|
||
[*.v] | ||
indent_style = tab |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
* text=auto eol=lf | ||
*.bat eol=crlf | ||
|
||
*.v linguist-language=V | ||
*.vv linguist-language=V | ||
*.vsh linguist-language=V | ||
v.mod linguist-language=V | ||
.vdocignore linguist-language=ignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Binaries for programs and plugins | ||
main | ||
a | ||
*.exe | ||
*.exe~ | ||
*.so | ||
*.dylib | ||
*.dll | ||
|
||
# Ignore binary output folders | ||
bin/ | ||
|
||
# Ignore common editor/system specific metadata | ||
.DS_Store | ||
.idea/ | ||
.vscode/ | ||
*.iml | ||
|
||
# ENV | ||
.env | ||
|
||
# vweb and database | ||
*.db | ||
*.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# Vanilla | ||
|
||
Vanilla is a raw V server. | ||
|
||
## Description | ||
|
||
This project is a simple server written in the V programming language. It aims to provide a minimalistic and efficient server implementation. | ||
|
||
## Features | ||
|
||
- Lightweight and fast | ||
- Minimal dependencies | ||
- Easy to understand and extend | ||
|
||
## Installation | ||
|
||
To install Vanilla, you need to have the V compiler installed. You can download it from the [official V website](https://vlang.io). | ||
|
||
## Usage | ||
|
||
To run the server, use the following command: | ||
|
||
```sh | ||
v -prod crun . | ||
``` | ||
|
||
This will start the server, and you can access it at `http://localhost:3000`. | ||
|
||
## Code Overview | ||
|
||
### Main Server | ||
|
||
The main server logic is implemented in [src/main.v](v/vanilla/src/main.v). The server is initialized and started in the `main` function: | ||
|
||
```v | ||
module main | ||
const port = 3000 | ||
fn main() { | ||
mut server := Server{ | ||
router: setup_router() | ||
} | ||
server.server_socket = create_server_socket(port) | ||
if server.server_socket < 0 { | ||
return | ||
} | ||
server.epoll_fd = C.epoll_create1(0) | ||
if server.epoll_fd < 0 { | ||
C.perror('epoll_create1 failed'.str) | ||
C.close(server.server_socket) | ||
return | ||
} | ||
server.lock_flag.lock() | ||
if add_fd_to_epoll(server.epoll_fd, server.server_socket, u32(C.EPOLLIN)) == -1 { | ||
C.close(server.server_socket) | ||
C.close(server.epoll_fd) | ||
server.lock_flag.unlock() | ||
return | ||
} | ||
server.lock_flag.unlock() | ||
server.lock_flag.init() | ||
for i := 0; i < 16; i++ { | ||
server.threads[i] = spawn worker_thread(&server) | ||
} | ||
println('listening on http://localhost:${port}/') | ||
event_loop(&server) | ||
} | ||
``` | ||
|
||
## Test | ||
|
||
### CURL | ||
|
||
```sh | ||
curl -X GET --verbose http://localhost:3000/ && | ||
curl -X POST --verbose http://localhost:3000/user && | ||
curl -X GET --verbose http://localhost:3000/user/1 | ||
|
||
``` | ||
|
||
### WRK | ||
|
||
```sh | ||
wrk --connection 512 --threads 16 --duration 10s http://localhost:3000 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
framework: | ||
github: vlang/v |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
module main | ||
|
||
import strings | ||
|
||
const http_ok_response = 'HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n'.bytes() | ||
|
||
const http_created_response = 'HTTP/1.1 201 Created\r\nContent-Type: application/json\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n'.bytes() | ||
|
||
fn home_controller(params []string) ![]u8 { | ||
return http_ok_response | ||
} | ||
|
||
fn get_users_controller(params []string) ![]u8 { | ||
return http_ok_response | ||
} | ||
|
||
@[direct_array_access; manualfree] | ||
fn get_user_controller(params []string) ![]u8 { | ||
if params.len == 0 { | ||
return tiny_bad_request_response | ||
} | ||
id := params[0] | ||
response_body := id | ||
|
||
mut sb := strings.new_builder(200) | ||
sb.write_string('HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: ') | ||
sb.write_string(response_body.len.str()) | ||
sb.write_string('\r\nConnection: keep-alive\r\n\r\n') | ||
sb.write_string(response_body) | ||
|
||
defer { | ||
unsafe { | ||
response_body.free() | ||
params.free() | ||
} | ||
} | ||
return sb | ||
} | ||
|
||
fn create_user_controller(params []string) ![]u8 { | ||
return http_created_response | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
module main | ||
|
||
const port = 3000 | ||
const max_thread_pool_size = 8 | ||
|
||
fn main() { | ||
mut server := Server{} | ||
|
||
server.server_socket = create_server_socket(port) | ||
if server.server_socket < 0 { | ||
return | ||
} | ||
server.epoll_fd = C.epoll_create1(0) | ||
if server.epoll_fd < 0 { | ||
C.perror('epoll_create1 failed'.str) | ||
C.close(server.server_socket) | ||
return | ||
} | ||
|
||
server.lock_flag.lock() | ||
if add_fd_to_epoll(server.epoll_fd, server.server_socket, u32(C.EPOLLIN)) == -1 { | ||
C.close(server.server_socket) | ||
C.close(server.epoll_fd) | ||
|
||
server.lock_flag.unlock() | ||
return | ||
} | ||
|
||
server.lock_flag.unlock() | ||
|
||
server.lock_flag.init() | ||
for i := 0; i < max_thread_pool_size; i++ { | ||
server.threads[i] = spawn worker_thread(&server) | ||
} | ||
println('listening on http://localhost:${port}/') | ||
event_loop(&server) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
module main | ||
|
||
struct Slice { | ||
start int | ||
len int | ||
} | ||
|
||
struct HttpRequest { | ||
mut: | ||
buffer []u8 | ||
method Slice | ||
path Slice | ||
version Slice | ||
} | ||
|
||
fn parse_request_line(mut req HttpRequest) ! { | ||
mut i := 0 | ||
// Parse HTTP method | ||
for i < req.buffer.len && req.buffer[i] != ` ` { | ||
i++ | ||
} | ||
req.method = Slice{ | ||
start: 0 | ||
len: i | ||
} | ||
i++ | ||
|
||
// Parse path | ||
mut path_start := i | ||
for i < req.buffer.len && req.buffer[i] != ` ` { | ||
i++ | ||
} | ||
req.path = Slice{ | ||
start: path_start | ||
len: i - path_start | ||
} | ||
i++ | ||
|
||
// Parse HTTP version | ||
mut version_start := i | ||
for i < req.buffer.len && req.buffer[i] != `\r` { | ||
i++ | ||
} | ||
req.version = Slice{ | ||
start: version_start | ||
len: i - version_start | ||
} | ||
|
||
// Move to the end of the request line | ||
if i + 1 < req.buffer.len && req.buffer[i] == `\r` && req.buffer[i + 1] == `\n` { | ||
i += 2 | ||
} else { | ||
return error('Invalid HTTP request line') | ||
} | ||
} | ||
|
||
fn decode_http_request(buffer []u8) !HttpRequest { | ||
mut req := HttpRequest{ | ||
buffer: buffer | ||
} | ||
|
||
parse_request_line(mut req)! | ||
|
||
return req | ||
} | ||
|
||
// Helper function to convert Slice to string for debugging | ||
fn slice_to_string(buffer []u8, s Slice) string { | ||
return buffer[s.start..s.start + s.len].bytestr() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module main | ||
|
||
// handle_request finds and executes the handler for a given route. | ||
// It takes an HttpRequest object as an argument and returns the response as a byte array. | ||
fn handle_request(req HttpRequest) ![]u8 { | ||
method := unsafe { tos(&req.buffer[req.method.start], req.method.len) } | ||
path := unsafe { tos(&req.buffer[req.path.start], req.path.len) } | ||
|
||
if method == 'GET' { | ||
if path == '/' { | ||
return home_controller([]) | ||
} else if path.starts_with('/user/') { | ||
id := path[6..] | ||
return get_user_controller([id]) | ||
} | ||
} else if method == 'POST' { | ||
if path == '/user' { | ||
return create_user_controller([]) | ||
} | ||
} | ||
|
||
return tiny_bad_request_response | ||
} |
Oops, something went wrong.