From 3bda79f7ce3a412a0cfc099361cc02afe0ae1a05 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 21 Jun 2022 15:47:42 +0200 Subject: [PATCH] refactor: simplified api call functions --- containers.v | 19 +++++++++++-------- docker.v | 33 +++++++++++++++++++++++++++++---- errors.v | 21 +++++++++++++++++++++ images.v | 7 +++---- volumes.v | 15 +++------------ 5 files changed, 67 insertions(+), 28 deletions(-) create mode 100644 errors.v diff --git a/containers.v b/containers.v index 886c739..0abedff 100644 --- a/containers.v +++ b/containers.v @@ -1,12 +1,15 @@ module vdocker import json -import net.urllib import time import net.http { Method } -struct DockerError { - message string +pub struct ContainerListItem { + id string [json: Id] + names []string [json: Names] + image string [json: Image] + image_id string [json: ImageID] + command string [json: Command] } pub struct NewContainer { @@ -26,7 +29,7 @@ pub: // create_container creates a new container with the given config. pub fn (mut d DockerConn) create_container(c NewContainer) ?CreatedContainer { - d.send_request_with_json(Method.post, urllib.parse('/v1.41/containers/create')?, c)? + d.send_request_with_json(Method.post, '/containers/create', c)? head, res := d.read_response()? if head.status_code != 201 { @@ -42,7 +45,7 @@ pub fn (mut d DockerConn) create_container(c NewContainer) ?CreatedContainer { // start_container starts the container with the given id. pub fn (mut d DockerConn) start_container(id string) ? { - d.send_request(Method.post, urllib.parse('/v1.41/containers/$id/start')?)? + d.send_request(Method.post, 'containers/$id/start')? head, body := d.read_response()? if head.status_code != 204 { @@ -72,7 +75,7 @@ pub mut: // inspect_container returns detailed information for a given container. pub fn (mut d DockerConn) inspect_container(id string) ?ContainerInspect { - d.send_request(Method.get, urllib.parse('/v1.41/containers/$id/json')?)? + d.send_request(Method.get, 'containers/$id/json')? head, body := d.read_response()? if head.status_code != 200 { @@ -95,7 +98,7 @@ pub fn (mut d DockerConn) inspect_container(id string) ?ContainerInspect { // remove_container removes the container with the given id. pub fn (mut d DockerConn) remove_container(id string) ? { - d.send_request(Method.delete, urllib.parse('/v1.41/containers/$id')?)? + d.send_request(Method.delete, 'containers/$id')? head, body := d.read_response()? if head.status_code != 204 { @@ -108,7 +111,7 @@ pub fn (mut d DockerConn) remove_container(id string) ? { // get_container_logs returns a reader object allowing access to the // container's logs. pub fn (mut d DockerConn) get_container_logs(id string) ?&StreamFormatReader { - d.send_request(Method.get, urllib.parse('/v1.41/containers/$id/logs?stdout=true&stderr=true')?)? + d.send_request(Method.get, 'containers/$id/logs?stdout=true&stderr=true')? head := d.read_response_head()? if head.status_code != 200 { diff --git a/docker.v b/docker.v index 1784599..4920203 100644 --- a/docker.v +++ b/docker.v @@ -7,12 +7,15 @@ import strings import net.urllib import json import util +import time const ( socket = '/var/run/docker.sock' buf_len = 10 * 1024 http_separator = [u8(`\r`), `\n`, `\r`, `\n`] http_chunk_separator = [u8(`\r`), `\n`] + timestamp_attr = 'timestamp' + api_version = 'v1.41' ) pub struct DockerConn { @@ -39,7 +42,8 @@ pub fn (mut d DockerConn) close() ? { } // send_request sends an HTTP request without body. -fn (mut d DockerConn) send_request(method http.Method, url urllib.URL) ? { +fn (mut d DockerConn) send_request(method http.Method, url_str string) ? { + url := urllib.parse('/$api_version$url_str')? req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\n\n' d.socket.write_string(req)? @@ -49,7 +53,8 @@ fn (mut d DockerConn) send_request(method http.Method, url urllib.URL) ? { } // send_request_with_body sends an HTTP request with the given body. -fn (mut d DockerConn) send_request_with_body(method http.Method, url urllib.URL, content_type string, body string) ? { +fn (mut d DockerConn) send_request_with_body(method http.Method, url_str string, content_type string, body string) ? { + url := urllib.parse('/$api_version$url_str')? 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)? @@ -60,10 +65,10 @@ fn (mut d DockerConn) send_request_with_body(method http.Method, url urllib.URL, // send_request_with_json is a convenience wrapper around // send_request_with_body that encodes the input as JSON. -fn (mut d DockerConn) send_request_with_json(method http.Method, url urllib.URL, data &T) ? { +fn (mut d DockerConn) send_request_with_json(method http.Method, url_str string, data &T) ? { body := json.encode(data) - return d.send_request_with_body(method, url, 'application/json', body) + return d.send_request_with_body(method, url_str, 'application/json', body) } // read_response_head consumes the socket's contents until it encounters @@ -119,6 +124,26 @@ fn (mut d DockerConn) read_response() ?(http.Response, string) { return head, res } +fn (mut d DockerConn) read_json_response() ?T { + head, body := d.read_response()? + + if head.status_code < 200 || head.status_code > 300 { + data := json.decode(DockerError, body)? + + return docker_error(head.status_code, data.message) + } + + mut data := json.decode(T, body)? + + /* $for field in T.fields { */ + /* $if field.typ is time.Time { */ + /* data.$(field.name) = time.parse_rfc3339(data.$(field.name + '_str'))? */ + /* } */ + /* } */ + + return data +} + // get_chunked_response_reader returns a ChunkedResponseReader using the socket // as reader. fn (mut d DockerConn) get_chunked_response_reader() &ChunkedResponseReader { diff --git a/errors.v b/errors.v new file mode 100644 index 0000000..ff24028 --- /dev/null +++ b/errors.v @@ -0,0 +1,21 @@ +module vdocker + +struct DockerError { + status int [skip] + message string +} + +fn (err DockerError) code() int { + return err.status +} + +fn (err DockerError) msg() string { + return err.message +} + +fn docker_error(status int, message string) IError { + return IError(DockerError{ + status: status + message: message + }) +} diff --git a/images.v b/images.v index 945951d..aeaa53f 100644 --- a/images.v +++ b/images.v @@ -1,7 +1,6 @@ module vdocker import net.http { Method } -import net.urllib import json struct Image { @@ -11,7 +10,7 @@ pub: // pull_image pulls the given image:tag. pub fn (mut d DockerConn) pull_image(image string, tag string) ? { - d.send_request(Method.post, urllib.parse('/v1.41/images/create?fromImage=$image&tag=$tag')?)? + d.send_request(Method.post, 'images/create?fromImage=$image&tag=$tag')? head := d.read_response_head()? if head.status_code != 200 { @@ -34,7 +33,7 @@ pub fn (mut d DockerConn) pull_image(image string, tag string) ? { // create_image_from_container creates a new image from a container. pub fn (mut d DockerConn) create_image_from_container(id string, repo string, tag string) ?Image { - d.send_request(Method.post, urllib.parse('/v1.41/commit?container=$id&repo=$repo&tag=$tag')?)? + d.send_request(Method.post, 'commit?container=$id&repo=$repo&tag=$tag')? head, body := d.read_response()? if head.status_code != 201 { @@ -50,7 +49,7 @@ pub fn (mut d DockerConn) create_image_from_container(id string, repo string, ta // remove_image removes the image with the given id. pub fn (mut d DockerConn) remove_image(id string) ? { - d.send_request(Method.delete, urllib.parse('/v1.41/images/$id')?)? + d.send_request(Method.delete, 'images/$id')? head, body := d.read_response()? if head.status_code != 200 { diff --git a/volumes.v b/volumes.v index 1ef10b0..b0c6a04 100644 --- a/volumes.v +++ b/volumes.v @@ -1,8 +1,6 @@ module vdocker import net.http { Method } -import net.urllib -import json import time struct UsageData { @@ -13,10 +11,10 @@ struct UsageData { struct Volume { created_at_str string [json: CreatedAt] pub mut: + created_at time.Time [skip] name string [json: Name] driver string [json: Driver] mountpoint string [json: Mountpoint] - created_at time.Time [skip] status map[string]string [json: Status] labels map[string]string [json: Labels] scope string [json: Scope] @@ -30,16 +28,9 @@ struct VolumeListResponse { } pub fn (mut d DockerConn) volume_list() ?VolumeListResponse { - d.send_request(Method.get, urllib.parse('/v1.41/volumes')?)? - head, body := d.read_response()? + d.send_request(Method.get, '/volumes')? - if head.status_code != 200 { - data := json.decode(DockerError, body)? - - return error(data.message) - } - - mut data := json.decode(VolumeListResponse, body)? + mut data := d.read_json_response()? for mut vol in data.volumes { vol.created_at = time.parse_rfc3339(vol.created_at_str)?