mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: change optional to result of io (#16075)
This commit is contained in:
parent
6e46933c55
commit
f6844e9766
@ -43,7 +43,7 @@ fn main() {
|
|||||||
vexe := pref.vexe_path()
|
vexe := pref.vexe_path()
|
||||||
vroot := os.dir(vexe)
|
vroot := os.dir(vexe)
|
||||||
util.set_vroot_folder(vroot)
|
util.set_vroot_folder(vroot)
|
||||||
os.chdir(vroot)?
|
os.chdir(vroot)!
|
||||||
cmd := diff.find_working_diff_command() or { '' }
|
cmd := diff.find_working_diff_command() or { '' }
|
||||||
mut app := App{
|
mut app := App{
|
||||||
diff_cmd: cmd
|
diff_cmd: cmd
|
||||||
|
@ -15,7 +15,7 @@ const vdir = @VEXEROOT
|
|||||||
fn main() {
|
fn main() {
|
||||||
dump(fast_dir)
|
dump(fast_dir)
|
||||||
dump(vdir)
|
dump(vdir)
|
||||||
os.chdir(fast_dir)?
|
os.chdir(fast_dir)!
|
||||||
if !os.exists('$vdir/v') && !os.is_dir('$vdir/vlib') {
|
if !os.exists('$vdir/v') && !os.is_dir('$vdir/vlib') {
|
||||||
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
|
println('fast.html generator needs to be located in `v/cmd/tools/fast`')
|
||||||
}
|
}
|
||||||
@ -32,11 +32,11 @@ fn main() {
|
|||||||
// fetch the last commit's hash
|
// fetch the last commit's hash
|
||||||
commit := exec('git rev-parse HEAD')[..8]
|
commit := exec('git rev-parse HEAD')[..8]
|
||||||
if !os.exists('table.html') {
|
if !os.exists('table.html') {
|
||||||
os.create('table.html')?
|
os.create('table.html')!
|
||||||
}
|
}
|
||||||
mut table := os.read_file('table.html')?
|
mut table := os.read_file('table.html')!
|
||||||
if os.exists('website/index.html') {
|
if os.exists('website/index.html') {
|
||||||
uploaded_index := os.read_file('website/index.html')?
|
uploaded_index := os.read_file('website/index.html')!
|
||||||
if uploaded_index.contains('>$commit<') {
|
if uploaded_index.contains('>$commit<') {
|
||||||
println('nothing to benchmark')
|
println('nothing to benchmark')
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -48,7 +48,7 @@ fn main() {
|
|||||||
|
|
||||||
// build an optimized V
|
// build an optimized V
|
||||||
println(' Building vprod...')
|
println(' Building vprod...')
|
||||||
os.chdir(vdir)?
|
os.chdir(vdir)!
|
||||||
if os.args.contains('-noprod') {
|
if os.args.contains('-noprod') {
|
||||||
exec('./v -o vprod cmd/v') // for faster debugging
|
exec('./v -o vprod cmd/v') // for faster debugging
|
||||||
} else {
|
} else {
|
||||||
@ -82,8 +82,8 @@ fn main() {
|
|||||||
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
|
commit_date := exec('git log -n1 --pretty="format:%at" $commit')
|
||||||
date := time.unix(commit_date.int())
|
date := time.unix(commit_date.int())
|
||||||
|
|
||||||
os.chdir(fast_dir)?
|
os.chdir(fast_dir)!
|
||||||
mut out := os.create('table.html')?
|
mut out := os.create('table.html')!
|
||||||
|
|
||||||
// place the new row on top
|
// place the new row on top
|
||||||
html_message := message.replace_each(['<', '<', '>', '>'])
|
html_message := message.replace_each(['<', '<', '>', '>'])
|
||||||
@ -105,25 +105,25 @@ fn main() {
|
|||||||
<td>${int(f64(vlines) / f64(diff1) * 1000.0)}</td>
|
<td>${int(f64(vlines) / f64(diff1) * 1000.0)}</td>
|
||||||
</tr>\n' +
|
</tr>\n' +
|
||||||
table.trim_space()
|
table.trim_space()
|
||||||
out.writeln(table)?
|
out.writeln(table)!
|
||||||
out.close()
|
out.close()
|
||||||
|
|
||||||
// regenerate index.html
|
// regenerate index.html
|
||||||
header := os.read_file('header.html')?
|
header := os.read_file('header.html')!
|
||||||
footer := os.read_file('footer.html')?
|
footer := os.read_file('footer.html')!
|
||||||
mut res := os.create('index.html')?
|
mut res := os.create('index.html')!
|
||||||
res.writeln(header)?
|
res.writeln(header)!
|
||||||
res.writeln(table)?
|
res.writeln(table)!
|
||||||
res.writeln(footer)?
|
res.writeln(footer)!
|
||||||
res.close()
|
res.close()
|
||||||
|
|
||||||
// upload the result to github pages
|
// upload the result to github pages
|
||||||
if os.args.contains('-upload') {
|
if os.args.contains('-upload') {
|
||||||
println('uploading...')
|
println('uploading...')
|
||||||
os.chdir('website')?
|
os.chdir('website')!
|
||||||
os.execute_or_exit('git checkout gh-pages')
|
os.execute_or_exit('git checkout gh-pages')
|
||||||
os.cp('../index.html', 'index.html')?
|
os.cp('../index.html', 'index.html')!
|
||||||
os.rm('../index.html')?
|
os.rm('../index.html')!
|
||||||
os.system('git commit -am "update benchmark"')
|
os.system('git commit -am "update benchmark"')
|
||||||
os.system('git push origin gh-pages')
|
os.system('git push origin gh-pages')
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,14 @@ fn main() {
|
|||||||
files := os.args#[1..]
|
files := os.args#[1..]
|
||||||
if files.len > 0 && files[0].starts_with('@') {
|
if files.len > 0 && files[0].starts_with('@') {
|
||||||
lst_path := files[0].all_after('@')
|
lst_path := files[0].all_after('@')
|
||||||
listed_files := os.read_file(lst_path)?.split('\n')
|
listed_files := os.read_file(lst_path)!.split('\n')
|
||||||
process_files(listed_files)?
|
process_files(listed_files)!
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
process_files(files)?
|
process_files(files)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_files(files []string) ? {
|
fn process_files(files []string) ! {
|
||||||
mut pref := pref.new_preferences()
|
mut pref := pref.new_preferences()
|
||||||
pref.is_fmt = true
|
pref.is_fmt = true
|
||||||
pref.skip_warnings = true
|
pref.skip_warnings = true
|
||||||
@ -31,7 +31,7 @@ fn process_files(files []string) ? {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sw.restart()
|
sw.restart()
|
||||||
s := scanner.new_scanner_file(f, .skip_comments, pref)?
|
s := scanner.new_scanner_file(f, .skip_comments, pref)!
|
||||||
f_us := sw.elapsed().microseconds()
|
f_us := sw.elapsed().microseconds()
|
||||||
total_us += f_us
|
total_us += f_us
|
||||||
total_bytes += s.text.len
|
total_bytes += s.text.len
|
||||||
|
@ -125,7 +125,7 @@ fn main() {
|
|||||||
should_sync := fp.bool('cache-sync', `s`, false, 'Update the local cache')
|
should_sync := fp.bool('cache-sync', `s`, false, 'Update the local cache')
|
||||||
context.is_bisect = fp.bool('bisect', `b`, false, 'Bisect mode. Use the current commit in the repo where oldv is.')
|
context.is_bisect = fp.bool('bisect', `b`, false, 'Bisect mode. Use the current commit in the repo where oldv is.')
|
||||||
if !should_sync && !context.is_bisect {
|
if !should_sync && !context.is_bisect {
|
||||||
fp.limit_free_args(1, 1)?
|
fp.limit_free_args(1, 1)!
|
||||||
}
|
}
|
||||||
////
|
////
|
||||||
context.cleanup = fp.bool('clean', 0, false, 'Clean before running (slower).')
|
context.cleanup = fp.bool('clean', 0, false, 'Clean before running (slower).')
|
||||||
|
@ -194,7 +194,7 @@ fn main() {
|
|||||||
fp.description(tool_description)
|
fp.description(tool_description)
|
||||||
fp.arguments_description('COMMIT_BEFORE [COMMIT_AFTER]')
|
fp.arguments_description('COMMIT_BEFORE [COMMIT_AFTER]')
|
||||||
fp.skip_executable()
|
fp.skip_executable()
|
||||||
fp.limit_free_args(1, 2)?
|
fp.limit_free_args(1, 2)!
|
||||||
context.vflags = fp.string('vflags', 0, '', 'Additional options to pass to the v commands, for example "-cc tcc"')
|
context.vflags = fp.string('vflags', 0, '', 'Additional options to pass to the v commands, for example "-cc tcc"')
|
||||||
context.hyperfineopts = fp.string('hyperfine_options', 0, '', 'Additional options passed to hyperfine.
|
context.hyperfineopts = fp.string('hyperfine_options', 0, '', 'Additional options passed to hyperfine.
|
||||||
${flag.space}For example on linux, you may want to pass:
|
${flag.space}For example on linux, you may want to pass:
|
||||||
|
@ -143,19 +143,19 @@ const (
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
mut context := Context{}
|
mut context := Context{}
|
||||||
context.parse_options()?
|
context.parse_options()!
|
||||||
context.run()
|
context.run()
|
||||||
context.show_diff_summary()
|
context.show_diff_summary()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut context Context) parse_options() ? {
|
fn (mut context Context) parse_options() ! {
|
||||||
mut fp := flag.new_flag_parser(os.args)
|
mut fp := flag.new_flag_parser(os.args)
|
||||||
fp.application(os.file_name(os.executable()))
|
fp.application(os.file_name(os.executable()))
|
||||||
fp.version('0.0.1')
|
fp.version('0.0.1')
|
||||||
fp.description('Repeat command(s) and collect statistics. Note: you have to quote each command, if it contains spaces.')
|
fp.description('Repeat command(s) and collect statistics. Note: you have to quote each command, if it contains spaces.')
|
||||||
fp.arguments_description('CMD1 CMD2 ...')
|
fp.arguments_description('CMD1 CMD2 ...')
|
||||||
fp.skip_executable()
|
fp.skip_executable()
|
||||||
fp.limit_free_args_to_at_least(1)?
|
fp.limit_free_args_to_at_least(1)!
|
||||||
context.count = fp.int('count', `c`, 10, 'Repetition count.')
|
context.count = fp.int('count', `c`, 10, 'Repetition count.')
|
||||||
context.series = fp.int('series', `s`, 2, 'Series count. `-s 2 -c 4 a b` => aaaabbbbaaaabbbb, while `-s 3 -c 2 a b` => aabbaabbaabb.')
|
context.series = fp.int('series', `s`, 2, 'Series count. `-s 2 -c 4 a b` => aaaabbbbaaaabbbb, while `-s 3 -c 2 a b` => aabbaabbaabb.')
|
||||||
context.warmup = fp.int('warmup', `w`, 2, 'Warmup runs. These are done *only at the start*, and are ignored.')
|
context.warmup = fp.int('warmup', `w`, 2, 'Warmup runs. These are done *only at the start*, and are ignored.')
|
||||||
|
@ -60,16 +60,16 @@ fn (result MyResult) matches(gpattern string) MyResult {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_test(tname string, tcontent string) ?string {
|
fn create_test(tname string, tcontent string) !string {
|
||||||
tpath := os.join_path(tdir, tname)
|
tpath := os.join_path(tdir, tname)
|
||||||
os.write_file(tpath, tcontent)?
|
os.write_file(tpath, tcontent)!
|
||||||
eprintln('>>>>>>>> tpath: $tpath | tcontent: $tcontent')
|
eprintln('>>>>>>>> tpath: $tpath | tcontent: $tcontent')
|
||||||
return os.quoted_path(tpath)
|
return os.quoted_path(tpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_assert_continues_works() ? {
|
fn check_assert_continues_works() ! {
|
||||||
os.chdir(tdir)?
|
os.chdir(tdir)!
|
||||||
create_test('assert_continues_option_works_test.v', 'fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false }')?
|
create_test('assert_continues_option_works_test.v', 'fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false }')!
|
||||||
result := check_fail('$vexe -assert continues assert_continues_option_works_test.v')
|
result := check_fail('$vexe -assert continues assert_continues_option_works_test.v')
|
||||||
result.has('assert_continues_option_works_test.v:1: fn test_fail1')
|
result.has('assert_continues_option_works_test.v:1: fn test_fail1')
|
||||||
result.has('assert_continues_option_works_test.v:2: fn test_fail1')
|
result.has('assert_continues_option_works_test.v:2: fn test_fail1')
|
||||||
@ -77,7 +77,7 @@ fn check_assert_continues_works() ? {
|
|||||||
result.has('assert_continues_option_works_test.v:5: fn test_fail2')
|
result.has('assert_continues_option_works_test.v:5: fn test_fail2')
|
||||||
result.has('> assert 2 == 4').has('> assert 2 == 1').has('> assert 2 == 0')
|
result.has('> assert 2 == 4').has('> assert 2 == 1').has('> assert 2 == 0')
|
||||||
// Check if a test function, tagged with [assert_continues], has the same behaviour, without needing additional options
|
// Check if a test function, tagged with [assert_continues], has the same behaviour, without needing additional options
|
||||||
create_test('assert_continues_tag_works_test.v', '[assert_continues]fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false\n assert false }')?
|
create_test('assert_continues_tag_works_test.v', '[assert_continues]fn test_fail1() { assert 2==4\nassert 2==1\nassert 2==0 }\nfn test_ok(){ assert true }\nfn test_fail2() { assert false\n assert false }')!
|
||||||
tag_res := check_fail('$vexe assert_continues_tag_works_test.v')
|
tag_res := check_fail('$vexe assert_continues_tag_works_test.v')
|
||||||
tag_res.has('assert_continues_tag_works_test.v:1: fn test_fail1')
|
tag_res.has('assert_continues_tag_works_test.v:1: fn test_fail1')
|
||||||
tag_res.has('assert_continues_tag_works_test.v:2: fn test_fail1')
|
tag_res.has('assert_continues_tag_works_test.v:2: fn test_fail1')
|
||||||
@ -113,23 +113,23 @@ fn main() {
|
|||||||
os.chdir(os.wd_at_startup) or {}
|
os.chdir(os.wd_at_startup) or {}
|
||||||
}
|
}
|
||||||
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
|
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
|
||||||
ok_fpath := create_test('a_single_ok_test.v', 'fn test_ok(){ assert true }')?
|
ok_fpath := create_test('a_single_ok_test.v', 'fn test_ok(){ assert true }')!
|
||||||
if check_ok('$vexe $ok_fpath') != '' {
|
if check_ok('$vexe $ok_fpath') != '' {
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
check_ok('$vexe test $ok_fpath').matches('*OK*a_single_ok_test.v*')
|
check_ok('$vexe test $ok_fpath').matches('*OK*a_single_ok_test.v*')
|
||||||
check_ok('$vexe test "$tdir"').matches('*OK*a_single_ok_test.v*')
|
check_ok('$vexe test "$tdir"').matches('*OK*a_single_ok_test.v*')
|
||||||
//
|
//
|
||||||
fail_fpath := create_test('a_single_failing_test.v', 'fn test_fail(){ assert 1 == 2 }')?
|
fail_fpath := create_test('a_single_failing_test.v', 'fn test_fail(){ assert 1 == 2 }')!
|
||||||
check_fail('$vexe $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail')
|
check_fail('$vexe $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail')
|
||||||
check_fail('$vexe test $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail')
|
check_fail('$vexe test $fail_fpath').has('> assert 1 == 2').has('a_single_failing_test.v:1: fn test_fail')
|
||||||
check_fail('$vexe test "$tdir"').has('> assert 1 == 2')
|
check_fail('$vexe test "$tdir"').has('> assert 1 == 2')
|
||||||
rel_dir := os.join_path(tdir, rand.ulid())
|
rel_dir := os.join_path(tdir, rand.ulid())
|
||||||
os.mkdir(rel_dir)?
|
os.mkdir(rel_dir)!
|
||||||
os.chdir(rel_dir)?
|
os.chdir(rel_dir)!
|
||||||
relative_path := '..' + os.path_separator + 'a_single_ok_test.v'
|
relative_path := '..' + os.path_separator + 'a_single_ok_test.v'
|
||||||
check_ok('$vexe test ${os.quoted_path(relative_path)}').has('OK').has('a_single_ok_test.v')
|
check_ok('$vexe test ${os.quoted_path(relative_path)}').has('OK').has('a_single_ok_test.v')
|
||||||
//
|
//
|
||||||
check_assert_continues_works()?
|
check_assert_continues_works()!
|
||||||
println('> all done')
|
println('> all done')
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@ fn main() {
|
|||||||
}
|
}
|
||||||
// Git clone c2v
|
// Git clone c2v
|
||||||
if !os.exists(c2v_dir) {
|
if !os.exists(c2v_dir) {
|
||||||
os.mkdir_all(vmodules)?
|
os.mkdir_all(vmodules)!
|
||||||
println('C2V is not installed. Cloning C2V to $c2v_dir ...')
|
println('C2V is not installed. Cloning C2V to $c2v_dir ...')
|
||||||
os.chdir(vmodules)?
|
os.chdir(vmodules)!
|
||||||
res := os.execute('git clone https://github.com/vlang/c2v')
|
res := os.execute('git clone https://github.com/vlang/c2v')
|
||||||
if res.exit_code != 0 {
|
if res.exit_code != 0 {
|
||||||
eprintln('Failed to download C2V.')
|
eprintln('Failed to download C2V.')
|
||||||
@ -27,7 +27,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
// Compile c2v
|
// Compile c2v
|
||||||
if !os.exists(c2v_bin) {
|
if !os.exists(c2v_bin) {
|
||||||
os.chdir(c2v_dir)?
|
os.chdir(c2v_dir)!
|
||||||
println('Compiling c2v ...')
|
println('Compiling c2v ...')
|
||||||
res2 := os.execute('${os.quoted_path(vexe)} -o ${os.quoted_path(c2v_bin)} -keepc -g -experimental .')
|
res2 := os.execute('${os.quoted_path(vexe)} -o ${os.quoted_path(c2v_bin)} -keepc -g -experimental .')
|
||||||
if res2.exit_code != 0 {
|
if res2.exit_code != 0 {
|
||||||
@ -42,7 +42,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
passed_args := util.args_quote_paths(os.args[2..])
|
passed_args := util.args_quote_paths(os.args[2..])
|
||||||
// println(passed_args)
|
// println(passed_args)
|
||||||
os.chdir(os.wd_at_startup)?
|
os.chdir(os.wd_at_startup)!
|
||||||
c2v_cmd := '${os.quoted_path(c2v_bin)} $passed_args'
|
c2v_cmd := '${os.quoted_path(c2v_bin)} $passed_args'
|
||||||
res := os.system(c2v_cmd)
|
res := os.system(c2v_cmd)
|
||||||
if res != 0 {
|
if res != 0 {
|
||||||
|
@ -44,7 +44,7 @@ fn main() {
|
|||||||
for hf in hfields.split(',') {
|
for hf in hfields.split(',') {
|
||||||
ctx.hide_names[hf] = true
|
ctx.hide_names[hf] = true
|
||||||
}
|
}
|
||||||
fp.limit_free_args_to_at_least(1)?
|
fp.limit_free_args_to_at_least(1)!
|
||||||
rest_of_args := fp.remaining_parameters()
|
rest_of_args := fp.remaining_parameters()
|
||||||
for vfile in rest_of_args {
|
for vfile in rest_of_args {
|
||||||
file := get_abs_path(vfile)
|
file := get_abs_path(vfile)
|
||||||
|
@ -73,7 +73,7 @@ fn (context Context) file2v(bname string, fbytes []u8, bn_max int) string {
|
|||||||
return sb.str()
|
return sb.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (context Context) bname_and_bytes(file string) ?(string, []u8) {
|
fn (context Context) bname_and_bytes(file string) !(string, []u8) {
|
||||||
fname := os.file_name(file)
|
fname := os.file_name(file)
|
||||||
fname_escaped := fname.replace_each(['.', '_', '-', '_'])
|
fname_escaped := fname.replace_each(['.', '_', '-', '_'])
|
||||||
byte_name := '$context.prefix$fname_escaped'.to_lower()
|
byte_name := '$context.prefix$fname_escaped'.to_lower()
|
||||||
@ -130,12 +130,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
max_bname := context.max_bname_len(file_byte_map.keys())
|
max_bname := context.max_bname_len(file_byte_map.keys())
|
||||||
if context.write_file.len > 0 {
|
if context.write_file.len > 0 {
|
||||||
mut out_file := os.create(context.write_file)?
|
mut out_file := os.create(context.write_file)!
|
||||||
out_file.write_string(context.header())?
|
out_file.write_string(context.header())!
|
||||||
for bname, fbytes in file_byte_map {
|
for bname, fbytes in file_byte_map {
|
||||||
out_file.write_string(context.file2v(bname, fbytes, max_bname))?
|
out_file.write_string(context.file2v(bname, fbytes, max_bname))!
|
||||||
}
|
}
|
||||||
out_file.write_string(context.footer())?
|
out_file.write_string(context.footer())!
|
||||||
} else {
|
} else {
|
||||||
print(context.header())
|
print(context.header())
|
||||||
for bname, fbytes in file_byte_map {
|
for bname, fbytes in file_byte_map {
|
||||||
|
@ -23,7 +23,7 @@ fn main() {
|
|||||||
args_string := os.args[1..].join(' ')
|
args_string := os.args[1..].join(' ')
|
||||||
vexe := os.getenv('VEXE')
|
vexe := os.getenv('VEXE')
|
||||||
vroot := os.dir(vexe)
|
vroot := os.dir(vexe)
|
||||||
os.chdir(vroot)?
|
os.chdir(vroot)!
|
||||||
folder := os.join_path('cmd', 'tools')
|
folder := os.join_path('cmd', 'tools')
|
||||||
tfolder := os.join_path(vroot, 'cmd', 'tools')
|
tfolder := os.join_path(vroot, 'cmd', 'tools')
|
||||||
main_label := 'Building $folder ...'
|
main_label := 'Building $folder ...'
|
||||||
@ -47,7 +47,7 @@ fn main() {
|
|||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
mut executables := os.ls(session.vtmp_dir)?
|
mut executables := os.ls(session.vtmp_dir)!
|
||||||
executables.sort()
|
executables.sort()
|
||||||
for texe in executables {
|
for texe in executables {
|
||||||
tname := texe.replace(os.file_ext(texe), '')
|
tname := texe.replace(os.file_ext(texe), '')
|
||||||
|
@ -73,25 +73,25 @@ fn main() {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
fn run_individual_test(case BumpTestCase) ? {
|
fn run_individual_test(case BumpTestCase) ! {
|
||||||
test_file := os.join_path_single(tfolder, case.file_name)
|
test_file := os.join_path_single(tfolder, case.file_name)
|
||||||
|
|
||||||
os.rm(test_file) or {}
|
os.rm(test_file) or {}
|
||||||
os.write_file(test_file, case.contents)?
|
os.write_file(test_file, case.contents)!
|
||||||
//
|
//
|
||||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --patch ${os.quoted_path(test_file)}')
|
os.execute_or_exit('${os.quoted_path(vexe)} bump --patch ${os.quoted_path(test_file)}')
|
||||||
patch_lines := os.read_lines(test_file)?
|
patch_lines := os.read_lines(test_file)!
|
||||||
assert patch_lines[case.line] == case.expected_patch
|
assert patch_lines[case.line] == case.expected_patch
|
||||||
|
|
||||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --minor ${os.quoted_path(test_file)}')
|
os.execute_or_exit('${os.quoted_path(vexe)} bump --minor ${os.quoted_path(test_file)}')
|
||||||
minor_lines := os.read_lines(test_file)?
|
minor_lines := os.read_lines(test_file)!
|
||||||
assert minor_lines[case.line] == case.expected_minor
|
assert minor_lines[case.line] == case.expected_minor
|
||||||
|
|
||||||
os.execute_or_exit('${os.quoted_path(vexe)} bump --major ${os.quoted_path(test_file)}')
|
os.execute_or_exit('${os.quoted_path(vexe)} bump --major ${os.quoted_path(test_file)}')
|
||||||
major_lines := os.read_lines(test_file)?
|
major_lines := os.read_lines(test_file)!
|
||||||
assert major_lines[case.line] == case.expected_major
|
assert major_lines[case.line] == case.expected_major
|
||||||
//
|
//
|
||||||
os.rm(test_file)?
|
os.rm(test_file)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_all_bump_cases() {
|
fn test_all_bump_cases() {
|
||||||
|
@ -2,10 +2,10 @@ import os
|
|||||||
|
|
||||||
const test_path = os.join_path(os.temp_dir(), 'v', 'vcreate_test')
|
const test_path = os.join_path(os.temp_dir(), 'v', 'vcreate_test')
|
||||||
|
|
||||||
fn init_and_check() ? {
|
fn init_and_check() ! {
|
||||||
os.execute_or_exit('${os.quoted_path(@VEXE)} init')
|
os.execute_or_exit('${os.quoted_path(@VEXE)} init')
|
||||||
|
|
||||||
assert os.read_file('vcreate_test.v')? == [
|
assert os.read_file('vcreate_test.v')! == [
|
||||||
'module main\n',
|
'module main\n',
|
||||||
'fn main() {',
|
'fn main() {',
|
||||||
" println('Hello World!')",
|
" println('Hello World!')",
|
||||||
@ -13,7 +13,7 @@ fn init_and_check() ? {
|
|||||||
'',
|
'',
|
||||||
].join_lines()
|
].join_lines()
|
||||||
|
|
||||||
assert os.read_file('v.mod')? == [
|
assert os.read_file('v.mod')! == [
|
||||||
'Module {',
|
'Module {',
|
||||||
" name: 'vcreate_test'",
|
" name: 'vcreate_test'",
|
||||||
" description: ''",
|
" description: ''",
|
||||||
@ -24,7 +24,7 @@ fn init_and_check() ? {
|
|||||||
'',
|
'',
|
||||||
].join_lines()
|
].join_lines()
|
||||||
|
|
||||||
assert os.read_file('.gitignore')? == [
|
assert os.read_file('.gitignore')! == [
|
||||||
'# Binaries for programs and plugins',
|
'# Binaries for programs and plugins',
|
||||||
'main',
|
'main',
|
||||||
'vcreate_test',
|
'vcreate_test',
|
||||||
@ -37,7 +37,7 @@ fn init_and_check() ? {
|
|||||||
'',
|
'',
|
||||||
].join_lines()
|
].join_lines()
|
||||||
|
|
||||||
assert os.read_file('.gitattributes')? == [
|
assert os.read_file('.gitattributes')! == [
|
||||||
'*.v linguist-language=V text=auto eol=lf',
|
'*.v linguist-language=V text=auto eol=lf',
|
||||||
'*.vv linguist-language=V text=auto eol=lf',
|
'*.vv linguist-language=V text=auto eol=lf',
|
||||||
'*.vsh linguist-language=V text=auto eol=lf',
|
'*.vsh linguist-language=V text=auto eol=lf',
|
||||||
@ -45,7 +45,7 @@ fn init_and_check() ? {
|
|||||||
'',
|
'',
|
||||||
].join_lines()
|
].join_lines()
|
||||||
|
|
||||||
assert os.read_file('.editorconfig')? == [
|
assert os.read_file('.editorconfig')! == [
|
||||||
'[*]',
|
'[*]',
|
||||||
'charset = utf-8',
|
'charset = utf-8',
|
||||||
'end_of_line = lf',
|
'end_of_line = lf',
|
||||||
@ -59,28 +59,28 @@ fn init_and_check() ? {
|
|||||||
].join_lines()
|
].join_lines()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_test_path() ? {
|
fn prepare_test_path() ! {
|
||||||
os.rmdir_all(test_path) or {}
|
os.rmdir_all(test_path) or {}
|
||||||
os.mkdir_all(test_path) or {}
|
os.mkdir_all(test_path) or {}
|
||||||
os.chdir(test_path)?
|
os.chdir(test_path)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_v_init() {
|
fn test_v_init() {
|
||||||
prepare_test_path()?
|
prepare_test_path()!
|
||||||
init_and_check()?
|
init_and_check()!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_v_init_in_git_dir() {
|
fn test_v_init_in_git_dir() {
|
||||||
prepare_test_path()?
|
prepare_test_path()!
|
||||||
os.execute_or_exit('git init .')
|
os.execute_or_exit('git init .')
|
||||||
init_and_check()?
|
init_and_check()!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_v_init_no_overwrite_gitignore() {
|
fn test_v_init_no_overwrite_gitignore() {
|
||||||
prepare_test_path()?
|
prepare_test_path()!
|
||||||
os.write_file('.gitignore', 'blah')?
|
os.write_file('.gitignore', 'blah')!
|
||||||
os.execute_or_exit('${os.quoted_path(@VEXE)} init')
|
os.execute_or_exit('${os.quoted_path(@VEXE)} init')
|
||||||
assert os.read_file('.gitignore')? == 'blah'
|
assert os.read_file('.gitignore')! == 'blah'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_v_init_no_overwrite_gitattributes_and_editorconfig() {
|
fn test_v_init_no_overwrite_gitattributes_and_editorconfig() {
|
||||||
@ -95,13 +95,13 @@ trim_trailing_whitespace = true
|
|||||||
indent_style = tab
|
indent_style = tab
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
'
|
'
|
||||||
prepare_test_path()?
|
prepare_test_path()!
|
||||||
os.write_file('.gitattributes', git_attributes_content)?
|
os.write_file('.gitattributes', git_attributes_content)!
|
||||||
os.write_file('.editorconfig', editor_config_content)?
|
os.write_file('.editorconfig', editor_config_content)!
|
||||||
os.execute_or_exit('${os.quoted_path(@VEXE)} init')
|
os.execute_or_exit('${os.quoted_path(@VEXE)} init')
|
||||||
|
|
||||||
assert os.read_file('.gitattributes')? == git_attributes_content
|
assert os.read_file('.gitattributes')! == git_attributes_content
|
||||||
assert os.read_file('.editorconfig')? == editor_config_content
|
assert os.read_file('.editorconfig')! == editor_config_content
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testsuite_end() {
|
fn testsuite_end() {
|
||||||
|
@ -166,7 +166,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
|
toml_conf := fp.string('toml-config', `t`, default_toml, 'Path or string with TOML configuration')
|
||||||
arg_paths := fp.finalize()?
|
arg_paths := fp.finalize()!
|
||||||
if show_help {
|
if show_help {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
exit(0)
|
exit(0)
|
||||||
@ -179,7 +179,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !os.exists(tmp_dir) {
|
if !os.exists(tmp_dir) {
|
||||||
os.mkdir_all(tmp_dir)?
|
os.mkdir_all(tmp_dir)!
|
||||||
}
|
}
|
||||||
|
|
||||||
opt.config = new_config(opt.root_path, toml_conf) or { panic(err) }
|
opt.config = new_config(opt.root_path, toml_conf) or { panic(err) }
|
||||||
@ -202,7 +202,7 @@ fn main() {
|
|||||||
eprintln('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
|
eprintln('Compare paths can not be the same directory `$path`/`$target_path`/`$gen_in_path`')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
compare_screenshots(opt, gen_in_path, target_path)?
|
compare_screenshots(opt, gen_in_path, target_path)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +254,7 @@ fn generate_screenshots(mut opt Options, output_path string) ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
fn compare_screenshots(opt Options, output_path string, target_path string) ! {
|
||||||
mut fails := map[string]string{}
|
mut fails := map[string]string{}
|
||||||
mut warns := map[string]string{}
|
mut warns := map[string]string{}
|
||||||
for app_config in opt.config.apps {
|
for app_config in opt.config.apps {
|
||||||
@ -306,14 +306,14 @@ fn compare_screenshots(opt Options, output_path string, target_path string) ? {
|
|||||||
}
|
}
|
||||||
first := fails.keys()[0]
|
first := fails.keys()[0]
|
||||||
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
|
fail_copy := os.join_path(os.temp_dir(), 'fail.' + first.all_after_last('.'))
|
||||||
os.cp(first, fail_copy)?
|
os.cp(first, fail_copy)!
|
||||||
eprintln('First failed file `$first` is copied to `$fail_copy`')
|
eprintln('First failed file `$first` is copied to `$fail_copy`')
|
||||||
|
|
||||||
diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
|
diff_file := os.join_path(os.temp_dir(), os.file_name(first).all_before_last('.') +
|
||||||
'.diff.tif')
|
'.diff.tif')
|
||||||
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
|
diff_copy := os.join_path(os.temp_dir(), 'diff.tif')
|
||||||
if os.is_file(diff_file) {
|
if os.is_file(diff_file) {
|
||||||
os.cp(diff_file, diff_copy)?
|
os.cp(diff_file, diff_copy)!
|
||||||
eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`')
|
eprintln('First failed diff file `$diff_file` is copied to `$diff_copy`')
|
||||||
eprintln('Removing alpha channel from $diff_copy ...')
|
eprintln('Removing alpha channel from $diff_copy ...')
|
||||||
final_fail_result_file := os.join_path(os.temp_dir(), 'diff.png')
|
final_fail_result_file := os.join_path(os.temp_dir(), 'diff.png')
|
||||||
|
@ -67,16 +67,16 @@ const json_enc = json2.Encoder{
|
|||||||
escape_unicode: false
|
escape_unicode: false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) check_or_create_vls_folder() ? {
|
fn (upd VlsUpdater) check_or_create_vls_folder() ! {
|
||||||
if !os.exists(vls_folder) {
|
if !os.exists(vls_folder) {
|
||||||
upd.log('Creating .vls folder...')
|
upd.log('Creating .vls folder...')
|
||||||
os.mkdir(vls_folder)?
|
os.mkdir(vls_folder)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) manifest_config() ?map[string]json2.Any {
|
fn (upd VlsUpdater) manifest_config() !map[string]json2.Any {
|
||||||
manifest_buf := os.read_file(vls_manifest_path) or { '{}' }
|
manifest_buf := os.read_file(vls_manifest_path) or { '{}' }
|
||||||
manifest_contents := json2.raw_decode(manifest_buf)?.as_map()
|
manifest_contents := json2.raw_decode(manifest_buf)!.as_map()
|
||||||
return manifest_contents
|
return manifest_contents
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,9 +88,9 @@ fn (upd VlsUpdater) exec_asset_file_name() string {
|
|||||||
return 'vls_${os_name}_${arch + ext}'
|
return 'vls_${os_name}_${arch + ext}'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp time.Time) ? {
|
fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp time.Time) ! {
|
||||||
upd.log('Updating permissions...')
|
upd.log('Updating permissions...')
|
||||||
os.chmod(new_path, 755)?
|
os.chmod(new_path, 755)!
|
||||||
|
|
||||||
upd.log('Updating vls.config.json...')
|
upd.log('Updating vls.config.json...')
|
||||||
mut manifest := upd.manifest_config() or {
|
mut manifest := upd.manifest_config() or {
|
||||||
@ -103,7 +103,7 @@ fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mut manifest_file := os.open_file(vls_manifest_path, 'w+')?
|
mut manifest_file := os.open_file(vls_manifest_path, 'w+')!
|
||||||
defer {
|
defer {
|
||||||
manifest_file.close()
|
manifest_file.close()
|
||||||
}
|
}
|
||||||
@ -112,31 +112,31 @@ fn (upd VlsUpdater) update_manifest(new_path string, from_source bool, timestamp
|
|||||||
manifest['last_updated'] = json2.Any(timestamp.format_ss())
|
manifest['last_updated'] = json2.Any(timestamp.format_ss())
|
||||||
manifest['from_source'] = json2.Any(from_source)
|
manifest['from_source'] = json2.Any(from_source)
|
||||||
|
|
||||||
json_enc.encode_value(manifest, mut manifest_file)?
|
json_enc.encode_value(manifest, mut manifest_file)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) init_download_prebuilt() ? {
|
fn (upd VlsUpdater) init_download_prebuilt() ! {
|
||||||
if !os.exists(vls_cache_folder) {
|
if !os.exists(vls_cache_folder) {
|
||||||
os.mkdir(vls_cache_folder)?
|
os.mkdir(vls_cache_folder)!
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.exists(vls_bin_folder) {
|
if os.exists(vls_bin_folder) {
|
||||||
os.rmdir_all(vls_bin_folder)?
|
os.rmdir_all(vls_bin_folder)!
|
||||||
}
|
}
|
||||||
|
|
||||||
os.mkdir(vls_bin_folder)?
|
os.mkdir(vls_bin_folder)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) get_last_updated_at() ?time.Time {
|
fn (upd VlsUpdater) get_last_updated_at() !time.Time {
|
||||||
if manifest := upd.manifest_config() {
|
if manifest := upd.manifest_config() {
|
||||||
if 'last_updated' in manifest {
|
if 'last_updated' in manifest {
|
||||||
return time.parse(manifest['last_updated'] or { '' }.str()) or { return none }
|
return time.parse(manifest['last_updated'] or { '' }.str()) or { return error('none') }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) download_prebuilt() ? {
|
fn (upd VlsUpdater) download_prebuilt() ! {
|
||||||
mut has_last_updated_at := true
|
mut has_last_updated_at := true
|
||||||
last_updated_at := upd.get_last_updated_at() or {
|
last_updated_at := upd.get_last_updated_at() or {
|
||||||
has_last_updated_at = false
|
has_last_updated_at = false
|
||||||
@ -147,14 +147,15 @@ fn (upd VlsUpdater) download_prebuilt() ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
upd.log('Finding prebuilt executables from GitHub release..')
|
upd.log('Finding prebuilt executables from GitHub release..')
|
||||||
resp := http.get('https://api.github.com/repos/vlang/vls/releases')?
|
resp := http.get('https://api.github.com/repos/vlang/vls/releases')!
|
||||||
releases_json := json2.raw_decode(resp.body)?.arr()
|
releases_json := json2.raw_decode(resp.body)!.arr()
|
||||||
if releases_json.len == 0 {
|
if releases_json.len == 0 {
|
||||||
return error('Unable to fetch latest VLS release data: No releases found.')
|
return error('Unable to fetch latest VLS release data: No releases found.')
|
||||||
}
|
}
|
||||||
|
|
||||||
latest_release := releases_json[0].as_map()
|
latest_release := releases_json[0].as_map()
|
||||||
assets := latest_release['assets']?.arr()
|
latest_assets := latest_release['assets'] or { return }
|
||||||
|
assets := latest_assets.arr()
|
||||||
|
|
||||||
mut checksum_asset_idx := -1
|
mut checksum_asset_idx := -1
|
||||||
mut exec_asset_idx := -1
|
mut exec_asset_idx := -1
|
||||||
@ -164,7 +165,8 @@ fn (upd VlsUpdater) download_prebuilt() ? {
|
|||||||
|
|
||||||
for asset_idx, raw_asset in assets {
|
for asset_idx, raw_asset in assets {
|
||||||
asset := raw_asset.as_map()
|
asset := raw_asset.as_map()
|
||||||
match asset['name']?.str() {
|
t_asset := asset['name'] or { return }
|
||||||
|
match t_asset.str() {
|
||||||
exp_asset_name {
|
exp_asset_name {
|
||||||
exec_asset_idx = asset_idx
|
exec_asset_idx = asset_idx
|
||||||
|
|
||||||
@ -196,13 +198,15 @@ fn (upd VlsUpdater) download_prebuilt() ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
upd.log('Executable found for this system. Downloading...')
|
upd.log('Executable found for this system. Downloading...')
|
||||||
upd.init_download_prebuilt()?
|
upd.init_download_prebuilt()!
|
||||||
http.download_file(exec_asset['browser_download_url']?.str(), exec_asset_file_path)?
|
t_asset := exec_asset['browser_download_url'] or { return }
|
||||||
|
http.download_file(t_asset.str(), exec_asset_file_path)!
|
||||||
|
|
||||||
checksum_file_path := os.join_path(vls_cache_folder, 'checksums.txt')
|
checksum_file_path := os.join_path(vls_cache_folder, 'checksums.txt')
|
||||||
checksum_file_asset := assets[checksum_asset_idx].as_map()
|
checksum_file_asset := assets[checksum_asset_idx].as_map()
|
||||||
http.download_file(checksum_file_asset['browser_download_url']?.str(), checksum_file_path)?
|
t_checksum_asset := checksum_file_asset['browser_download_url'] or { return }
|
||||||
checksums := os.read_file(checksum_file_path)?.split_into_lines()
|
http.download_file(t_checksum_asset.str(), checksum_file_path)!
|
||||||
|
checksums := os.read_file(checksum_file_path)!.split_into_lines()
|
||||||
|
|
||||||
upd.log('Verifying checksum...')
|
upd.log('Verifying checksum...')
|
||||||
for checksum_result in checksums {
|
for checksum_result in checksums {
|
||||||
@ -217,7 +221,7 @@ fn (upd VlsUpdater) download_prebuilt() ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
new_exec_path := os.join_path(vls_bin_folder, exp_asset_name)
|
new_exec_path := os.join_path(vls_bin_folder, exp_asset_name)
|
||||||
os.cp(exec_asset_file_path, new_exec_path)?
|
os.cp(exec_asset_file_path, new_exec_path)!
|
||||||
upd.update_manifest(new_exec_path, false, asset_last_updated_at) or {
|
upd.update_manifest(new_exec_path, false, asset_last_updated_at) or {
|
||||||
upd.log('Unable to update config but the executable was updated successfully.')
|
upd.log('Unable to update config but the executable was updated successfully.')
|
||||||
}
|
}
|
||||||
@ -231,12 +235,12 @@ fn (upd VlsUpdater) print_new_vls_version(new_vls_exec_path string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_checksum(file_path string) ?string {
|
fn calculate_checksum(file_path string) !string {
|
||||||
data := os.read_file(file_path)?
|
data := os.read_file(file_path)!
|
||||||
return sha256.hexhash(data)
|
return sha256.hexhash(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) compile_from_source() ? {
|
fn (upd VlsUpdater) compile_from_source() ! {
|
||||||
git := os.find_abs_path_of_executable('git') or { return error('Git not found.') }
|
git := os.find_abs_path_of_executable('git') or { return error('Git not found.') }
|
||||||
|
|
||||||
if !os.exists(vls_src_folder) {
|
if !os.exists(vls_src_folder) {
|
||||||
@ -280,22 +284,22 @@ fn (upd VlsUpdater) compile_from_source() ? {
|
|||||||
upd.print_new_vls_version(exec_path)
|
upd.print_new_vls_version(exec_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) find_ls_path() ?string {
|
fn (upd VlsUpdater) find_ls_path() !string {
|
||||||
manifest := upd.manifest_config()?
|
manifest := upd.manifest_config()!
|
||||||
if 'server_path' in manifest {
|
if 'server_path' in manifest {
|
||||||
server_path := manifest['server_path']?
|
server_path := manifest['server_path'] or { return error('none') }
|
||||||
if server_path is string {
|
if server_path is string {
|
||||||
if server_path.len == 0 {
|
if server_path.len == 0 {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
return server_path
|
return server_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut upd VlsUpdater) parse(mut fp flag.FlagParser) ? {
|
fn (mut upd VlsUpdater) parse(mut fp flag.FlagParser) ! {
|
||||||
is_json := fp.bool('json', ` `, false, 'Print the output as JSON.')
|
is_json := fp.bool('json', ` `, false, 'Print the output as JSON.')
|
||||||
if is_json {
|
if is_json {
|
||||||
upd.output = .json
|
upd.output = .json
|
||||||
@ -364,7 +368,7 @@ fn (mut upd VlsUpdater) parse(mut fp flag.FlagParser) ? {
|
|||||||
fp.allow_unknown_args()
|
fp.allow_unknown_args()
|
||||||
upd.args << fp.finalize() or { fp.remaining_parameters() }
|
upd.args << fp.finalize() or { fp.remaining_parameters() }
|
||||||
} else {
|
} else {
|
||||||
fp.finalize()?
|
fp.finalize()!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,23 +440,23 @@ fn (upd VlsUpdater) check_installation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (upd VlsUpdater) run(fp flag.FlagParser) ? {
|
fn (upd VlsUpdater) run(fp flag.FlagParser) ! {
|
||||||
if upd.is_check {
|
if upd.is_check {
|
||||||
upd.check_installation()
|
upd.check_installation()
|
||||||
} else if upd.setup_kind != .none_ {
|
} else if upd.setup_kind != .none_ {
|
||||||
upd.check_or_create_vls_folder()?
|
upd.check_or_create_vls_folder()!
|
||||||
|
|
||||||
match upd.update_source {
|
match upd.update_source {
|
||||||
.github_releases {
|
.github_releases {
|
||||||
upd.download_prebuilt() or {
|
upd.download_prebuilt() or {
|
||||||
if err.code() == 100 {
|
if err.code() == 100 {
|
||||||
upd.compile_from_source()?
|
upd.compile_from_source()!
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.git_repo {
|
.git_repo {
|
||||||
upd.compile_from_source()?
|
upd.compile_from_source()!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if upd.pass_to_ls {
|
} else if upd.pass_to_ls {
|
||||||
|
@ -133,7 +133,7 @@ fn (r &Repl) function_call(line string) (bool, FnType) {
|
|||||||
// TODO(vincenzopalazzo) Remove this fancy check and add a regex
|
// TODO(vincenzopalazzo) Remove this fancy check and add a regex
|
||||||
fn (r &Repl) is_function_call(line string) bool {
|
fn (r &Repl) is_function_call(line string) bool {
|
||||||
return !line.starts_with('[') && line.contains('.') && line.contains('(')
|
return !line.starts_with('[') && line.contains('.') && line.contains('(')
|
||||||
&& (line.ends_with(')') || line.ends_with('?'))
|
&& (line.ends_with(')') || line.ends_with('?') || line.ends_with('!'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the list of modules that we parsed already,
|
// Convert the list of modules that we parsed already,
|
||||||
|
@ -12,11 +12,11 @@ fn main() {
|
|||||||
fp.version('0.0.1')
|
fp.version('0.0.1')
|
||||||
fp.description('\nScan .v source files, and print the V tokens contained in them.')
|
fp.description('\nScan .v source files, and print the V tokens contained in them.')
|
||||||
fp.arguments_description('PATH [PATH]...')
|
fp.arguments_description('PATH [PATH]...')
|
||||||
fp.limit_free_args_to_at_least(1)?
|
fp.limit_free_args_to_at_least(1)!
|
||||||
pref := pref.new_preferences()
|
pref := pref.new_preferences()
|
||||||
mut all_paths := fp.remaining_parameters()
|
mut all_paths := fp.remaining_parameters()
|
||||||
for path in all_paths {
|
for path in all_paths {
|
||||||
mut scanner := scanner.new_scanner_file(path, .parse_comments, pref)?
|
mut scanner := scanner.new_scanner_file(path, .parse_comments, pref)!
|
||||||
mut tok := token.Token{}
|
mut tok := token.Token{}
|
||||||
for tok.kind != .eof {
|
for tok.kind != .eof {
|
||||||
tok = scanner.scan()
|
tok = scanner.scan()
|
||||||
|
@ -15,7 +15,7 @@ fn main() {
|
|||||||
short_v_name := vexe_name.all_before('.')
|
short_v_name := vexe_name.all_before('.')
|
||||||
//
|
//
|
||||||
recompilation.must_be_enabled(vroot, 'Please install V from source, to use `$vexe_name self` .')
|
recompilation.must_be_enabled(vroot, 'Please install V from source, to use `$vexe_name self` .')
|
||||||
os.chdir(vroot)?
|
os.chdir(vroot)!
|
||||||
os.setenv('VCOLORS', 'always', true)
|
os.setenv('VCOLORS', 'always', true)
|
||||||
args := os.args[1..].filter(it != 'self')
|
args := os.args[1..].filter(it != 'self')
|
||||||
jargs := args.join(' ')
|
jargs := args.join(' ')
|
||||||
@ -60,7 +60,7 @@ fn list_folder(short_v_name string, bmessage string, message string) {
|
|||||||
println(message)
|
println(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn backup_old_version_and_rename_newer(short_v_name string) ?bool {
|
fn backup_old_version_and_rename_newer(short_v_name string) !bool {
|
||||||
mut errors := []string{}
|
mut errors := []string{}
|
||||||
short_v_file := if os.user_os() == 'windows' { '${short_v_name}.exe' } else { '$short_v_name' }
|
short_v_file := if os.user_os() == 'windows' { '${short_v_name}.exe' } else { '$short_v_name' }
|
||||||
short_v2_file := if os.user_os() == 'windows' { 'v2.exe' } else { 'v2' }
|
short_v2_file := if os.user_os() == 'windows' { 'v2.exe' } else { 'v2' }
|
||||||
|
@ -11,7 +11,7 @@ fn main() {
|
|||||||
$if windows {
|
$if windows {
|
||||||
println('Setup freetype...')
|
println('Setup freetype...')
|
||||||
vroot := os.dir(pref.vexe_path())
|
vroot := os.dir(pref.vexe_path())
|
||||||
os.chdir(vroot)?
|
os.chdir(vroot)!
|
||||||
if os.is_dir(freetype_folder) {
|
if os.is_dir(freetype_folder) {
|
||||||
println('Thirdparty "freetype" is already installed.')
|
println('Thirdparty "freetype" is already installed.')
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,7 +122,7 @@ fn shader_program_name(shader_file string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validate_shader_file returns an error if `shader_file` isn't valid.
|
// validate_shader_file returns an error if `shader_file` isn't valid.
|
||||||
fn validate_shader_file(shader_file string) ? {
|
fn validate_shader_file(shader_file string) ! {
|
||||||
shader_program := os.read_lines(shader_file) or {
|
shader_program := os.read_lines(shader_file) or {
|
||||||
return error('shader program at "$shader_file" could not be opened for reading')
|
return error('shader program at "$shader_file" could not be opened for reading')
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ fn validate_shader_file(shader_file string) ? {
|
|||||||
|
|
||||||
// compile_shaders compiles all `*.glsl` files found in `input_path`
|
// compile_shaders compiles all `*.glsl` files found in `input_path`
|
||||||
// to their C header file representatives.
|
// to their C header file representatives.
|
||||||
fn compile_shaders(opt Options, input_path string) ? {
|
fn compile_shaders(opt Options, input_path string) ! {
|
||||||
mut path := os.real_path(input_path)
|
mut path := os.real_path(input_path)
|
||||||
path = path.trim_right('/')
|
path = path.trim_right('/')
|
||||||
if os.is_file(path) {
|
if os.is_file(path) {
|
||||||
@ -172,12 +172,12 @@ fn compile_shaders(opt Options, input_path string) ? {
|
|||||||
// Currently sokol-shdc allows for multiple --input flags
|
// Currently sokol-shdc allows for multiple --input flags
|
||||||
// - but it's only the last entry that's actually compiled/used
|
// - but it's only the last entry that's actually compiled/used
|
||||||
// Given this fact - we can only compile one '.glsl' file to one C '.h' header
|
// Given this fact - we can only compile one '.glsl' file to one C '.h' header
|
||||||
compile_shader(co, shader_file)?
|
compile_shader(co, shader_file)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile_shader compiles `shader_file` to a C header file.
|
// compile_shader compiles `shader_file` to a C header file.
|
||||||
fn compile_shader(opt CompileOptions, shader_file string) ? {
|
fn compile_shader(opt CompileOptions, shader_file string) ! {
|
||||||
path := opt.invoke_path
|
path := opt.invoke_path
|
||||||
// The output convetion, for now, is to use the name of the .glsl file
|
// The output convetion, for now, is to use the name of the .glsl file
|
||||||
mut out_file := os.file_name(shader_file).all_before_last('.') + '.h'
|
mut out_file := os.file_name(shader_file).all_before_last('.') + '.h'
|
||||||
@ -231,12 +231,12 @@ fn collect(path string, mut list []string) {
|
|||||||
|
|
||||||
// ensure_external_tools returns nothing if the external
|
// ensure_external_tools returns nothing if the external
|
||||||
// tools can be setup or is already in place.
|
// tools can be setup or is already in place.
|
||||||
fn ensure_external_tools(opt Options) ? {
|
fn ensure_external_tools(opt Options) ! {
|
||||||
if !os.exists(cache_dir) {
|
if !os.exists(cache_dir) {
|
||||||
os.mkdir_all(cache_dir)?
|
os.mkdir_all(cache_dir)!
|
||||||
}
|
}
|
||||||
if opt.force_update {
|
if opt.force_update {
|
||||||
download_shdc(opt)?
|
download_shdc(opt)!
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +250,7 @@ fn ensure_external_tools(opt Options) ? {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
download_shdc(opt)?
|
download_shdc(opt)!
|
||||||
}
|
}
|
||||||
|
|
||||||
// shdc_exe returns an absolute path to the `sokol-shdc` tool.
|
// shdc_exe returns an absolute path to the `sokol-shdc` tool.
|
||||||
@ -261,7 +261,7 @@ fn shdc_exe() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// download_shdc downloads the `sokol-shdc` tool to an OS specific cache directory.
|
// download_shdc downloads the `sokol-shdc` tool to an OS specific cache directory.
|
||||||
fn download_shdc(opt Options) ? {
|
fn download_shdc(opt Options) ! {
|
||||||
// We want to use the same, runtime, OS type as this tool is invoked on.
|
// We want to use the same, runtime, OS type as this tool is invoked on.
|
||||||
download_url := shdc_urls[runtime_os] or { '' }
|
download_url := shdc_urls[runtime_os] or { '' }
|
||||||
if download_url == '' {
|
if download_url == '' {
|
||||||
@ -277,26 +277,26 @@ fn download_shdc(opt Options) ? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if os.exists(file) {
|
if os.exists(file) {
|
||||||
os.rm(file)?
|
os.rm(file)!
|
||||||
}
|
}
|
||||||
|
|
||||||
mut dtmp_file, dtmp_path := util.temp_file(util.TempFileOptions{ path: os.dir(file) })?
|
mut dtmp_file, dtmp_path := util.temp_file(util.TempFileOptions{ path: os.dir(file) })!
|
||||||
dtmp_file.close()
|
dtmp_file.close()
|
||||||
if opt.verbose {
|
if opt.verbose {
|
||||||
eprintln('$tool_name downloading sokol-shdc from $download_url')
|
eprintln('$tool_name downloading sokol-shdc from $download_url')
|
||||||
}
|
}
|
||||||
http.download_file(download_url, dtmp_path) or {
|
http.download_file(download_url, dtmp_path) or {
|
||||||
os.rm(dtmp_path)?
|
os.rm(dtmp_path)!
|
||||||
return error('$tool_name failed to download sokol-shdc needed for shader compiling: $err')
|
return error('$tool_name failed to download sokol-shdc needed for shader compiling: $err')
|
||||||
}
|
}
|
||||||
// Make it executable
|
// Make it executable
|
||||||
os.chmod(dtmp_path, 0o775)?
|
os.chmod(dtmp_path, 0o775)!
|
||||||
// Move downloaded file in place
|
// Move downloaded file in place
|
||||||
os.mv(dtmp_path, file)?
|
os.mv(dtmp_path, file)!
|
||||||
if runtime_os in ['linux', 'macos'] {
|
if runtime_os in ['linux', 'macos'] {
|
||||||
// Use the .exe file ending to minimize platform friction.
|
// Use the .exe file ending to minimize platform friction.
|
||||||
os.mv(file, shdc)?
|
os.mv(file, shdc)!
|
||||||
}
|
}
|
||||||
// Update internal version file
|
// Update internal version file
|
||||||
os.write_file(shdc_version_file, update_to_shdc_version)?
|
os.write_file(shdc_version_file, update_to_shdc_version)!
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ fn main() {
|
|||||||
context.pref = &pref.Preferences{
|
context.pref = &pref.Preferences{
|
||||||
output_mode: .silent
|
output_mode: .silent
|
||||||
}
|
}
|
||||||
mut source := os.read_file(context.path)?
|
mut source := os.read_file(context.path)!
|
||||||
source = source[..context.cut_index]
|
source = source[..context.cut_index]
|
||||||
|
|
||||||
go fn (ms int) {
|
go fn (ms int) {
|
||||||
|
@ -6,7 +6,7 @@ import v.pref
|
|||||||
fn main() {
|
fn main() {
|
||||||
vexe := pref.vexe_path()
|
vexe := pref.vexe_path()
|
||||||
vroot := os.dir(vexe)
|
vroot := os.dir(vexe)
|
||||||
os.chdir(vroot)?
|
os.chdir(vroot)!
|
||||||
os.setenv('VCOLORS', 'always', true)
|
os.setenv('VCOLORS', 'always', true)
|
||||||
self_idx := os.args.index('tracev')
|
self_idx := os.args.index('tracev')
|
||||||
args := os.args[1..self_idx]
|
args := os.args[1..self_idx]
|
||||||
|
@ -26,7 +26,7 @@ fn new_app() App {
|
|||||||
fn main() {
|
fn main() {
|
||||||
app := new_app()
|
app := new_app()
|
||||||
recompilation.must_be_enabled(app.vroot, 'Please install V from source, to use `v up` .')
|
recompilation.must_be_enabled(app.vroot, 'Please install V from source, to use `v up` .')
|
||||||
os.chdir(app.vroot)?
|
os.chdir(app.vroot)!
|
||||||
println('Updating V...')
|
println('Updating V...')
|
||||||
app.update_from_master()
|
app.update_from_master()
|
||||||
v_hash := version.githash(false)
|
v_hash := version.githash(false)
|
||||||
|
@ -14,7 +14,7 @@ fn find_diff_cmd() string {
|
|||||||
fn test_vet() {
|
fn test_vet() {
|
||||||
vexe := os.getenv('VEXE')
|
vexe := os.getenv('VEXE')
|
||||||
vroot := os.dir(vexe)
|
vroot := os.dir(vexe)
|
||||||
os.chdir(vroot)?
|
os.chdir(vroot)!
|
||||||
test_dir := 'cmd/tools/vvet/tests'
|
test_dir := 'cmd/tools/vvet/tests'
|
||||||
tests := get_tests_in_dir(test_dir)
|
tests := get_tests_in_dir(test_dir)
|
||||||
fails := check_path(vexe, test_dir, tests)
|
fails := check_path(vexe, test_dir, tests)
|
||||||
|
@ -318,7 +318,7 @@ fn main() {
|
|||||||
fp.description('Collect all .v files needed for a compilation, then re-run the compilation when any of the source changes.')
|
fp.description('Collect all .v files needed for a compilation, then re-run the compilation when any of the source changes.')
|
||||||
fp.arguments_description('[--silent] [--clear] [--ignore .db] [--add /path/to/a/file.v] [run] program.v')
|
fp.arguments_description('[--silent] [--clear] [--ignore .db] [--add /path/to/a/file.v] [run] program.v')
|
||||||
fp.allow_unknown_args()
|
fp.allow_unknown_args()
|
||||||
fp.limit_free_args_to_at_least(1)?
|
fp.limit_free_args_to_at_least(1)!
|
||||||
context.is_worker = fp.bool('vwatchworker', 0, false, 'Internal flag. Used to distinguish vwatch manager and worker processes.')
|
context.is_worker = fp.bool('vwatchworker', 0, false, 'Internal flag. Used to distinguish vwatch manager and worker processes.')
|
||||||
context.silent = fp.bool('silent', `s`, false, 'Be more silent; do not print the watch timestamp before each re-run.')
|
context.silent = fp.bool('silent', `s`, false, 'Be more silent; do not print the watch timestamp before each re-run.')
|
||||||
context.clear_terminal = fp.bool('clear', `c`, false, 'Clears the terminal before each re-run.')
|
context.clear_terminal = fp.bool('clear', `c`, false, 'Clears the terminal before each re-run.')
|
||||||
|
@ -145,7 +145,7 @@ fn maybe_color(term_color fn (string) string, str string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_v_files(path string, recursive bool) ?[]string {
|
fn collect_v_files(path string, recursive bool) ![]string {
|
||||||
if path.len == 0 {
|
if path.len == 0 {
|
||||||
return error('path cannot be empty')
|
return error('path cannot be empty')
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ fn collect_v_files(path string, recursive bool) ?[]string {
|
|||||||
return error('path does not exist or is not a directory')
|
return error('path does not exist or is not a directory')
|
||||||
}
|
}
|
||||||
mut all_files := []string{}
|
mut all_files := []string{}
|
||||||
mut entries := os.ls(path)?
|
mut entries := os.ls(path)!
|
||||||
mut local_path_separator := os.path_separator
|
mut local_path_separator := os.path_separator
|
||||||
if path.ends_with(os.path_separator) {
|
if path.ends_with(os.path_separator) {
|
||||||
local_path_separator = ''
|
local_path_separator = ''
|
||||||
@ -161,7 +161,7 @@ fn collect_v_files(path string, recursive bool) ?[]string {
|
|||||||
for entry in entries {
|
for entry in entries {
|
||||||
file := path + local_path_separator + entry
|
file := path + local_path_separator + entry
|
||||||
if os.is_dir(file) && !os.is_link(file) && recursive {
|
if os.is_dir(file) && !os.is_link(file) && recursive {
|
||||||
all_files << collect_v_files(file, recursive)?
|
all_files << collect_v_files(file, recursive)!
|
||||||
} else if os.exists(file) && (file.ends_with('.v') || file.ends_with('.vsh')) {
|
} else if os.exists(file) && (file.ends_with('.v') || file.ends_with('.vsh')) {
|
||||||
all_files << file
|
all_files << file
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ fn collect_v_files(path string, recursive bool) ?[]string {
|
|||||||
return all_files
|
return all_files
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_module(path string) ?string {
|
fn resolve_module(path string) !string {
|
||||||
if os.is_dir(path) {
|
if os.is_dir(path) {
|
||||||
return path
|
return path
|
||||||
} else if os.is_dir(os.join_path(vmod_dir, path)) {
|
} else if os.is_dir(os.join_path(vmod_dir, path)) {
|
||||||
|
@ -1901,8 +1901,8 @@ enum State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write log file and return number of bytes written
|
// write log file and return number of bytes written
|
||||||
fn write_log(s State) ?int {
|
fn write_log(s State) !int {
|
||||||
mut f := os.create('log.txt')?
|
mut f := os.create('log.txt')!
|
||||||
defer {
|
defer {
|
||||||
f.close()
|
f.close()
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ import io
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Make a new connection
|
// Make a new connection
|
||||||
mut conn := net.dial_tcp('google.com:80')?
|
mut conn := net.dial_tcp('google.com:80')!
|
||||||
// Simple http HEAD request for a file
|
// Simple http HEAD request for a file
|
||||||
conn.write_string('GET /index.html HTTP/1.0\r\n\r\n')?
|
conn.write_string('GET /index.html HTTP/1.0\r\n\r\n')!
|
||||||
// Wrap in a buffered reader
|
// Wrap in a buffered reader
|
||||||
mut r := io.new_buffered_reader(reader: conn)
|
mut r := io.new_buffered_reader(reader: conn)
|
||||||
for {
|
for {
|
||||||
|
@ -2,9 +2,9 @@ import net.http
|
|||||||
import sync
|
import sync
|
||||||
import time
|
import time
|
||||||
|
|
||||||
fn vlang_time(mut wg sync.WaitGroup) ?string {
|
fn vlang_time(mut wg sync.WaitGroup) !string {
|
||||||
start := time.ticks()
|
start := time.ticks()
|
||||||
data := http.get('https://vlang.io/utc_now')?
|
data := http.get('https://vlang.io/utc_now')!
|
||||||
finish := time.ticks()
|
finish := time.ticks()
|
||||||
println('Finish getting time ${finish - start} ms')
|
println('Finish getting time ${finish - start} ms')
|
||||||
println(data.body)
|
println(data.body)
|
||||||
@ -12,9 +12,9 @@ fn vlang_time(mut wg sync.WaitGroup) ?string {
|
|||||||
return data.body
|
return data.body
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remote_ip(mut wg sync.WaitGroup) ?string {
|
fn remote_ip(mut wg sync.WaitGroup) !string {
|
||||||
start := time.ticks()
|
start := time.ticks()
|
||||||
data := http.get('https://api.ipify.org')?
|
data := http.get('https://api.ipify.org')!
|
||||||
finish := time.ticks()
|
finish := time.ticks()
|
||||||
println('Finish getting ip ${finish - start} ms')
|
println('Finish getting ip ${finish - start} ms')
|
||||||
println(data.body)
|
println(data.body)
|
||||||
|
@ -10,9 +10,9 @@ type FNAdder = fn (int, int) int
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
library_file_path := os.join_path(os.dir(@FILE), dl.get_libname('library'))
|
library_file_path := os.join_path(os.dir(@FILE), dl.get_libname('library'))
|
||||||
handle := dl.open_opt(library_file_path, dl.rtld_lazy)?
|
handle := dl.open_opt(library_file_path, dl.rtld_lazy)!
|
||||||
eprintln('handle: ${ptr_str(handle)}')
|
eprintln('handle: ${ptr_str(handle)}')
|
||||||
f := FNAdder(dl.sym_opt(handle, 'add_1')?)
|
f := FNAdder(dl.sym_opt(handle, 'add_1')!)
|
||||||
eprintln('f: ${ptr_str(f)}')
|
eprintln('f: ${ptr_str(f)}')
|
||||||
res := f(1, 2)
|
res := f(1, 2)
|
||||||
eprintln('res: $res')
|
eprintln('res: $res')
|
||||||
|
@ -34,5 +34,5 @@ fn main() {
|
|||||||
mut server := Server{
|
mut server := Server{
|
||||||
handler: ExampleHandler{}
|
handler: ExampleHandler{}
|
||||||
}
|
}
|
||||||
server.listen_and_serve()?
|
server.listen_and_serve()
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import os
|
|||||||
const numeric_char = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `.`, `e`, `E`]
|
const numeric_char = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `.`, `e`, `E`]
|
||||||
|
|
||||||
// Convert expression to Reverse Polish Notation.
|
// Convert expression to Reverse Polish Notation.
|
||||||
fn expr_to_rev_pol(expr string) ?[]string {
|
fn expr_to_rev_pol(expr string) ![]string {
|
||||||
if expr == '' {
|
if expr == '' {
|
||||||
return error('err: empty expression')
|
return error('err: empty expression')
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ fn expr_to_rev_pol(expr string) ?[]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate the result of Reverse Polish Notation.
|
// Evaluate the result of Reverse Polish Notation.
|
||||||
fn eval_rev_pol(rev_pol []string) ?f64 {
|
fn eval_rev_pol(rev_pol []string) !f64 {
|
||||||
mut stack := []f64{}
|
mut stack := []f64{}
|
||||||
for item in rev_pol {
|
for item in rev_pol {
|
||||||
if is_num_string(item) {
|
if is_num_string(item) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import net
|
import net
|
||||||
|
|
||||||
conn := net.dial_tcp('[::1]:57000')?
|
conn := net.dial_tcp('[::1]:57000')!
|
||||||
peer_addr := conn.peer_addr()?
|
peer_addr := conn.peer_addr()!
|
||||||
println('$peer_addr')
|
println('$peer_addr')
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import net
|
import net
|
||||||
|
|
||||||
conn := net.dial_tcp('google.com:80')?
|
conn := net.dial_tcp('google.com:80')!
|
||||||
peer_addr := conn.peer_addr()?
|
peer_addr := conn.peer_addr()!
|
||||||
println('$peer_addr')
|
println('$peer_addr')
|
||||||
|
@ -3,18 +3,18 @@ import io
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Make a new connection
|
// Make a new connection
|
||||||
mut conn := net.dial_tcp('google.com:80')?
|
mut conn := net.dial_tcp('google.com:80')!
|
||||||
defer {
|
defer {
|
||||||
conn.close() or {}
|
conn.close() or {}
|
||||||
}
|
}
|
||||||
|
|
||||||
println(' peer: ${conn.peer_addr()?}')
|
println(' peer: ${conn.peer_addr()!}')
|
||||||
println('local: ${conn.addr()?}')
|
println('local: ${conn.addr()!}')
|
||||||
|
|
||||||
// Simple http HEAD request for a file
|
// Simple http HEAD request for a file
|
||||||
conn.write_string('HEAD /index.html HTTP/1.0\r\n\r\n')?
|
conn.write_string('HEAD /index.html HTTP/1.0\r\n\r\n')!
|
||||||
// Read all the data that is waiting
|
// Read all the data that is waiting
|
||||||
result := io.read_all(reader: conn)?
|
result := io.read_all(reader: conn)!
|
||||||
// Cast to string and print result
|
// Cast to string and print result
|
||||||
println(result.bytestr())
|
println(result.bytestr())
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ import net.http
|
|||||||
import sync
|
import sync
|
||||||
import time
|
import time
|
||||||
|
|
||||||
fn send_request(mut wg sync.WaitGroup) ?string {
|
fn send_request(mut wg sync.WaitGroup) !string {
|
||||||
start := time.ticks()
|
start := time.ticks()
|
||||||
data := http.get('https://google.com')?
|
data := http.get('https://google.com')!
|
||||||
finish := time.ticks()
|
finish := time.ticks()
|
||||||
println('Finish getting time ${finish - start} ms')
|
println('Finish getting time ${finish - start} ms')
|
||||||
wg.done()
|
wg.done()
|
||||||
|
@ -12,7 +12,7 @@ fn main() {
|
|||||||
mut buf := []u8{len: 100}
|
mut buf := []u8{len: 100}
|
||||||
if is_server {
|
if is_server {
|
||||||
println('UDP echo server, listening for udp packets on port: $port')
|
println('UDP echo server, listening for udp packets on port: $port')
|
||||||
mut c := net.listen_udp(':$port')?
|
mut c := net.listen_udp(':$port')!
|
||||||
for {
|
for {
|
||||||
read, addr := c.read(mut buf) or { continue }
|
read, addr := c.read(mut buf) or { continue }
|
||||||
println('received $read bytes from $addr')
|
println('received $read bytes from $addr')
|
||||||
@ -23,7 +23,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println('UDP client, sending packets to port: ${port}.\nType `exit` to exit.')
|
println('UDP client, sending packets to port: ${port}.\nType `exit` to exit.')
|
||||||
mut c := net.dial_udp('localhost:$port')?
|
mut c := net.dial_udp('localhost:$port')!
|
||||||
for {
|
for {
|
||||||
mut line := os.input('client > ')
|
mut line := os.input('client > ')
|
||||||
match line {
|
match line {
|
||||||
@ -36,8 +36,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
c.write_string(line)?
|
c.write_string(line)!
|
||||||
read, _ := c.read(mut buf)?
|
read, _ := c.read(mut buf)!
|
||||||
println('server : ' + buf[0..read].bytestr())
|
println('server : ' + buf[0..read].bytestr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import sim.anim
|
|||||||
import sim.args as simargs
|
import sim.args as simargs
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
args := simargs.parse_args(extra_workers: 1)? as simargs.ParallelArgs
|
args := simargs.parse_args(extra_workers: 1)! as simargs.ParallelArgs
|
||||||
|
|
||||||
mut app := anim.new_app(args)
|
mut app := anim.new_app(args)
|
||||||
mut workers := []thread{cap: args.workers}
|
mut workers := []thread{cap: args.workers}
|
||||||
@ -27,7 +27,7 @@ fn main() {
|
|||||||
workers << go sim.sim_worker(id, app.request_chan, [app.result_chan])
|
workers << go sim.sim_worker(id, app.request_chan, [app.result_chan])
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_request := fn [app] (request &sim.SimRequest) ? {
|
handle_request := fn [app] (request &sim.SimRequest) ! {
|
||||||
app.request_chan <- request
|
app.request_chan <- request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,11 +7,11 @@ import sim.args as simargs
|
|||||||
import sim.img
|
import sim.img
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
args := simargs.parse_args(extra_workers: 2)? as simargs.ParallelArgs
|
args := simargs.parse_args(extra_workers: 2)! as simargs.ParallelArgs
|
||||||
|
|
||||||
img_settings := img.image_settings_from_grid(args.grid)
|
img_settings := img.image_settings_from_grid(args.grid)
|
||||||
|
|
||||||
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)?
|
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)!
|
||||||
|
|
||||||
mut app := anim.new_app(args)
|
mut app := anim.new_app(args)
|
||||||
mut workers := []thread{cap: args.workers + 1}
|
mut workers := []thread{cap: args.workers + 1}
|
||||||
@ -41,7 +41,7 @@ fn main() {
|
|||||||
workers << go sim.sim_worker(id, app.request_chan, [app.result_chan, img_result_chan])
|
workers << go sim.sim_worker(id, app.request_chan, [app.result_chan, img_result_chan])
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_request := fn [app] (request &sim.SimRequest) ? {
|
handle_request := fn [app] (request &sim.SimRequest) ! {
|
||||||
app.request_chan <- request
|
app.request_chan <- request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,21 +31,21 @@ pub:
|
|||||||
|
|
||||||
pub type SimArgs = ParallelArgs | SequentialArgs
|
pub type SimArgs = ParallelArgs | SequentialArgs
|
||||||
|
|
||||||
pub fn parse_args(config ParserSettings) ?SimArgs {
|
pub fn parse_args(config ParserSettings) !SimArgs {
|
||||||
if config.sequential {
|
if config.sequential {
|
||||||
args := parse_sequential_args()?
|
args := parse_sequential_args()!
|
||||||
return SimArgs(args)
|
return SimArgs(args)
|
||||||
} else {
|
} else {
|
||||||
args := parse_parallel_args(config.extra_workers)?
|
args := parse_parallel_args(config.extra_workers)!
|
||||||
return SimArgs(args)
|
return SimArgs(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_sequential_args() ?SequentialArgs {
|
fn parse_sequential_args() !SequentialArgs {
|
||||||
mut fp := flag.new_flag_parser(os.args)
|
mut fp := flag.new_flag_parser(os.args)
|
||||||
fp.application('vps')
|
fp.application('vps')
|
||||||
fp.version('v0.1.0')
|
fp.version('v0.1.0')
|
||||||
fp.limit_free_args(0, 0)?
|
fp.limit_free_args(0, 0)!
|
||||||
fp.description('This is a pendulum simulation written in pure V')
|
fp.description('This is a pendulum simulation written in pure V')
|
||||||
fp.skip_executable()
|
fp.skip_executable()
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ fn parse_sequential_args() ?SequentialArgs {
|
|||||||
|
|
||||||
fp.finalize() or {
|
fp.finalize() or {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
params := sim.sim_params(
|
params := sim.sim_params(
|
||||||
@ -92,11 +92,11 @@ fn parse_sequential_args() ?SequentialArgs {
|
|||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_parallel_args(extra_workers int) ?ParallelArgs {
|
fn parse_parallel_args(extra_workers int) !ParallelArgs {
|
||||||
mut fp := flag.new_flag_parser(os.args)
|
mut fp := flag.new_flag_parser(os.args)
|
||||||
fp.application('vps')
|
fp.application('vps')
|
||||||
fp.version('v0.1.0')
|
fp.version('v0.1.0')
|
||||||
fp.limit_free_args(0, 0)?
|
fp.limit_free_args(0, 0)!
|
||||||
fp.description('This is a pendulum simulation written in pure V')
|
fp.description('This is a pendulum simulation written in pure V')
|
||||||
fp.skip_executable()
|
fp.skip_executable()
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ fn parse_parallel_args(extra_workers int) ?ParallelArgs {
|
|||||||
|
|
||||||
fp.finalize() or {
|
fp.finalize() or {
|
||||||
println(fp.usage())
|
println(fp.usage())
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
params := sim.sim_params(
|
params := sim.sim_params(
|
||||||
|
@ -39,34 +39,34 @@ mut:
|
|||||||
cache_size int
|
cache_size int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ppm_writer_for_fname(fname string, settings ImageSettings) ?&PPMWriter {
|
pub fn ppm_writer_for_fname(fname string, settings ImageSettings) !&PPMWriter {
|
||||||
mut writer := &PPMWriter{
|
mut writer := &PPMWriter{
|
||||||
cache_size: settings.cache_size
|
cache_size: settings.cache_size
|
||||||
cache: []u8{cap: settings.cache_size}
|
cache: []u8{cap: settings.cache_size}
|
||||||
}
|
}
|
||||||
writer.start_for_file(fname, settings)?
|
writer.start_for_file(fname, settings)!
|
||||||
return writer
|
return writer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut writer PPMWriter) start_for_file(fname string, settings ImageSettings) ? {
|
pub fn (mut writer PPMWriter) start_for_file(fname string, settings ImageSettings) ! {
|
||||||
writer.file = os.create(fname)?
|
writer.file = os.create(fname)!
|
||||||
writer.file.writeln('P6 $settings.width $settings.height 255')?
|
writer.file.writeln('P6 $settings.width $settings.height 255')!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut writer PPMWriter) handle_pixel(p gx.Color) ? {
|
pub fn (mut writer PPMWriter) handle_pixel(p gx.Color) ! {
|
||||||
if writer.cache.len >= writer.cache_size {
|
if writer.cache.len >= writer.cache_size {
|
||||||
writer.write()?
|
writer.write()!
|
||||||
writer.flush()?
|
writer.flush()!
|
||||||
}
|
}
|
||||||
writer.cache << [p.r, p.g, p.b]
|
writer.cache << [p.r, p.g, p.b]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut writer PPMWriter) flush() ? {
|
pub fn (mut writer PPMWriter) flush() ! {
|
||||||
writer.cache.clear()
|
writer.cache.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut writer PPMWriter) write() ? {
|
pub fn (mut writer PPMWriter) write() ! {
|
||||||
writer.file.write(writer.cache)?
|
writer.file.write(writer.cache)!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut writer PPMWriter) close() {
|
pub fn (mut writer PPMWriter) close() {
|
||||||
|
@ -29,7 +29,7 @@ pub fn new_image_writer(mut writer PPMWriter, settings ImageSettings) &ImageWrit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut iw ImageWritter) handle(result sim.SimResult) ?int {
|
pub fn (mut iw ImageWritter) handle(result sim.SimResult) !int {
|
||||||
total_pixels := iw.settings.width * iw.settings.height
|
total_pixels := iw.settings.width * iw.settings.height
|
||||||
|
|
||||||
// find the closest magnet
|
// find the closest magnet
|
||||||
@ -46,7 +46,7 @@ pub fn (mut iw ImageWritter) handle(result sim.SimResult) ?int {
|
|||||||
|
|
||||||
if iw.current_index == total_pixels {
|
if iw.current_index == total_pixels {
|
||||||
iw.writer.write() or { panic('Could not write image') }
|
iw.writer.write() or { panic('Could not write image') }
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
return iw.current_index
|
return iw.current_index
|
||||||
|
@ -3,11 +3,11 @@ module sim
|
|||||||
import benchmark
|
import benchmark
|
||||||
import term
|
import term
|
||||||
|
|
||||||
pub type SimRequestHandler = fn (request &SimRequest) ?
|
pub type SimRequestHandler = fn (request &SimRequest) !
|
||||||
|
|
||||||
pub type SimStartHandler = fn () ?
|
pub type SimStartHandler = fn () !
|
||||||
|
|
||||||
pub type SimFinishHandler = fn () ?
|
pub type SimFinishHandler = fn () !
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
default_width = 600
|
default_width = 600
|
||||||
|
@ -6,7 +6,7 @@ import sim.args as simargs
|
|||||||
import sim.img
|
import sim.img
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
args := simargs.parse_args()? as simargs.ParallelArgs
|
args := simargs.parse_args()! as simargs.ParallelArgs
|
||||||
|
|
||||||
img_settings := img.image_settings_from_grid(args.grid)
|
img_settings := img.image_settings_from_grid(args.grid)
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ fn main() {
|
|||||||
request_chan := chan &sim.SimRequest{cap: args.workers}
|
request_chan := chan &sim.SimRequest{cap: args.workers}
|
||||||
result_chan := chan &sim.SimResult{cap: args.workers}
|
result_chan := chan &sim.SimResult{cap: args.workers}
|
||||||
|
|
||||||
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)?
|
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)!
|
||||||
mut image_writer := img.new_image_writer(mut writer, img_settings)
|
mut image_writer := img.new_image_writer(mut writer, img_settings)
|
||||||
|
|
||||||
mut workers := []thread{cap: args.workers}
|
mut workers := []thread{cap: args.workers}
|
||||||
|
@ -6,14 +6,14 @@ import sim.args as simargs
|
|||||||
import sim.img
|
import sim.img
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
args := simargs.parse_args(extra_workers: 1)? as simargs.ParallelArgs
|
args := simargs.parse_args(extra_workers: 1)! as simargs.ParallelArgs
|
||||||
|
|
||||||
img_settings := img.image_settings_from_grid(args.grid)
|
img_settings := img.image_settings_from_grid(args.grid)
|
||||||
|
|
||||||
request_chan := chan &sim.SimRequest{cap: args.workers}
|
request_chan := chan &sim.SimRequest{cap: args.workers}
|
||||||
result_chan := chan &sim.SimResult{cap: args.workers}
|
result_chan := chan &sim.SimResult{cap: args.workers}
|
||||||
|
|
||||||
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)?
|
mut writer := img.ppm_writer_for_fname(args.filename, img_settings)!
|
||||||
|
|
||||||
mut workers := []thread{cap: args.workers + 1}
|
mut workers := []thread{cap: args.workers + 1}
|
||||||
mut bmark := benchmark.start()
|
mut bmark := benchmark.start()
|
||||||
@ -39,7 +39,7 @@ fn main() {
|
|||||||
|
|
||||||
workers << go img.image_worker(mut writer, result_chan, img_settings)
|
workers << go img.image_worker(mut writer, result_chan, img_settings)
|
||||||
|
|
||||||
handle_request := fn [request_chan] (request &sim.SimRequest) ? {
|
handle_request := fn [request_chan] (request &sim.SimRequest) ! {
|
||||||
request_chan <- request
|
request_chan <- request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,19 +6,19 @@ import sim.args as simargs
|
|||||||
import sim.img
|
import sim.img
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
args := simargs.parse_args(sequential: true)? as simargs.SequentialArgs
|
args := simargs.parse_args(sequential: true)! as simargs.SequentialArgs
|
||||||
|
|
||||||
mut bmark := benchmark.start()
|
mut bmark := benchmark.start()
|
||||||
defer {
|
defer {
|
||||||
bmark.measure(@FN)
|
bmark.measure(@FN)
|
||||||
}
|
}
|
||||||
|
|
||||||
mut writer := img.ppm_writer_for_fname(args.filename, img.image_settings_from_grid(args.grid))?
|
mut writer := img.ppm_writer_for_fname(args.filename, img.image_settings_from_grid(args.grid))!
|
||||||
defer {
|
defer {
|
||||||
writer.close()
|
writer.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_request := fn [mut writer] (request &sim.SimRequest) ? {
|
handle_request := fn [mut writer] (request &sim.SimRequest) ! {
|
||||||
result := sim.compute_result(request)
|
result := sim.compute_result(request)
|
||||||
pixel := img.compute_pixel(result)
|
pixel := img.compute_pixel(result)
|
||||||
return writer.handle_pixel(pixel)
|
return writer.handle_pixel(pixel)
|
||||||
@ -26,5 +26,5 @@ fn main() {
|
|||||||
|
|
||||||
sim.run(args.params, grid: args.grid, on_request: sim.SimRequestHandler(handle_request))
|
sim.run(args.params, grid: args.grid, on_request: sim.SimRequestHandler(handle_request))
|
||||||
|
|
||||||
writer.write()?
|
writer.write()!
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,11 @@ import net
|
|||||||
// telnet 127.0.0.1 12345
|
// telnet 127.0.0.1 12345
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
mut server := net.listen_tcp(.ip6, ':12345')?
|
mut server := net.listen_tcp(.ip6, ':12345')!
|
||||||
laddr := server.addr()?
|
laddr := server.addr()!
|
||||||
eprintln('Listen on $laddr ...')
|
eprintln('Listen on $laddr ...')
|
||||||
for {
|
for {
|
||||||
mut socket := server.accept()?
|
mut socket := server.accept()!
|
||||||
go handle_client(mut socket)
|
go handle_client(mut socket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,21 +14,21 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create TCP listener
|
// create TCP listener
|
||||||
mut listener := net.listen_tcp(.ip, 'localhost:9001')?
|
mut listener := net.listen_tcp(.ip, 'localhost:9001')!
|
||||||
defer {
|
defer {
|
||||||
listener.close() or {}
|
listener.close() or {}
|
||||||
}
|
}
|
||||||
addr := listener.addr()?
|
addr := listener.addr()!
|
||||||
eprintln('Listening on $addr')
|
eprintln('Listening on $addr')
|
||||||
eprintln('Type `stop` to stop the server')
|
eprintln('Type `stop` to stop the server')
|
||||||
|
|
||||||
// create file descriptor notifier
|
// create file descriptor notifier
|
||||||
mut notifier := notify.new()?
|
mut notifier := notify.new()!
|
||||||
defer {
|
defer {
|
||||||
notifier.close() or {}
|
notifier.close() or {}
|
||||||
}
|
}
|
||||||
notifier.add(os.stdin().fd, .read)?
|
notifier.add(os.stdin().fd, .read)!
|
||||||
notifier.add(listener.sock.handle, .read)?
|
notifier.add(listener.sock.handle, .read)!
|
||||||
|
|
||||||
for {
|
for {
|
||||||
for event in notifier.wait(time.infinite) {
|
for event in notifier.wait(time.infinite) {
|
||||||
|
@ -150,10 +150,10 @@ fn (item_list Item_list) get_file_path() string {
|
|||||||
* Scan functions
|
* Scan functions
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
fn (mut item_list Item_list) scan_folder(path string, in_index int) ? {
|
fn (mut item_list Item_list) scan_folder(path string, in_index int) ! {
|
||||||
println('Scanning [$path]')
|
println('Scanning [$path]')
|
||||||
mut folder_list := []string{}
|
mut folder_list := []string{}
|
||||||
lst := os.ls(path)?
|
lst := os.ls(path)!
|
||||||
|
|
||||||
// manage the single files
|
// manage the single files
|
||||||
for c, x in lst {
|
for c, x in lst {
|
||||||
@ -171,7 +171,7 @@ fn (mut item_list Item_list) scan_folder(path string, in_index int) ? {
|
|||||||
if ext == .zip {
|
if ext == .zip {
|
||||||
item.i_type = .zip
|
item.i_type = .zip
|
||||||
item_list.lst << item
|
item_list.lst << item
|
||||||
item_list.scan_zip(pt, item_list.lst.len - 1)?
|
item_list.scan_zip(pt, item_list.lst.len - 1)!
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if is_image(ext) == true {
|
if is_image(ext) == true {
|
||||||
@ -194,7 +194,7 @@ fn (mut item_list Item_list) scan_folder(path string, in_index int) ? {
|
|||||||
i_type: .folder
|
i_type: .folder
|
||||||
}
|
}
|
||||||
item_list.lst << item
|
item_list.lst << item
|
||||||
item_list.scan_folder(pt, item_list.lst.len - 1)?
|
item_list.scan_folder(pt, item_list.lst.len - 1)!
|
||||||
}
|
}
|
||||||
// println(item_list.lst.len)
|
// println(item_list.lst.len)
|
||||||
// println("==================================")
|
// println("==================================")
|
||||||
|
@ -11,14 +11,14 @@
|
|||||||
import sokol.gfx
|
import sokol.gfx
|
||||||
import szip
|
import szip
|
||||||
|
|
||||||
fn (mut il Item_list) scan_zip(path string, in_index int) ? {
|
fn (mut il Item_list) scan_zip(path string, in_index int) ! {
|
||||||
println('Scanning ZIP [$path]')
|
println('Scanning ZIP [$path]')
|
||||||
mut zp := szip.open(path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)?
|
mut zp := szip.open(path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)!
|
||||||
n_entries := zp.total()?
|
n_entries := zp.total()!
|
||||||
// println(n_entries)
|
// println(n_entries)
|
||||||
for index in 0 .. n_entries {
|
for index in 0 .. n_entries {
|
||||||
zp.open_entry_by_index(index)?
|
zp.open_entry_by_index(index)!
|
||||||
is_dir := zp.is_dir()?
|
is_dir := zp.is_dir()!
|
||||||
name := zp.name()
|
name := zp.name()
|
||||||
size := zp.size()
|
size := zp.size()
|
||||||
// println("$index ${name} ${size:10} $is_dir")
|
// println("$index ${name} ${size:10} $is_dir")
|
||||||
@ -47,7 +47,7 @@ fn (mut il Item_list) scan_zip(path string, in_index int) ? {
|
|||||||
zp.close()
|
zp.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut app App) load_texture_from_zip() ?(gfx.Image, int, int) {
|
fn (mut app App) load_texture_from_zip() !(gfx.Image, int, int) {
|
||||||
item := app.item_list.lst[app.item_list.item_index]
|
item := app.item_list.lst[app.item_list.item_index]
|
||||||
// println("Load from zip [${item.path}]")
|
// println("Load from zip [${item.path}]")
|
||||||
|
|
||||||
@ -58,15 +58,15 @@ fn (mut app App) load_texture_from_zip() ?(gfx.Image, int, int) {
|
|||||||
}
|
}
|
||||||
app.zip_index = item.container_index
|
app.zip_index = item.container_index
|
||||||
// println("Opening the zip [${item.path}]")
|
// println("Opening the zip [${item.path}]")
|
||||||
app.zip = szip.open(item.path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)?
|
app.zip = szip.open(item.path, szip.CompressionLevel.no_compression, szip.OpenMode.read_only)!
|
||||||
}
|
}
|
||||||
// println("Now get the image")
|
// println("Now get the image")
|
||||||
app.zip.open_entry_by_index(item.container_item_index)?
|
app.zip.open_entry_by_index(item.container_item_index)!
|
||||||
zip_entry_size := int(item.size)
|
zip_entry_size := int(item.size)
|
||||||
|
|
||||||
app.resize_buf_if_needed(zip_entry_size)
|
app.resize_buf_if_needed(zip_entry_size)
|
||||||
|
|
||||||
app.zip.read_entry_buf(app.mem_buf, app.mem_buf_size)?
|
app.zip.read_entry_buf(app.mem_buf, app.mem_buf_size)!
|
||||||
app.zip.close_entry()
|
app.zip.close_entry()
|
||||||
return app.load_texture_from_buffer(app.mem_buf, zip_entry_size)
|
return app.load_texture_from_buffer(app.mem_buf, zip_entry_size)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ fn main() {
|
|||||||
mut app := &App{}
|
mut app := &App{}
|
||||||
app.serve_static('/favicon.ico', 'favicon.ico')
|
app.serve_static('/favicon.ico', 'favicon.ico')
|
||||||
// Automatically make available known static mime types found in given directory.
|
// Automatically make available known static mime types found in given directory.
|
||||||
os.chdir(os.dir(os.executable()))?
|
os.chdir(os.dir(os.executable()))!
|
||||||
app.handle_static('assets', true)
|
app.handle_static('assets', true)
|
||||||
vweb.run(app, port)
|
vweb.run(app, port)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import term
|
|||||||
// it connects to the server who will broadcast your messages
|
// it connects to the server who will broadcast your messages
|
||||||
// to all other connected clients
|
// to all other connected clients
|
||||||
fn main() {
|
fn main() {
|
||||||
mut ws := start_client()?
|
mut ws := start_client()!
|
||||||
println(term.green('client $ws.id ready'))
|
println(term.green('client $ws.id ready'))
|
||||||
println('Write message and enter to send...')
|
println('Write message and enter to send...')
|
||||||
for {
|
for {
|
||||||
@ -16,7 +16,7 @@ fn main() {
|
|||||||
if line == '' {
|
if line == '' {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ws.write_string(line)?
|
ws.write_string(line)!
|
||||||
}
|
}
|
||||||
ws.close(1000, 'normal') or { println(term.red('panicing $err')) }
|
ws.close(1000, 'normal') or { println(term.red('panicing $err')) }
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -24,23 +24,23 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_client() ?&websocket.Client {
|
fn start_client() !&websocket.Client {
|
||||||
mut ws := websocket.new_client('ws://localhost:30000')?
|
mut ws := websocket.new_client('ws://localhost:30000')!
|
||||||
// mut ws := websocket.new_client('wss://echo.websocket.org:443')?
|
// mut ws := websocket.new_client('wss://echo.websocket.org:443')?
|
||||||
// use on_open_ref if you want to send any reference object
|
// use on_open_ref if you want to send any reference object
|
||||||
ws.on_open(fn (mut ws websocket.Client) ? {
|
ws.on_open(fn (mut ws websocket.Client) ! {
|
||||||
println(term.green('websocket connected to the server and ready to send messages...'))
|
println(term.green('websocket connected to the server and ready to send messages...'))
|
||||||
})
|
})
|
||||||
// use on_error_ref if you want to send any reference object
|
// use on_error_ref if you want to send any reference object
|
||||||
ws.on_error(fn (mut ws websocket.Client, err string) ? {
|
ws.on_error(fn (mut ws websocket.Client, err string) ! {
|
||||||
println(term.red('error: $err'))
|
println(term.red('error: $err'))
|
||||||
})
|
})
|
||||||
// use on_close_ref if you want to send any reference object
|
// use on_close_ref if you want to send any reference object
|
||||||
ws.on_close(fn (mut ws websocket.Client, code int, reason string) ? {
|
ws.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
|
||||||
println(term.green('the connection to the server successfully closed'))
|
println(term.green('the connection to the server successfully closed'))
|
||||||
})
|
})
|
||||||
// on new messages from other clients, display them in blue text
|
// on new messages from other clients, display them in blue text
|
||||||
ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
|
ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
|
||||||
if msg.payload.len > 0 {
|
if msg.payload.len > 0 {
|
||||||
message := msg.payload.bytestr()
|
message := msg.payload.bytestr()
|
||||||
println(term.blue('$message'))
|
println(term.blue('$message'))
|
||||||
|
@ -6,24 +6,24 @@ import term
|
|||||||
// this server accepts client connections and broadcast all messages to other connected clients
|
// this server accepts client connections and broadcast all messages to other connected clients
|
||||||
fn main() {
|
fn main() {
|
||||||
println('press ctrl-c to quit...')
|
println('press ctrl-c to quit...')
|
||||||
start_server()?
|
start_server()!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_server() ? {
|
fn start_server() ! {
|
||||||
mut s := websocket.new_server(.ip6, 30000, '')
|
mut s := websocket.new_server(.ip6, 30000, '')
|
||||||
// Make that in execution test time give time to execute at least one time
|
// Make that in execution test time give time to execute at least one time
|
||||||
s.ping_interval = 100
|
s.ping_interval = 100
|
||||||
s.on_connect(fn (mut s websocket.ServerClient) ?bool {
|
s.on_connect(fn (mut s websocket.ServerClient) !bool {
|
||||||
// Here you can look att the client info and accept or not accept
|
// Here you can look att the client info and accept or not accept
|
||||||
// just returning a true/false
|
// just returning a true/false
|
||||||
if s.resource_name != '/' {
|
if s.resource_name != '/' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})?
|
})!
|
||||||
|
|
||||||
// on_message_ref, broadcast all incoming messages to all clients except the one sent it
|
// on_message_ref, broadcast all incoming messages to all clients except the one sent it
|
||||||
s.on_message_ref(fn (mut ws websocket.Client, msg &websocket.Message, mut m websocket.Server) ? {
|
s.on_message_ref(fn (mut ws websocket.Client, msg &websocket.Message, mut m websocket.Server) ! {
|
||||||
// for _, cli in m.clients {
|
// for _, cli in m.clients {
|
||||||
for i, _ in m.clients {
|
for i, _ in m.clients {
|
||||||
mut c := m.clients[i]
|
mut c := m.clients[i]
|
||||||
@ -33,7 +33,7 @@ fn start_server() ? {
|
|||||||
}
|
}
|
||||||
}, s)
|
}, s)
|
||||||
|
|
||||||
s.on_close(fn (mut ws websocket.Client, code int, reason string) ? {
|
s.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
|
||||||
println(term.green('client ($ws.id) closed connection'))
|
println(term.green('client ($ws.id) closed connection'))
|
||||||
})
|
})
|
||||||
s.listen() or { println(term.red('error on server listen: $err')) }
|
s.listen() or { println(term.red('error on server listen: $err')) }
|
||||||
|
@ -6,27 +6,27 @@ import net.websocket
|
|||||||
fn main() {
|
fn main() {
|
||||||
go start_server()
|
go start_server()
|
||||||
time.sleep(100 * time.millisecond)
|
time.sleep(100 * time.millisecond)
|
||||||
start_client()?
|
start_client()!
|
||||||
}
|
}
|
||||||
|
|
||||||
// start_server starts the websocket server, it receives messages
|
// start_server starts the websocket server, it receives messages
|
||||||
// and send it back to the client that sent it
|
// and send it back to the client that sent it
|
||||||
fn start_server() ? {
|
fn start_server() ! {
|
||||||
mut s := websocket.new_server(.ip6, 30000, '')
|
mut s := websocket.new_server(.ip6, 30000, '')
|
||||||
// Make that in execution test time give time to execute at least one time
|
// Make that in execution test time give time to execute at least one time
|
||||||
s.ping_interval = 100
|
s.ping_interval = 100
|
||||||
s.on_connect(fn (mut s websocket.ServerClient) ?bool {
|
s.on_connect(fn (mut s websocket.ServerClient) !bool {
|
||||||
// Here you can look att the client info and accept or not accept
|
// Here you can look att the client info and accept or not accept
|
||||||
// just returning a true/false
|
// just returning a true/false
|
||||||
if s.resource_name != '/' {
|
if s.resource_name != '/' {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})?
|
})!
|
||||||
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
|
s.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
|
||||||
ws.write(msg.payload, msg.opcode) or { panic(err) }
|
ws.write(msg.payload, msg.opcode) or { panic(err) }
|
||||||
})
|
})
|
||||||
s.on_close(fn (mut ws websocket.Client, code int, reason string) ? {
|
s.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
|
||||||
// println('client ($ws.id) closed connection')
|
// println('client ($ws.id) closed connection')
|
||||||
})
|
})
|
||||||
s.listen() or { println('error on server listen: $err') }
|
s.listen() or { println('error on server listen: $err') }
|
||||||
@ -37,23 +37,23 @@ fn start_server() ? {
|
|||||||
|
|
||||||
// start_client starts the websocket client, it writes a message to
|
// start_client starts the websocket client, it writes a message to
|
||||||
// the server and prints all the messages received
|
// the server and prints all the messages received
|
||||||
fn start_client() ? {
|
fn start_client() ! {
|
||||||
mut ws := websocket.new_client('ws://localhost:30000')?
|
mut ws := websocket.new_client('ws://localhost:30000')!
|
||||||
// mut ws := websocket.new_client('wss://echo.websocket.org:443')?
|
// mut ws := websocket.new_client('wss://echo.websocket.org:443')?
|
||||||
// use on_open_ref if you want to send any reference object
|
// use on_open_ref if you want to send any reference object
|
||||||
ws.on_open(fn (mut ws websocket.Client) ? {
|
ws.on_open(fn (mut ws websocket.Client) ! {
|
||||||
println('open!')
|
println('open!')
|
||||||
})
|
})
|
||||||
// use on_error_ref if you want to send any reference object
|
// use on_error_ref if you want to send any reference object
|
||||||
ws.on_error(fn (mut ws websocket.Client, err string) ? {
|
ws.on_error(fn (mut ws websocket.Client, err string) ! {
|
||||||
println('error: $err')
|
println('error: $err')
|
||||||
})
|
})
|
||||||
// use on_close_ref if you want to send any reference object
|
// use on_close_ref if you want to send any reference object
|
||||||
ws.on_close(fn (mut ws websocket.Client, code int, reason string) ? {
|
ws.on_close(fn (mut ws websocket.Client, code int, reason string) ! {
|
||||||
println('closed')
|
println('closed')
|
||||||
})
|
})
|
||||||
// use on_message_ref if you want to send any reference object
|
// use on_message_ref if you want to send any reference object
|
||||||
ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ? {
|
ws.on_message(fn (mut ws websocket.Client, msg &websocket.Message) ! {
|
||||||
if msg.payload.len > 0 {
|
if msg.payload.len > 0 {
|
||||||
message := msg.payload.bytestr()
|
message := msg.payload.bytestr()
|
||||||
println('client got type: $msg.opcode payload:\n$message')
|
println('client got type: $msg.opcode payload:\n$message')
|
||||||
@ -72,7 +72,7 @@ fn start_client() ? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_echo(mut ws websocket.Client) ? {
|
fn write_echo(mut ws websocket.Client) ! {
|
||||||
message := 'echo this'
|
message := 'echo this'
|
||||||
for i := 0; i <= 10; i++ {
|
for i := 0; i <= 10; i++ {
|
||||||
// Server will send pings every 30 seconds
|
// Server will send pings every 30 seconds
|
||||||
|
@ -624,7 +624,7 @@ pub fn (s string) u64() u64 {
|
|||||||
// This method directly exposes the `parse_int` function from `strconv`
|
// This method directly exposes the `parse_int` function from `strconv`
|
||||||
// as a method on `string`. For more advanced features,
|
// as a method on `string`. For more advanced features,
|
||||||
// consider calling `strconv.common_parse_int` directly.
|
// consider calling `strconv.common_parse_int` directly.
|
||||||
pub fn (s string) parse_uint(_base int, _bit_size int) ?u64 {
|
pub fn (s string) parse_uint(_base int, _bit_size int) !u64 {
|
||||||
return strconv.parse_uint(s, _base, _bit_size)
|
return strconv.parse_uint(s, _base, _bit_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,7 +644,7 @@ pub fn (s string) parse_uint(_base int, _bit_size int) ?u64 {
|
|||||||
// This method directly exposes the `parse_uint` function from `strconv`
|
// This method directly exposes the `parse_uint` function from `strconv`
|
||||||
// as a method on `string`. For more advanced features,
|
// as a method on `string`. For more advanced features,
|
||||||
// consider calling `strconv.common_parse_uint` directly.
|
// consider calling `strconv.common_parse_uint` directly.
|
||||||
pub fn (s string) parse_int(_base int, _bit_size int) ?i64 {
|
pub fn (s string) parse_int(_base int, _bit_size int) !i64 {
|
||||||
return strconv.parse_int(s, _base, _bit_size)
|
return strconv.parse_int(s, _base, _bit_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ pub fn get_libname(libname string) string {
|
|||||||
|
|
||||||
// open_opt - loads the dynamic shared object.
|
// open_opt - loads the dynamic shared object.
|
||||||
// Unlike open, open_opt return an option.
|
// Unlike open, open_opt return an option.
|
||||||
pub fn open_opt(filename string, flags int) ?voidptr {
|
pub fn open_opt(filename string, flags int) !voidptr {
|
||||||
shared_object_handle := open(filename, flags)
|
shared_object_handle := open(filename, flags)
|
||||||
if shared_object_handle == 0 {
|
if shared_object_handle == 0 {
|
||||||
e := dlerror()
|
e := dlerror()
|
||||||
@ -39,7 +39,7 @@ pub fn open_opt(filename string, flags int) ?voidptr {
|
|||||||
|
|
||||||
// sym_opt returns the address of a symbol in a given shared object, if found.
|
// sym_opt returns the address of a symbol in a given shared object, if found.
|
||||||
// Unlike sym, sym_opt returns an option.
|
// Unlike sym, sym_opt returns an option.
|
||||||
pub fn sym_opt(shared_object_handle voidptr, symbol string) ?voidptr {
|
pub fn sym_opt(shared_object_handle voidptr, symbol string) !voidptr {
|
||||||
sym_handle := sym(shared_object_handle, symbol)
|
sym_handle := sym(shared_object_handle, symbol)
|
||||||
if sym_handle == 0 {
|
if sym_handle == 0 {
|
||||||
e := dlerror()
|
e := dlerror()
|
||||||
|
@ -71,7 +71,7 @@ pub fn (af []Flag) str() string {
|
|||||||
// That structure is created with `mut parser := flag.new_flag_parser(os.args)`,
|
// That structure is created with `mut parser := flag.new_flag_parser(os.args)`,
|
||||||
// The returned instance can be further customised by calling various methods,
|
// The returned instance can be further customised by calling various methods,
|
||||||
// for specifying the accepted options and their values. The user should finally
|
// for specifying the accepted options and their values. The user should finally
|
||||||
// call `rest := parser.finalize()?` to get the rest of the non optional arguments
|
// call `rest := parser.finalize()!` to get the rest of the non optional arguments
|
||||||
// (if there are any left).
|
// (if there are any left).
|
||||||
pub struct FlagParser {
|
pub struct FlagParser {
|
||||||
pub:
|
pub:
|
||||||
@ -278,7 +278,7 @@ fn (mut fs FlagParser) parse_value(longhand string, shorthand u8) []string {
|
|||||||
// special: it is allowed to define bool flags without value
|
// special: it is allowed to define bool flags without value
|
||||||
// -> '--flag' is parsed as true
|
// -> '--flag' is parsed as true
|
||||||
// -> '--flag' is equal to '--flag=true'
|
// -> '--flag' is equal to '--flag=true'
|
||||||
fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand u8) ?string {
|
fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand u8) !string {
|
||||||
{
|
{
|
||||||
full := '--$longhand'
|
full := '--$longhand'
|
||||||
for i, arg in fs.args {
|
for i, arg in fs.args {
|
||||||
@ -317,7 +317,7 @@ fn (mut fs FlagParser) parse_bool_value(longhand string, shorthand u8) ?string {
|
|||||||
// bool_opt returns an option with the bool value of the given command line flag, named `name`.
|
// bool_opt returns an option with the bool value of the given command line flag, named `name`.
|
||||||
// It returns an error, when the flag is not given by the user.
|
// It returns an error, when the flag is not given by the user.
|
||||||
// This version supports abbreviations.
|
// This version supports abbreviations.
|
||||||
pub fn (mut fs FlagParser) bool_opt(name string, abbr u8, usage string) ?bool {
|
pub fn (mut fs FlagParser) bool_opt(name string, abbr u8, usage string) !bool {
|
||||||
mut res := false
|
mut res := false
|
||||||
{
|
{
|
||||||
fs.add_flag(name, abbr, usage, '<bool>')
|
fs.add_flag(name, abbr, usage, '<bool>')
|
||||||
@ -354,7 +354,7 @@ pub fn (mut fs FlagParser) int_multi(name string, abbr u8, usage string) []int {
|
|||||||
// int_opt returns an option with the integer value, associated with the flag in `name`.
|
// int_opt returns an option with the integer value, associated with the flag in `name`.
|
||||||
// When the flag is not given by the user, it returns an error.
|
// When the flag is not given by the user, it returns an error.
|
||||||
// This version supports abbreviations.
|
// This version supports abbreviations.
|
||||||
pub fn (mut fs FlagParser) int_opt(name string, abbr u8, usage string) ?int {
|
pub fn (mut fs FlagParser) int_opt(name string, abbr u8, usage string) !int {
|
||||||
mut res := 0
|
mut res := 0
|
||||||
{
|
{
|
||||||
fs.add_flag(name, abbr, usage, '<int>')
|
fs.add_flag(name, abbr, usage, '<int>')
|
||||||
@ -393,7 +393,7 @@ pub fn (mut fs FlagParser) float_multi(name string, abbr u8, usage string) []f64
|
|||||||
// float_opt returns an option with the floating point value, associated with the flag in `name`.
|
// float_opt returns an option with the floating point value, associated with the flag in `name`.
|
||||||
// When the flag is not given by the user, it returns an error.
|
// When the flag is not given by the user, it returns an error.
|
||||||
// This version supports abbreviations.
|
// This version supports abbreviations.
|
||||||
pub fn (mut fs FlagParser) float_opt(name string, abbr u8, usage string) ?f64 {
|
pub fn (mut fs FlagParser) float_opt(name string, abbr u8, usage string) !f64 {
|
||||||
mut res := 0.0
|
mut res := 0.0
|
||||||
{
|
{
|
||||||
fs.add_flag(name, abbr, usage, '<float>')
|
fs.add_flag(name, abbr, usage, '<float>')
|
||||||
@ -426,7 +426,7 @@ pub fn (mut fs FlagParser) string_multi(name string, abbr u8, usage string) []st
|
|||||||
// string_opt returns an option with the string value, associated with the flag in `name`.
|
// string_opt returns an option with the string value, associated with the flag in `name`.
|
||||||
// When the flag is not given by the user, it returns an error.
|
// When the flag is not given by the user, it returns an error.
|
||||||
// This version supports abbreviations.
|
// This version supports abbreviations.
|
||||||
pub fn (mut fs FlagParser) string_opt(name string, abbr u8, usage string) ?string {
|
pub fn (mut fs FlagParser) string_opt(name string, abbr u8, usage string) !string {
|
||||||
mut res := ''
|
mut res := ''
|
||||||
{
|
{
|
||||||
fs.add_flag(name, abbr, usage, '<string>')
|
fs.add_flag(name, abbr, usage, '<string>')
|
||||||
@ -451,7 +451,7 @@ pub fn (mut fs FlagParser) string(name string, abbr u8, sdefault string, usage s
|
|||||||
// limit_free_args_to_at_least restricts the list of free arguments (non options) to be
|
// limit_free_args_to_at_least restricts the list of free arguments (non options) to be
|
||||||
// at least `n` in length. If the user gives less free arguments to the program,
|
// at least `n` in length. If the user gives less free arguments to the program,
|
||||||
// the parser will return an error.
|
// the parser will return an error.
|
||||||
pub fn (mut fs FlagParser) limit_free_args_to_at_least(n int) ? {
|
pub fn (mut fs FlagParser) limit_free_args_to_at_least(n int) ! {
|
||||||
if n > flag.max_args_number {
|
if n > flag.max_args_number {
|
||||||
return error('flag.limit_free_args_to_at_least expect n to be smaller than $flag.max_args_number')
|
return error('flag.limit_free_args_to_at_least expect n to be smaller than $flag.max_args_number')
|
||||||
}
|
}
|
||||||
@ -464,7 +464,7 @@ pub fn (mut fs FlagParser) limit_free_args_to_at_least(n int) ? {
|
|||||||
// limit_free_args_to_exactly restricts the list of free arguments (non options) to be
|
// limit_free_args_to_exactly restricts the list of free arguments (non options) to be
|
||||||
// at exactly `n` in length. If the user gives more or less free arguments to the program,
|
// at exactly `n` in length. If the user gives more or less free arguments to the program,
|
||||||
// the parser will return an error.
|
// the parser will return an error.
|
||||||
pub fn (mut fs FlagParser) limit_free_args_to_exactly(n int) ? {
|
pub fn (mut fs FlagParser) limit_free_args_to_exactly(n int) ! {
|
||||||
if n > flag.max_args_number {
|
if n > flag.max_args_number {
|
||||||
return error('flag.limit_free_args_to_exactly expect n to be smaller than $flag.max_args_number')
|
return error('flag.limit_free_args_to_exactly expect n to be smaller than $flag.max_args_number')
|
||||||
}
|
}
|
||||||
@ -478,7 +478,7 @@ pub fn (mut fs FlagParser) limit_free_args_to_exactly(n int) ? {
|
|||||||
// limit_free_args restricts the list of free arguments (non options) to be between
|
// limit_free_args restricts the list of free arguments (non options) to be between
|
||||||
// `min` and `max` in length. If the user gives more or less free arguments to the program,
|
// `min` and `max` in length. If the user gives more or less free arguments to the program,
|
||||||
// the parser will return an error.
|
// the parser will return an error.
|
||||||
pub fn (mut fs FlagParser) limit_free_args(min int, max int) ? {
|
pub fn (mut fs FlagParser) limit_free_args(min int, max int) ! {
|
||||||
if min > max {
|
if min > max {
|
||||||
return error('flag.limit_free_args expect min < max, got $min >= $max')
|
return error('flag.limit_free_args expect min < max, got $min >= $max')
|
||||||
}
|
}
|
||||||
@ -578,7 +578,7 @@ pub fn (fs FlagParser) usage() string {
|
|||||||
|
|
||||||
// find_existing_flag looks up the given flag by name, and returns
|
// find_existing_flag looks up the given flag by name, and returns
|
||||||
// it, if it was found in the FlagParser. If it was not, it returns an error.
|
// it, if it was found in the FlagParser. If it was not, it returns an error.
|
||||||
fn (mut fs FlagParser) find_existing_flag(fname string) ?Flag {
|
fn (mut fs FlagParser) find_existing_flag(fname string) !Flag {
|
||||||
for f in fs.flags {
|
for f in fs.flags {
|
||||||
if f.name == fname {
|
if f.name == fname {
|
||||||
return f
|
return f
|
||||||
@ -614,7 +614,7 @@ fn (mut fs FlagParser) handle_builtin_options() {
|
|||||||
// The remaining arguments are returned in the same order they are
|
// The remaining arguments are returned in the same order they are
|
||||||
// defined on the command line. If additional flags are found, i.e.
|
// defined on the command line. If additional flags are found, i.e.
|
||||||
// (things starting with '--' or '-'), it returns an error.
|
// (things starting with '--' or '-'), it returns an error.
|
||||||
pub fn (mut fs FlagParser) finalize() ?[]string {
|
pub fn (mut fs FlagParser) finalize() ![]string {
|
||||||
fs.handle_builtin_options()
|
fs.handle_builtin_options()
|
||||||
mut remaining := fs.args.clone()
|
mut remaining := fs.args.clone()
|
||||||
if !fs.allow_unknown_args {
|
if !fs.allow_unknown_args {
|
||||||
|
@ -153,9 +153,9 @@ fn test_finalize_returns_error_for_unknown_flags_short() {
|
|||||||
assert finalized.len < 0 // expect error to be returned
|
assert finalized.len < 0 // expect error to be returned
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_allow_to_build_usage_message() ? {
|
fn test_allow_to_build_usage_message() {
|
||||||
mut fp := flag.new_flag_parser([])
|
mut fp := flag.new_flag_parser([])
|
||||||
fp.limit_free_args(1, 4)?
|
fp.limit_free_args(1, 4)!
|
||||||
fp.application('flag_tool')
|
fp.application('flag_tool')
|
||||||
fp.version('v0.0.0')
|
fp.version('v0.0.0')
|
||||||
fp.description('some short information about this tool')
|
fp.description('some short information about this tool')
|
||||||
@ -194,9 +194,9 @@ fn test_if_no_options_given_usage_message_does_not_contain_options() {
|
|||||||
assert !fp.usage().contains('Options:')
|
assert !fp.usage().contains('Options:')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_free_args_could_be_limited() ? {
|
fn test_free_args_could_be_limited() {
|
||||||
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
||||||
fp1.limit_free_args(1, 4)?
|
fp1.limit_free_args(1, 4)!
|
||||||
args := fp1.finalize() or {
|
args := fp1.finalize() or {
|
||||||
assert false
|
assert false
|
||||||
return
|
return
|
||||||
@ -206,9 +206,9 @@ fn test_free_args_could_be_limited() ? {
|
|||||||
assert args[2] == 'c'
|
assert args[2] == 'c'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_error_for_to_few_free_args() ? {
|
fn test_error_for_to_few_free_args() {
|
||||||
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
||||||
fp1.limit_free_args(5, 6)?
|
fp1.limit_free_args(5, 6)!
|
||||||
args := fp1.finalize() or {
|
args := fp1.finalize() or {
|
||||||
assert err.msg().starts_with('Expected at least 5 arguments')
|
assert err.msg().starts_with('Expected at least 5 arguments')
|
||||||
return
|
return
|
||||||
@ -216,9 +216,9 @@ fn test_error_for_to_few_free_args() ? {
|
|||||||
assert args.len < 0 // expect an error and need to use args
|
assert args.len < 0 // expect an error and need to use args
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_error_for_to_much_free_args() ? {
|
fn test_error_for_to_much_free_args() {
|
||||||
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
mut fp1 := flag.new_flag_parser(['a', 'b', 'c'])
|
||||||
fp1.limit_free_args(1, 2)?
|
fp1.limit_free_args(1, 2)!
|
||||||
args := fp1.finalize() or {
|
args := fp1.finalize() or {
|
||||||
assert err.msg().starts_with('Expected at most 2 arguments')
|
assert err.msg().starts_with('Expected at most 2 arguments')
|
||||||
return
|
return
|
||||||
@ -226,9 +226,9 @@ fn test_error_for_to_much_free_args() ? {
|
|||||||
assert args.len < 0 // expect an error and need to use args
|
assert args.len < 0 // expect an error and need to use args
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_could_expect_no_free_args() ? {
|
fn test_could_expect_no_free_args() {
|
||||||
mut fp1 := flag.new_flag_parser(['a'])
|
mut fp1 := flag.new_flag_parser(['a'])
|
||||||
fp1.limit_free_args(0, 0)?
|
fp1.limit_free_args(0, 0)!
|
||||||
args := fp1.finalize() or {
|
args := fp1.finalize() or {
|
||||||
assert err.msg().starts_with('Expected no arguments')
|
assert err.msg().starts_with('Expected no arguments')
|
||||||
return
|
return
|
||||||
@ -383,7 +383,7 @@ fn test_optional_flags() {
|
|||||||
assert b == 'some_default_value'
|
assert b == 'some_default_value'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_dashdash_acts_as_parser_full_stop() ? {
|
fn test_dashdash_acts_as_parser_full_stop() {
|
||||||
mut fp := flag.new_flag_parser(['-b', '5', '--', '-d', '-x', '-b', '4', '-a', '-c', 'hello',
|
mut fp := flag.new_flag_parser(['-b', '5', '--', '-d', '-x', '-b', '4', '-a', '-c', 'hello',
|
||||||
'some', 'other', 'parameters'])
|
'some', 'other', 'parameters'])
|
||||||
a := fp.bool_opt('a-bool-flag', `a`, '') or { false }
|
a := fp.bool_opt('a-bool-flag', `a`, '') or { false }
|
||||||
@ -392,17 +392,17 @@ fn test_dashdash_acts_as_parser_full_stop() ? {
|
|||||||
assert a == false
|
assert a == false
|
||||||
assert b == 5
|
assert b == 5
|
||||||
assert c == 'default'
|
assert c == 'default'
|
||||||
args := fp.finalize()?
|
args := fp.finalize()!
|
||||||
assert args.len > 0
|
assert args.len > 0
|
||||||
assert args[0] != '--'
|
assert args[0] != '--'
|
||||||
assert args == ['-d', '-x', '-b', '4', '-a', '-c', 'hello', 'some', 'other', 'parameters']
|
assert args == ['-d', '-x', '-b', '4', '-a', '-c', 'hello', 'some', 'other', 'parameters']
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_dashdash_acts_as_parser_full_stop_dashdash_at_end() ? {
|
fn test_dashdash_acts_as_parser_full_stop_dashdash_at_end() {
|
||||||
mut fp := flag.new_flag_parser(['-b', '5', '-b', '4', 'other', 'params', '--'])
|
mut fp := flag.new_flag_parser(['-b', '5', '-b', '4', 'other', 'params', '--'])
|
||||||
b := fp.int_multi('an-int-flag', `b`, '')
|
b := fp.int_multi('an-int-flag', `b`, '')
|
||||||
assert b == [5, 4]
|
assert b == [5, 4]
|
||||||
args := fp.finalize()?
|
args := fp.finalize()!
|
||||||
assert args.len > 0
|
assert args.len > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,9 +107,9 @@ pub fn (r BufferedReader) end_of_stream() bool {
|
|||||||
// read_line attempts to read a line from the buffered reader
|
// read_line attempts to read a line from the buffered reader
|
||||||
// it will read until it finds a new line character (\n) or
|
// it will read until it finds a new line character (\n) or
|
||||||
// the end of stream
|
// the end of stream
|
||||||
pub fn (mut r BufferedReader) read_line() ?string {
|
pub fn (mut r BufferedReader) read_line() !string {
|
||||||
if r.end_of_stream {
|
if r.end_of_stream {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
mut line := []u8{}
|
mut line := []u8{}
|
||||||
for {
|
for {
|
||||||
@ -119,7 +119,7 @@ pub fn (mut r BufferedReader) read_line() ?string {
|
|||||||
// We are at the end of the stream
|
// We are at the end of the stream
|
||||||
if line.len == 0 {
|
if line.len == 0 {
|
||||||
// we had nothing so return nothing
|
// we had nothing so return nothing
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
return line.bytestr()
|
return line.bytestr()
|
||||||
}
|
}
|
||||||
@ -144,5 +144,5 @@ pub fn (mut r BufferedReader) read_line() ?string {
|
|||||||
line << r.buf[r.offset..i]
|
line << r.buf[r.offset..i]
|
||||||
r.offset = i
|
r.offset = i
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ const (
|
|||||||
buf_max_len = 1024
|
buf_max_len = 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
pub fn cp(mut src Reader, mut dst Writer) ? {
|
pub fn cp(mut src Reader, mut dst Writer) ! {
|
||||||
mut buf := []u8{len: io.buf_max_len}
|
mut buf := []u8{len: io.buf_max_len}
|
||||||
for {
|
for {
|
||||||
len := src.read(mut buf) or { break }
|
len := src.read(mut buf) or { break }
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
|
||||||
fn test_cp() ? {
|
fn test_cp() {
|
||||||
mut f := os.open(@FILE) or { panic(err) }
|
mut f := os.open(@FILE) or { panic(err) }
|
||||||
defer {
|
defer {
|
||||||
f.close()
|
f.close()
|
||||||
}
|
}
|
||||||
mut r := io.new_buffered_reader(reader: f)
|
mut r := io.new_buffered_reader(reader: f)
|
||||||
mut stdout := os.stdout()
|
mut stdout := os.stdout()
|
||||||
io.cp(mut r, mut stdout)?
|
io.cp(mut r, mut stdout)!
|
||||||
assert true
|
assert true
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ fn (mut b Buf) read(mut buf []u8) !int {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut w Writ) write(buf []u8) ?int {
|
fn (mut w Writ) write(buf []u8) !int {
|
||||||
if buf.len <= 0 {
|
if buf.len <= 0 {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
w.bytes << buf
|
w.bytes << buf
|
||||||
return buf.len
|
return buf.len
|
||||||
|
@ -22,9 +22,9 @@ pub mut:
|
|||||||
// written. If any writer fails to write the full length an error is returned
|
// written. If any writer fails to write the full length an error is returned
|
||||||
// and writing to other writers stops. If any writer returns an error the error
|
// and writing to other writers stops. If any writer returns an error the error
|
||||||
// is returned immediately and writing to other writers stops.
|
// is returned immediately and writing to other writers stops.
|
||||||
pub fn (mut m MultiWriter) write(buf []u8) ?int {
|
pub fn (mut m MultiWriter) write(buf []u8) !int {
|
||||||
for mut w in m.writers {
|
for mut w in m.writers {
|
||||||
n := w.write(buf)?
|
n := w.write(buf)!
|
||||||
if n != buf.len {
|
if n != buf.len {
|
||||||
return error('io: incomplete write to writer of MultiWriter')
|
return error('io: incomplete write to writer of MultiWriter')
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ pub mut:
|
|||||||
bytes []u8
|
bytes []u8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut w TestWriter) write(buf []u8) ?int {
|
fn (mut w TestWriter) write(buf []u8) !int {
|
||||||
w.bytes << buf
|
w.bytes << buf
|
||||||
return buf.len
|
return buf.len
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ pub mut:
|
|||||||
bytes []u8
|
bytes []u8
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut w TestIncompleteWriter) write(buf []u8) ?int {
|
fn (mut w TestIncompleteWriter) write(buf []u8) !int {
|
||||||
b := buf[..buf.len - 1]
|
b := buf[..buf.len - 1]
|
||||||
w.bytes << b
|
w.bytes << b
|
||||||
return b.len
|
return b.len
|
||||||
@ -61,6 +61,6 @@ fn (mut w TestIncompleteWriter) write(buf []u8) ?int {
|
|||||||
|
|
||||||
struct TestErrorWriter {}
|
struct TestErrorWriter {}
|
||||||
|
|
||||||
fn (mut w TestErrorWriter) write(buf []u8) ?int {
|
fn (mut w TestErrorWriter) write(buf []u8) !int {
|
||||||
return error('error writer errored')
|
return error('error writer errored')
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ mut:
|
|||||||
|
|
||||||
// read_all reads all bytes from a reader until either a 0 length read
|
// read_all reads all bytes from a reader until either a 0 length read
|
||||||
// or if read_to_end_of_stream is true then the end of the stream (`none`)
|
// or if read_to_end_of_stream is true then the end of the stream (`none`)
|
||||||
pub fn read_all(config ReadAllConfig) ?[]u8 {
|
pub fn read_all(config ReadAllConfig) ![]u8 {
|
||||||
mut r := config.reader
|
mut r := config.reader
|
||||||
read_till_eof := config.read_to_end_of_stream
|
read_till_eof := config.read_to_end_of_stream
|
||||||
|
|
||||||
@ -65,11 +65,11 @@ pub fn read_all(config ReadAllConfig) ?[]u8 {
|
|||||||
|
|
||||||
// read_any reads any available bytes from a reader
|
// read_any reads any available bytes from a reader
|
||||||
// (until the reader returns a read of 0 length)
|
// (until the reader returns a read of 0 length)
|
||||||
pub fn read_any(mut r Reader) ?[]u8 {
|
pub fn read_any(mut r Reader) ![]u8 {
|
||||||
mut b := []u8{len: io.read_all_len}
|
mut b := []u8{len: io.read_all_len}
|
||||||
mut read := 0
|
mut read := 0
|
||||||
for {
|
for {
|
||||||
new_read := r.read(mut b[read..]) or { return none }
|
new_read := r.read(mut b[read..]) or { return error('none') }
|
||||||
read += new_read
|
read += new_read
|
||||||
if new_read == 0 {
|
if new_read == 0 {
|
||||||
break
|
break
|
||||||
@ -83,5 +83,5 @@ pub fn read_any(mut r Reader) ?[]u8 {
|
|||||||
|
|
||||||
// RandomReader represents a stream of data that can be read from at a random location
|
// RandomReader represents a stream of data that can be read from at a random location
|
||||||
pub interface RandomReader {
|
pub interface RandomReader {
|
||||||
read_from(pos u64, mut buf []u8) ?int
|
read_from(pos u64, mut buf []u8) !int
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ pub fn (mut r ReaderWriterImpl) read(mut buf []u8) !int {
|
|||||||
return r.r.read(mut buf)
|
return r.r.read(mut buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut r ReaderWriterImpl) write(buf []u8) ?int {
|
pub fn (mut r ReaderWriterImpl) write(buf []u8) !int {
|
||||||
return r.w.write(buf)
|
return r.w.write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ pub struct TempFileOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// temp_file returns an uniquely named, open, writable, `os.File` and it's path
|
// temp_file returns an uniquely named, open, writable, `os.File` and it's path
|
||||||
pub fn temp_file(tfo TempFileOptions) ?(os.File, string) {
|
pub fn temp_file(tfo TempFileOptions) !(os.File, string) {
|
||||||
mut d := tfo.path
|
mut d := tfo.path
|
||||||
if d == '' {
|
if d == '' {
|
||||||
d = os.temp_dir()
|
d = os.temp_dir()
|
||||||
@ -47,7 +47,7 @@ pub struct TempDirOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// temp_dir returns an uniquely named, writable, directory path
|
// temp_dir returns an uniquely named, writable, directory path
|
||||||
pub fn temp_dir(tdo TempFileOptions) ?string {
|
pub fn temp_dir(tdo TempFileOptions) !string {
|
||||||
mut d := tdo.path
|
mut d := tdo.path
|
||||||
if d == '' {
|
if d == '' {
|
||||||
d = os.temp_dir()
|
d = os.temp_dir()
|
||||||
|
@ -3,11 +3,11 @@ module io
|
|||||||
// Writer represents a stream of data that can be wrote to
|
// Writer represents a stream of data that can be wrote to
|
||||||
pub interface Writer {
|
pub interface Writer {
|
||||||
mut:
|
mut:
|
||||||
write(buf []u8) ?int
|
write(buf []u8) !int
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomWriter represents a stream of data that can be wrote to
|
// RandomWriter represents a stream of data that can be wrote to
|
||||||
// at a random pos
|
// at a random pos
|
||||||
pub interface RandomWriter {
|
pub interface RandomWriter {
|
||||||
write_to(pos u64, buf []u8) ?int
|
write_to(pos u64, buf []u8) !int
|
||||||
}
|
}
|
||||||
|
@ -44,15 +44,15 @@ fn new_ip(port u16, addr [4]u8) Addr {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
fn temp_unix() ?Addr {
|
fn temp_unix() !Addr {
|
||||||
// create a temp file to get a filename
|
// create a temp file to get a filename
|
||||||
// close it
|
// close it
|
||||||
// remove it
|
// remove it
|
||||||
// then reuse the filename
|
// then reuse the filename
|
||||||
mut file, filename := util.temp_file()?
|
mut file, filename := util.temp_file()!
|
||||||
file.close()
|
file.close()
|
||||||
os.rm(filename)?
|
os.rm(filename)!
|
||||||
addrs := resolve_addrs(filename, .unix, .udp)?
|
addrs := resolve_addrs(filename, .unix, .udp)!
|
||||||
return addrs[0]
|
return addrs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ fn (a Addr) len() u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ?[]Addr {
|
pub fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ![]Addr {
|
||||||
match family {
|
match family {
|
||||||
.ip, .ip6, .unspec {
|
.ip, .ip6, .unspec {
|
||||||
return resolve_ipaddrs(addr, family, @type)
|
return resolve_ipaddrs(addr, family, @type)
|
||||||
@ -143,9 +143,9 @@ pub fn resolve_addrs(addr string, family AddrFamily, @type SocketType) ?[]Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ?[]Addr {
|
pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ![]Addr {
|
||||||
if addr.len == 0 {
|
if addr.len == 0 {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a small heuristic to figure out what address family this is
|
// Use a small heuristic to figure out what address family this is
|
||||||
@ -160,8 +160,8 @@ pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ?[]Addr {
|
|||||||
return resolve_addrs(addr, .unix, @type)
|
return resolve_addrs(addr, .unix, @type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ?[]Addr {
|
pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr {
|
||||||
address, port := split_address(addr)?
|
address, port := split_address(addr)!
|
||||||
|
|
||||||
if addr[0] == `:` {
|
if addr[0] == `:` {
|
||||||
match family {
|
match family {
|
||||||
@ -191,10 +191,10 @@ pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ?[]Addr {
|
|||||||
|
|
||||||
// This might look silly but is recommended by MSDN
|
// This might look silly but is recommended by MSDN
|
||||||
$if windows {
|
$if windows {
|
||||||
socket_error(0 - C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results))?
|
socket_error(0 - C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results))!
|
||||||
} $else {
|
} $else {
|
||||||
x := C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results)
|
x := C.getaddrinfo(&char(address.str), &char(sport.str), &hints, &results)
|
||||||
wrap_error(x)?
|
wrap_error(x)!
|
||||||
}
|
}
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
|
@ -17,18 +17,18 @@ pub const no_timeout = time.Duration(0)
|
|||||||
pub const infinite_timeout = time.infinite
|
pub const infinite_timeout = time.infinite
|
||||||
|
|
||||||
// Shutdown shutsdown a socket and closes it
|
// Shutdown shutsdown a socket and closes it
|
||||||
fn shutdown(handle int) ? {
|
fn shutdown(handle int) ! {
|
||||||
$if windows {
|
$if windows {
|
||||||
C.shutdown(handle, C.SD_BOTH)
|
C.shutdown(handle, C.SD_BOTH)
|
||||||
socket_error(C.closesocket(handle))?
|
socket_error(C.closesocket(handle))!
|
||||||
} $else {
|
} $else {
|
||||||
C.shutdown(handle, C.SHUT_RDWR)
|
C.shutdown(handle, C.SHUT_RDWR)
|
||||||
socket_error(C.close(handle))?
|
socket_error(C.close(handle))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select waits for an io operation (specified by parameter `test`) to be available
|
// Select waits for an io operation (specified by parameter `test`) to be available
|
||||||
fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||||
set := C.fd_set{}
|
set := C.fd_set{}
|
||||||
|
|
||||||
C.FD_ZERO(&set)
|
C.FD_ZERO(&set)
|
||||||
@ -52,13 +52,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
|||||||
|
|
||||||
match test {
|
match test {
|
||||||
.read {
|
.read {
|
||||||
socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))?
|
socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.write {
|
.write {
|
||||||
socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))?
|
socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.except {
|
.except {
|
||||||
socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))?
|
socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn select_deadline(handle int, test Select, deadline time.Time) ?bool {
|
fn select_deadline(handle int, test Select, deadline time.Time) !bool {
|
||||||
// if we have a 0 deadline here then the timeout that was passed was infinite...
|
// if we have a 0 deadline here then the timeout that was passed was infinite...
|
||||||
infinite := deadline.unix_time() == 0
|
infinite := deadline.unix_time() == 0
|
||||||
for infinite || time.now() <= deadline {
|
for infinite || time.now() <= deadline {
|
||||||
@ -89,7 +89,7 @@ fn select_deadline(handle int, test Select, deadline time.Time) ?bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait_for_common wraps the common wait code
|
// wait_for_common wraps the common wait code
|
||||||
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? {
|
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ! {
|
||||||
// Convert timeouts to deadlines
|
// Convert timeouts to deadlines
|
||||||
real_deadline := if timeout == net.infinite_timeout {
|
real_deadline := if timeout == net.infinite_timeout {
|
||||||
time.unix(0)
|
time.unix(0)
|
||||||
@ -104,7 +104,7 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
|
|||||||
time.now().add(timeout)
|
time.now().add(timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
ready := select_deadline(handle, test, real_deadline)?
|
ready := select_deadline(handle, test, real_deadline)!
|
||||||
|
|
||||||
if ready {
|
if ready {
|
||||||
return
|
return
|
||||||
@ -114,11 +114,11 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait_for_write waits for a write io operation to be available
|
// wait_for_write waits for a write io operation to be available
|
||||||
fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ? {
|
fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ! {
|
||||||
return wait_for_common(handle, deadline, timeout, .write)
|
return wait_for_common(handle, deadline, timeout, .write)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait_for_read waits for a read io operation to be available
|
// wait_for_read waits for a read io operation to be available
|
||||||
fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ? {
|
fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ! {
|
||||||
return wait_for_common(handle, deadline, timeout, .read)
|
return wait_for_common(handle, deadline, timeout, .read)
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,11 @@ pub const (
|
|||||||
err_connection_refused = error_with_code('net: connection refused', errors_base + 10)
|
err_connection_refused = error_with_code('net: connection refused', errors_base + 10)
|
||||||
)
|
)
|
||||||
|
|
||||||
pub fn socket_error_message(potential_code int, s string) ?int {
|
pub fn socket_error_message(potential_code int, s string) !int {
|
||||||
return socket_error(potential_code) or { return error('$err.msg(); $s') }
|
return socket_error(potential_code) or { return error('$err.msg(); $s') }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn socket_error(potential_code int) ?int {
|
pub fn socket_error(potential_code int) !int {
|
||||||
$if windows {
|
$if windows {
|
||||||
if potential_code < 0 {
|
if potential_code < 0 {
|
||||||
last_error_int := C.WSAGetLastError()
|
last_error_int := C.WSAGetLastError()
|
||||||
@ -43,7 +43,7 @@ pub fn socket_error(potential_code int) ?int {
|
|||||||
return potential_code
|
return potential_code
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wrap_error(error_code int) ? {
|
pub fn wrap_error(error_code int) ! {
|
||||||
if error_code == 0 {
|
if error_code == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -59,17 +59,17 @@ pub fn wrap_error(error_code int) ? {
|
|||||||
// connection termination and returns none
|
// connection termination and returns none
|
||||||
// e.g. res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))?
|
// e.g. res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))?
|
||||||
[inline]
|
[inline]
|
||||||
fn wrap_read_result(result int) ?int {
|
fn wrap_read_result(result int) !int {
|
||||||
if result == 0 {
|
if result == 0 {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn wrap_write_result(result int) ?int {
|
fn wrap_write_result(result int) !int {
|
||||||
if result == 0 {
|
if result == 0 {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ mut:
|
|||||||
port int
|
port int
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut dtp DTP) read() ?[]u8 {
|
fn (mut dtp DTP) read() ![]u8 {
|
||||||
mut data := []u8{}
|
mut data := []u8{}
|
||||||
mut buf := []u8{len: 1024}
|
mut buf := []u8{len: 1024}
|
||||||
for {
|
for {
|
||||||
@ -75,15 +75,15 @@ pub fn new() FTP {
|
|||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut zftp FTP) write(data string) ?int {
|
fn (mut zftp FTP) write(data string) !int {
|
||||||
$if debug {
|
$if debug {
|
||||||
println('FTP.v >>> $data')
|
println('FTP.v >>> $data')
|
||||||
}
|
}
|
||||||
return zftp.conn.write('$data\r\n'.bytes())
|
return zftp.conn.write('$data\r\n'.bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut zftp FTP) read() ?(int, string) {
|
fn (mut zftp FTP) read() !(int, string) {
|
||||||
mut data := zftp.reader.read_line()?
|
mut data := zftp.reader.read_line()!
|
||||||
$if debug {
|
$if debug {
|
||||||
println('FTP.v <<< $data')
|
println('FTP.v <<< $data')
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ fn (mut zftp FTP) read() ?(int, string) {
|
|||||||
code := data[..3].int()
|
code := data[..3].int()
|
||||||
if data[3] == `-` {
|
if data[3] == `-` {
|
||||||
for {
|
for {
|
||||||
data = zftp.reader.read_line()?
|
data = zftp.reader.read_line()!
|
||||||
if data[..3].int() == code && data[3] != `-` {
|
if data[..3].int() == code && data[3] != `-` {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -103,10 +103,10 @@ fn (mut zftp FTP) read() ?(int, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// connect establishes an FTP connection to the host at `ip` port 21.
|
// connect establishes an FTP connection to the host at `ip` port 21.
|
||||||
pub fn (mut zftp FTP) connect(ip string) ?bool {
|
pub fn (mut zftp FTP) connect(ip string) !bool {
|
||||||
zftp.conn = net.dial_tcp('$ip:21')?
|
zftp.conn = net.dial_tcp('$ip:21')!
|
||||||
zftp.reader = io.new_buffered_reader(reader: zftp.conn)
|
zftp.reader = io.new_buffered_reader(reader: zftp.conn)
|
||||||
code, _ := zftp.read()?
|
code, _ := zftp.read()!
|
||||||
if code == ftp.connected {
|
if code == ftp.connected {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -114,14 +114,14 @@ pub fn (mut zftp FTP) connect(ip string) ?bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// login sends the "USER `user`" and "PASS `passwd`" commands to the remote host.
|
// login sends the "USER `user`" and "PASS `passwd`" commands to the remote host.
|
||||||
pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
|
pub fn (mut zftp FTP) login(user string, passwd string) !bool {
|
||||||
zftp.write('USER $user') or {
|
zftp.write('USER $user') or {
|
||||||
$if debug {
|
$if debug {
|
||||||
println('ERROR sending user')
|
println('ERROR sending user')
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
mut code, _ := zftp.read()?
|
mut code, _ := zftp.read()!
|
||||||
if code == ftp.logged_in {
|
if code == ftp.logged_in {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
code, _ = zftp.read()?
|
code, _ = zftp.read()!
|
||||||
if code == ftp.logged_in {
|
if code == ftp.logged_in {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -142,15 +142,15 @@ pub fn (mut zftp FTP) login(user string, passwd string) ?bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// close closes the FTP connection.
|
// close closes the FTP connection.
|
||||||
pub fn (mut zftp FTP) close() ? {
|
pub fn (mut zftp FTP) close() ! {
|
||||||
zftp.write('QUIT')?
|
zftp.write('QUIT')!
|
||||||
zftp.conn.close()?
|
zftp.conn.close()!
|
||||||
}
|
}
|
||||||
|
|
||||||
// pwd returns the current working directory on the remote host for the logged in user.
|
// pwd returns the current working directory on the remote host for the logged in user.
|
||||||
pub fn (mut zftp FTP) pwd() ?string {
|
pub fn (mut zftp FTP) pwd() !string {
|
||||||
zftp.write('PWD')?
|
zftp.write('PWD')!
|
||||||
_, data := zftp.read()?
|
_, data := zftp.read()!
|
||||||
spl := data.split('"') // "
|
spl := data.split('"') // "
|
||||||
if spl.len >= 2 {
|
if spl.len >= 2 {
|
||||||
return spl[1]
|
return spl[1]
|
||||||
@ -159,9 +159,9 @@ pub fn (mut zftp FTP) pwd() ?string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cd changes the current working directory to the specified remote directory `dir`.
|
// cd changes the current working directory to the specified remote directory `dir`.
|
||||||
pub fn (mut zftp FTP) cd(dir string) ? {
|
pub fn (mut zftp FTP) cd(dir string) ! {
|
||||||
zftp.write('CWD $dir') or { return }
|
zftp.write('CWD $dir') or { return }
|
||||||
mut code, mut data := zftp.read()?
|
mut code, mut data := zftp.read()!
|
||||||
match int(code) {
|
match int(code) {
|
||||||
ftp.denied {
|
ftp.denied {
|
||||||
$if debug {
|
$if debug {
|
||||||
@ -169,7 +169,7 @@ pub fn (mut zftp FTP) cd(dir string) ? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ftp.complete {
|
ftp.complete {
|
||||||
code, data = zftp.read()?
|
code, data = zftp.read()!
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
@ -178,7 +178,7 @@ pub fn (mut zftp FTP) cd(dir string) ? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_dtp(msg string) ?&DTP {
|
fn new_dtp(msg string) !&DTP {
|
||||||
if !is_dtp_message_valid(msg) {
|
if !is_dtp_message_valid(msg) {
|
||||||
return error('Bad message')
|
return error('Bad message')
|
||||||
}
|
}
|
||||||
@ -194,32 +194,32 @@ fn new_dtp(msg string) ?&DTP {
|
|||||||
return dtp
|
return dtp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut zftp FTP) pasv() ?&DTP {
|
fn (mut zftp FTP) pasv() !&DTP {
|
||||||
zftp.write('PASV')?
|
zftp.write('PASV')!
|
||||||
code, data := zftp.read()?
|
code, data := zftp.read()!
|
||||||
$if debug {
|
$if debug {
|
||||||
println('pass: $data')
|
println('pass: $data')
|
||||||
}
|
}
|
||||||
if code != ftp.passive_mode {
|
if code != ftp.passive_mode {
|
||||||
return error('pasive mode not allowed')
|
return error('pasive mode not allowed')
|
||||||
}
|
}
|
||||||
dtp := new_dtp(data)?
|
dtp := new_dtp(data)!
|
||||||
return dtp
|
return dtp
|
||||||
}
|
}
|
||||||
|
|
||||||
// dir returns a list of the files in the current working directory.
|
// dir returns a list of the files in the current working directory.
|
||||||
pub fn (mut zftp FTP) dir() ?[]string {
|
pub fn (mut zftp FTP) dir() ![]string {
|
||||||
mut dtp := zftp.pasv() or { return error('Cannot establish data connection') }
|
mut dtp := zftp.pasv() or { return error('Cannot establish data connection') }
|
||||||
zftp.write('LIST')?
|
zftp.write('LIST')!
|
||||||
code, _ := zftp.read()?
|
code, _ := zftp.read()!
|
||||||
if code == ftp.denied {
|
if code == ftp.denied {
|
||||||
return error('`LIST` denied')
|
return error('`LIST` denied')
|
||||||
}
|
}
|
||||||
if code != ftp.open_data_connection {
|
if code != ftp.open_data_connection {
|
||||||
return error('Data channel empty')
|
return error('Data channel empty')
|
||||||
}
|
}
|
||||||
list_dir := dtp.read()?
|
list_dir := dtp.read()!
|
||||||
result, _ := zftp.read()?
|
result, _ := zftp.read()!
|
||||||
if result != ftp.close_data_connection {
|
if result != ftp.close_data_connection {
|
||||||
println('`LIST` not ok')
|
println('`LIST` not ok')
|
||||||
}
|
}
|
||||||
@ -235,17 +235,17 @@ pub fn (mut zftp FTP) dir() ?[]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get retrieves `file` from the remote host.
|
// get retrieves `file` from the remote host.
|
||||||
pub fn (mut zftp FTP) get(file string) ?[]u8 {
|
pub fn (mut zftp FTP) get(file string) ![]u8 {
|
||||||
mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') }
|
mut dtp := zftp.pasv() or { return error('Cannot stablish data connection') }
|
||||||
zftp.write('RETR $file')?
|
zftp.write('RETR $file')!
|
||||||
code, _ := zftp.read()?
|
code, _ := zftp.read()!
|
||||||
if code == ftp.denied {
|
if code == ftp.denied {
|
||||||
return error('Permission denied')
|
return error('Permission denied')
|
||||||
}
|
}
|
||||||
if code != ftp.open_data_connection {
|
if code != ftp.open_data_connection {
|
||||||
return error('Data connection not ready')
|
return error('Data connection not ready')
|
||||||
}
|
}
|
||||||
blob := dtp.read()?
|
blob := dtp.read()!
|
||||||
dtp.close()
|
dtp.close()
|
||||||
return blob
|
return blob
|
||||||
}
|
}
|
||||||
|
@ -11,17 +11,17 @@ fn test_ftp_cleint() {
|
|||||||
ftp_client_test_inside() or { panic(err) }
|
ftp_client_test_inside() or { panic(err) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ftp_client_test_inside() ? {
|
fn ftp_client_test_inside() ! {
|
||||||
mut zftp := ftp.new()
|
mut zftp := ftp.new()
|
||||||
// eprintln(zftp)
|
// eprintln(zftp)
|
||||||
defer {
|
defer {
|
||||||
zftp.close() or { panic(err) }
|
zftp.close() or { panic(err) }
|
||||||
}
|
}
|
||||||
connect_result := zftp.connect('ftp.redhat.com')?
|
connect_result := zftp.connect('ftp.redhat.com')!
|
||||||
assert connect_result
|
assert connect_result
|
||||||
login_result := zftp.login('ftp', 'ftp')?
|
login_result := zftp.login('ftp', 'ftp')!
|
||||||
assert login_result
|
assert login_result
|
||||||
pwd := zftp.pwd()?
|
pwd := zftp.pwd()!
|
||||||
assert pwd.len > 0
|
assert pwd.len > 0
|
||||||
zftp.cd('/') or {
|
zftp.cd('/') or {
|
||||||
assert false
|
assert false
|
||||||
|
@ -6,14 +6,14 @@ module http
|
|||||||
import net.ssl
|
import net.ssl
|
||||||
import strings
|
import strings
|
||||||
|
|
||||||
fn (req &Request) ssl_do(port int, method Method, host_name string, path string) ?Response {
|
fn (req &Request) ssl_do(port int, method Method, host_name string, path string) !Response {
|
||||||
mut ssl_conn := ssl.new_ssl_conn(
|
mut ssl_conn := ssl.new_ssl_conn(
|
||||||
verify: req.verify
|
verify: req.verify
|
||||||
cert: req.cert
|
cert: req.cert
|
||||||
cert_key: req.cert_key
|
cert_key: req.cert_key
|
||||||
validate: req.validate
|
validate: req.validate
|
||||||
in_memory_verification: req.in_memory_verification
|
in_memory_verification: req.in_memory_verification
|
||||||
)?
|
)!
|
||||||
ssl_conn.dial(host_name, port) or { return err }
|
ssl_conn.dial(host_name, port) or { return err }
|
||||||
|
|
||||||
req_headers := req.build_request_headers(method, host_name, path)
|
req_headers := req.build_request_headers(method, host_name, path)
|
||||||
@ -38,7 +38,7 @@ fn (req &Request) ssl_do(port int, method Method, host_name string, path string)
|
|||||||
}
|
}
|
||||||
unsafe { content.write_ptr(bp, len) }
|
unsafe { content.write_ptr(bp, len) }
|
||||||
}
|
}
|
||||||
ssl_conn.shutdown()?
|
ssl_conn.shutdown()!
|
||||||
response_text := content.str()
|
response_text := content.str()
|
||||||
$if trace_http_response ? {
|
$if trace_http_response ? {
|
||||||
eprintln('< $response_text')
|
eprintln('< $response_text')
|
||||||
|
@ -13,7 +13,7 @@ $if gcboehm ? {
|
|||||||
|
|
||||||
fn C.new_tls_context() C.TlsContext
|
fn C.new_tls_context() C.TlsContext
|
||||||
|
|
||||||
fn (req &Request) ssl_do(port int, method Method, host_name string, path string) ?Response {
|
fn (req &Request) ssl_do(port int, method Method, host_name string, path string) !Response {
|
||||||
mut ctx := C.new_tls_context()
|
mut ctx := C.new_tls_context()
|
||||||
C.vschannel_init(&ctx)
|
C.vschannel_init(&ctx)
|
||||||
mut buff := unsafe { malloc_noscan(C.vsc_init_resp_buff_size) }
|
mut buff := unsafe { malloc_noscan(C.vsc_init_resp_buff_size) }
|
||||||
|
@ -294,7 +294,7 @@ pub fn is_cookie_domain_name(_s string) bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cookie_value(_raw string, allow_double_quote bool) ?string {
|
fn parse_cookie_value(_raw string, allow_double_quote bool) !string {
|
||||||
mut raw := _raw
|
mut raw := _raw
|
||||||
// Strip the quotes, if present
|
// Strip the quotes, if present
|
||||||
if allow_double_quote && raw.len > 1 && raw[0] == `"` && raw[raw.len - 1] == `"` {
|
if allow_double_quote && raw.len > 1 && raw[0] == `"` && raw[raw.len - 1] == `"` {
|
||||||
@ -320,7 +320,7 @@ fn is_cookie_name_valid(name string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cookie(line string) ?Cookie {
|
fn parse_cookie(line string) !Cookie {
|
||||||
mut parts := line.trim_space().split(';')
|
mut parts := line.trim_space().split(';')
|
||||||
if parts.len == 1 && parts[0] == '' {
|
if parts.len == 1 && parts[0] == '' {
|
||||||
return error('malformed cookie')
|
return error('malformed cookie')
|
||||||
|
@ -7,7 +7,7 @@ import os
|
|||||||
|
|
||||||
// download_file retrieves a document from the URL `url`,
|
// download_file retrieves a document from the URL `url`,
|
||||||
// and saves it in the output file path `out_file_path`.
|
// and saves it in the output file path `out_file_path`.
|
||||||
pub fn download_file(url string, out_file_path string) ? {
|
pub fn download_file(url string, out_file_path string) ! {
|
||||||
$if debug_http ? {
|
$if debug_http ? {
|
||||||
println('http.download_file url=$url out_file_path=$out_file_path')
|
println('http.download_file url=$url out_file_path=$out_file_path')
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ pub fn download_file(url string, out_file_path string) ? {
|
|||||||
$if debug_http ? {
|
$if debug_http ? {
|
||||||
println('http.download_file saving $s.body.len bytes')
|
println('http.download_file saving $s.body.len bytes')
|
||||||
}
|
}
|
||||||
os.write_file(out_file_path, s.body)?
|
os.write_file(out_file_path, s.body)!
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement download_file_with_progress
|
// TODO: implement download_file_with_progress
|
||||||
|
@ -363,9 +363,9 @@ pub fn new_header_from_map(kvs map[CommonHeader]string) Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// new_custom_header_from_map creates a Header from string key value pairs
|
// new_custom_header_from_map creates a Header from string key value pairs
|
||||||
pub fn new_custom_header_from_map(kvs map[string]string) ?Header {
|
pub fn new_custom_header_from_map(kvs map[string]string) !Header {
|
||||||
mut h := new_header()
|
mut h := new_header()
|
||||||
h.add_custom_map(kvs)?
|
h.add_custom_map(kvs)!
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,8 +378,8 @@ pub fn (mut h Header) add(key CommonHeader, value string) {
|
|||||||
|
|
||||||
// add_custom appends a value to a custom header key. This function will
|
// add_custom appends a value to a custom header key. This function will
|
||||||
// return an error if the key contains invalid header characters.
|
// return an error if the key contains invalid header characters.
|
||||||
pub fn (mut h Header) add_custom(key string, value string) ? {
|
pub fn (mut h Header) add_custom(key string, value string) ! {
|
||||||
is_valid(key)?
|
is_valid(key)!
|
||||||
h.data[key] << value
|
h.data[key] << value
|
||||||
h.add_key(key)
|
h.add_key(key)
|
||||||
}
|
}
|
||||||
@ -392,9 +392,9 @@ pub fn (mut h Header) add_map(kvs map[CommonHeader]string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add_custom_map appends the value for each custom header key.
|
// add_custom_map appends the value for each custom header key.
|
||||||
pub fn (mut h Header) add_custom_map(kvs map[string]string) ? {
|
pub fn (mut h Header) add_custom_map(kvs map[string]string) ! {
|
||||||
for k, v in kvs {
|
for k, v in kvs {
|
||||||
h.add_custom(k, v)?
|
h.add_custom(k, v)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,8 +410,8 @@ pub fn (mut h Header) set(key CommonHeader, value string) {
|
|||||||
// function will clear any other values that exist for the header. This
|
// function will clear any other values that exist for the header. This
|
||||||
// function will return an error if the key contains invalid header
|
// function will return an error if the key contains invalid header
|
||||||
// characters.
|
// characters.
|
||||||
pub fn (mut h Header) set_custom(key string, value string) ? {
|
pub fn (mut h Header) set_custom(key string, value string) ! {
|
||||||
is_valid(key)?
|
is_valid(key)!
|
||||||
h.data[key] = [value]
|
h.data[key] = [value]
|
||||||
h.add_key(key)
|
h.add_key(key)
|
||||||
}
|
}
|
||||||
@ -479,37 +479,37 @@ pub fn (h Header) contains_custom(key string, flags HeaderQueryConfig) bool {
|
|||||||
|
|
||||||
// get gets the first value for the CommonHeader, or none if the key
|
// get gets the first value for the CommonHeader, or none if the key
|
||||||
// does not exist.
|
// does not exist.
|
||||||
pub fn (h Header) get(key CommonHeader) ?string {
|
pub fn (h Header) get(key CommonHeader) !string {
|
||||||
return h.get_custom(key.str())
|
return h.get_custom(key.str())
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_custom gets the first value for the custom header, or none if
|
// get_custom gets the first value for the custom header, or none if
|
||||||
// the key does not exist.
|
// the key does not exist.
|
||||||
pub fn (h Header) get_custom(key string, flags HeaderQueryConfig) ?string {
|
pub fn (h Header) get_custom(key string, flags HeaderQueryConfig) !string {
|
||||||
mut data_key := key
|
mut data_key := key
|
||||||
if !flags.exact {
|
if !flags.exact {
|
||||||
// get the first key from key metadata
|
// get the first key from key metadata
|
||||||
k := key.to_lower()
|
k := key.to_lower()
|
||||||
if h.keys[k].len == 0 {
|
if h.keys[k].len == 0 {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
data_key = h.keys[k][0]
|
data_key = h.keys[k][0]
|
||||||
}
|
}
|
||||||
if h.data[data_key].len == 0 {
|
if h.data[data_key].len == 0 {
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
return h.data[data_key][0]
|
return h.data[data_key][0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// starting_with gets the first header starting with key, or none if
|
// starting_with gets the first header starting with key, or none if
|
||||||
// the key does not exist.
|
// the key does not exist.
|
||||||
pub fn (h Header) starting_with(key string) ?string {
|
pub fn (h Header) starting_with(key string) !string {
|
||||||
for k, _ in h.data {
|
for k, _ in h.data {
|
||||||
if k.starts_with(key) {
|
if k.starts_with(key) {
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
// values gets all values for the CommonHeader.
|
// values gets all values for the CommonHeader.
|
||||||
@ -642,7 +642,7 @@ pub fn (err HeaderKeyError) code() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// is_valid checks if the header token contains all valid bytes
|
// is_valid checks if the header token contains all valid bytes
|
||||||
fn is_valid(header string) ? {
|
fn is_valid(header string) ! {
|
||||||
for _, c in header {
|
for _, c in header {
|
||||||
if int(c) >= 128 || !is_token(c) {
|
if int(c) >= 128 || !is_token(c) {
|
||||||
return IError(HeaderKeyError{
|
return IError(HeaderKeyError{
|
||||||
@ -676,7 +676,7 @@ pub fn (h Header) str() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse_headers parses a newline delimited string into a Header struct
|
// parse_headers parses a newline delimited string into a Header struct
|
||||||
fn parse_headers(s string) ?Header {
|
fn parse_headers(s string) !Header {
|
||||||
mut h := new_header()
|
mut h := new_header()
|
||||||
mut last_key := ''
|
mut last_key := ''
|
||||||
mut last_value := ''
|
mut last_value := ''
|
||||||
@ -689,15 +689,15 @@ fn parse_headers(s string) ?Header {
|
|||||||
last_value += ' ${line.trim(' \t')}'
|
last_value += ' ${line.trim(' \t')}'
|
||||||
continue
|
continue
|
||||||
} else if last_key != '' {
|
} else if last_key != '' {
|
||||||
h.add_custom(last_key, last_value)?
|
h.add_custom(last_key, last_value)!
|
||||||
}
|
}
|
||||||
last_key, last_value = parse_header(line)?
|
last_key, last_value = parse_header(line)!
|
||||||
}
|
}
|
||||||
h.add_custom(last_key, last_value)?
|
h.add_custom(last_key, last_value)!
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_header(s string) ?(string, string) {
|
fn parse_header(s string) !(string, string) {
|
||||||
if !s.contains(':') {
|
if !s.contains(':') {
|
||||||
return error('missing colon in header')
|
return error('missing colon in header')
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ pub mut:
|
|||||||
allow_redirect bool = true // whether to allow redirect
|
allow_redirect bool = true // whether to allow redirect
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_request(method Method, url_ string, data string) ?Request {
|
pub fn new_request(method Method, url_ string, data string) !Request {
|
||||||
url := if method == .get && !url_.contains('?') { url_ + '?' + data } else { url_ }
|
url := if method == .get && !url_.contains('?') { url_ + '?' + data } else { url_ }
|
||||||
// println('new req() method=$method url="$url" dta="$data"')
|
// println('new req() method=$method url="$url" dta="$data"')
|
||||||
return Request{
|
return Request{
|
||||||
@ -47,12 +47,12 @@ pub fn new_request(method Method, url_ string, data string) ?Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get sends a GET HTTP request to the URL
|
// get sends a GET HTTP request to the URL
|
||||||
pub fn get(url string) ?Response {
|
pub fn get(url string) !Response {
|
||||||
return fetch(method: .get, url: url)
|
return fetch(method: .get, url: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// post sends a POST HTTP request to the URL with a string data
|
// post sends a POST HTTP request to the URL with a string data
|
||||||
pub fn post(url string, data string) ?Response {
|
pub fn post(url string, data string) !Response {
|
||||||
return fetch(
|
return fetch(
|
||||||
method: .post
|
method: .post
|
||||||
url: url
|
url: url
|
||||||
@ -62,7 +62,7 @@ pub fn post(url string, data string) ?Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// post_json sends a POST HTTP request to the URL with a JSON data
|
// post_json sends a POST HTTP request to the URL with a JSON data
|
||||||
pub fn post_json(url string, data string) ?Response {
|
pub fn post_json(url string, data string) !Response {
|
||||||
return fetch(
|
return fetch(
|
||||||
method: .post
|
method: .post
|
||||||
url: url
|
url: url
|
||||||
@ -72,7 +72,7 @@ pub fn post_json(url string, data string) ?Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// post_form sends a POST HTTP request to the URL with X-WWW-FORM-URLENCODED data
|
// post_form sends a POST HTTP request to the URL with X-WWW-FORM-URLENCODED data
|
||||||
pub fn post_form(url string, data map[string]string) ?Response {
|
pub fn post_form(url string, data map[string]string) !Response {
|
||||||
return fetch(
|
return fetch(
|
||||||
method: .post
|
method: .post
|
||||||
url: url
|
url: url
|
||||||
@ -90,7 +90,7 @@ pub mut:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// post_multipart_form sends a POST HTTP request to the URL with multipart form data
|
// post_multipart_form sends a POST HTTP request to the URL with multipart form data
|
||||||
pub fn post_multipart_form(url string, conf PostMultipartFormConfig) ?Response {
|
pub fn post_multipart_form(url string, conf PostMultipartFormConfig) !Response {
|
||||||
body, boundary := multipart_form_body(conf.form, conf.files)
|
body, boundary := multipart_form_body(conf.form, conf.files)
|
||||||
mut header := conf.header
|
mut header := conf.header
|
||||||
header.set(.content_type, 'multipart/form-data; boundary="$boundary"')
|
header.set(.content_type, 'multipart/form-data; boundary="$boundary"')
|
||||||
@ -103,7 +103,7 @@ pub fn post_multipart_form(url string, conf PostMultipartFormConfig) ?Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// put sends a PUT HTTP request to the URL with a string data
|
// put sends a PUT HTTP request to the URL with a string data
|
||||||
pub fn put(url string, data string) ?Response {
|
pub fn put(url string, data string) !Response {
|
||||||
return fetch(
|
return fetch(
|
||||||
method: .put
|
method: .put
|
||||||
url: url
|
url: url
|
||||||
@ -113,7 +113,7 @@ pub fn put(url string, data string) ?Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// patch sends a PATCH HTTP request to the URL with a string data
|
// patch sends a PATCH HTTP request to the URL with a string data
|
||||||
pub fn patch(url string, data string) ?Response {
|
pub fn patch(url string, data string) !Response {
|
||||||
return fetch(
|
return fetch(
|
||||||
method: .patch
|
method: .patch
|
||||||
url: url
|
url: url
|
||||||
@ -123,17 +123,17 @@ pub fn patch(url string, data string) ?Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// head sends a HEAD HTTP request to the URL
|
// head sends a HEAD HTTP request to the URL
|
||||||
pub fn head(url string) ?Response {
|
pub fn head(url string) !Response {
|
||||||
return fetch(method: .head, url: url)
|
return fetch(method: .head, url: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete sends a DELETE HTTP request to the URL
|
// delete sends a DELETE HTTP request to the URL
|
||||||
pub fn delete(url string) ?Response {
|
pub fn delete(url string) !Response {
|
||||||
return fetch(method: .delete, url: url)
|
return fetch(method: .delete, url: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch sends an HTTP request to the URL with the given method and configurations
|
// fetch sends an HTTP request to the URL with the given method and configurations
|
||||||
pub fn fetch(config FetchConfig) ?Response {
|
pub fn fetch(config FetchConfig) !Response {
|
||||||
if config.url == '' {
|
if config.url == '' {
|
||||||
return error('http.fetch: empty url')
|
return error('http.fetch: empty url')
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ pub fn fetch(config FetchConfig) ?Response {
|
|||||||
in_memory_verification: config.in_memory_verification
|
in_memory_verification: config.in_memory_verification
|
||||||
allow_redirect: config.allow_redirect
|
allow_redirect: config.allow_redirect
|
||||||
}
|
}
|
||||||
res := req.do()?
|
res := req.do()!
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,14 +176,14 @@ pub fn url_encode_form_data(data map[string]string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[deprecated: 'use fetch()']
|
[deprecated: 'use fetch()']
|
||||||
fn fetch_with_method(method Method, _config FetchConfig) ?Response {
|
fn fetch_with_method(method Method, _config FetchConfig) !Response {
|
||||||
mut config := _config
|
mut config := _config
|
||||||
config.method = method
|
config.method = method
|
||||||
return fetch(config)
|
return fetch(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_url_from_fetch(config FetchConfig) ?string {
|
fn build_url_from_fetch(config FetchConfig) !string {
|
||||||
mut url := urllib.parse(config.url)?
|
mut url := urllib.parse(config.url)!
|
||||||
if config.params.len == 0 {
|
if config.params.len == 0 {
|
||||||
return url.str()
|
return url.str()
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ struct HttpbinResponseBody {
|
|||||||
url string
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response {
|
fn http_fetch_mock(_methods []string, _config FetchConfig) ![]Response {
|
||||||
url := 'https://httpbin.org/'
|
url := 'https://httpbin.org/'
|
||||||
methods := if _methods.len == 0 { ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'] } else { _methods }
|
methods := if _methods.len == 0 { ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'] } else { _methods }
|
||||||
mut config := _config
|
mut config := _config
|
||||||
@ -23,7 +23,7 @@ fn http_fetch_mock(_methods []string, _config FetchConfig) ?[]Response {
|
|||||||
for method in methods {
|
for method in methods {
|
||||||
lmethod := method.to_lower()
|
lmethod := method.to_lower()
|
||||||
config.method = method_from_str(method)
|
config.method = method_from_str(method)
|
||||||
res := fetch(FetchConfig{ ...config, url: url + lmethod })?
|
res := fetch(FetchConfig{ ...config, url: url + lmethod })!
|
||||||
// TODO
|
// TODO
|
||||||
// body := json.decode(HttpbinResponseBody,res.body)?
|
// body := json.decode(HttpbinResponseBody,res.body)?
|
||||||
result << res
|
result << res
|
||||||
@ -75,12 +75,12 @@ fn test_http_fetch_with_params() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_http_fetch_with_headers() ? {
|
fn test_http_fetch_with_headers() ! {
|
||||||
$if !network ? {
|
$if !network ? {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mut header := new_header()
|
mut header := new_header()
|
||||||
header.add_custom('Test-Header', 'hello world')?
|
header.add_custom('Test-Header', 'hello world')!
|
||||||
responses := http_fetch_mock([],
|
responses := http_fetch_mock([],
|
||||||
header: header
|
header: header
|
||||||
) or { panic(err) }
|
) or { panic(err) }
|
||||||
|
@ -48,12 +48,12 @@ pub fn (mut req Request) add_header(key CommonHeader, val string) {
|
|||||||
|
|
||||||
// add_custom_header adds the key and value of an HTTP request header
|
// add_custom_header adds the key and value of an HTTP request header
|
||||||
// This method may fail if the key contains characters that are not permitted
|
// This method may fail if the key contains characters that are not permitted
|
||||||
pub fn (mut req Request) add_custom_header(key string, val string) ? {
|
pub fn (mut req Request) add_custom_header(key string, val string) ! {
|
||||||
return req.header.add_custom(key, val)
|
return req.header.add_custom(key, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// do will send the HTTP request and returns `http.Response` as soon as the response is recevied
|
// do will send the HTTP request and returns `http.Response` as soon as the response is recevied
|
||||||
pub fn (req &Request) do() ?Response {
|
pub fn (req &Request) do() !Response {
|
||||||
mut url := urllib.parse(req.url) or { return error('http.Request.do: invalid url $req.url') }
|
mut url := urllib.parse(req.url) or { return error('http.Request.do: invalid url $req.url') }
|
||||||
mut rurl := url
|
mut rurl := url
|
||||||
mut resp := Response{}
|
mut resp := Response{}
|
||||||
@ -62,7 +62,7 @@ pub fn (req &Request) do() ?Response {
|
|||||||
if no_redirects == max_redirects {
|
if no_redirects == max_redirects {
|
||||||
return error('http.request.do: maximum number of redirects reached ($max_redirects)')
|
return error('http.request.do: maximum number of redirects reached ($max_redirects)')
|
||||||
}
|
}
|
||||||
qresp := req.method_and_url_to_response(req.method, rurl)?
|
qresp := req.method_and_url_to_response(req.method, rurl)!
|
||||||
resp = qresp
|
resp = qresp
|
||||||
if !req.allow_redirect {
|
if !req.allow_redirect {
|
||||||
break
|
break
|
||||||
@ -88,7 +88,7 @@ pub fn (req &Request) do() ?Response {
|
|||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (req &Request) method_and_url_to_response(method Method, url urllib.URL) ?Response {
|
fn (req &Request) method_and_url_to_response(method Method, url urllib.URL) !Response {
|
||||||
host_name := url.hostname()
|
host_name := url.hostname()
|
||||||
scheme := url.scheme
|
scheme := url.scheme
|
||||||
p := url.escaped_path().trim_left('/')
|
p := url.escaped_path().trim_left('/')
|
||||||
@ -105,11 +105,11 @@ fn (req &Request) method_and_url_to_response(method Method, url urllib.URL) ?Res
|
|||||||
// println('fetch $method, $scheme, $host_name, $nport, $path ')
|
// println('fetch $method, $scheme, $host_name, $nport, $path ')
|
||||||
if scheme == 'https' {
|
if scheme == 'https' {
|
||||||
// println('ssl_do( $nport, $method, $host_name, $path )')
|
// println('ssl_do( $nport, $method, $host_name, $path )')
|
||||||
res := req.ssl_do(nport, method, host_name, path)?
|
res := req.ssl_do(nport, method, host_name, path)!
|
||||||
return res
|
return res
|
||||||
} else if scheme == 'http' {
|
} else if scheme == 'http' {
|
||||||
// println('http_do( $nport, $method, $host_name, $path )')
|
// println('http_do( $nport, $method, $host_name, $path )')
|
||||||
res := req.http_do('$host_name:$nport', method, path)?
|
res := req.http_do('$host_name:$nport', method, path)!
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
return error('http.request.method_and_url_to_response: unsupported scheme: "$scheme"')
|
return error('http.request.method_and_url_to_response: unsupported scheme: "$scheme"')
|
||||||
@ -151,19 +151,19 @@ fn (req &Request) build_request_cookies_header() string {
|
|||||||
return 'Cookie: ' + cookie.join('; ') + '\r\n'
|
return 'Cookie: ' + cookie.join('; ') + '\r\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (req &Request) http_do(host string, method Method, path string) ?Response {
|
fn (req &Request) http_do(host string, method Method, path string) !Response {
|
||||||
host_name, _ := net.split_address(host)?
|
host_name, _ := net.split_address(host)!
|
||||||
s := req.build_request_headers(method, host_name, path)
|
s := req.build_request_headers(method, host_name, path)
|
||||||
mut client := net.dial_tcp(host)?
|
mut client := net.dial_tcp(host)!
|
||||||
client.set_read_timeout(req.read_timeout)
|
client.set_read_timeout(req.read_timeout)
|
||||||
client.set_write_timeout(req.write_timeout)
|
client.set_write_timeout(req.write_timeout)
|
||||||
// TODO this really needs to be exposed somehow
|
// TODO this really needs to be exposed somehow
|
||||||
client.write(s.bytes())?
|
client.write(s.bytes())!
|
||||||
$if trace_http_request ? {
|
$if trace_http_request ? {
|
||||||
eprintln('> $s')
|
eprintln('> $s')
|
||||||
}
|
}
|
||||||
mut bytes := io.read_all(reader: client)?
|
mut bytes := io.read_all(reader: client)!
|
||||||
client.close()?
|
client.close()!
|
||||||
response_text := bytes.bytestr()
|
response_text := bytes.bytestr()
|
||||||
$if trace_http_response ? {
|
$if trace_http_response ? {
|
||||||
eprintln('< $response_text')
|
eprintln('< $response_text')
|
||||||
@ -178,8 +178,8 @@ pub fn (req &Request) referer() string {
|
|||||||
|
|
||||||
// parse_request parses a raw HTTP request into a Request object.
|
// parse_request parses a raw HTTP request into a Request object.
|
||||||
// See also: `parse_request_head`, which parses only the headers.
|
// See also: `parse_request_head`, which parses only the headers.
|
||||||
pub fn parse_request(mut reader io.BufferedReader) ?Request {
|
pub fn parse_request(mut reader io.BufferedReader) !Request {
|
||||||
mut request := parse_request_head(mut reader)?
|
mut request := parse_request_head(mut reader)!
|
||||||
|
|
||||||
// body
|
// body
|
||||||
mut body := []u8{}
|
mut body := []u8{}
|
||||||
@ -199,18 +199,18 @@ pub fn parse_request(mut reader io.BufferedReader) ?Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parse_request_head parses *only* the header of a raw HTTP request into a Request object
|
// parse_request_head parses *only* the header of a raw HTTP request into a Request object
|
||||||
pub fn parse_request_head(mut reader io.BufferedReader) ?Request {
|
pub fn parse_request_head(mut reader io.BufferedReader) !Request {
|
||||||
// request line
|
// request line
|
||||||
mut line := reader.read_line()?
|
mut line := reader.read_line()!
|
||||||
method, target, version := parse_request_line(line)?
|
method, target, version := parse_request_line(line)!
|
||||||
|
|
||||||
// headers
|
// headers
|
||||||
mut header := new_header()
|
mut header := new_header()
|
||||||
line = reader.read_line()?
|
line = reader.read_line()!
|
||||||
for line != '' {
|
for line != '' {
|
||||||
key, value := parse_header(line)?
|
key, value := parse_header(line)!
|
||||||
header.add_custom(key, value)?
|
header.add_custom(key, value)!
|
||||||
line = reader.read_line()?
|
line = reader.read_line()!
|
||||||
}
|
}
|
||||||
header.coerce(canonicalize: true)
|
header.coerce(canonicalize: true)
|
||||||
|
|
||||||
@ -228,13 +228,13 @@ pub fn parse_request_head(mut reader io.BufferedReader) ?Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_request_line(s string) ?(Method, urllib.URL, Version) {
|
fn parse_request_line(s string) !(Method, urllib.URL, Version) {
|
||||||
words := s.split(' ')
|
words := s.split(' ')
|
||||||
if words.len != 3 {
|
if words.len != 3 {
|
||||||
return error('malformed request line')
|
return error('malformed request line')
|
||||||
}
|
}
|
||||||
method := method_from_str(words[0])
|
method := method_from_str(words[0])
|
||||||
target := urllib.parse(words[1])?
|
target := urllib.parse(words[1])!
|
||||||
version := version_from_str(words[2])
|
version := version_from_str(words[2])
|
||||||
if version == .unknown {
|
if version == .unknown {
|
||||||
return error('unsupported version')
|
return error('unsupported version')
|
||||||
|
@ -178,7 +178,7 @@ fn test_parse_large_body() {
|
|||||||
body := 'A'.repeat(101) // greater than max_bytes
|
body := 'A'.repeat(101) // greater than max_bytes
|
||||||
req := 'GET / HTTP/1.1\r\nContent-Length: $body.len\r\n\r\n$body'
|
req := 'GET / HTTP/1.1\r\nContent-Length: $body.len\r\n\r\n$body'
|
||||||
mut reader_ := reader(req)
|
mut reader_ := reader(req)
|
||||||
result := parse_request(mut reader_)?
|
result := parse_request(mut reader_)!
|
||||||
assert result.data.len == body.len
|
assert result.data.len == body.len
|
||||||
assert result.data == body
|
assert result.data == body
|
||||||
}
|
}
|
||||||
|
@ -35,11 +35,11 @@ pub fn (resp Response) bytestr() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse a raw HTTP response into a Response object
|
// Parse a raw HTTP response into a Response object
|
||||||
pub fn parse_response(resp string) ?Response {
|
pub fn parse_response(resp string) !Response {
|
||||||
version, status_code, status_msg := parse_status_line(resp.all_before('\n'))?
|
version, status_code, status_msg := parse_status_line(resp.all_before('\n'))!
|
||||||
// Build resp header map and separate the body
|
// Build resp header map and separate the body
|
||||||
start_idx, end_idx := find_headers_range(resp)?
|
start_idx, end_idx := find_headers_range(resp)!
|
||||||
header := parse_headers(resp.substr(start_idx, end_idx))?
|
header := parse_headers(resp.substr(start_idx, end_idx))!
|
||||||
mut body := resp.substr(end_idx, resp.len)
|
mut body := resp.substr(end_idx, resp.len)
|
||||||
if header.get(.transfer_encoding) or { '' } == 'chunked' {
|
if header.get(.transfer_encoding) or { '' } == 'chunked' {
|
||||||
body = chunked.decode(body)
|
body = chunked.decode(body)
|
||||||
@ -56,7 +56,7 @@ pub fn parse_response(resp string) ?Response {
|
|||||||
|
|
||||||
// parse_status_line parses the first HTTP response line into the HTTP
|
// parse_status_line parses the first HTTP response line into the HTTP
|
||||||
// version, status code, and reason phrase
|
// version, status code, and reason phrase
|
||||||
fn parse_status_line(line string) ?(string, int, string) {
|
fn parse_status_line(line string) !(string, int, string) {
|
||||||
if line.len < 5 || line[..5].to_lower() != 'http/' {
|
if line.len < 5 || line[..5].to_lower() != 'http/' {
|
||||||
return error('response does not start with HTTP/')
|
return error('response does not start with HTTP/')
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ fn parse_status_line(line string) ?(string, int, string) {
|
|||||||
for digit in digits {
|
for digit in digits {
|
||||||
strconv.atoi(digit) or { return error('HTTP version must contain only integers') }
|
strconv.atoi(digit) or { return error('HTTP version must contain only integers') }
|
||||||
}
|
}
|
||||||
return version, strconv.atoi(data[1])?, data[2]
|
return version, strconv.atoi(data[1])!, data[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
// cookies parses the Set-Cookie headers into Cookie objects
|
// cookies parses the Set-Cookie headers into Cookie objects
|
||||||
@ -138,7 +138,7 @@ pub fn new_response(conf ResponseConfig) Response {
|
|||||||
// index of the headers in the string, including the trailing newlines. This
|
// index of the headers in the string, including the trailing newlines. This
|
||||||
// helper function expects the first line in `data` to be the HTTP status line
|
// helper function expects the first line in `data` to be the HTTP status line
|
||||||
// (HTTP/1.1 200 OK).
|
// (HTTP/1.1 200 OK).
|
||||||
fn find_headers_range(data string) ?(int, int) {
|
fn find_headers_range(data string) !(int, int) {
|
||||||
start_idx := data.index('\n') or { return error('no start index found') } + 1
|
start_idx := data.index('\n') or { return error('no start index found') } + 1
|
||||||
mut count := 0
|
mut count := 0
|
||||||
for i := start_idx; i < data.len; i++ {
|
for i := start_idx; i < data.len; i++ {
|
||||||
|
@ -26,7 +26,7 @@ fn test_response_bytestr() {
|
|||||||
// check_headers is a helper function for asserting all expected headers
|
// check_headers is a helper function for asserting all expected headers
|
||||||
// are found because rendered header order is not guaranteed. The check
|
// are found because rendered header order is not guaranteed. The check
|
||||||
// is O(n^2) which is fine for small lists.
|
// is O(n^2) which is fine for small lists.
|
||||||
fn check_headers(expected []string, found []string) ? {
|
fn check_headers(expected []string, found []string) ! {
|
||||||
assert expected.len == found.len
|
assert expected.len == found.len
|
||||||
for header in expected {
|
for header in expected {
|
||||||
if !found.contains(header) {
|
if !found.contains(header) {
|
||||||
|
@ -34,11 +34,14 @@ pub mut:
|
|||||||
accept_timeout time.Duration = 30 * time.second
|
accept_timeout time.Duration = 30 * time.second
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s Server) listen_and_serve() ? {
|
pub fn (mut s Server) listen_and_serve() {
|
||||||
if s.handler is DebugHandler {
|
if s.handler is DebugHandler {
|
||||||
eprintln('Server handler not set, using debug handler')
|
eprintln('Server handler not set, using debug handler')
|
||||||
}
|
}
|
||||||
s.listener = net.listen_tcp(.ip6, ':$s.port')?
|
s.listener = net.listen_tcp(.ip6, ':$s.port') or {
|
||||||
|
eprintln('Listening on :$s.port failed')
|
||||||
|
return
|
||||||
|
}
|
||||||
s.listener.set_accept_timeout(s.accept_timeout)
|
s.listener.set_accept_timeout(s.accept_timeout)
|
||||||
eprintln('Listening on :$s.port')
|
eprintln('Listening on :$s.port')
|
||||||
s.state = .running
|
s.state = .running
|
||||||
|
@ -11,7 +11,7 @@ fn test_server_stop() {
|
|||||||
server.stop()
|
server.stop()
|
||||||
assert server.status() == .stopped
|
assert server.status() == .stopped
|
||||||
assert watch.elapsed() < 100 * time.millisecond
|
assert watch.elapsed() < 100 * time.millisecond
|
||||||
t.wait()?
|
t.wait()
|
||||||
assert watch.elapsed() < 999 * time.millisecond
|
assert watch.elapsed() < 999 * time.millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ fn test_server_close() {
|
|||||||
server.close()
|
server.close()
|
||||||
assert server.status() == .closed
|
assert server.status() == .closed
|
||||||
assert watch.elapsed() < 100 * time.millisecond
|
assert watch.elapsed() < 100 * time.millisecond
|
||||||
t.wait()?
|
t.wait()
|
||||||
assert watch.elapsed() < 999 * time.millisecond
|
assert watch.elapsed() < 999 * time.millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,19 +71,19 @@ fn test_server_custom_handler() {
|
|||||||
for server.status() != .running {
|
for server.status() != .running {
|
||||||
time.sleep(10 * time.millisecond)
|
time.sleep(10 * time.millisecond)
|
||||||
}
|
}
|
||||||
x := http.fetch(url: 'http://localhost:$cport/endpoint?abc=xyz', data: 'my data')?
|
x := http.fetch(url: 'http://localhost:$cport/endpoint?abc=xyz', data: 'my data')!
|
||||||
assert x.body == 'my data, /endpoint?abc=xyz'
|
assert x.body == 'my data, /endpoint?abc=xyz'
|
||||||
assert x.status_code == 200
|
assert x.status_code == 200
|
||||||
assert x.http_version == '1.1'
|
assert x.http_version == '1.1'
|
||||||
y := http.fetch(url: 'http://localhost:$cport/another/endpoint', data: 'abcde')?
|
y := http.fetch(url: 'http://localhost:$cport/another/endpoint', data: 'abcde')!
|
||||||
assert y.body == 'abcde, /another/endpoint'
|
assert y.body == 'abcde, /another/endpoint'
|
||||||
assert y.status_code == 200
|
assert y.status_code == 200
|
||||||
assert y.status() == .ok
|
assert y.status() == .ok
|
||||||
assert y.http_version == '1.1'
|
assert y.http_version == '1.1'
|
||||||
//
|
//
|
||||||
http.fetch(url: 'http://localhost:$cport/something/else')?
|
http.fetch(url: 'http://localhost:$cport/something/else')!
|
||||||
server.stop()
|
server.stop()
|
||||||
t.wait()?
|
t.wait()
|
||||||
assert handler.counter == 3
|
assert handler.counter == 3
|
||||||
assert handler.oks == 2
|
assert handler.oks == 2
|
||||||
assert handler.not_founds == 1
|
assert handler.not_founds == 1
|
||||||
|
@ -52,7 +52,7 @@ pub struct SSLConnectConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// new_ssl_conn returns a new SSLConn with the given config.
|
// new_ssl_conn returns a new SSLConn with the given config.
|
||||||
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn {
|
pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
|
||||||
mut conn := &SSLConn{
|
mut conn := &SSLConn{
|
||||||
config: config
|
config: config
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ enum Select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// shutdown terminates the ssl connection and does cleanup
|
// shutdown terminates the ssl connection and does cleanup
|
||||||
pub fn (mut s SSLConn) shutdown() ? {
|
pub fn (mut s SSLConn) shutdown() ! {
|
||||||
if !s.opened {
|
if !s.opened {
|
||||||
return error('ssl connection not open')
|
return error('ssl connection not open')
|
||||||
}
|
}
|
||||||
@ -82,16 +82,16 @@ pub fn (mut s SSLConn) shutdown() ? {
|
|||||||
if s.owns_socket {
|
if s.owns_socket {
|
||||||
$if windows {
|
$if windows {
|
||||||
C.shutdown(s.handle, C.SD_BOTH)
|
C.shutdown(s.handle, C.SD_BOTH)
|
||||||
net.socket_error(C.closesocket(s.handle))?
|
net.socket_error(C.closesocket(s.handle))!
|
||||||
} $else {
|
} $else {
|
||||||
C.shutdown(s.handle, C.SHUT_RDWR)
|
C.shutdown(s.handle, C.SHUT_RDWR)
|
||||||
net.socket_error(C.close(s.handle))?
|
net.socket_error(C.close(s.handle))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// connect to server using mbedtls
|
// connect to server using mbedtls
|
||||||
fn (mut s SSLConn) init() ? {
|
fn (mut s SSLConn) init() ! {
|
||||||
C.mbedtls_net_init(&s.server_fd)
|
C.mbedtls_net_init(&s.server_fd)
|
||||||
C.mbedtls_ssl_init(&s.ssl)
|
C.mbedtls_ssl_init(&s.ssl)
|
||||||
C.mbedtls_ssl_config_init(&s.conf)
|
C.mbedtls_ssl_config_init(&s.conf)
|
||||||
@ -157,7 +157,7 @@ fn (mut s SSLConn) init() ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// connect sets up an ssl connection on an existing TCP connection
|
// connect sets up an ssl connection on an existing TCP connection
|
||||||
pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? {
|
pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ! {
|
||||||
if s.opened {
|
if s.opened {
|
||||||
return error('ssl connection already open')
|
return error('ssl connection already open')
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dial opens an ssl connection on hostname:port
|
// dial opens an ssl connection on hostname:port
|
||||||
pub fn (mut s SSLConn) dial(hostname string, port int) ? {
|
pub fn (mut s SSLConn) dial(hostname string, port int) ! {
|
||||||
s.owns_socket = true
|
s.owns_socket = true
|
||||||
if s.opened {
|
if s.opened {
|
||||||
return error('ssl connection already open')
|
return error('ssl connection already open')
|
||||||
@ -216,7 +216,7 @@ pub fn (mut s SSLConn) dial(hostname string, port int) ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// socket_read_into_ptr reads `len` bytes into `buf`
|
// socket_read_into_ptr reads `len` bytes into `buf`
|
||||||
pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int {
|
pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) !int {
|
||||||
mut res := 0
|
mut res := 0
|
||||||
for {
|
for {
|
||||||
res = C.mbedtls_ssl_read(&s.ssl, buf_ptr, len)
|
res = C.mbedtls_ssl_read(&s.ssl, buf_ptr, len)
|
||||||
@ -227,13 +227,13 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int {
|
|||||||
} else {
|
} else {
|
||||||
match res {
|
match res {
|
||||||
C.MBEDTLS_ERR_SSL_WANT_READ {
|
C.MBEDTLS_ERR_SSL_WANT_READ {
|
||||||
ready := @select(s.handle, .read, s.duration)?
|
ready := @select(s.handle, .read, s.duration)!
|
||||||
if !ready {
|
if !ready {
|
||||||
return net.err_timed_out
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
C.MBEDTLS_ERR_SSL_WANT_WRITE {
|
C.MBEDTLS_ERR_SSL_WANT_WRITE {
|
||||||
ready := @select(s.handle, .write, s.duration)?
|
ready := @select(s.handle, .write, s.duration)!
|
||||||
if !ready {
|
if !ready {
|
||||||
return net.err_timed_out
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ pub fn (mut s SSLConn) read(mut buffer []u8) !int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write_ptr writes `len` bytes from `bytes` to the ssl connection
|
// write_ptr writes `len` bytes from `bytes` to the ssl connection
|
||||||
pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
|
pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) !int {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut ptr_base := bytes
|
mut ptr_base := bytes
|
||||||
mut total_sent := 0
|
mut total_sent := 0
|
||||||
@ -269,7 +269,7 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
|
|||||||
match sent {
|
match sent {
|
||||||
C.MBEDTLS_ERR_SSL_WANT_READ {
|
C.MBEDTLS_ERR_SSL_WANT_READ {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .read, s.duration)?
|
ready := @select(s.handle, .read, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -278,7 +278,7 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
C.MBEDTLS_ERR_SSL_WANT_WRITE {
|
C.MBEDTLS_ERR_SSL_WANT_WRITE {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .write, s.duration)?
|
ready := @select(s.handle, .write, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -297,12 +297,12 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write writes data from `bytes` to the ssl connection
|
// write writes data from `bytes` to the ssl connection
|
||||||
pub fn (mut s SSLConn) write(bytes []u8) ?int {
|
pub fn (mut s SSLConn) write(bytes []u8) !int {
|
||||||
return s.write_ptr(&u8(bytes.data), bytes.len)
|
return s.write_ptr(&u8(bytes.data), bytes.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_string writes a string to the ssl connection
|
// write_string writes a string to the ssl connection
|
||||||
pub fn (mut s SSLConn) write_string(str string) ?int {
|
pub fn (mut s SSLConn) write_string(str string) !int {
|
||||||
return s.write_ptr(str.str, str.len)
|
return s.write_ptr(str.str, str.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ This is basically a copy of Emily socket implementation of select.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Select waits for an io operation (specified by parameter `test`) to be available
|
// Select waits for an io operation (specified by parameter `test`) to be available
|
||||||
fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||||
set := C.fd_set{}
|
set := C.fd_set{}
|
||||||
|
|
||||||
C.FD_ZERO(&set)
|
C.FD_ZERO(&set)
|
||||||
@ -336,13 +336,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
|||||||
|
|
||||||
match test {
|
match test {
|
||||||
.read {
|
.read {
|
||||||
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.write {
|
.write {
|
||||||
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.except {
|
.except {
|
||||||
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
module openssl
|
module openssl
|
||||||
|
|
||||||
// ssl_error returns non error ssl code or error if unrecoverable and we should panic
|
// ssl_error returns non error ssl code or error if unrecoverable and we should panic
|
||||||
fn ssl_error(ret int, ssl voidptr) ?SSLError {
|
fn ssl_error(ret int, ssl voidptr) !SSLError {
|
||||||
res := C.SSL_get_error(ssl, ret)
|
res := C.SSL_get_error(ssl, ret)
|
||||||
match unsafe { SSLError(res) } {
|
match unsafe { SSLError(res) } {
|
||||||
.ssl_error_syscall {
|
.ssl_error_syscall {
|
||||||
|
@ -28,7 +28,7 @@ pub struct SSLConnectConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// new_ssl_conn instance an new SSLCon struct
|
// new_ssl_conn instance an new SSLCon struct
|
||||||
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn {
|
pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
|
||||||
mut conn := &SSLConn{
|
mut conn := &SSLConn{
|
||||||
config: config
|
config: config
|
||||||
sslctx: 0
|
sslctx: 0
|
||||||
@ -47,7 +47,7 @@ enum Select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// shutdown closes the ssl connection and does cleanup
|
// shutdown closes the ssl connection and does cleanup
|
||||||
pub fn (mut s SSLConn) shutdown() ? {
|
pub fn (mut s SSLConn) shutdown() ! {
|
||||||
if s.ssl != 0 {
|
if s.ssl != 0 {
|
||||||
mut res := 0
|
mut res := 0
|
||||||
for {
|
for {
|
||||||
@ -100,15 +100,15 @@ pub fn (mut s SSLConn) shutdown() ? {
|
|||||||
if s.owns_socket {
|
if s.owns_socket {
|
||||||
$if windows {
|
$if windows {
|
||||||
C.shutdown(s.handle, C.SD_BOTH)
|
C.shutdown(s.handle, C.SD_BOTH)
|
||||||
net.socket_error(C.closesocket(s.handle))?
|
net.socket_error(C.closesocket(s.handle))!
|
||||||
} $else {
|
} $else {
|
||||||
C.shutdown(s.handle, C.SHUT_RDWR)
|
C.shutdown(s.handle, C.SHUT_RDWR)
|
||||||
net.socket_error(C.close(s.handle))?
|
net.socket_error(C.close(s.handle))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s SSLConn) init() ? {
|
fn (mut s SSLConn) init() ! {
|
||||||
s.sslctx = unsafe { C.SSL_CTX_new(C.SSLv23_client_method()) }
|
s.sslctx = unsafe { C.SSL_CTX_new(C.SSLv23_client_method()) }
|
||||||
if s.sslctx == 0 {
|
if s.sslctx == 0 {
|
||||||
return error("Couldn't get ssl context")
|
return error("Couldn't get ssl context")
|
||||||
@ -136,13 +136,13 @@ fn (mut s SSLConn) init() ? {
|
|||||||
cert = os.temp_dir() + '/v_cert' + now
|
cert = os.temp_dir() + '/v_cert' + now
|
||||||
cert_key = os.temp_dir() + '/v_cert_key' + now
|
cert_key = os.temp_dir() + '/v_cert_key' + now
|
||||||
if s.config.verify != '' {
|
if s.config.verify != '' {
|
||||||
os.write_file(verify, s.config.verify)?
|
os.write_file(verify, s.config.verify)!
|
||||||
}
|
}
|
||||||
if s.config.cert != '' {
|
if s.config.cert != '' {
|
||||||
os.write_file(cert, s.config.cert)?
|
os.write_file(cert, s.config.cert)!
|
||||||
}
|
}
|
||||||
if s.config.cert_key != '' {
|
if s.config.cert_key != '' {
|
||||||
os.write_file(cert_key, s.config.cert_key)?
|
os.write_file(cert_key, s.config.cert_key)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.config.verify != '' {
|
if s.config.verify != '' {
|
||||||
@ -175,7 +175,7 @@ fn (mut s SSLConn) init() ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// connect to server using OpenSSL
|
// connect to server using OpenSSL
|
||||||
pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? {
|
pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ! {
|
||||||
s.handle = tcp_conn.sock.handle
|
s.handle = tcp_conn.sock.handle
|
||||||
s.duration = tcp_conn.read_timeout()
|
s.duration = tcp_conn.read_timeout()
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ pub fn (mut s SSLConn) connect(mut tcp_conn net.TcpConn, hostname string) ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dial opens an ssl connection on hostname:port
|
// dial opens an ssl connection on hostname:port
|
||||||
pub fn (mut s SSLConn) dial(hostname string, port int) ? {
|
pub fn (mut s SSLConn) dial(hostname string, port int) ! {
|
||||||
s.owns_socket = true
|
s.owns_socket = true
|
||||||
mut tcp_conn := net.dial_tcp('$hostname:$port') or { return err }
|
mut tcp_conn := net.dial_tcp('$hostname:$port') or { return err }
|
||||||
$if macos {
|
$if macos {
|
||||||
@ -201,14 +201,14 @@ pub fn (mut s SSLConn) dial(hostname string, port int) ? {
|
|||||||
s.connect(mut tcp_conn, hostname) or { return err }
|
s.connect(mut tcp_conn, hostname) or { return err }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s SSLConn) complete_connect() ? {
|
fn (mut s SSLConn) complete_connect() ! {
|
||||||
for {
|
for {
|
||||||
mut res := C.SSL_connect(voidptr(s.ssl))
|
mut res := C.SSL_connect(voidptr(s.ssl))
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
err_res := ssl_error(res, s.ssl)?
|
err_res := ssl_error(res, s.ssl)!
|
||||||
if err_res == .ssl_error_want_read {
|
if err_res == .ssl_error_want_read {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .read, s.duration)?
|
ready := @select(s.handle, .read, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -216,7 +216,7 @@ fn (mut s SSLConn) complete_connect() ? {
|
|||||||
continue
|
continue
|
||||||
} else if err_res == .ssl_error_want_write {
|
} else if err_res == .ssl_error_want_write {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .write, s.duration)?
|
ready := @select(s.handle, .write, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -232,10 +232,10 @@ fn (mut s SSLConn) complete_connect() ? {
|
|||||||
for {
|
for {
|
||||||
mut res := C.SSL_do_handshake(voidptr(s.ssl))
|
mut res := C.SSL_do_handshake(voidptr(s.ssl))
|
||||||
if res != 1 {
|
if res != 1 {
|
||||||
err_res := ssl_error(res, s.ssl)?
|
err_res := ssl_error(res, s.ssl)!
|
||||||
if err_res == .ssl_error_want_read {
|
if err_res == .ssl_error_want_read {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .read, s.duration)?
|
ready := @select(s.handle, .read, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -243,7 +243,7 @@ fn (mut s SSLConn) complete_connect() ? {
|
|||||||
continue
|
continue
|
||||||
} else if err_res == .ssl_error_want_write {
|
} else if err_res == .ssl_error_want_write {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .write, s.duration)?
|
ready := @select(s.handle, .write, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -267,7 +267,7 @@ fn (mut s SSLConn) complete_connect() ? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int {
|
pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) !int {
|
||||||
mut res := 0
|
mut res := 0
|
||||||
for {
|
for {
|
||||||
res = C.SSL_read(voidptr(s.ssl), buf_ptr, len)
|
res = C.SSL_read(voidptr(s.ssl), buf_ptr, len)
|
||||||
@ -276,16 +276,16 @@ pub fn (mut s SSLConn) socket_read_into_ptr(buf_ptr &u8, len int) ?int {
|
|||||||
} else if res == 0 {
|
} else if res == 0 {
|
||||||
return IError(io.Eof{})
|
return IError(io.Eof{})
|
||||||
} else {
|
} else {
|
||||||
err_res := ssl_error(res, s.ssl)?
|
err_res := ssl_error(res, s.ssl)!
|
||||||
match err_res {
|
match err_res {
|
||||||
.ssl_error_want_read {
|
.ssl_error_want_read {
|
||||||
ready := @select(s.handle, .read, s.duration)?
|
ready := @select(s.handle, .read, s.duration)!
|
||||||
if !ready {
|
if !ready {
|
||||||
return net.err_timed_out
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ssl_error_want_write {
|
.ssl_error_want_write {
|
||||||
ready := @select(s.handle, .write, s.duration)?
|
ready := @select(s.handle, .write, s.duration)!
|
||||||
if !ready {
|
if !ready {
|
||||||
return net.err_timed_out
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
@ -308,7 +308,7 @@ pub fn (mut s SSLConn) read(mut buffer []u8) !int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write_ptr writes `len` bytes from `bytes` to the ssl connection
|
// write_ptr writes `len` bytes from `bytes` to the ssl connection
|
||||||
pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
|
pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) !int {
|
||||||
unsafe {
|
unsafe {
|
||||||
mut ptr_base := bytes
|
mut ptr_base := bytes
|
||||||
mut total_sent := 0
|
mut total_sent := 0
|
||||||
@ -317,17 +317,17 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
|
|||||||
remaining := len - total_sent
|
remaining := len - total_sent
|
||||||
mut sent := C.SSL_write(voidptr(s.ssl), ptr, remaining)
|
mut sent := C.SSL_write(voidptr(s.ssl), ptr, remaining)
|
||||||
if sent <= 0 {
|
if sent <= 0 {
|
||||||
err_res := ssl_error(sent, s.ssl)?
|
err_res := ssl_error(sent, s.ssl)!
|
||||||
if err_res == .ssl_error_want_read {
|
if err_res == .ssl_error_want_read {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .read, s.duration)?
|
ready := @select(s.handle, .read, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if err_res == .ssl_error_want_write {
|
} else if err_res == .ssl_error_want_write {
|
||||||
for {
|
for {
|
||||||
ready := @select(s.handle, .write, s.duration)?
|
ready := @select(s.handle, .write, s.duration)!
|
||||||
if ready {
|
if ready {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -345,12 +345,12 @@ pub fn (mut s SSLConn) write_ptr(bytes &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write writes data from `bytes` to the ssl connection
|
// write writes data from `bytes` to the ssl connection
|
||||||
pub fn (mut s SSLConn) write(bytes []u8) ?int {
|
pub fn (mut s SSLConn) write(bytes []u8) !int {
|
||||||
return s.write_ptr(&u8(bytes.data), bytes.len)
|
return s.write_ptr(&u8(bytes.data), bytes.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_string writes a string to the ssl connection
|
// write_string writes a string to the ssl connection
|
||||||
pub fn (mut s SSLConn) write_string(str string) ?int {
|
pub fn (mut s SSLConn) write_string(str string) !int {
|
||||||
return s.write_ptr(str.str, str.len)
|
return s.write_ptr(str.str, str.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,7 +364,7 @@ This is basically a copy of Emily socket implementation of select.
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// Select waits for an io operation (specified by parameter `test`) to be available
|
// Select waits for an io operation (specified by parameter `test`) to be available
|
||||||
fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||||
set := C.fd_set{}
|
set := C.fd_set{}
|
||||||
|
|
||||||
C.FD_ZERO(&set)
|
C.FD_ZERO(&set)
|
||||||
@ -387,13 +387,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
|||||||
|
|
||||||
match test {
|
match test {
|
||||||
.read {
|
.read {
|
||||||
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.write {
|
.write {
|
||||||
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.except {
|
.except {
|
||||||
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ pub struct Mail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// new_client returns a new SMTP client and connects to it
|
// new_client returns a new SMTP client and connects to it
|
||||||
pub fn new_client(config Client) ?&Client {
|
pub fn new_client(config Client) !&Client {
|
||||||
if config.ssl && config.starttls {
|
if config.ssl && config.starttls {
|
||||||
return error('Can not use both implicit SSL and STARTTLS')
|
return error('Can not use both implicit SSL and STARTTLS')
|
||||||
}
|
}
|
||||||
@ -67,12 +67,12 @@ pub fn new_client(config Client) ?&Client {
|
|||||||
mut c := &Client{
|
mut c := &Client{
|
||||||
...config
|
...config
|
||||||
}
|
}
|
||||||
c.reconnect()?
|
c.reconnect()!
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// reconnect reconnects to the SMTP server if the connection was closed
|
// reconnect reconnects to the SMTP server if the connection was closed
|
||||||
pub fn (mut c Client) reconnect() ? {
|
pub fn (mut c Client) reconnect() ! {
|
||||||
if c.is_open {
|
if c.is_open {
|
||||||
return error('Already connected to server')
|
return error('Already connected to server')
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ pub fn (mut c Client) reconnect() ? {
|
|||||||
c.conn = conn
|
c.conn = conn
|
||||||
|
|
||||||
if c.ssl {
|
if c.ssl {
|
||||||
c.connect_ssl()?
|
c.connect_ssl()!
|
||||||
} else {
|
} else {
|
||||||
c.reader = io.new_buffered_reader(reader: c.conn)
|
c.reader = io.new_buffered_reader(reader: c.conn)
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ pub fn (mut c Client) reconnect() ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send sends an email
|
// send sends an email
|
||||||
pub fn (mut c Client) send(config Mail) ? {
|
pub fn (mut c Client) send(config Mail) ! {
|
||||||
if !c.is_open {
|
if !c.is_open {
|
||||||
return error('Disconnected from server')
|
return error('Disconnected from server')
|
||||||
}
|
}
|
||||||
@ -113,20 +113,20 @@ pub fn (mut c Client) send(config Mail) ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// quit closes the connection to the server
|
// quit closes the connection to the server
|
||||||
pub fn (mut c Client) quit() ? {
|
pub fn (mut c Client) quit() ! {
|
||||||
c.send_str('QUIT\r\n')?
|
c.send_str('QUIT\r\n')!
|
||||||
c.expect_reply(.close)?
|
c.expect_reply(.close)!
|
||||||
if c.encrypted {
|
if c.encrypted {
|
||||||
c.ssl_conn.shutdown()?
|
c.ssl_conn.shutdown()!
|
||||||
} else {
|
} else {
|
||||||
c.conn.close()?
|
c.conn.close()!
|
||||||
}
|
}
|
||||||
c.is_open = false
|
c.is_open = false
|
||||||
c.encrypted = false
|
c.encrypted = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Client) connect_ssl() ? {
|
fn (mut c Client) connect_ssl() ! {
|
||||||
c.ssl_conn = ssl.new_ssl_conn()?
|
c.ssl_conn = ssl.new_ssl_conn()!
|
||||||
c.ssl_conn.connect(mut c.conn, c.server) or {
|
c.ssl_conn.connect(mut c.conn, c.server) or {
|
||||||
return error('Connecting to server using OpenSSL failed: $err')
|
return error('Connecting to server using OpenSSL failed: $err')
|
||||||
}
|
}
|
||||||
@ -136,10 +136,10 @@ fn (mut c Client) connect_ssl() ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// expect_reply checks if the SMTP server replied with the expected reply code
|
// expect_reply checks if the SMTP server replied with the expected reply code
|
||||||
fn (mut c Client) expect_reply(expected ReplyCode) ? {
|
fn (mut c Client) expect_reply(expected ReplyCode) ! {
|
||||||
mut str := ''
|
mut str := ''
|
||||||
for {
|
for {
|
||||||
str = c.reader.read_line()?
|
str = c.reader.read_line()!
|
||||||
if str.len < 4 {
|
if str.len < 4 {
|
||||||
return error('Invalid SMTP response: $str')
|
return error('Invalid SMTP response: $str')
|
||||||
}
|
}
|
||||||
@ -167,7 +167,7 @@ fn (mut c Client) expect_reply(expected ReplyCode) ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Client) send_str(s string) ? {
|
fn (mut c Client) send_str(s string) ! {
|
||||||
$if smtp_debug ? {
|
$if smtp_debug ? {
|
||||||
eprintln('\n\n[SEND START]')
|
eprintln('\n\n[SEND START]')
|
||||||
eprint(s.trim_space())
|
eprint(s.trim_space())
|
||||||
@ -175,27 +175,27 @@ fn (mut c Client) send_str(s string) ? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.encrypted {
|
if c.encrypted {
|
||||||
c.ssl_conn.write(s.bytes())?
|
c.ssl_conn.write(s.bytes())!
|
||||||
} else {
|
} else {
|
||||||
c.conn.write(s.bytes())?
|
c.conn.write(s.bytes())!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Client) send_ehlo() ? {
|
fn (mut c Client) send_ehlo() ! {
|
||||||
c.send_str('EHLO $c.server\r\n')?
|
c.send_str('EHLO $c.server\r\n')!
|
||||||
c.expect_reply(.action_ok)?
|
c.expect_reply(.action_ok)!
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Client) send_starttls() ? {
|
fn (mut c Client) send_starttls() ! {
|
||||||
c.send_str('STARTTLS\r\n')?
|
c.send_str('STARTTLS\r\n')!
|
||||||
c.expect_reply(.ready)?
|
c.expect_reply(.ready)!
|
||||||
c.connect_ssl()?
|
c.connect_ssl()!
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Client) send_auth() ? {
|
fn (mut c Client) send_auth() ! {
|
||||||
if c.username.len == 0 {
|
if c.username.len == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -206,28 +206,28 @@ fn (mut c Client) send_auth() ? {
|
|||||||
sb.write_string(c.password)
|
sb.write_string(c.password)
|
||||||
a := sb.str()
|
a := sb.str()
|
||||||
auth := 'AUTH PLAIN ${base64.encode_str(a)}\r\n'
|
auth := 'AUTH PLAIN ${base64.encode_str(a)}\r\n'
|
||||||
c.send_str(auth)?
|
c.send_str(auth)!
|
||||||
c.expect_reply(.auth_ok)?
|
c.expect_reply(.auth_ok)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Client) send_mailfrom(from string) ? {
|
fn (mut c Client) send_mailfrom(from string) ! {
|
||||||
c.send_str('MAIL FROM: <$from>\r\n')?
|
c.send_str('MAIL FROM: <$from>\r\n')!
|
||||||
c.expect_reply(.action_ok)?
|
c.expect_reply(.action_ok)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Client) send_mailto(to string) ? {
|
fn (mut c Client) send_mailto(to string) ! {
|
||||||
for rcpt in to.split(';') {
|
for rcpt in to.split(';') {
|
||||||
c.send_str('RCPT TO: <$rcpt>\r\n')?
|
c.send_str('RCPT TO: <$rcpt>\r\n')!
|
||||||
c.expect_reply(.action_ok)?
|
c.expect_reply(.action_ok)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Client) send_data() ? {
|
fn (mut c Client) send_data() ! {
|
||||||
c.send_str('DATA\r\n')?
|
c.send_str('DATA\r\n')!
|
||||||
c.expect_reply(.mail_start)?
|
c.expect_reply(.mail_start)!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Client) send_body(cfg Mail) ? {
|
fn (mut c Client) send_body(cfg Mail) ! {
|
||||||
is_html := cfg.body_type == .html
|
is_html := cfg.body_type == .html
|
||||||
date := cfg.date.custom_format('ddd, D MMM YYYY HH:mm ZZ')
|
date := cfg.date.custom_format('ddd, D MMM YYYY HH:mm ZZ')
|
||||||
nonascii_subject := cfg.subject.bytes().any(it < u8(` `) || it > u8(`~`))
|
nonascii_subject := cfg.subject.bytes().any(it < u8(` `) || it > u8(`~`))
|
||||||
@ -253,6 +253,6 @@ fn (mut c Client) send_body(cfg Mail) ? {
|
|||||||
sb.write_string('\r\n\r\n')
|
sb.write_string('\r\n\r\n')
|
||||||
sb.write_string(base64.encode_str(cfg.body))
|
sb.write_string(base64.encode_str(cfg.body))
|
||||||
sb.write_string('\r\n.\r\n')
|
sb.write_string('\r\n.\r\n')
|
||||||
c.send_str(sb.str())?
|
c.send_str(sb.str())!
|
||||||
c.expect_reply(.action_ok)?
|
c.expect_reply(.action_ok)!
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,6 @@ pub:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// address gets the address of a socket
|
// address gets the address of a socket
|
||||||
pub fn (s &Socket) address() ?Addr {
|
pub fn (s &Socket) address() !Addr {
|
||||||
return addr_from_socket_handle(s.handle)
|
return addr_from_socket_handle(s.handle)
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ pub struct SSLConnectConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// new_ssl_conn returns a new SSLConn with the given config.
|
// new_ssl_conn returns a new SSLConn with the given config.
|
||||||
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn {
|
pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
|
||||||
c := openssl.new_ssl_conn(config.SSLConnectConfig) or { return err }
|
c := openssl.new_ssl_conn(config.SSLConnectConfig) or { return err }
|
||||||
return &SSLConn{c}
|
return &SSLConn{c}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ pub struct SSLConnectConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// new_ssl_conn returns a new SSLConn with the given config.
|
// new_ssl_conn returns a new SSLConn with the given config.
|
||||||
pub fn new_ssl_conn(config SSLConnectConfig) ?&SSLConn {
|
pub fn new_ssl_conn(config SSLConnectConfig) !&SSLConn {
|
||||||
c := mbedtls.new_ssl_conn(config.SSLConnectConfig) or { return err }
|
c := mbedtls.new_ssl_conn(config.SSLConnectConfig) or { return err }
|
||||||
return &SSLConn{c}
|
return &SSLConn{c}
|
||||||
}
|
}
|
||||||
|
120
vlib/net/tcp.v
120
vlib/net/tcp.v
@ -21,7 +21,7 @@ mut:
|
|||||||
is_blocking bool
|
is_blocking bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dial_tcp(address string) ?&TcpConn {
|
pub fn dial_tcp(address string) !&TcpConn {
|
||||||
addrs := resolve_addrs_fuzzy(address, .tcp) or {
|
addrs := resolve_addrs_fuzzy(address, .tcp) or {
|
||||||
return error('$err.msg(); could not resolve address $address in dial_tcp')
|
return error('$err.msg(); could not resolve address $address in dial_tcp')
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ pub fn dial_tcp(address string) ?&TcpConn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// bind local address and dial.
|
// bind local address and dial.
|
||||||
pub fn dial_tcp_with_bind(saddr string, laddr string) ?&TcpConn {
|
pub fn dial_tcp_with_bind(saddr string, laddr string) !&TcpConn {
|
||||||
addrs := resolve_addrs_fuzzy(saddr, .tcp) or {
|
addrs := resolve_addrs_fuzzy(saddr, .tcp) or {
|
||||||
return error('$err.msg(); could not resolve address $saddr in dial_tcp_with_bind')
|
return error('$err.msg(); could not resolve address $saddr in dial_tcp_with_bind')
|
||||||
}
|
}
|
||||||
@ -94,15 +94,15 @@ pub fn dial_tcp_with_bind(saddr string, laddr string) ?&TcpConn {
|
|||||||
return error('dial_tcp_with_bind failed for address $saddr')
|
return error('dial_tcp_with_bind failed for address $saddr')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c TcpConn) close() ? {
|
pub fn (mut c TcpConn) close() ! {
|
||||||
$if trace_tcp ? {
|
$if trace_tcp ? {
|
||||||
eprintln(' TcpConn.close | c.sock.handle: ${c.sock.handle:6}')
|
eprintln(' TcpConn.close | c.sock.handle: ${c.sock.handle:6}')
|
||||||
}
|
}
|
||||||
c.sock.close()?
|
c.sock.close()!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) ?int {
|
pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) !int {
|
||||||
mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))?
|
mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
|
||||||
$if trace_tcp ? {
|
$if trace_tcp ? {
|
||||||
eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
||||||
}
|
}
|
||||||
@ -115,8 +115,8 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
code := error_code()
|
code := error_code()
|
||||||
if code == int(error_ewouldblock) {
|
if code == int(error_ewouldblock) {
|
||||||
c.wait_for_read()?
|
c.wait_for_read()!
|
||||||
res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))?
|
res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
|
||||||
$if trace_tcp ? {
|
$if trace_tcp ? {
|
||||||
eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
eprintln('<<< TcpConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
||||||
}
|
}
|
||||||
@ -128,9 +128,9 @@ pub fn (c TcpConn) read_ptr(buf_ptr &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
return socket_error(res)
|
return socket_error(res)
|
||||||
} else {
|
} else {
|
||||||
wrap_error(code)?
|
wrap_error(code)!
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c TcpConn) read(mut buf []u8) !int {
|
pub fn (c TcpConn) read(mut buf []u8) !int {
|
||||||
@ -142,15 +142,15 @@ pub fn (c TcpConn) read(mut buf []u8) !int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c TcpConn) read_deadline() ?time.Time {
|
pub fn (mut c TcpConn) read_deadline() !time.Time {
|
||||||
if c.read_deadline.unix == 0 {
|
if c.read_deadline.unix == 0 {
|
||||||
return c.read_deadline
|
return c.read_deadline
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_ptr blocks and attempts to write all data
|
// write_ptr blocks and attempts to write all data
|
||||||
pub fn (mut c TcpConn) write_ptr(b &u8, len int) ?int {
|
pub fn (mut c TcpConn) write_ptr(b &u8, len int) !int {
|
||||||
$if trace_tcp ? {
|
$if trace_tcp ? {
|
||||||
eprintln(
|
eprintln(
|
||||||
'>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
|
'>>> TcpConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
|
||||||
@ -173,10 +173,10 @@ pub fn (mut c TcpConn) write_ptr(b &u8, len int) ?int {
|
|||||||
if sent < 0 {
|
if sent < 0 {
|
||||||
code := error_code()
|
code := error_code()
|
||||||
if code == int(error_ewouldblock) {
|
if code == int(error_ewouldblock) {
|
||||||
c.wait_for_write()?
|
c.wait_for_write()!
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
wrap_error(code)?
|
wrap_error(code)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total_sent += sent
|
total_sent += sent
|
||||||
@ -186,12 +186,12 @@ pub fn (mut c TcpConn) write_ptr(b &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write blocks and attempts to write all data
|
// write blocks and attempts to write all data
|
||||||
pub fn (mut c TcpConn) write(bytes []u8) ?int {
|
pub fn (mut c TcpConn) write(bytes []u8) !int {
|
||||||
return c.write_ptr(bytes.data, bytes.len)
|
return c.write_ptr(bytes.data, bytes.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_string blocks and attempts to write all data
|
// write_string blocks and attempts to write all data
|
||||||
pub fn (mut c TcpConn) write_string(s string) ?int {
|
pub fn (mut c TcpConn) write_string(s string) !int {
|
||||||
return c.write_ptr(s.str, s.len)
|
return c.write_ptr(s.str, s.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,11 +199,11 @@ pub fn (mut c TcpConn) set_read_deadline(deadline time.Time) {
|
|||||||
c.read_deadline = deadline
|
c.read_deadline = deadline
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c TcpConn) write_deadline() ?time.Time {
|
pub fn (mut c TcpConn) write_deadline() !time.Time {
|
||||||
if c.write_deadline.unix == 0 {
|
if c.write_deadline.unix == 0 {
|
||||||
return c.write_deadline
|
return c.write_deadline
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c TcpConn) set_write_deadline(deadline time.Time) {
|
pub fn (mut c TcpConn) set_write_deadline(deadline time.Time) {
|
||||||
@ -227,31 +227,31 @@ pub fn (mut c TcpConn) set_write_timeout(t time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (c TcpConn) wait_for_read() ? {
|
pub fn (c TcpConn) wait_for_read() ! {
|
||||||
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut c TcpConn) wait_for_write() ? {
|
pub fn (mut c TcpConn) wait_for_write() ! {
|
||||||
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &TcpConn) peer_addr() ?Addr {
|
pub fn (c &TcpConn) peer_addr() !Addr {
|
||||||
mut addr := Addr{
|
mut addr := Addr{
|
||||||
addr: AddrData{
|
addr: AddrData{
|
||||||
Ip6: Ip6{}
|
Ip6: Ip6{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut size := sizeof(Addr)
|
mut size := sizeof(Addr)
|
||||||
socket_error_message(C.getpeername(c.sock.handle, voidptr(&addr), &size), 'peer_addr failed')?
|
socket_error_message(C.getpeername(c.sock.handle, voidptr(&addr), &size), 'peer_addr failed')!
|
||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &TcpConn) peer_ip() ?string {
|
pub fn (c &TcpConn) peer_ip() !string {
|
||||||
return c.peer_addr()?.str()
|
return c.peer_addr()!.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &TcpConn) addr() ?Addr {
|
pub fn (c &TcpConn) addr() !Addr {
|
||||||
return c.sock.address()
|
return c.sock.address()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ mut:
|
|||||||
accept_deadline time.Time
|
accept_deadline time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen_tcp(family AddrFamily, saddr string) ?&TcpListener {
|
pub fn listen_tcp(family AddrFamily, saddr string) !&TcpListener {
|
||||||
s := new_tcp_socket(family) or { return error('$err.msg(); could not create new socket') }
|
s := new_tcp_socket(family) or { return error('$err.msg(); could not create new socket') }
|
||||||
|
|
||||||
addrs := resolve_addrs(saddr, family, .tcp) or {
|
addrs := resolve_addrs(saddr, family, .tcp) or {
|
||||||
@ -280,8 +280,8 @@ pub fn listen_tcp(family AddrFamily, saddr string) ?&TcpListener {
|
|||||||
|
|
||||||
// cast to the correct type
|
// cast to the correct type
|
||||||
alen := addr.len()
|
alen := addr.len()
|
||||||
socket_error_message(C.bind(s.handle, voidptr(&addr), alen), 'binding to $saddr failed')?
|
socket_error_message(C.bind(s.handle, voidptr(&addr), alen), 'binding to $saddr failed')!
|
||||||
socket_error_message(C.listen(s.handle, 128), 'listening on $saddr failed')?
|
socket_error_message(C.listen(s.handle, 128), 'listening on $saddr failed')!
|
||||||
return &TcpListener{
|
return &TcpListener{
|
||||||
sock: s
|
sock: s
|
||||||
accept_deadline: no_deadline
|
accept_deadline: no_deadline
|
||||||
@ -289,19 +289,19 @@ pub fn listen_tcp(family AddrFamily, saddr string) ?&TcpListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut l TcpListener) accept() ?&TcpConn {
|
pub fn (mut l TcpListener) accept() !&TcpConn {
|
||||||
$if trace_tcp ? {
|
$if trace_tcp ? {
|
||||||
eprintln(' TcpListener.accept | l.sock.handle: ${l.sock.handle:6}')
|
eprintln(' TcpListener.accept | l.sock.handle: ${l.sock.handle:6}')
|
||||||
}
|
}
|
||||||
mut new_handle := C.accept(l.sock.handle, 0, 0)
|
mut new_handle := C.accept(l.sock.handle, 0, 0)
|
||||||
if new_handle <= 0 {
|
if new_handle <= 0 {
|
||||||
l.wait_for_accept()?
|
l.wait_for_accept()!
|
||||||
new_handle = C.accept(l.sock.handle, 0, 0)
|
new_handle = C.accept(l.sock.handle, 0, 0)
|
||||||
if new_handle == -1 || new_handle == 0 {
|
if new_handle == -1 || new_handle == 0 {
|
||||||
return error('accept failed')
|
return error('accept failed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new_sock := tcp_socket_from_handle(new_handle)?
|
new_sock := tcp_socket_from_handle(new_handle)!
|
||||||
$if trace_tcp ? {
|
$if trace_tcp ? {
|
||||||
eprintln(' TcpListener.accept | << new_sock.handle: ${new_sock.handle:6}')
|
eprintln(' TcpListener.accept | << new_sock.handle: ${new_sock.handle:6}')
|
||||||
}
|
}
|
||||||
@ -312,7 +312,7 @@ pub fn (mut l TcpListener) accept() ?&TcpConn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &TcpListener) accept_deadline() ?time.Time {
|
pub fn (c &TcpListener) accept_deadline() !time.Time {
|
||||||
if c.accept_deadline.unix != 0 {
|
if c.accept_deadline.unix != 0 {
|
||||||
return c.accept_deadline
|
return c.accept_deadline
|
||||||
}
|
}
|
||||||
@ -331,15 +331,15 @@ pub fn (mut c TcpListener) set_accept_timeout(t time.Duration) {
|
|||||||
c.accept_timeout = t
|
c.accept_timeout = t
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c TcpListener) wait_for_accept() ? {
|
pub fn (mut c TcpListener) wait_for_accept() ! {
|
||||||
return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout)
|
return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c TcpListener) close() ? {
|
pub fn (mut c TcpListener) close() ! {
|
||||||
c.sock.close()?
|
c.sock.close()!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &TcpListener) addr() ?Addr {
|
pub fn (c &TcpListener) addr() !Addr {
|
||||||
return c.sock.address()
|
return c.sock.address()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,8 +347,8 @@ struct TcpSocket {
|
|||||||
Socket
|
Socket
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_tcp_socket(family AddrFamily) ?TcpSocket {
|
fn new_tcp_socket(family AddrFamily) !TcpSocket {
|
||||||
handle := socket_error(C.socket(family, SocketType.tcp, 0))?
|
handle := socket_error(C.socket(family, SocketType.tcp, 0))!
|
||||||
mut s := TcpSocket{
|
mut s := TcpSocket{
|
||||||
handle: handle
|
handle: handle
|
||||||
}
|
}
|
||||||
@ -362,20 +362,20 @@ fn new_tcp_socket(family AddrFamily) ?TcpSocket {
|
|||||||
|
|
||||||
// TODO(emily):
|
// TODO(emily):
|
||||||
// Move this to its own function on the socket
|
// Move this to its own function on the socket
|
||||||
s.set_option_int(.reuse_addr, 1)?
|
s.set_option_int(.reuse_addr, 1)!
|
||||||
|
|
||||||
$if !net_blocking_sockets ? {
|
$if !net_blocking_sockets ? {
|
||||||
$if windows {
|
$if windows {
|
||||||
t := u32(1) // true
|
t := u32(1) // true
|
||||||
socket_error(C.ioctlsocket(handle, fionbio, &t))?
|
socket_error(C.ioctlsocket(handle, fionbio, &t))!
|
||||||
} $else {
|
} $else {
|
||||||
socket_error(C.fcntl(handle, C.F_SETFL, C.fcntl(handle, C.F_GETFL) | C.O_NONBLOCK))?
|
socket_error(C.fcntl(handle, C.F_SETFL, C.fcntl(handle, C.F_GETFL) | C.O_NONBLOCK))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
|
fn tcp_socket_from_handle(sockfd int) !TcpSocket {
|
||||||
mut s := TcpSocket{
|
mut s := TcpSocket{
|
||||||
handle: sockfd
|
handle: sockfd
|
||||||
}
|
}
|
||||||
@ -383,22 +383,22 @@ fn tcp_socket_from_handle(sockfd int) ?TcpSocket {
|
|||||||
eprintln(' tcp_socket_from_handle | s.handle: ${s.handle:6}')
|
eprintln(' tcp_socket_from_handle | s.handle: ${s.handle:6}')
|
||||||
}
|
}
|
||||||
// s.set_option_bool(.reuse_addr, true)?
|
// s.set_option_bool(.reuse_addr, true)?
|
||||||
s.set_option_int(.reuse_addr, 1)?
|
s.set_option_int(.reuse_addr, 1)!
|
||||||
s.set_dualstack(true) or {
|
s.set_dualstack(true) or {
|
||||||
// Not ipv6, we dont care
|
// Not ipv6, we dont care
|
||||||
}
|
}
|
||||||
$if !net_blocking_sockets ? {
|
$if !net_blocking_sockets ? {
|
||||||
$if windows {
|
$if windows {
|
||||||
t := u32(1) // true
|
t := u32(1) // true
|
||||||
socket_error(C.ioctlsocket(sockfd, fionbio, &t))?
|
socket_error(C.ioctlsocket(sockfd, fionbio, &t))!
|
||||||
} $else {
|
} $else {
|
||||||
socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK))?
|
socket_error(C.fcntl(sockfd, C.F_SETFL, C.fcntl(sockfd, C.F_GETFL) | C.O_NONBLOCK))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
pub fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ! {
|
||||||
// TODO reenable when this `in` operation works again
|
// TODO reenable when this `in` operation works again
|
||||||
// if opt !in opts_can_set {
|
// if opt !in opts_can_set {
|
||||||
// return err_option_not_settable
|
// return err_option_not_settable
|
||||||
@ -407,21 +407,21 @@ pub fn (mut s TcpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
|||||||
// return err_option_wrong_type
|
// return err_option_wrong_type
|
||||||
// }
|
// }
|
||||||
x := int(value)
|
x := int(value)
|
||||||
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))?
|
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s TcpSocket) set_dualstack(on bool) ? {
|
pub fn (mut s TcpSocket) set_dualstack(on bool) ! {
|
||||||
x := int(!on)
|
x := int(!on)
|
||||||
socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x,
|
socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x,
|
||||||
sizeof(int)))?
|
sizeof(int)))!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s TcpSocket) set_option_int(opt SocketOption, value int) ? {
|
pub fn (mut s TcpSocket) set_option_int(opt SocketOption, value int) ! {
|
||||||
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &value, sizeof(int)))?
|
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &value, sizeof(int)))!
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind a local rddress for TcpSocket
|
// bind a local rddress for TcpSocket
|
||||||
pub fn (mut s TcpSocket) bind(addr string) ? {
|
pub fn (mut s TcpSocket) bind(addr string) ! {
|
||||||
addrs := resolve_addrs(addr, AddrFamily.ip, .tcp) or {
|
addrs := resolve_addrs(addr, AddrFamily.ip, .tcp) or {
|
||||||
return error('$err.msg(); could not resolve address $addr')
|
return error('$err.msg(); could not resolve address $addr')
|
||||||
}
|
}
|
||||||
@ -436,11 +436,11 @@ pub fn (mut s TcpSocket) bind(addr string) ? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s TcpSocket) close() ? {
|
fn (mut s TcpSocket) close() ! {
|
||||||
return shutdown(s.handle)
|
return shutdown(s.handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s TcpSocket) @select(test Select, timeout time.Duration) ?bool {
|
fn (mut s TcpSocket) @select(test Select, timeout time.Duration) !bool {
|
||||||
return @select(s.handle, test, timeout)
|
return @select(s.handle, test, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,7 +448,7 @@ const (
|
|||||||
connect_timeout = 5 * time.second
|
connect_timeout = 5 * time.second
|
||||||
)
|
)
|
||||||
|
|
||||||
fn (mut s TcpSocket) connect(a Addr) ? {
|
fn (mut s TcpSocket) connect(a Addr) ! {
|
||||||
$if !net_blocking_sockets ? {
|
$if !net_blocking_sockets ? {
|
||||||
res := C.connect(s.handle, voidptr(&a), a.len())
|
res := C.connect(s.handle, voidptr(&a), a.len())
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
@ -467,7 +467,7 @@ fn (mut s TcpSocket) connect(a Addr) ? {
|
|||||||
// determine whether connect() completed successfully (SO_ERROR is zero) or
|
// determine whether connect() completed successfully (SO_ERROR is zero) or
|
||||||
// unsuccessfully (SO_ERROR is one of the usual error codes listed here,
|
// unsuccessfully (SO_ERROR is one of the usual error codes listed here,
|
||||||
// ex‐ plaining the reason for the failure).
|
// ex‐ plaining the reason for the failure).
|
||||||
write_result := s.@select(.write, net.connect_timeout)?
|
write_result := s.@select(.write, net.connect_timeout)!
|
||||||
err := 0
|
err := 0
|
||||||
len := sizeof(err)
|
len := sizeof(err)
|
||||||
xyz := C.getsockopt(s.handle, C.SOL_SOCKET, C.SO_ERROR, &err, &len)
|
xyz := C.getsockopt(s.handle, C.SOL_SOCKET, C.SO_ERROR, &err, &len)
|
||||||
@ -476,17 +476,17 @@ fn (mut s TcpSocket) connect(a Addr) ? {
|
|||||||
}
|
}
|
||||||
if write_result {
|
if write_result {
|
||||||
if xyz == 0 {
|
if xyz == 0 {
|
||||||
wrap_error(err)?
|
wrap_error(err)!
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return err_timed_out
|
return err_timed_out
|
||||||
}
|
}
|
||||||
wrap_error(ecode)?
|
wrap_error(ecode)!
|
||||||
return
|
return
|
||||||
} $else {
|
} $else {
|
||||||
x := C.connect(s.handle, voidptr(&a), a.len())
|
x := C.connect(s.handle, voidptr(&a), a.len())
|
||||||
socket_error(x)?
|
socket_error(x)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,14 +22,14 @@ pub fn (mut con TcpConn) get_blocking() bool {
|
|||||||
// when state is true, or non blocking (false).
|
// when state is true, or non blocking (false).
|
||||||
// The default for `net` tcp connections is the non blocking mode.
|
// The default for `net` tcp connections is the non blocking mode.
|
||||||
// Calling .read_line will set the connection to blocking mode.
|
// Calling .read_line will set the connection to blocking mode.
|
||||||
pub fn (mut con TcpConn) set_blocking(state bool) ? {
|
pub fn (mut con TcpConn) set_blocking(state bool) ! {
|
||||||
con.is_blocking = state
|
con.is_blocking = state
|
||||||
$if windows {
|
$if windows {
|
||||||
mut t := u32(0)
|
mut t := u32(0)
|
||||||
if !con.is_blocking {
|
if !con.is_blocking {
|
||||||
t = 1
|
t = 1
|
||||||
}
|
}
|
||||||
socket_error(C.ioctlsocket(con.sock.handle, fionbio, &t))?
|
socket_error(C.ioctlsocket(con.sock.handle, fionbio, &t))!
|
||||||
} $else {
|
} $else {
|
||||||
mut flags := C.fcntl(con.sock.handle, C.F_GETFL, 0)
|
mut flags := C.fcntl(con.sock.handle, C.F_GETFL, 0)
|
||||||
if state {
|
if state {
|
||||||
@ -37,7 +37,7 @@ pub fn (mut con TcpConn) set_blocking(state bool) ? {
|
|||||||
} else {
|
} else {
|
||||||
flags |= C.O_NONBLOCK
|
flags |= C.O_NONBLOCK
|
||||||
}
|
}
|
||||||
socket_error(C.fcntl(con.sock.handle, C.F_SETFL, flags))?
|
socket_error(C.fcntl(con.sock.handle, C.F_SETFL, flags))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +27,8 @@ mut:
|
|||||||
write_timeout time.Duration
|
write_timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dial_udp(raddr string) ?&UdpConn {
|
pub fn dial_udp(raddr string) !&UdpConn {
|
||||||
addrs := resolve_addrs_fuzzy(raddr, .udp)?
|
addrs := resolve_addrs_fuzzy(raddr, .udp)!
|
||||||
|
|
||||||
for addr in addrs {
|
for addr in addrs {
|
||||||
// create a local socket for this
|
// create a local socket for this
|
||||||
@ -43,7 +43,7 @@ pub fn dial_udp(raddr string) ?&UdpConn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn dial_udp(laddr string, raddr string) ?&UdpConn {
|
// pub fn dial_udp(laddr string, raddr string) ?&UdpConn {
|
||||||
@ -58,46 +58,46 @@ pub fn dial_udp(raddr string) ?&UdpConn {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn (mut c UdpConn) write_ptr(b &u8, len int) ?int {
|
pub fn (mut c UdpConn) write_ptr(b &u8, len int) !int {
|
||||||
remote := c.sock.remote() or { return err_no_udp_remote }
|
remote := c.sock.remote() or { return err_no_udp_remote }
|
||||||
return c.write_to_ptr(remote, b, len)
|
return c.write_to_ptr(remote, b, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c UdpConn) write(buf []u8) ?int {
|
pub fn (mut c UdpConn) write(buf []u8) !int {
|
||||||
return c.write_ptr(buf.data, buf.len)
|
return c.write_ptr(buf.data, buf.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c UdpConn) write_string(s string) ?int {
|
pub fn (mut c UdpConn) write_string(s string) !int {
|
||||||
return c.write_ptr(s.str, s.len)
|
return c.write_ptr(s.str, s.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c UdpConn) write_to_ptr(addr Addr, b &u8, len int) ?int {
|
pub fn (mut c UdpConn) write_to_ptr(addr Addr, b &u8, len int) !int {
|
||||||
res := C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len())
|
res := C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len())
|
||||||
if res >= 0 {
|
if res >= 0 {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
code := error_code()
|
code := error_code()
|
||||||
if code == int(error_ewouldblock) {
|
if code == int(error_ewouldblock) {
|
||||||
c.wait_for_write()?
|
c.wait_for_write()!
|
||||||
socket_error(C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len()))?
|
socket_error(C.sendto(c.sock.handle, b, len, 0, voidptr(&addr), addr.len()))!
|
||||||
} else {
|
} else {
|
||||||
wrap_error(code)?
|
wrap_error(code)!
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_to blocks and writes the buf to the remote addr specified
|
// write_to blocks and writes the buf to the remote addr specified
|
||||||
pub fn (mut c UdpConn) write_to(addr Addr, buf []u8) ?int {
|
pub fn (mut c UdpConn) write_to(addr Addr, buf []u8) !int {
|
||||||
return c.write_to_ptr(addr, buf.data, buf.len)
|
return c.write_to_ptr(addr, buf.data, buf.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_to_string blocks and writes the buf to the remote addr specified
|
// write_to_string blocks and writes the buf to the remote addr specified
|
||||||
pub fn (mut c UdpConn) write_to_string(addr Addr, s string) ?int {
|
pub fn (mut c UdpConn) write_to_string(addr Addr, s string) !int {
|
||||||
return c.write_to_ptr(addr, s.str, s.len)
|
return c.write_to_ptr(addr, s.str, s.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// read reads from the socket into buf up to buf.len returning the number of bytes read
|
// read reads from the socket into buf up to buf.len returning the number of bytes read
|
||||||
pub fn (mut c UdpConn) read(mut buf []u8) ?(int, Addr) {
|
pub fn (mut c UdpConn) read(mut buf []u8) !(int, Addr) {
|
||||||
mut addr := Addr{
|
mut addr := Addr{
|
||||||
addr: AddrData{
|
addr: AddrData{
|
||||||
Ip6: Ip6{}
|
Ip6: Ip6{}
|
||||||
@ -105,40 +105,40 @@ pub fn (mut c UdpConn) read(mut buf []u8) ?(int, Addr) {
|
|||||||
}
|
}
|
||||||
len := sizeof(Addr)
|
len := sizeof(Addr)
|
||||||
mut res := wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len,
|
mut res := wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len,
|
||||||
0, voidptr(&addr), &len))?
|
0, voidptr(&addr), &len))!
|
||||||
if res > 0 {
|
if res > 0 {
|
||||||
return res, addr
|
return res, addr
|
||||||
}
|
}
|
||||||
code := error_code()
|
code := error_code()
|
||||||
if code == int(error_ewouldblock) {
|
if code == int(error_ewouldblock) {
|
||||||
c.wait_for_read()?
|
c.wait_for_read()!
|
||||||
// same setup as in tcp
|
// same setup as in tcp
|
||||||
res = wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len, 0,
|
res = wrap_read_result(C.recvfrom(c.sock.handle, voidptr(buf.data), buf.len, 0,
|
||||||
voidptr(&addr), &len))?
|
voidptr(&addr), &len))!
|
||||||
res2 := socket_error(res)?
|
res2 := socket_error(res)!
|
||||||
return res2, addr
|
return res2, addr
|
||||||
} else {
|
} else {
|
||||||
wrap_error(code)?
|
wrap_error(code)!
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &UdpConn) read_deadline() ?time.Time {
|
pub fn (c &UdpConn) read_deadline() !time.Time {
|
||||||
if c.read_deadline.unix == 0 {
|
if c.read_deadline.unix == 0 {
|
||||||
return c.read_deadline
|
return c.read_deadline
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c UdpConn) set_read_deadline(deadline time.Time) {
|
pub fn (mut c UdpConn) set_read_deadline(deadline time.Time) {
|
||||||
c.read_deadline = deadline
|
c.read_deadline = deadline
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &UdpConn) write_deadline() ?time.Time {
|
pub fn (c &UdpConn) write_deadline() !time.Time {
|
||||||
if c.write_deadline.unix == 0 {
|
if c.write_deadline.unix == 0 {
|
||||||
return c.write_deadline
|
return c.write_deadline
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c UdpConn) set_write_deadline(deadline time.Time) {
|
pub fn (mut c UdpConn) set_write_deadline(deadline time.Time) {
|
||||||
@ -162,12 +162,12 @@ pub fn (mut c UdpConn) set_write_timeout(t time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut c UdpConn) wait_for_read() ? {
|
pub fn (mut c UdpConn) wait_for_read() ! {
|
||||||
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut c UdpConn) wait_for_write() ? {
|
pub fn (mut c UdpConn) wait_for_write() ! {
|
||||||
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,27 +176,27 @@ pub fn (c &UdpConn) str() string {
|
|||||||
return 'UdpConn'
|
return 'UdpConn'
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c UdpConn) close() ? {
|
pub fn (mut c UdpConn) close() ! {
|
||||||
return c.sock.close()
|
return c.sock.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen_udp(laddr string) ?&UdpConn {
|
pub fn listen_udp(laddr string) !&UdpConn {
|
||||||
addrs := resolve_addrs_fuzzy(laddr, .udp)?
|
addrs := resolve_addrs_fuzzy(laddr, .udp)!
|
||||||
// TODO(emily):
|
// TODO(emily):
|
||||||
// here we are binding to the first address
|
// here we are binding to the first address
|
||||||
// and that is probably not ideal
|
// and that is probably not ideal
|
||||||
addr := addrs[0]
|
addr := addrs[0]
|
||||||
return &UdpConn{
|
return &UdpConn{
|
||||||
sock: new_udp_socket(addr)?
|
sock: new_udp_socket(addr)!
|
||||||
read_timeout: net.udp_default_read_timeout
|
read_timeout: net.udp_default_read_timeout
|
||||||
write_timeout: net.udp_default_write_timeout
|
write_timeout: net.udp_default_write_timeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_udp_socket(local_addr Addr) ?&UdpSocket {
|
fn new_udp_socket(local_addr Addr) !&UdpSocket {
|
||||||
family := local_addr.family()
|
family := local_addr.family()
|
||||||
|
|
||||||
sockfd := socket_error(C.socket(family, SocketType.udp, 0))?
|
sockfd := socket_error(C.socket(family, SocketType.udp, 0))!
|
||||||
mut s := &UdpSocket{
|
mut s := &UdpSocket{
|
||||||
handle: sockfd
|
handle: sockfd
|
||||||
l: local_addr
|
l: local_addr
|
||||||
@ -207,28 +207,28 @@ fn new_udp_socket(local_addr Addr) ?&UdpSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.set_option_bool(.reuse_addr, true)?
|
s.set_option_bool(.reuse_addr, true)!
|
||||||
|
|
||||||
if family == .ip6 {
|
if family == .ip6 {
|
||||||
s.set_dualstack(true)?
|
s.set_dualstack(true)!
|
||||||
}
|
}
|
||||||
|
|
||||||
$if !net_blocking_sockets ? {
|
$if !net_blocking_sockets ? {
|
||||||
// NOTE: refer to comments in tcp.v
|
// NOTE: refer to comments in tcp.v
|
||||||
$if windows {
|
$if windows {
|
||||||
t := u32(1) // true
|
t := u32(1) // true
|
||||||
socket_error(C.ioctlsocket(sockfd, fionbio, &t))?
|
socket_error(C.ioctlsocket(sockfd, fionbio, &t))!
|
||||||
} $else {
|
} $else {
|
||||||
socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK))?
|
socket_error(C.fcntl(sockfd, C.F_SETFD, C.O_NONBLOCK))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cast to the correct type
|
// cast to the correct type
|
||||||
socket_error(C.bind(s.handle, voidptr(&local_addr), local_addr.len()))?
|
socket_error(C.bind(s.handle, voidptr(&local_addr), local_addr.len()))!
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_udp_socket_for_remote(raddr Addr) ?&UdpSocket {
|
fn new_udp_socket_for_remote(raddr Addr) !&UdpSocket {
|
||||||
// Invent a sutible local address for this remote addr
|
// Invent a sutible local address for this remote addr
|
||||||
// Appease compiler
|
// Appease compiler
|
||||||
mut addr := Addr{
|
mut addr := Addr{
|
||||||
@ -246,20 +246,20 @@ fn new_udp_socket_for_remote(raddr Addr) ?&UdpSocket {
|
|||||||
addr = new_ip6(0, addr_ip6_any)
|
addr = new_ip6(0, addr_ip6_any)
|
||||||
}
|
}
|
||||||
.unix {
|
.unix {
|
||||||
addr = temp_unix()?
|
addr = temp_unix()!
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
panic('Invalid family')
|
panic('Invalid family')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut sock := new_udp_socket(addr)?
|
mut sock := new_udp_socket(addr)!
|
||||||
sock.has_r = true
|
sock.has_r = true
|
||||||
sock.r = raddr
|
sock.r = raddr
|
||||||
|
|
||||||
return sock
|
return sock
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
pub fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ! {
|
||||||
// TODO reenable when this `in` operation works again
|
// TODO reenable when this `in` operation works again
|
||||||
// if opt !in opts_can_set {
|
// if opt !in opts_can_set {
|
||||||
// return err_option_not_settable
|
// return err_option_not_settable
|
||||||
@ -268,26 +268,26 @@ pub fn (mut s UdpSocket) set_option_bool(opt SocketOption, value bool) ? {
|
|||||||
// return err_option_wrong_type
|
// return err_option_wrong_type
|
||||||
// }
|
// }
|
||||||
x := int(value)
|
x := int(value)
|
||||||
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))?
|
socket_error(C.setsockopt(s.handle, C.SOL_SOCKET, int(opt), &x, sizeof(int)))!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s UdpSocket) set_dualstack(on bool) ? {
|
pub fn (mut s UdpSocket) set_dualstack(on bool) ! {
|
||||||
x := int(!on)
|
x := int(!on)
|
||||||
socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x,
|
socket_error(C.setsockopt(s.handle, C.IPPROTO_IPV6, int(SocketOption.ipv6_only), &x,
|
||||||
sizeof(int)))?
|
sizeof(int)))!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s UdpSocket) close() ? {
|
fn (mut s UdpSocket) close() ! {
|
||||||
return shutdown(s.handle)
|
return shutdown(s.handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s UdpSocket) @select(test Select, timeout time.Duration) ?bool {
|
fn (mut s UdpSocket) @select(test Select, timeout time.Duration) !bool {
|
||||||
return @select(s.handle, test, timeout)
|
return @select(s.handle, test, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s &UdpSocket) remote() ?Addr {
|
fn (s &UdpSocket) remote() !Addr {
|
||||||
if s.has_r {
|
if s.has_r {
|
||||||
return s.r
|
return s.r
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ fn echo_server(mut c net.UdpConn) {
|
|||||||
|
|
||||||
const server_addr = '127.0.0.1:40003'
|
const server_addr = '127.0.0.1:40003'
|
||||||
|
|
||||||
fn echo() ? {
|
fn echo() ! {
|
||||||
mut c := net.dial_udp(server_addr) or { panic('could not net.dial_udp: $err') }
|
mut c := net.dial_udp(server_addr) or { panic('could not net.dial_udp: $err') }
|
||||||
defer {
|
defer {
|
||||||
c.close() or {}
|
c.close() or {}
|
||||||
@ -48,7 +48,7 @@ fn echo() ? {
|
|||||||
|
|
||||||
println('Got "$buf.bytestr()"')
|
println('Got "$buf.bytestr()"')
|
||||||
|
|
||||||
c.close()?
|
c.close()!
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_udp() {
|
fn test_udp() {
|
||||||
|
@ -12,18 +12,18 @@ fn C.SUN_LEN(ptr &C.sockaddr_un) int
|
|||||||
fn C.strncpy(&char, &char, int)
|
fn C.strncpy(&char, &char, int)
|
||||||
|
|
||||||
// Shutdown shutsdown a socket and closes it
|
// Shutdown shutsdown a socket and closes it
|
||||||
fn shutdown(handle int) ? {
|
fn shutdown(handle int) ! {
|
||||||
$if windows {
|
$if windows {
|
||||||
C.shutdown(handle, C.SD_BOTH)
|
C.shutdown(handle, C.SD_BOTH)
|
||||||
net.socket_error(C.closesocket(handle))?
|
net.socket_error(C.closesocket(handle))!
|
||||||
} $else {
|
} $else {
|
||||||
C.shutdown(handle, C.SHUT_RDWR)
|
C.shutdown(handle, C.SHUT_RDWR)
|
||||||
net.socket_error(C.close(handle))?
|
net.socket_error(C.close(handle))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select waits for an io operation (specified by parameter `test`) to be available
|
// Select waits for an io operation (specified by parameter `test`) to be available
|
||||||
fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
fn @select(handle int, test Select, timeout time.Duration) !bool {
|
||||||
set := C.fd_set{}
|
set := C.fd_set{}
|
||||||
|
|
||||||
C.FD_ZERO(&set)
|
C.FD_ZERO(&set)
|
||||||
@ -47,13 +47,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
|||||||
|
|
||||||
match test {
|
match test {
|
||||||
.read {
|
.read {
|
||||||
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, &set, C.NULL, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.write {
|
.write {
|
||||||
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, C.NULL, &set, C.NULL, timeval_timeout))!
|
||||||
}
|
}
|
||||||
.except {
|
.except {
|
||||||
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))?
|
net.socket_error(C.@select(handle + 1, C.NULL, C.NULL, &set, timeval_timeout))!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,13 +61,13 @@ fn @select(handle int, test Select, timeout time.Duration) ?bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait_for_common wraps the common wait code
|
// wait_for_common wraps the common wait code
|
||||||
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ? {
|
fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test Select) ! {
|
||||||
if deadline.unix == 0 {
|
if deadline.unix == 0 {
|
||||||
// do not accept negative timeout
|
// do not accept negative timeout
|
||||||
if timeout < 0 {
|
if timeout < 0 {
|
||||||
return net.err_timed_out
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
ready := @select(handle, test, timeout)?
|
ready := @select(handle, test, timeout)!
|
||||||
if ready {
|
if ready {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
|
|||||||
return net.err_timed_out
|
return net.err_timed_out
|
||||||
}
|
}
|
||||||
|
|
||||||
ready := @select(handle, test, d_timeout)?
|
ready := @select(handle, test, d_timeout)!
|
||||||
if ready {
|
if ready {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -90,12 +90,12 @@ fn wait_for_common(handle int, deadline time.Time, timeout time.Duration, test S
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait_for_write waits for a write io operation to be available
|
// wait_for_write waits for a write io operation to be available
|
||||||
fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ? {
|
fn wait_for_write(handle int, deadline time.Time, timeout time.Duration) ! {
|
||||||
return wait_for_common(handle, deadline, timeout, .write)
|
return wait_for_common(handle, deadline, timeout, .write)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait_for_read waits for a read io operation to be available
|
// wait_for_read waits for a read io operation to be available
|
||||||
fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ? {
|
fn wait_for_read(handle int, deadline time.Time, timeout time.Duration) ! {
|
||||||
return wait_for_common(handle, deadline, timeout, .read)
|
return wait_for_common(handle, deadline, timeout, .read)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,9 +120,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn wrap_read_result(result int) ?int {
|
fn wrap_read_result(result int) !int {
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
@ -40,23 +40,23 @@ fn error_code() int {
|
|||||||
return C.errno
|
return C.errno
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_stream_socket() ?StreamSocket {
|
fn new_stream_socket() !StreamSocket {
|
||||||
sockfd := net.socket_error(C.socket(net.AddrFamily.unix, net.SocketType.tcp, 0))?
|
sockfd := net.socket_error(C.socket(net.AddrFamily.unix, net.SocketType.tcp, 0))!
|
||||||
mut s := StreamSocket{
|
mut s := StreamSocket{
|
||||||
handle: sockfd
|
handle: sockfd
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s StreamSocket) close() ? {
|
fn (mut s StreamSocket) close() ! {
|
||||||
return shutdown(s.handle)
|
return shutdown(s.handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s StreamSocket) @select(test Select, timeout time.Duration) ?bool {
|
fn (mut s StreamSocket) @select(test Select, timeout time.Duration) !bool {
|
||||||
return @select(s.handle, test, timeout)
|
return @select(s.handle, test, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut s StreamSocket) connect(a string) ? {
|
fn (mut s StreamSocket) connect(a string) ! {
|
||||||
if a.len >= max_sun_path {
|
if a.len >= max_sun_path {
|
||||||
return error('Socket path too long! Max length: ${max_sun_path - 1} chars.')
|
return error('Socket path too long! Max length: ${max_sun_path - 1} chars.')
|
||||||
}
|
}
|
||||||
@ -73,12 +73,12 @@ fn (mut s StreamSocket) connect(a string) ? {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ := error_code()
|
_ := error_code()
|
||||||
write_result := s.@select(.write, unix.connect_timeout)?
|
write_result := s.@select(.write, unix.connect_timeout)!
|
||||||
if write_result {
|
if write_result {
|
||||||
// succeeded
|
// succeeded
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
except_result := s.@select(.except, unix.connect_timeout)?
|
except_result := s.@select(.except, unix.connect_timeout)!
|
||||||
if except_result {
|
if except_result {
|
||||||
return net.err_connect_failed
|
return net.err_connect_failed
|
||||||
}
|
}
|
||||||
@ -86,11 +86,11 @@ fn (mut s StreamSocket) connect(a string) ? {
|
|||||||
return net.err_connect_timed_out
|
return net.err_connect_timed_out
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen_stream(sock string) ?&StreamListener {
|
pub fn listen_stream(sock string) !&StreamListener {
|
||||||
if sock.len >= max_sun_path {
|
if sock.len >= max_sun_path {
|
||||||
return error('Socket path too long! Max length: ${max_sun_path - 1} chars.')
|
return error('Socket path too long! Max length: ${max_sun_path - 1} chars.')
|
||||||
}
|
}
|
||||||
mut s := new_stream_socket()?
|
mut s := new_stream_socket()!
|
||||||
s.path = sock
|
s.path = sock
|
||||||
mut addr := C.sockaddr_un{}
|
mut addr := C.sockaddr_un{}
|
||||||
unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) }
|
unsafe { C.memset(&addr, 0, sizeof(C.sockaddr_un)) }
|
||||||
@ -98,19 +98,19 @@ pub fn listen_stream(sock string) ?&StreamListener {
|
|||||||
unsafe { C.strncpy(&addr.sun_path[0], &char(sock.str), max_sun_path) }
|
unsafe { C.strncpy(&addr.sun_path[0], &char(sock.str), max_sun_path) }
|
||||||
size := C.SUN_LEN(&addr)
|
size := C.SUN_LEN(&addr)
|
||||||
if os.exists(sock) {
|
if os.exists(sock) {
|
||||||
os.rm(sock)?
|
os.rm(sock)!
|
||||||
}
|
}
|
||||||
net.socket_error(C.bind(s.handle, voidptr(&addr), size))?
|
net.socket_error(C.bind(s.handle, voidptr(&addr), size))!
|
||||||
os.chmod(sock, 0o777)?
|
os.chmod(sock, 0o777)!
|
||||||
net.socket_error(C.listen(s.handle, 128))?
|
net.socket_error(C.listen(s.handle, 128))!
|
||||||
return &StreamListener{
|
return &StreamListener{
|
||||||
sock: s
|
sock: s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_stream(path string) ?&StreamConn {
|
pub fn connect_stream(path string) !&StreamConn {
|
||||||
mut s := new_stream_socket()?
|
mut s := new_stream_socket()!
|
||||||
s.connect(path)?
|
s.connect(path)!
|
||||||
return &StreamConn{
|
return &StreamConn{
|
||||||
sock: s
|
sock: s
|
||||||
read_timeout: unix.unix_default_read_timeout
|
read_timeout: unix.unix_default_read_timeout
|
||||||
@ -118,10 +118,10 @@ pub fn connect_stream(path string) ?&StreamConn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut l StreamListener) accept() ?&StreamConn {
|
pub fn (mut l StreamListener) accept() !&StreamConn {
|
||||||
mut new_handle := C.accept(l.sock.handle, 0, 0)
|
mut new_handle := C.accept(l.sock.handle, 0, 0)
|
||||||
if new_handle <= 0 {
|
if new_handle <= 0 {
|
||||||
l.wait_for_accept()?
|
l.wait_for_accept()!
|
||||||
new_handle = C.accept(l.sock.handle, 0, 0)
|
new_handle = C.accept(l.sock.handle, 0, 0)
|
||||||
if new_handle == -1 || new_handle == 0 {
|
if new_handle == -1 || new_handle == 0 {
|
||||||
return error('accept failed')
|
return error('accept failed')
|
||||||
@ -137,7 +137,7 @@ pub fn (mut l StreamListener) accept() ?&StreamConn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c &StreamListener) accept_deadline() ?time.Time {
|
pub fn (c &StreamListener) accept_deadline() !time.Time {
|
||||||
if c.accept_deadline.unix != 0 {
|
if c.accept_deadline.unix != 0 {
|
||||||
return c.accept_deadline
|
return c.accept_deadline
|
||||||
}
|
}
|
||||||
@ -156,21 +156,21 @@ pub fn (mut c StreamListener) set_accept_timeout(t time.Duration) {
|
|||||||
c.accept_timeout = t
|
c.accept_timeout = t
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamListener) wait_for_accept() ? {
|
pub fn (mut c StreamListener) wait_for_accept() ! {
|
||||||
return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout)
|
return wait_for_read(c.sock.handle, c.accept_deadline, c.accept_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamListener) close() ? {
|
pub fn (mut c StreamListener) close() ! {
|
||||||
os.rm(c.sock.path)?
|
os.rm(c.sock.path)!
|
||||||
c.sock.close()?
|
c.sock.close()!
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamConn) close() ? {
|
pub fn (mut c StreamConn) close() ! {
|
||||||
c.sock.close()?
|
c.sock.close()!
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_ptr blocks and attempts to write all data
|
// write_ptr blocks and attempts to write all data
|
||||||
pub fn (mut c StreamConn) write_ptr(b &u8, len int) ?int {
|
pub fn (mut c StreamConn) write_ptr(b &u8, len int) !int {
|
||||||
$if trace_unix ? {
|
$if trace_unix ? {
|
||||||
eprintln(
|
eprintln(
|
||||||
'>>> StreamConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
|
'>>> StreamConn.write_ptr | c.sock.handle: $c.sock.handle | b: ${ptr_str(b)} len: $len |\n' +
|
||||||
@ -186,10 +186,10 @@ pub fn (mut c StreamConn) write_ptr(b &u8, len int) ?int {
|
|||||||
if sent < 0 {
|
if sent < 0 {
|
||||||
code := error_code()
|
code := error_code()
|
||||||
if code == int(error_ewouldblock) {
|
if code == int(error_ewouldblock) {
|
||||||
c.wait_for_write()?
|
c.wait_for_write()!
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
net.wrap_error(code)?
|
net.wrap_error(code)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
total_sent += sent
|
total_sent += sent
|
||||||
@ -199,17 +199,17 @@ pub fn (mut c StreamConn) write_ptr(b &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write blocks and attempts to write all data
|
// write blocks and attempts to write all data
|
||||||
pub fn (mut c StreamConn) write(bytes []u8) ?int {
|
pub fn (mut c StreamConn) write(bytes []u8) !int {
|
||||||
return c.write_ptr(bytes.data, bytes.len)
|
return c.write_ptr(bytes.data, bytes.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_string blocks and attempts to write all data
|
// write_string blocks and attempts to write all data
|
||||||
pub fn (mut c StreamConn) write_string(s string) ?int {
|
pub fn (mut c StreamConn) write_string(s string) !int {
|
||||||
return c.write_ptr(s.str, s.len)
|
return c.write_ptr(s.str, s.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamConn) read_ptr(buf_ptr &u8, len int) ?int {
|
pub fn (mut c StreamConn) read_ptr(buf_ptr &u8, len int) !int {
|
||||||
mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))?
|
mut res := wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
|
||||||
$if trace_unix ? {
|
$if trace_unix ? {
|
||||||
eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
||||||
}
|
}
|
||||||
@ -218,38 +218,38 @@ pub fn (mut c StreamConn) read_ptr(buf_ptr &u8, len int) ?int {
|
|||||||
}
|
}
|
||||||
code := error_code()
|
code := error_code()
|
||||||
if code == int(error_ewouldblock) {
|
if code == int(error_ewouldblock) {
|
||||||
c.wait_for_read()?
|
c.wait_for_read()!
|
||||||
res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))?
|
res = wrap_read_result(C.recv(c.sock.handle, voidptr(buf_ptr), len, 0))!
|
||||||
$if trace_unix ? {
|
$if trace_unix ? {
|
||||||
eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
eprintln('<<< StreamConn.read_ptr | c.sock.handle: $c.sock.handle | buf_ptr: ${ptr_str(buf_ptr)} len: $len | res: $res')
|
||||||
}
|
}
|
||||||
return net.socket_error(res)
|
return net.socket_error(res)
|
||||||
} else {
|
} else {
|
||||||
net.wrap_error(code)?
|
net.wrap_error(code)!
|
||||||
}
|
}
|
||||||
return net.socket_error(code)
|
return net.socket_error(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamConn) read(mut buf []u8) ?int {
|
pub fn (mut c StreamConn) read(mut buf []u8) !int {
|
||||||
return c.read_ptr(buf.data, buf.len)
|
return c.read_ptr(buf.data, buf.len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamConn) read_deadline() ?time.Time {
|
pub fn (mut c StreamConn) read_deadline() !time.Time {
|
||||||
if c.read_deadline.unix == 0 {
|
if c.read_deadline.unix == 0 {
|
||||||
return c.read_deadline
|
return c.read_deadline
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamConn) set_read_deadline(deadline time.Time) {
|
pub fn (mut c StreamConn) set_read_deadline(deadline time.Time) {
|
||||||
c.read_deadline = deadline
|
c.read_deadline = deadline
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamConn) write_deadline() ?time.Time {
|
pub fn (mut c StreamConn) write_deadline() !time.Time {
|
||||||
if c.write_deadline.unix == 0 {
|
if c.write_deadline.unix == 0 {
|
||||||
return c.write_deadline
|
return c.write_deadline
|
||||||
}
|
}
|
||||||
return none
|
return error('none')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c StreamConn) set_write_deadline(deadline time.Time) {
|
pub fn (mut c StreamConn) set_write_deadline(deadline time.Time) {
|
||||||
@ -273,12 +273,12 @@ pub fn (mut c StreamConn) set_write_timeout(t time.Duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut c StreamConn) wait_for_read() ? {
|
pub fn (mut c StreamConn) wait_for_read() ! {
|
||||||
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
return wait_for_read(c.sock.handle, c.read_deadline, c.read_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (mut c StreamConn) wait_for_write() ? {
|
pub fn (mut c StreamConn) wait_for_write() ! {
|
||||||
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
return wait_for_write(c.sock.handle, c.write_deadline, c.write_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,22 +27,22 @@ fn handle_conn(mut c unix.StreamConn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn echo_server(mut l unix.StreamListener) ? {
|
fn echo_server(mut l unix.StreamListener) ! {
|
||||||
for {
|
for {
|
||||||
mut new_conn := l.accept() or { continue }
|
mut new_conn := l.accept() or { continue }
|
||||||
go handle_conn(mut new_conn)
|
go handle_conn(mut new_conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn echo() ? {
|
fn echo() ! {
|
||||||
mut c := unix.connect_stream(test_port)?
|
mut c := unix.connect_stream(test_port)!
|
||||||
defer {
|
defer {
|
||||||
c.close() or {}
|
c.close() or {}
|
||||||
}
|
}
|
||||||
data := 'Hello from vlib/net!'
|
data := 'Hello from vlib/net!'
|
||||||
c.write_string(data)?
|
c.write_string(data)!
|
||||||
mut buf := []u8{len: 4096}
|
mut buf := []u8{len: 4096}
|
||||||
read := c.read(mut buf)?
|
read := c.read(mut buf)!
|
||||||
assert read == data.len
|
assert read == data.len
|
||||||
for i := 0; i < read; i++ {
|
for i := 0; i < read; i++ {
|
||||||
assert buf[i] == data[i]
|
assert buf[i] == data[i]
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user