mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vweb: first step to revive it
This commit is contained in:
parent
2032da7fe2
commit
892d1c6aab
@ -3,7 +3,7 @@ module main
|
||||
import vweb
|
||||
|
||||
const (
|
||||
Port = 8082
|
||||
port = 8082
|
||||
)
|
||||
|
||||
struct App {
|
||||
@ -13,7 +13,9 @@ pub mut:
|
||||
}
|
||||
|
||||
fn main() {
|
||||
vweb.run<App>(Port)
|
||||
mut app := App{}
|
||||
vweb.run(app, port)
|
||||
//vweb.run<App>(Port)
|
||||
}
|
||||
|
||||
pub fn (app mut App) init() {
|
@ -275,8 +275,8 @@ fn (p mut Parser) fn_decl() {
|
||||
// C function header def? (fn C.NSMakeRect(int,int,int,int))
|
||||
is_c := f.name == 'C' && p.tok == .dot
|
||||
// Just fn signature? only builtin.v + default build mode
|
||||
if p.pref.build_mode == .build_module {
|
||||
//println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
|
||||
if p.pref.is_verbose { // p.pref.build_mode == .build_module {
|
||||
println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen')
|
||||
}
|
||||
if is_c {
|
||||
p.check(.dot)
|
||||
@ -561,8 +561,10 @@ fn (p mut Parser) check_unused_variables() {
|
||||
if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated {
|
||||
p.production_error_with_token_index('`$var.name` declared and not used', var.token_idx )
|
||||
}
|
||||
if !var.is_changed && var.is_mut && !p.pref.is_repl && !p.pref.translated {
|
||||
p.error_with_token_index( '`$var.name` is declared as mutable, but it was never changed', var.token_idx )
|
||||
if !var.is_changed && var.is_mut && !p.pref.is_repl &&
|
||||
!p.pref.translated && var.typ != 'T*'
|
||||
{
|
||||
p.error_with_token_index('`$var.name` is declared as mutable, but it was never changed', var.token_idx )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -472,7 +472,7 @@ fn (p mut Parser) import_statement() {
|
||||
if p.tok != .name {
|
||||
p.error('bad import format')
|
||||
}
|
||||
if p.peek() == .number { // && p.scanner.text[p.scanner.pos + 1] == `.` {
|
||||
if p.peek() == .number {
|
||||
p.error('bad import format. module/submodule names cannot begin with a number')
|
||||
}
|
||||
import_tok_idx := p.token_idx-1
|
||||
@ -513,14 +513,6 @@ fn (p mut Parser) const_decl() {
|
||||
if is_pub {
|
||||
p.next()
|
||||
}
|
||||
if p.tok == .key_import {
|
||||
p.error_with_token_index(
|
||||
'`import const` was removed from the language, ' +
|
||||
'because predeclaring C constants is not needed anymore. ' +
|
||||
'You can use them directly with C.CONST_NAME',
|
||||
p.cur_tok_index()
|
||||
)
|
||||
}
|
||||
p.inside_const = true
|
||||
p.check(.key_const)
|
||||
p.fspace()
|
||||
@ -659,13 +651,13 @@ fn (p mut Parser) interface_method(field_name, receiver string) &Fn {
|
||||
|
||||
fn key_to_type_cat(tok TokenKind) TypeCategory {
|
||||
match tok {
|
||||
.key_interface { return TypeCategory.interface_ }
|
||||
.key_struct { return TypeCategory.struct_ }
|
||||
.key_union { return TypeCategory.union_ }
|
||||
//TokenKind.key_ => return .interface_
|
||||
.key_interface { return .interface_ }
|
||||
.key_struct { return .struct_ }
|
||||
.key_union { return .union_ }
|
||||
//TokenKind.key_ => return .interface_
|
||||
}
|
||||
verror('Unknown token: $tok')
|
||||
return TypeCategory.builtin
|
||||
return .builtin
|
||||
}
|
||||
|
||||
// check_name checks for a name token and returns its literal
|
||||
@ -727,10 +719,10 @@ fn (p mut Parser) check(expected TokenKind) {
|
||||
*/
|
||||
p.next()
|
||||
|
||||
if p.scanner.line_comment != '' {
|
||||
//p.fgenln('// ! "$p.scanner.line_comment"')
|
||||
//p.scanner.line_comment = ''
|
||||
}
|
||||
//if p.scanner.line_comment != '' {
|
||||
//p.fgenln('// ! "$p.scanner.line_comment"')
|
||||
//p.scanner.line_comment = ''
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
@ -894,7 +886,7 @@ fn (p mut Parser) get_type() string {
|
||||
p.error('unknown type `$typ`')
|
||||
}
|
||||
}
|
||||
else if !t.is_public && t.mod != p.mod && t.name != '' {
|
||||
else if !t.is_public && t.mod != p.mod && t.name != '' && !p.first_pass() {
|
||||
p.error('type `$t.name` is private')
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ fn (p mut Parser) struct_decl() {
|
||||
typ.is_placeholder = false
|
||||
typ.cat = cat
|
||||
typ.parent = objc_parent
|
||||
typ.is_public = is_pub
|
||||
p.table.rewrite_type(typ)
|
||||
}
|
||||
else {
|
||||
|
@ -11,9 +11,9 @@ const (
|
||||
max_redirects = 4
|
||||
)
|
||||
|
||||
struct Request {
|
||||
pub struct Request {
|
||||
pub:
|
||||
headers map[string]string
|
||||
headers map[string]string
|
||||
method string
|
||||
// cookies map[string]string
|
||||
h string
|
||||
@ -27,10 +27,10 @@ pub:
|
||||
user_agent string
|
||||
}
|
||||
|
||||
struct Response {
|
||||
pub struct Response {
|
||||
pub:
|
||||
text string
|
||||
headers map[string]string
|
||||
headers map[string]string
|
||||
status_code int
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ pub fn post(url, data string) ?Response {
|
||||
|
||||
pub fn new_request(typ, _url, _data string) ?Request {
|
||||
if _url == '' {
|
||||
return error('bad url')
|
||||
return error('bad url')
|
||||
}
|
||||
mut url := _url
|
||||
mut data := _data
|
||||
@ -77,9 +77,9 @@ pub fn new_request(typ, _url, _data string) ?Request {
|
||||
}
|
||||
|
||||
pub fn get_text(url string) string {
|
||||
resp := get(url) or { return '' }
|
||||
return resp.text
|
||||
}
|
||||
resp := get(url) or { return '' }
|
||||
return resp.text
|
||||
}
|
||||
|
||||
fn (req mut Request) free() {
|
||||
req.headers.free()
|
||||
@ -172,29 +172,29 @@ fn (req &Request) method_and_url_to_response(method string, url net_dot_urllib.U
|
||||
|
||||
fn parse_response(resp string) Response {
|
||||
mut headers := map[string]string
|
||||
first_header := resp.all_before('\n')
|
||||
mut status_code := 0
|
||||
first_header := resp.all_before('\n')
|
||||
mut status_code := 0
|
||||
if first_header.contains('HTTP/') {
|
||||
val := first_header.find_between(' ', ' ')
|
||||
status_code = val.int()
|
||||
}
|
||||
mut text := ''
|
||||
// Build resp headers map and separate the body
|
||||
mut nl_pos := 3
|
||||
mut i := 1
|
||||
for {
|
||||
old_pos := nl_pos
|
||||
nl_pos = resp.index_after('\n', nl_pos+1)
|
||||
mut text := ''
|
||||
// Build resp headers map and separate the body
|
||||
mut nl_pos := 3
|
||||
mut i := 1
|
||||
for {
|
||||
old_pos := nl_pos
|
||||
nl_pos = resp.index_after('\n', nl_pos+1)
|
||||
if nl_pos == -1 {
|
||||
break
|
||||
}
|
||||
h := resp.substr(old_pos + 1, nl_pos)
|
||||
// End of headers
|
||||
break
|
||||
}
|
||||
h := resp.substr(old_pos + 1, nl_pos)
|
||||
// End of headers
|
||||
if h.len <= 1 {
|
||||
text = resp.right(nl_pos + 1)
|
||||
break
|
||||
}
|
||||
i++
|
||||
text = resp.right(nl_pos + 1)
|
||||
break
|
||||
}
|
||||
i++
|
||||
pos := h.index(':')
|
||||
if pos == -1 {
|
||||
continue
|
||||
@ -212,9 +212,9 @@ fn parse_response(resp string) Response {
|
||||
}
|
||||
|
||||
return Response {
|
||||
status_code: status_code
|
||||
status_code: status_code
|
||||
headers: headers
|
||||
text: text
|
||||
text: text
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,33 +222,33 @@ fn (req &Request) build_request_headers(method, host_name, path string) string {
|
||||
ua := req.user_agent
|
||||
mut uheaders := []string
|
||||
for key, val in req.headers {
|
||||
uheaders << '${key}: ${val}\r\n'
|
||||
uheaders << '${key}: ${val}\r\n'
|
||||
}
|
||||
if req.data.len > 0 {
|
||||
uheaders << 'Content-Length: ${req.data.len}\r\n'
|
||||
}
|
||||
return '$method $path HTTP/1.1\r\n' +
|
||||
'Host: $host_name\r\n' +
|
||||
return '$method $path HTTP/1.1\r\n' +
|
||||
'Host: $host_name\r\n' +
|
||||
'User-Agent: $ua\r\n' +
|
||||
uheaders.join('') +
|
||||
'Connection: close\r\n\r\n' +
|
||||
'Connection: close\r\n\r\n' +
|
||||
req.data
|
||||
}
|
||||
|
||||
pub fn unescape_url(s string) string {
|
||||
panic('http.unescape_url() was replaced with urllib.query_unescape()')
|
||||
panic('http.unescape_url() was replaced with urllib.query_unescape()')
|
||||
}
|
||||
|
||||
pub fn escape_url(s string) string {
|
||||
panic('http.escape_url() was replaced with urllib.query_escape()')
|
||||
panic('http.escape_url() was replaced with urllib.query_escape()')
|
||||
}
|
||||
|
||||
pub fn unescape(s string) string {
|
||||
panic('http.unescape() was replaced with http.unescape_url()')
|
||||
panic('http.unescape() was replaced with http.unescape_url()')
|
||||
}
|
||||
|
||||
pub fn escape(s string) string {
|
||||
panic('http.escape() was replaced with http.escape_url()')
|
||||
panic('http.escape() was replaced with http.escape_url()')
|
||||
}
|
||||
|
||||
type wsfn fn (s string, ptr voidptr)
|
||||
|
@ -2,7 +2,7 @@ module net
|
||||
|
||||
import os
|
||||
|
||||
struct Socket {
|
||||
pub struct Socket {
|
||||
pub:
|
||||
sockfd int
|
||||
family int
|
||||
|
111
vlib/vweb/vweb.v
111
vlib/vweb/vweb.v
@ -1,11 +1,15 @@
|
||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module vweb
|
||||
|
||||
import (
|
||||
os
|
||||
net
|
||||
http
|
||||
net.urllib
|
||||
)
|
||||
net
|
||||
http
|
||||
net.urllib
|
||||
)
|
||||
|
||||
const (
|
||||
methods_with_form = ['POST', 'PUT', 'PATCH']
|
||||
@ -27,16 +31,16 @@ const (
|
||||
}
|
||||
)
|
||||
|
||||
struct Context {
|
||||
static_files map[string]string
|
||||
static_mime_types map[string]string
|
||||
pub:
|
||||
req http.Request
|
||||
conn net.Socket
|
||||
form map[string]string
|
||||
// TODO Response
|
||||
mut:
|
||||
headers string // response headers
|
||||
pub struct Context {
|
||||
static_files map[string]string
|
||||
static_mime_types map[string]string
|
||||
pub:
|
||||
req http.Request
|
||||
conn net.Socket
|
||||
form map[string]string
|
||||
// TODO Response
|
||||
mut:
|
||||
headers string // response headers
|
||||
}
|
||||
|
||||
pub fn (ctx Context) html(html string) {
|
||||
@ -48,11 +52,11 @@ pub fn (ctx Context) text(s string) {
|
||||
}
|
||||
|
||||
pub fn (ctx Context) json(s string) {
|
||||
ctx.conn.write('HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n$ctx.headers\r\n\r\n$s')
|
||||
ctx.conn.write('HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n$ctx.headers\r\n\r\n$s')
|
||||
}
|
||||
|
||||
pub fn (ctx Context) redirect(url string) {
|
||||
ctx.conn.write('HTTP/1.1 302 Found\r\nLocation: $url\r\n\r\n$ctx.headers')
|
||||
ctx.conn.write('HTTP/1.1 302 Found\r\nLocation: $url\r\n\r\n$ctx.headers')
|
||||
}
|
||||
|
||||
pub fn (ctx Context) not_found(s string) {
|
||||
@ -84,15 +88,16 @@ fn (ctx mut Context) get_header(key string) string {
|
||||
return ctx.headers.find_between('\r\n$key: ', '\r\n')
|
||||
}
|
||||
|
||||
pub fn run<T>(port int) {
|
||||
println('Running vweb app on http://localhost:$port ...')
|
||||
l := net.listen(port) or { panic('failed to listen') }
|
||||
mut app := T{}
|
||||
app.init()
|
||||
//pub fn run<T>(port int) {
|
||||
pub fn run<T>(app T, port int) {
|
||||
println('Running vweb app on http://localhost:$port ...')
|
||||
l := net.listen(port) or { panic('failed to listen') }
|
||||
//mut app := T{}
|
||||
app.init()
|
||||
for {
|
||||
conn := l.accept() or {
|
||||
panic('accept() failed')
|
||||
}
|
||||
}
|
||||
//foobar<T>()
|
||||
// TODO move this to handle_conn<T>(conn, app)
|
||||
s := conn.read_line()
|
||||
@ -123,35 +128,35 @@ pub fn run<T>(port int) {
|
||||
ws_func: 0
|
||||
user_ptr: 0
|
||||
method: vals[0]
|
||||
url: vals[1]
|
||||
}
|
||||
url: vals[1]
|
||||
}
|
||||
$if debug {
|
||||
println('vweb action = "$action"')
|
||||
}
|
||||
//mut app := T{
|
||||
app.vweb = Context{
|
||||
req: req
|
||||
conn: conn
|
||||
req: req
|
||||
conn: conn
|
||||
form: map[string]string
|
||||
static_files: map[string]string
|
||||
static_mime_types: map[string]string
|
||||
}
|
||||
//}
|
||||
}
|
||||
//}
|
||||
if req.method in methods_with_form {
|
||||
app.vweb.parse_form(s)
|
||||
}
|
||||
app.vweb.parse_form(s)
|
||||
}
|
||||
if vals.len < 2 {
|
||||
$if debug {
|
||||
println('no vals for http')
|
||||
}
|
||||
conn.close()
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Serve a static file if it's one
|
||||
// Serve a static file if it's one
|
||||
// if app.vweb.handle_static() {
|
||||
// conn.close()
|
||||
// continue
|
||||
// continue
|
||||
// }
|
||||
|
||||
// Call the right action
|
||||
@ -163,13 +168,13 @@ pub fn run<T>(port int) {
|
||||
}
|
||||
|
||||
|
||||
pub fn foobar<T>() {
|
||||
}
|
||||
pub fn foobar<T>() {
|
||||
}
|
||||
|
||||
fn (ctx mut Context) parse_form(s string) {
|
||||
fn (ctx mut Context) parse_form(s string) {
|
||||
if !(ctx.req.method in methods_with_form) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
pos := s.index('\r\n\r\n')
|
||||
if pos > -1 {
|
||||
mut str_form := s.substr(pos, s.len)
|
||||
@ -177,18 +182,18 @@ fn (ctx mut Context) parse_form(s string) {
|
||||
words := str_form.split('&')
|
||||
for word in words {
|
||||
$if debug {
|
||||
println('parse form keyval="$word"')
|
||||
println('parse form keyval="$word"')
|
||||
}
|
||||
keyval := word.trim_space().split('=')
|
||||
if keyval.len != 2 { continue }
|
||||
keyval := word.trim_space().split('=')
|
||||
if keyval.len != 2 { continue }
|
||||
key := keyval[0]
|
||||
val := urllib.query_unescape(keyval[1]) or {
|
||||
continue
|
||||
continue
|
||||
}
|
||||
$if debug {
|
||||
println('http form "$key" => "$val"')
|
||||
$if debug {
|
||||
println('http form "$key" => "$val"')
|
||||
}
|
||||
ctx.form[key] = val
|
||||
ctx.form[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,15 +232,15 @@ pub fn (ctx mut Context) handle_static(directory_path string) bool {
|
||||
static_file := ctx.static_files[ctx.req.url]
|
||||
mime_type := ctx.static_mime_types[ctx.req.url]
|
||||
|
||||
if static_file != '' {
|
||||
data := os.read_file(static_file) or { return false }
|
||||
if static_file != '' {
|
||||
data := os.read_file(static_file) or { return false }
|
||||
ctx.conn.write('HTTP/1.1 200 OK\r\nContent-Type: $mime_type\r\n\r\n$data')
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn (ctx mut Context) serve_static(url, file_path, mime_type string) {
|
||||
ctx.static_files[url] = file_path
|
||||
ctx.static_files[url] = file_path
|
||||
ctx.static_mime_types[url] = mime_type
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user