feat(docker): added ChunkedResponseReader implementation
parent
da46b8b4ae
commit
92cbea69d6
|
@ -17,7 +17,7 @@ const build_image_repo = 'vieter-build'
|
||||||
// makepkg with. The base image should be some Linux distribution that uses
|
// makepkg with. The base image should be some Linux distribution that uses
|
||||||
// Pacman as its package manager.
|
// Pacman as its package manager.
|
||||||
pub fn create_build_image(base_image string) ?string {
|
pub fn create_build_image(base_image string) ?string {
|
||||||
mut dd := docker.new_conn() ?
|
mut dd := docker.new_conn()?
|
||||||
|
|
||||||
commands := [
|
commands := [
|
||||||
// Update repos & install required packages
|
// Update repos & install required packages
|
||||||
|
@ -51,12 +51,12 @@ pub fn create_build_image(base_image string) ?string {
|
||||||
docker.pull_image(image_name, image_tag)?
|
docker.pull_image(image_name, image_tag)?
|
||||||
|
|
||||||
id := dd.create_container(c)?.id
|
id := dd.create_container(c)?.id
|
||||||
/* id := docker.create_container(c)? */
|
// id := docker.create_container(c)?
|
||||||
dd.start_container(id)?
|
dd.start_container(id)?
|
||||||
|
|
||||||
// This loop waits until the container has stopped, so we can remove it after
|
// This loop waits until the container has stopped, so we can remove it after
|
||||||
for {
|
for {
|
||||||
println('wot')
|
println('wot')
|
||||||
data := dd.inspect_container(id)?
|
data := dd.inspect_container(id)?
|
||||||
|
|
||||||
if !data.state.running {
|
if !data.state.running {
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub struct NewContainer {
|
||||||
|
|
||||||
struct CreatedContainer {
|
struct CreatedContainer {
|
||||||
pub:
|
pub:
|
||||||
id string [json: Id]
|
id string [json: Id]
|
||||||
warnings []string [json: Warnings]
|
warnings []string [json: Warnings]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ pub fn (mut d DockerDaemon) create_container(c NewContainer) ?CreatedContainer {
|
||||||
|
|
||||||
pub fn (mut d DockerDaemon) start_container(id string) ? {
|
pub fn (mut d DockerDaemon) start_container(id string) ? {
|
||||||
d.send_request('POST', urllib.parse('/v1.41/containers/$id/start')?)?
|
d.send_request('POST', urllib.parse('/v1.41/containers/$id/start')?)?
|
||||||
head, body := d.read_response() ?
|
head, body := d.read_response()?
|
||||||
|
|
||||||
if head.status_code != 204 {
|
if head.status_code != 204 {
|
||||||
data := json.decode(DockerError, body)?
|
data := json.decode(DockerError, body)?
|
||||||
|
@ -152,7 +152,7 @@ pub fn inspect_container(id string) ?ContainerInspect {
|
||||||
|
|
||||||
pub fn (mut d DockerDaemon) remove_container(id string) ? {
|
pub fn (mut d DockerDaemon) remove_container(id string) ? {
|
||||||
d.send_request('DELETE', urllib.parse('/v1.41/containers/$id')?)?
|
d.send_request('DELETE', urllib.parse('/v1.41/containers/$id')?)?
|
||||||
head, body := d.read_response() ?
|
head, body := d.read_response()?
|
||||||
|
|
||||||
if head.status_code != 204 {
|
if head.status_code != 204 {
|
||||||
data := json.decode(DockerError, body)?
|
data := json.decode(DockerError, body)?
|
||||||
|
|
|
@ -9,6 +9,32 @@ pub:
|
||||||
id string [json: Id]
|
id string [json: Id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut d DockerDaemon) pull_image(image string, tag string) ? {
|
||||||
|
d.send_request('POST', urllib.parse('/v1.41/images/create?fromImage=$image&tag=$tag')?)?
|
||||||
|
head := d.read_response_head()?
|
||||||
|
|
||||||
|
if head.status_code != 200 {
|
||||||
|
content_length := head.header.get(http.CommonHeader.content_length)?.int()
|
||||||
|
body := d.read_response_body(content_length)?
|
||||||
|
data := json.decode(DockerError, body)?
|
||||||
|
|
||||||
|
return error(data.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
mut body := d.get_chunked_response_reader()
|
||||||
|
|
||||||
|
mut buf := []u8{len: 1024}
|
||||||
|
|
||||||
|
for {
|
||||||
|
c := body.read(mut buf)?
|
||||||
|
|
||||||
|
if c == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
print(buf[..c].bytestr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pull_image pulls tries to pull the image for the given image & tag
|
// pull_image pulls tries to pull the image for the given image & tag
|
||||||
pub fn pull_image(image string, tag string) ?http.Response {
|
pub fn pull_image(image string, tag string) ?http.Response {
|
||||||
return request('POST', urllib.parse('/v1.41/images/create?fromImage=$image&tag=$tag')?)
|
return request('POST', urllib.parse('/v1.41/images/create?fromImage=$image&tag=$tag')?)
|
||||||
|
|
|
@ -6,11 +6,13 @@ import net.http
|
||||||
import strings
|
import strings
|
||||||
import net.urllib
|
import net.urllib
|
||||||
import json
|
import json
|
||||||
|
import util
|
||||||
|
|
||||||
const (
|
const (
|
||||||
socket = '/var/run/docker.sock'
|
socket = '/var/run/docker.sock'
|
||||||
buf_len = 10 * 1024
|
buf_len = 10 * 1024
|
||||||
http_separator = [u8(`\r`), `\n`, `\r`, `\n`]
|
http_separator = [u8(`\r`), `\n`, `\r`, `\n`]
|
||||||
|
http_chunk_separator = [u8(`\r`), `\n`]
|
||||||
)
|
)
|
||||||
|
|
||||||
pub struct DockerDaemon {
|
pub struct DockerDaemon {
|
||||||
|
@ -61,17 +63,18 @@ pub fn (mut d DockerDaemon) read_response_head() ?http.Response {
|
||||||
c = d.reader.read(mut buf)?
|
c = d.reader.read(mut buf)?
|
||||||
res << buf[..c]
|
res << buf[..c]
|
||||||
|
|
||||||
mut i := 0
|
match_len := util.match_array_in_array(buf[..c], docker.http_separator)
|
||||||
mut match_len := 0
|
// mut i := 0
|
||||||
|
// mut match_len := 0
|
||||||
|
|
||||||
for i + match_len < c {
|
// for i + match_len < c {
|
||||||
if buf[i + match_len] == docker.http_separator[match_len] {
|
// if buf[i + match_len] == docker.http_separator[match_len] {
|
||||||
match_len += 1
|
// match_len += 1
|
||||||
} else {
|
// } else {
|
||||||
i += match_len + 1
|
// i += match_len + 1
|
||||||
match_len = 0
|
// match_len = 0
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
if match_len == 4 {
|
if match_len == 4 {
|
||||||
break
|
break
|
||||||
|
@ -114,3 +117,9 @@ pub fn (mut d DockerDaemon) read_response() ?(http.Response, string) {
|
||||||
|
|
||||||
return head, res
|
return head, res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut d DockerDaemon) get_chunked_response_reader() &ChunkedResponseReader {
|
||||||
|
r := new_chunked_response_reader(d.reader)
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,99 @@
|
||||||
module docker
|
module docker
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
import util
|
||||||
|
import encoding.binary
|
||||||
|
import encoding.hex
|
||||||
|
|
||||||
struct ChunkedResponseStream {
|
struct ChunkedResponseReader {
|
||||||
|
mut:
|
||||||
reader io.Reader
|
reader io.Reader
|
||||||
|
// buf []u8
|
||||||
|
// offset int
|
||||||
|
// len int
|
||||||
|
bytes_left_in_chunk u64
|
||||||
|
end_of_stream bool
|
||||||
|
started bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_chunked_response_reader(reader io.Reader) &ChunkedResponseReader {
|
||||||
|
r := &ChunkedResponseReader{
|
||||||
|
reader: reader
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// We satisfy the io.Reader interface
|
||||||
|
pub fn (mut r ChunkedResponseReader) read(mut buf []u8) ?int {
|
||||||
|
if r.end_of_stream {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.bytes_left_in_chunk == 0 {
|
||||||
|
r.bytes_left_in_chunk = r.read_chunk_size()?
|
||||||
|
|
||||||
|
if r.end_of_stream {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mut c := 0
|
||||||
|
|
||||||
|
if buf.len > r.bytes_left_in_chunk {
|
||||||
|
c = r.reader.read(mut buf[..r.bytes_left_in_chunk])?
|
||||||
|
} else {
|
||||||
|
c = r.reader.read(mut buf)?
|
||||||
|
}
|
||||||
|
|
||||||
|
r.bytes_left_in_chunk -= u64(c)
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut r ChunkedResponseReader) read_chunk_size() ?u64 {
|
||||||
|
mut buf := []u8{len: 2}
|
||||||
|
mut res := []u8{}
|
||||||
|
|
||||||
|
if r.started {
|
||||||
|
// Each chunk ends with a `\r\n` which we want to skip first
|
||||||
|
r.reader.read(mut buf) ?
|
||||||
|
}
|
||||||
|
|
||||||
|
r.started = true
|
||||||
|
|
||||||
|
for {
|
||||||
|
c := r.reader.read(mut buf)?
|
||||||
|
res << buf[..c]
|
||||||
|
|
||||||
|
match_len := util.match_array_in_array(buf[..c], http_chunk_separator)
|
||||||
|
|
||||||
|
if match_len == http_chunk_separator.len {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if match_len > 0 {
|
||||||
|
mut buf2 := []u8{len: 2 - match_len}
|
||||||
|
c2 := r.reader.read(mut buf2)?
|
||||||
|
res << buf2[..c2]
|
||||||
|
|
||||||
|
if buf2 == http_chunk_separator[match_len..] {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mut num_data := hex.decode(res#[..-2].bytestr())?
|
||||||
|
|
||||||
|
for num_data.len < 8 {
|
||||||
|
num_data.insert(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
num := binary.big_endian_u64(num_data)
|
||||||
|
|
||||||
|
if num == 0 {
|
||||||
|
r.end_of_stream = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
|
@ -92,3 +92,19 @@ pub fn pretty_bytes(bytes int) string {
|
||||||
|
|
||||||
return '${n:.2}${util.prefixes[i]}'
|
return '${n:.2}${util.prefixes[i]}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn match_array_in_array<T>(a1 []T, a2 []T) int {
|
||||||
|
mut i := 0
|
||||||
|
mut match_len := 0
|
||||||
|
|
||||||
|
for i + match_len < a1.len {
|
||||||
|
if a1[i + match_len] == a2[match_len] {
|
||||||
|
match_len += 1
|
||||||
|
} else {
|
||||||
|
i += match_len + 1
|
||||||
|
match_len = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match_len
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue