forked from vieter-v/vieter
				
			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
 | 
			
		||||
// Pacman as its package manager.
 | 
			
		||||
pub fn create_build_image(base_image string) ?string {
 | 
			
		||||
	mut dd := docker.new_conn() ?
 | 
			
		||||
	mut dd := docker.new_conn()?
 | 
			
		||||
 | 
			
		||||
	commands := [
 | 
			
		||||
		// 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)?
 | 
			
		||||
 | 
			
		||||
	id := dd.create_container(c)?.id
 | 
			
		||||
	/* id := docker.create_container(c)? */
 | 
			
		||||
	// id := docker.create_container(c)?
 | 
			
		||||
	dd.start_container(id)?
 | 
			
		||||
 | 
			
		||||
	// This loop waits until the container has stopped, so we can remove it after
 | 
			
		||||
	for {
 | 
			
		||||
	println('wot')
 | 
			
		||||
		println('wot')
 | 
			
		||||
		data := dd.inspect_container(id)?
 | 
			
		||||
 | 
			
		||||
		if !data.state.running {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ pub struct NewContainer {
 | 
			
		|||
 | 
			
		||||
struct CreatedContainer {
 | 
			
		||||
pub:
 | 
			
		||||
	id string [json: Id]
 | 
			
		||||
	id       string   [json: Id]
 | 
			
		||||
	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) ? {
 | 
			
		||||
	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 {
 | 
			
		||||
		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) ? {
 | 
			
		||||
	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 {
 | 
			
		||||
		data := json.decode(DockerError, body)?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,32 @@ pub:
 | 
			
		|||
	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
 | 
			
		||||
pub fn pull_image(image string, tag string) ?http.Response {
 | 
			
		||||
	return request('POST', urllib.parse('/v1.41/images/create?fromImage=$image&tag=$tag')?)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,11 +6,13 @@ import net.http
 | 
			
		|||
import strings
 | 
			
		||||
import net.urllib
 | 
			
		||||
import json
 | 
			
		||||
import util
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	socket         = '/var/run/docker.sock'
 | 
			
		||||
	buf_len        = 10 * 1024
 | 
			
		||||
	http_separator = [u8(`\r`), `\n`, `\r`, `\n`]
 | 
			
		||||
	socket               = '/var/run/docker.sock'
 | 
			
		||||
	buf_len              = 10 * 1024
 | 
			
		||||
	http_separator       = [u8(`\r`), `\n`, `\r`, `\n`]
 | 
			
		||||
	http_chunk_separator = [u8(`\r`), `\n`]
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
pub struct DockerDaemon {
 | 
			
		||||
| 
						 | 
				
			
			@ -61,17 +63,18 @@ pub fn (mut d DockerDaemon) read_response_head() ?http.Response {
 | 
			
		|||
		c = d.reader.read(mut buf)?
 | 
			
		||||
		res << buf[..c]
 | 
			
		||||
 | 
			
		||||
		mut i := 0
 | 
			
		||||
		mut match_len := 0
 | 
			
		||||
		match_len := util.match_array_in_array(buf[..c], docker.http_separator)
 | 
			
		||||
		// 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
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// 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
 | 
			
		||||
| 
						 | 
				
			
			@ -114,3 +117,9 @@ pub fn (mut d DockerDaemon) read_response() ?(http.Response, string) {
 | 
			
		|||
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
import io
 | 
			
		||||
import util
 | 
			
		||||
import encoding.binary
 | 
			
		||||
import encoding.hex
 | 
			
		||||
 | 
			
		||||
struct ChunkedResponseStream {
 | 
			
		||||
struct ChunkedResponseReader {
 | 
			
		||||
mut:
 | 
			
		||||
	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]}'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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