diff options
| author | ubq323 <ubq323@ubq323.website> | 2024-04-13 00:49:14 +0100 | 
|---|---|---|
| committer | ubq323 <ubq323@ubq323.website> | 2024-04-13 00:49:14 +0100 | 
| commit | bf03e2a0d86a4b5202a72aa66da5dc0e2c0b412b (patch) | |
| tree | da47f07c9f3c7946044153f21b7d4bcf991ea1bf | |
| parent | 0eeff114b44ccdd6bc430bc5f9583e2a3eea9823 (diff) | |
multiple packet types. code quality is declining steadily
| -rw-r--r-- | client/main.ha | 13 | ||||
| -rw-r--r-- | drawing/op.ha | 8 | ||||
| -rw-r--r-- | packet_reader/packet_reader.ha | 66 | ||||
| -rw-r--r-- | server/main.ha | 68 | 
4 files changed, 112 insertions, 43 deletions
| diff --git a/client/main.ha b/client/main.ha index fa63004..242a101 100644 --- a/client/main.ha +++ b/client/main.ha @@ -87,16 +87,21 @@ export fn main() void = {  		case void => yield;  		case let op: drawing::op =>  			drawing::perform(pictures, op); -			drawing::send_op(conn, op)!; +			packet_reader::send(conn, op: packet_reader::packet_drawop)!;  		};  		const n = poll::poll(pollfd, poll::NONBLOCK)!;  		if (n > 0) {  			fmt::println("data available")!;  			packet_reader::read(&packet_reader, conn)!; -			for (const packet_bytes => packet_reader::next(&packet_reader)) { -				const op = drawing::deser_op(packet_bytes); -				drawing::perform(pictures, op); +			for (const packet => packet_reader::next(&packet_reader)!) { +				match (packet) { +				case let op: packet_reader::packet_drawop => +					const opc = op as drawing::op_circle; +					drawing::perform(pictures, opc); +				case => +					abort("other packet not supported yet"); +				};  			};  		}; diff --git a/drawing/op.ha b/drawing/op.ha index deda81c..acbca29 100644 --- a/drawing/op.ha +++ b/drawing/op.ha @@ -7,13 +7,13 @@ export type op_other = void;  export type op = (op_circle| op_other); - -export fn send_op(file: io::handle, op: op) (void | io::error) = { -	static let buf: [8]u8 = [0...]; +// return value must be freed... for now. ehh +export fn ser_op(op: op) []u8 = {  	const opc = op as op_circle; +	let buf: []u8 = alloc([0...],8);  	endian::leputu32(buf[0..4], opc.0: u32);  	endian::leputu32(buf[4..8], opc.1: u32); -	io::writeall(file, buf)?; +	return buf;  };  export fn deser_op(bytes: []u8) op = { diff --git a/packet_reader/packet_reader.ha b/packet_reader/packet_reader.ha index 43b85d1..9cae444 100644 --- a/packet_reader/packet_reader.ha +++ b/packet_reader/packet_reader.ha @@ -1,24 +1,33 @@  use io;  use fmt; +use endian; +use drawing; -export type packet = []u8; -def PCKSZ: size = 8; +export type error = !str;  export type packet_reader = struct { -	buf: [256]u8, +	buf: []u8,  	good: []u8,  };  export fn new() packet_reader = {  	let pr = packet_reader { -		buf = [0...], +		buf = alloc([0...],512*512*4*2), // ehhh  		...  	};  	pr.good = pr.buf[0..0];  	return pr; +}; +export type packet_type = enum u8 { +	DRAW_OP, +	SEND_CHUNK,  }; +export type packet_drawop = drawing::op; +export type packet_sendchunk = []u32; +export type packet = (packet_drawop | packet_sendchunk); +  // call when input is ready. could block otherwise  export fn read(pr: *packet_reader, sock: io::handle) (void | io::error | io::EOF) = {  	const remaining_amt = len(pr.good); @@ -39,14 +48,53 @@ export fn read(pr: *packet_reader, sock: io::handle) (void | io::error | io::EOF  	fmt::printfln("now {} bytes in buffer",total_amt)!;  }; +// packet format: +// u32 size +// u32 type +// [size-8]u8 data... +// size includes size of header (size and type fields) -export fn next(pr: *packet_reader) (packet | done) = { +export fn next(pr: *packet_reader) (packet | done | error) = {  	// either parse a full packet out of the front of good,  	// move good along that many bytes,  	// and return the packet,  	// or, ascertain there is no full packet, and return done -	if (len(pr.good) < PCKSZ) return done; -	const packet_bytes = pr.good[..PCKSZ]; -	pr.good = pr.good[PCKSZ..]; -	return packet_bytes; +	if (len(pr.good) < size(u32)) return done; +	const packet_len = endian::legetu32(pr.good[0..4]); +	if (packet_len < 8) return "packet size field too small": error; +	if (len(pr.good) < packet_len) return done; + +	const packet_bytes = pr.good[..packet_len]; +	pr.good = pr.good[packet_len..]; + +	const ty = endian::legetu32(packet_bytes[4..8]): packet_type; +	switch (ty) { +	case packet_type::DRAW_OP => +		const op = drawing::deser_op(packet_bytes[8..]); +		return op: packet_drawop; +	case packet_type::SEND_CHUNK => +		// in an ideal world we would need no copies +		const totally_necessary_copy = alloc(packet_bytes[8..]...); +		return totally_necessary_copy: packet_sendchunk; +	}; +}; + +export fn send_raw(sock: io::file, ty: packet_type, data: []u8) (void | io::error) = { +	// ehh +	const header: [8]u8 = [0...]; +	endian::leputu32(header[0..4], 8u32 + len(data):u32); +	endian::leputu32(header[4..8], ty); +	io::writeall(sock, header)?; +	io::writeall(sock, data)?; +}; + +export fn send(sock: io::file, packet: packet) (void | io::error) = { +	match (packet) { +	case let op: packet_drawop => +		const ser_op = drawing::ser_op(op); +		defer free(ser_op); +		send_raw(sock, packet_type::DRAW_OP, ser_op)?; +	case let chunkdata: packet_sendchunk => +		abort("not implemented sendchunk yet"); +	};  }; diff --git a/server/main.ha b/server/main.ha index abcb0fe..9f21932 100644 --- a/server/main.ha +++ b/server/main.ha @@ -45,7 +45,7 @@ export fn main() void = {  	loop(listener, pictures);  }; -def save_interval = 5 * time::SECOND; +def save_interval = 20 * time::SECOND;  fn save_world(pictures: []drawing::picture) void = {  	fmt::printfln("saving world!")!; @@ -59,13 +59,20 @@ fn save_world(pictures: []drawing::picture) void = {  			fmt::printfln("\t. {}",filename)!;  			io::close(file)!;  		}; +  		const header = fmt::asprintf("P6\n{} {}\n{}\n", pic.w, pic.h, 255);  		defer free(header);  		io::writeall(file, strings::toutf8(header))!; + +		let buf: []u8 = alloc([0...],3*pic.w*pic.h); +		defer free(buf);  		for (let i = 0z; i < pic.w * pic.h; i += 1) {  			const px = pic.d[i]; -			io::writeall(file, [(px&0xff): u8, ((px>>8)&0xff): u8, ((px>>16)&0xff): u8])!; +			buf[3*i  ] = ((px>>16)&0xff): u8; +			buf[3*i+1] = ((px>>8) &0xff): u8; +			buf[3*i+2] = ((px)    &0xff): u8;  		}; +		io::writeall(file, buf)!;  	};  }; @@ -81,6 +88,7 @@ fn loop(listener: net::socket, pictures: []drawing::picture) void = {  	let now = time::now(time::clock::MONOTONIC);  	let next = time::add(now, save_interval); +	save_world(pictures);  	for (true) {  		fmt::println("poll.")!; @@ -104,36 +112,44 @@ fn loop(listener: net::socket, pictures: []drawing::picture) void = {  			append(packet_readers, packet_reader::new());  			fmt::printfln("there are now {},{} conns.",len(pollfds),len(packet_readers))!;  		}; -		for (let i = 1z; i < len(pollfds); i += 1) { -			if (0 != pollfds[i].revents & poll::event::POLLIN) { -				match (packet_reader::read(&packet_readers[i-1], pollfds[i].fd)) { +		for (let connidx = 1z; connidx < len(pollfds); connidx += 1) { +			if (0 != pollfds[connidx].revents & poll::event::POLLIN) { +				match (packet_reader::read(&packet_readers[connidx-1], pollfds[connidx].fd)) {  				case void => -					let j = 1; -					for (const packet_bytes => packet_reader::next(&packet_readers[i-1])) { -						fmt::printf("#{}:{} got {:2}",i,j,len(packet_bytes))!; -						j += 1; -						for (let byte .. packet_bytes) fmt::printf(" {:x}",byte)!; -						const op = drawing::deser_op(packet_bytes) as drawing::op_circle; -						drawing::perform(pictures, op); -						fmt::printfln("\t({:+6},{:+6})",op.0,op.1)!; -						for (let k = 1z; k < len(pollfds); k += 1) { -							if (k == i) continue; -							fmt::printfln("\t -> #{}",k)!; -							io::writeall(pollfds[k].fd, packet_bytes)!; -						}; +					for (const packet => packet_reader::next(&packet_readers[connidx-1])!) { +						handle_packet(pictures, pollfds, packet, connidx);  					};  				case let err: io::error => -					fmt::printfln("#{} error: {}",i,io::strerror(err))!; -					delete(pollfds[i]); -					delete(packet_readers[i-1]); -					i -= 1; +					fmt::printfln("#{} error: {}",connidx,io::strerror(err))!; +					delete(pollfds[connidx]); +					delete(packet_readers[connidx-1]); +					connidx -= 1;  				case io::EOF => -					fmt::printfln("#{} disconnect",i)!; -					delete(pollfds[i]); -					delete(packet_readers[i-1]); -					i -= 1; +					fmt::printfln("#{} disconnect",connidx)!; +					delete(pollfds[connidx]); +					delete(packet_readers[connidx-1]); +					connidx -= 1;  				};  			};  		};  	};  }; + +// ehh, really need a struct to put pollfds, pictures, connections... in +fn handle_packet(pictures: []drawing::picture, pollfds: []poll::pollfd, packet: packet_reader::packet, connidx: size) void = { +	match (packet) { +	case let op: packet_reader::packet_drawop => +		const opc = op as drawing::op_circle; +		fmt::printfln("#{}: drawop  ({:+6},{:+6})",connidx,opc.0,opc.1)!; +		drawing::perform(pictures, opc); +		for (let otheridx = 1z; otheridx < len(pollfds); otheridx += 1) { +			if (otheridx == connidx) continue; +			fmt::printfln("\t -> #{}",otheridx)!; +			// ehhh shouldn't reserialize for each other thing +			packet_reader::send(pollfds[otheridx].fd, packet)!; +		}; +	case => +		abort("other packets not supported yet"); +	}; +}; + | 
