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