-
Notifications
You must be signed in to change notification settings - Fork 684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
V: pure v server #7932
Merged
Merged
V: pure v server #7932
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
8498398
update v
enghitalo 22ced7c
Merge remote-tracking branch 'upstream/master'
enghitalo 1534857
Merge remote-tracking branch 'upstream/master'
enghitalo 819b3ae
Merge remote-tracking branch 'upstream/master'
enghitalo bfc6d56
Merge remote-tracking branch 'upstream/master'
enghitalo 84e6c16
Merge remote-tracking branch 'upstream/master'
enghitalo dbcc761
Merge remote-tracking branch 'upstream/master'
enghitalo c0bc232
v: pure V server
enghitalo 2517228
doc
enghitalo c379945
doc
enghitalo 8fa49b2
remove binary
enghitalo cd871ae
manualfree
enghitalo c9752e2
manualfree
enghitalo f63836b
changes after code review
enghitalo 71a17ec
merge
enghitalo 2df7c74
fix: router problem removing Router. It also, make everything faster
enghitalo e8a70c4
remove until find a better solution
enghitalo 2c45583
remove gitignore
enghitalo c75798b
update doc
enghitalo 8d60cc7
update V version
enghitalo 15e338e
fix: wrong http_ok_response
enghitalo a1b8a3f
ops
enghitalo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could master be considered as stable ?
I mean since v is not at 1.0, it could be ok to point to master, but it could be inconvenient to fix compilation issues (or else) in there is some
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems reasonable to me. V is so fast moving at the moment that this definitely makes sense @waghanza. I frankly don't think anyone is going to want to support older snapshots with so many updates coming in constantly and consistently... but I should defer to @enghitalo on his intention here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@waghanza For now, master is as stable as previous releases. I changed to master because "weekly.2024.49" is breaking the CI.