use bufio; use fmt; use net; use net::tcp; use net::ip; use io; use os; use fs; use strings; use time; use time::date; use time::chrono; use unix::poll; use drawing; use drawing::{pos}; use packet_reader; def PORT: u16 = 41460; type conn = net::socket; def CHUNKSIZE = 512; export fn main() void = { // create 4 pictures. later we will have more pictures // but for now there are just 4, and they are at fixed positions const offs: [_]pos = [ (0,0), (0,CHUNKSIZE), (CHUNKSIZE,0), (CHUNKSIZE,CHUNKSIZE), ]; let pictures: []drawing::picture = alloc([],len(offs)); for (let i = 0z; i < len(offs); i +=1){ append(pictures, drawing::picture { w = CHUNKSIZE, h = CHUNKSIZE, d = alloc([0...],CHUNKSIZE*CHUNKSIZE: size): *[*]u32, world_pos = offs[i], }); }; for (const p &.. pictures) drawing::clear_picture(p, 0xffffff); const listener = tcp::listen(ip::ANY_V4, PORT)!; loop(listener, pictures); }; def save_interval = 20 * time::SECOND; fn save_world(pictures: []drawing::picture) void = { fmt::printfln("saving world!")!; for (const pic &.. pictures) { const filename = fmt::asprintf("./c.{}.{}.ppm",pic.world_pos.0, pic.world_pos.1); fmt::printfln("\t-> {}",filename)!; defer free(filename); const mode = fs::mode::USER_RW | fs::mode::GROUP_RW; const file = os::create(filename, mode)!; defer { 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]; 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)!; }; }; fn loop(listener: net::socket, pictures: []drawing::picture) void = { // pollfds[0] is the listener // pollfds[n>0] corresponds to packet_readers[n-1] let pollfds: []poll::pollfd = alloc([ poll::pollfd { fd = listener, events = poll::event::POLLIN, revents = 0 }]); let packet_readers: []packet_reader::packet_reader = []; let now = time::now(time::clock::MONOTONIC); let next = time::add(now, save_interval); save_world(pictures); for (true) { fmt::println("poll.")!; const timeout = time::diff(now, next); poll::poll(pollfds, timeout)!; now = time::now(time::clock::MONOTONIC); if (time::compare(now, next) >= 0) { save_world(pictures); next = time::add(now, save_interval); }; if (0 != pollfds[0].revents & poll::event::POLLIN) { fmt::println("new conn")!; const new_conn = tcp::accept(pollfds[0].fd)!; fmt::println("a")!; append(pollfds, poll::pollfd { fd = new_conn, events = poll::event::POLLIN, revents = 0 }); append(packet_readers, packet_reader::new()); fmt::printfln("there are now {},{} conns.",len(pollfds),len(packet_readers))!; }; 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 => for (const packet => packet_reader::next(&packet_readers[connidx-1])!) { handle_packet(pictures, pollfds, packet, connidx); }; case let err: io::error => fmt::printfln("#{} error: {}",connidx,io::strerror(err))!; delete(pollfds[connidx]); delete(packet_readers[connidx-1]); connidx -= 1; case io::EOF => 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"); }; };