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