From dd9958ea28982d39c4dba26036cb9f03c304e27d Mon Sep 17 00:00:00 2001 From: Jef Roosens Date: Fri, 13 May 2022 21:28:24 +0200 Subject: [PATCH] refactor: ran vfmt with new defaults feat(docker): started work on new implementation --- src/docker/containers.v | 13 +++++-- src/docker/docker.v | 20 +++++----- src/docker/socket.v | 83 ++++++++++++++++++++++++++++++++++------- src/main.v | 2 +- 4 files changed, 88 insertions(+), 30 deletions(-) diff --git a/src/docker/containers.v b/src/docker/containers.v index 14ac12d..3b674e6 100644 --- a/src/docker/containers.v +++ b/src/docker/containers.v @@ -3,17 +3,22 @@ module docker import json import net.urllib import time +import net.http struct Container { id string [json: Id] names []string [json: Names] } -// containers returns a list of all currently running containers -pub fn containers() ?[]Container { - res := request('GET', urllib.parse('/v1.41/containers/json')?)? +pub fn (mut d DockerDaemon) containers() ?[]Container { + d.send_request('GET', urllib.parse('/v1.41/containers/json')?)? + res_header := d.read_response_head()? + content_length := res_header.header.get(http.CommonHeader.content_length)?.int() + res := d.read_response_body(content_length)? - return json.decode([]Container, res.text) or {} + data := json.decode([]Container, res)? + + return data } pub struct NewContainer { diff --git a/src/docker/docker.v b/src/docker/docker.v index ce01e7e..fa83d89 100644 --- a/src/docker/docker.v +++ b/src/docker/docker.v @@ -9,8 +9,8 @@ import json // it. fn send(req &string) ?http.Response { // Open a connection to the socket - mut s := unix.connect_stream(docker.socket) or { - return error('Failed to connect to socket ${docker.socket}.') + mut s := unix.connect_stream(socket) or { + return error('Failed to connect to socket ${socket}.') } defer { @@ -21,19 +21,19 @@ fn send(req &string) ?http.Response { } // Write the request to the socket - s.write_string(req) or { return error('Failed to write request to socket ${docker.socket}.') } + s.write_string(req) or { return error('Failed to write request to socket ${socket}.') } s.wait_for_write()? mut c := 0 - mut buf := []u8{len: docker.buf_len} + mut buf := []u8{len: buf_len} mut res := []u8{} for { - c = s.read(mut buf) or { return error('Failed to read data from socket ${docker.socket}.') } + c = s.read(mut buf) or { return error('Failed to read data from socket ${socket}.') } res << buf[..c] - if c < docker.buf_len { + if c < buf_len { break } } @@ -41,7 +41,7 @@ fn send(req &string) ?http.Response { // After reading the first part of the response, we parse it into an HTTP // response. If it isn't chunked, we return early with the data. parsed := http.parse_response(res.bytestr()) or { - return error('Failed to parse HTTP response from socket ${docker.socket}.') + return error('Failed to parse HTTP response from socket ${socket}.') } if parsed.header.get(http.CommonHeader.transfer_encoding) or { '' } != 'chunked' { @@ -55,12 +55,10 @@ fn send(req &string) ?http.Response { s.wait_for_write()? for { - c = s.read(mut buf) or { - return error('Failed to read data from socket ${docker.socket}.') - } + c = s.read(mut buf) or { return error('Failed to read data from socket ${socket}.') } res << buf[..c] - if c < docker.buf_len { + if c < buf_len { break } } diff --git a/src/docker/socket.v b/src/docker/socket.v index 3a72f14..7815435 100644 --- a/src/docker/socket.v +++ b/src/docker/socket.v @@ -3,10 +3,15 @@ module docker import net.unix import io import net.http +import strings +import net.urllib +import json -const socket = '/var/run/docker.sock' - -const buf_len = 10 * 1024 +const ( + socket = '/var/run/docker.sock' + buf_len = 10 * 1024 + http_separator = [u8(`\r`), `\n`, `\r`, `\n`] +) pub struct DockerDaemon { mut: @@ -14,34 +19,84 @@ mut: reader &io.BufferedReader } -pub fn new_conn() ?DockerDaemon { - s := unix.connect_stream(socket) ? +pub fn new_conn() ?&DockerDaemon { + s := unix.connect_stream(docker.socket)? - d := DockerDaemon{socket: s, reader: io.new_buffered_reader(reader: s)} + d := &DockerDaemon{ + socket: s + reader: io.new_buffered_reader(reader: s) + } return d } -fn (mut d DockerDaemon) send_request(req &string) ? { - d.socket.write_string(req) ? - d.socket.wait_for_write() ? +pub fn (mut d DockerDaemon) send_request(method string, url urllib.URL) ? { + req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\n\n' + + d.socket.write_string(req)? +} + +pub fn (mut d DockerDaemon) send_request_with_body(method string, url urllib.URL, content_type string, body string) ? { + req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\nContent-Type: $content_type\nContent-Length: $body.len\n\n$body\n\n' + + d.socket.write_string(req)? +} + +pub fn (mut d DockerDaemon) request_with_json(method string, url urllib.URL, data &T) ? { + body := json.encode(data) + + return request_with_body(method, url, 'application/json', body) } // read_response_head consumes the socket's contents until it encounters -// '\n\n', after which it parses the response as an HTTP response. -fn (mut d DockerDaemon) read_response_head() ?http.Response { +// '\r\n\r\n', after which it parses the response as an HTTP response. +pub fn (mut d DockerDaemon) read_response_head() ?http.Response { mut c := 0 - mut buf := [buf_len]u8{len: docker.buf_len} + mut buf := []u8{len: 4} mut res := []u8{} for { - c = d.socket.read(mut buf) ? + c = d.reader.read(mut buf)? res << buf[..c] - if res#[-2..] == [u8(`\n`), `\n`] { + mut i := 0 + mut match_len := 0 + + for i + match_len < c { + if buf[i + match_len] == docker.http_separator[match_len] { + match_len += 1 + } else { + i += match_len + 1 + match_len = 0 + } + } + + if match_len == 4 { break + } else if match_len > 0 { + mut buf2 := []u8{len: 4 - match_len} + c2 := d.reader.read(mut buf2)? + res << buf2[..c2] + + if buf2 == docker.http_separator[match_len..] { + break + } } } return http.parse_response(res.bytestr()) } + +pub fn (mut d DockerDaemon) read_response_body(length int) ?string { + mut buf := []u8{len: docker.buf_len} + mut c := 0 + mut builder := strings.new_builder(docker.buf_len) + + for builder.len < length { + c = d.reader.read(mut buf) or { break } + + builder.write(buf[..c])? + } + + return builder.str() +} diff --git a/src/main.v b/src/main.v index 41d0d33..db6d5ef 100644 --- a/src/main.v +++ b/src/main.v @@ -31,7 +31,7 @@ fn main() { logs.cmd(), ] } - app.setup() app.parse(os.args) + return }