forked from vieter-v/vieter
				
			doc: documented new Docker code
							parent
							
								
									f22ed29631
								
							
						
					
					
						commit
						1811ebbe3f
					
				|  | @ -14,6 +14,7 @@ struct Container { | |||
| 	names []string [json: Names] | ||||
| } | ||||
| 
 | ||||
| // containers returns a list of all containers. | ||||
| pub fn (mut d DockerDaemon) containers() ?[]Container { | ||||
| 	d.send_request('GET', urllib.parse('/v1.41/containers/json')?)? | ||||
| 	head, res := d.read_response()? | ||||
|  | @ -45,6 +46,7 @@ pub: | |||
| 	warnings []string [json: Warnings] | ||||
| } | ||||
| 
 | ||||
| // create_container creates a new container with the given config. | ||||
| pub fn (mut d DockerDaemon) create_container(c NewContainer) ?CreatedContainer { | ||||
| 	d.send_request_with_json('POST', urllib.parse('/v1.41/containers/create')?, c)? | ||||
| 	head, res := d.read_response()? | ||||
|  | @ -60,6 +62,7 @@ pub fn (mut d DockerDaemon) create_container(c NewContainer) ?CreatedContainer { | |||
| 	return data | ||||
| } | ||||
| 
 | ||||
| // start_container starts the container with the given id. | ||||
| 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()? | ||||
|  | @ -109,6 +112,7 @@ pub mut: | |||
| 	end_time   time.Time [skip] | ||||
| } | ||||
| 
 | ||||
| // inspect_container returns detailed information for a given container. | ||||
| pub fn (mut d DockerDaemon) inspect_container(id string) ?ContainerInspect { | ||||
| 	d.send_request('GET', urllib.parse('/v1.41/containers/$id/json')?)? | ||||
| 	head, body := d.read_response()? | ||||
|  | @ -150,6 +154,7 @@ pub fn inspect_container(id string) ?ContainerInspect { | |||
| 	return data | ||||
| } | ||||
| 
 | ||||
| // remove_container removes the container with the given id. | ||||
| pub fn (mut d DockerDaemon) remove_container(id string) ? { | ||||
| 	d.send_request('DELETE', urllib.parse('/v1.41/containers/$id')?)? | ||||
| 	head, body := d.read_response()? | ||||
|  | @ -168,6 +173,8 @@ pub fn remove_container(id string) ?bool { | |||
| 	return res.status_code == 204 | ||||
| } | ||||
| 
 | ||||
| // get_container_logs returns a reader object allowing access to the | ||||
| // container's logs. | ||||
| pub fn (mut d DockerDaemon) get_container_logs(id string) ?&StreamFormatReader { | ||||
| 	d.send_request('GET', urllib.parse('/v1.41/containers/$id/logs?stdout=true&stderr=true')?)? | ||||
| 	head := d.read_response_head()? | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ pub: | |||
| 	id string [json: Id] | ||||
| } | ||||
| 
 | ||||
| // pull_image pulls the given image:tag. | ||||
| 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()? | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ mut: | |||
| 	reader &io.BufferedReader | ||||
| } | ||||
| 
 | ||||
| // new_conn creates a new connection to the Docker daemon. | ||||
| pub fn new_conn() ?&DockerDaemon { | ||||
| 	s := unix.connect_stream(docker.socket)? | ||||
| 
 | ||||
|  | @ -32,18 +33,22 @@ pub fn new_conn() ?&DockerDaemon { | |||
| 	return d | ||||
| } | ||||
| 
 | ||||
| // send_request sends an HTTP request without body. | ||||
| pub fn (mut d DockerDaemon) send_request(method string, url urllib.URL) ? { | ||||
| 	req := '$method $url.request_uri() HTTP/1.1\nHost: localhost\n\n' | ||||
| 
 | ||||
| 	d.socket.write_string(req)? | ||||
| } | ||||
| 
 | ||||
| // send_request_with_body sends an HTTP request with the given body. | ||||
| pub fn (mut d DockerDaemon) send_request_with_body(method string, url urllib.URL, content_type string, body string) ? { | ||||
| 	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)? | ||||
| } | ||||
| 
 | ||||
| // send_request_with_json<T> is a convenience wrapper around | ||||
| // send_request_with_body that encodes the input as JSON. | ||||
| pub fn (mut d DockerDaemon) send_request_with_json<T>(method string, url urllib.URL, data &T) ? { | ||||
| 	body := json.encode(data) | ||||
| 
 | ||||
|  | @ -52,8 +57,8 @@ pub fn (mut d DockerDaemon) send_request_with_json<T>(method string, url urllib. | |||
| 
 | ||||
| // read_response_head consumes the socket's contents until it encounters | ||||
| // '\r\n\r\n', after which it parses the response as an HTTP response. | ||||
| // Importantly, this function never consumes past the HTTP separator, so the | ||||
| // body can be read fully later on. | ||||
| // Importantly, this function never consumes the reader past the HTTP | ||||
| // separator, so the body can be read fully later on. | ||||
| pub fn (mut d DockerDaemon) read_response_head() ?http.Response { | ||||
| 	mut c := 0 | ||||
| 	mut buf := []u8{len: 4} | ||||
|  | @ -64,21 +69,12 @@ pub fn (mut d DockerDaemon) read_response_head() ?http.Response { | |||
| 		res << buf[..c] | ||||
| 
 | ||||
| 		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 | ||||
| 		//	} | ||||
| 		//} | ||||
| 
 | ||||
| 		if match_len == 4 { | ||||
| 			break | ||||
| 		} else if match_len > 0 { | ||||
| 		} | ||||
| 
 | ||||
| 		if match_len > 0 { | ||||
| 			mut buf2 := []u8{len: 4 - match_len} | ||||
| 			c2 := d.reader.read(mut buf2)? | ||||
| 			res << buf2[..c2] | ||||
|  | @ -92,6 +88,8 @@ pub fn (mut d DockerDaemon) read_response_head() ?http.Response { | |||
| 	return http.parse_response(res.bytestr()) | ||||
| } | ||||
| 
 | ||||
| // read_response_body reads `length` bytes from the stream. It can be used when | ||||
| // the response encoding isn't chunked to fully read it. | ||||
| pub fn (mut d DockerDaemon) read_response_body(length int) ?string { | ||||
| 	if length == 0 { | ||||
| 		return '' | ||||
|  | @ -110,6 +108,9 @@ pub fn (mut d DockerDaemon) read_response_body(length int) ?string { | |||
| 	return builder.str() | ||||
| } | ||||
| 
 | ||||
| // read_response is a convenience function combining read_response_head & | ||||
| // read_response_body. It can be used when you know for certain the response | ||||
| // won't be chunked. | ||||
| pub fn (mut d DockerDaemon) read_response() ?(http.Response, string) { | ||||
| 	head := d.read_response_head()? | ||||
| 	content_length := head.header.get(http.CommonHeader.content_length)?.int() | ||||
|  | @ -118,12 +119,16 @@ pub fn (mut d DockerDaemon) read_response() ?(http.Response, string) { | |||
| 	return head, res | ||||
| } | ||||
| 
 | ||||
| // get_chunked_response_reader returns a ChunkedResponseReader using the socket | ||||
| // as reader. | ||||
| pub fn (mut d DockerDaemon) get_chunked_response_reader() &ChunkedResponseReader { | ||||
| 	r := new_chunked_response_reader(d.reader) | ||||
| 
 | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| // get_stream_format_reader returns a StreamFormatReader using the socket as | ||||
| // reader. | ||||
| pub fn (mut d DockerDaemon) get_stream_format_reader() &StreamFormatReader { | ||||
| 	r := new_chunked_response_reader(d.reader) | ||||
| 	r2 := new_stream_format_reader(r) | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ import util | |||
| import encoding.binary | ||||
| import encoding.hex | ||||
| 
 | ||||
| // ChunkedResponseReader parses an underlying HTTP chunked response, exposing | ||||
| // it as if it was a continuous stream of data. | ||||
| struct ChunkedResponseReader { | ||||
| mut: | ||||
| 	reader              io.Reader | ||||
|  | @ -13,6 +15,8 @@ mut: | |||
| 	started             bool | ||||
| } | ||||
| 
 | ||||
| // new_chunked_response_reader creates a new ChunkedResponseReader on the heap | ||||
| // with the provided reader. | ||||
| pub fn new_chunked_response_reader(reader io.Reader) &ChunkedResponseReader { | ||||
| 	r := &ChunkedResponseReader{ | ||||
| 		reader: reader | ||||
|  | @ -21,7 +25,7 @@ pub fn new_chunked_response_reader(reader io.Reader) &ChunkedResponseReader { | |||
| 	return r | ||||
| } | ||||
| 
 | ||||
| // We satisfy the io.Reader interface | ||||
| // read satisfies the io.Reader interface. | ||||
| pub fn (mut r ChunkedResponseReader) read(mut buf []u8) ?int { | ||||
| 	if r.end_of_stream { | ||||
| 		return none | ||||
|  | @ -37,6 +41,8 @@ pub fn (mut r ChunkedResponseReader) read(mut buf []u8) ?int { | |||
| 
 | ||||
| 	mut c := 0 | ||||
| 
 | ||||
| 	// Make sure we don't read more than we can safely read. This is to avoid | ||||
| 	// the underlying reader from becoming out of sync with our parsing: | ||||
| 	if buf.len > r.bytes_left_in_chunk { | ||||
| 		c = r.reader.read(mut buf[..r.bytes_left_in_chunk])? | ||||
| 	} else { | ||||
|  | @ -48,6 +54,9 @@ pub fn (mut r ChunkedResponseReader) read(mut buf []u8) ?int { | |||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // read_chunk_size advances the reader & reads the size of the next HTTP chunk. | ||||
| // This function should only be called if the previous chunk has been | ||||
| // completely consumed. | ||||
| fn (mut r ChunkedResponseReader) read_chunk_size() ?u64 { | ||||
| 	mut buf := []u8{len: 2} | ||||
| 	mut res := []u8{} | ||||
|  | @ -80,6 +89,7 @@ fn (mut r ChunkedResponseReader) read_chunk_size() ?u64 { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// The length of the next chunk is provided as a hexadecimal | ||||
| 	mut num_data := hex.decode(res#[..-2].bytestr())? | ||||
| 
 | ||||
| 	for num_data.len < 8 { | ||||
|  | @ -88,6 +98,8 @@ fn (mut r ChunkedResponseReader) read_chunk_size() ?u64 { | |||
| 
 | ||||
| 	num := binary.big_endian_u64(num_data) | ||||
| 
 | ||||
| 	// This only occurs for the very last chunk, which always reports a size of | ||||
| 	// 0. | ||||
| 	if num == 0 { | ||||
| 		r.end_of_stream = true | ||||
| 	} | ||||
|  | @ -95,16 +107,17 @@ fn (mut r ChunkedResponseReader) read_chunk_size() ?u64 { | |||
| 	return num | ||||
| } | ||||
| 
 | ||||
| // StreamFormatReader parses an underlying stream of Docker logs, removing the | ||||
| // header bytes. | ||||
| struct StreamFormatReader { | ||||
| 	stdout bool | ||||
| 	stderr bool | ||||
| 	stdin  bool | ||||
| mut: | ||||
| 	reader              io.Reader | ||||
| 	bytes_left_in_chunk u32 | ||||
| 	end_of_stream       bool | ||||
| } | ||||
| 
 | ||||
| // new_stream_format_reader creates a new StreamFormatReader using the given | ||||
| // reader. | ||||
| pub fn new_stream_format_reader(reader io.Reader) &StreamFormatReader { | ||||
| 	r := &StreamFormatReader{ | ||||
| 		reader: reader | ||||
|  | @ -113,6 +126,7 @@ pub fn new_stream_format_reader(reader io.Reader) &StreamFormatReader { | |||
| 	return r | ||||
| } | ||||
| 
 | ||||
| // read satisfies the io.Reader interface. | ||||
| pub fn (mut r StreamFormatReader) read(mut buf []u8) ?int { | ||||
| 	if r.end_of_stream { | ||||
| 		return none | ||||
|  | @ -139,6 +153,8 @@ pub fn (mut r StreamFormatReader) read(mut buf []u8) ?int { | |||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // read_chunk_size advances the reader & reads the header bytes for the length | ||||
| // of the next chunk. | ||||
| fn (mut r StreamFormatReader) read_chunk_size() ?u32 { | ||||
| 	mut buf := []u8{len: 8} | ||||
| 
 | ||||
|  |  | |||
|  | @ -93,6 +93,9 @@ pub fn pretty_bytes(bytes int) string { | |||
| 	return '${n:.2}${util.prefixes[i]}' | ||||
| } | ||||
| 
 | ||||
| // match_array_in_array<T> returns how many elements of a2 overlap with a1. For | ||||
| // example, if a1 = "abcd" & a2 = "cd", the result will be 2. If the match is | ||||
| // not at the end of a1, the result is 0. | ||||
| pub fn match_array_in_array<T>(a1 []T, a2 []T) int { | ||||
| 	mut i := 0 | ||||
| 	mut match_len := 0 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue