Lindenii Project Forge
Login

hare-ev

Temporary fork of hare-ev for... reasons
Commit info
ID
1bbb27d1a9c12a1d17df30e66637ed167c2891a9
Author
Drew DeVault <sir@cmpwn.com>
Author date
Thu, 28 Sep 2023 10:48:26 +0200
Committer
Drew DeVault <sir@cmpwn.com>
Committer date
Thu, 28 Sep 2023 10:48:26 +0200
Actions
cmd/hget: use URI from os::args
use ev;
use ev::dial;
use fmt;
use io;
use net::ip;
use net::uri;
use os;
use strings;

type state = struct {
	loop: *ev::loop,
	uri: *uri::uri,
	exit: int,
	buf: []u8,
	buf: [os::BUFSZ]u8,
};

export fn main() void = {
	const loop = ev::newloop()!;
	defer ev::finish(&loop);

	const uri = net::uri::parse(os::args[1])!;
	defer uri::finish(&uri);

	let state = state {
		loop = &loop,
		exit = os::status::SUCCESS,
		buf = [],
		uri = &uri,
		buf = [0...],
	};

	const uri = net::uri::parse("http://example.org")!;
	defer uri::finish(&uri);

	dial::dial_uri(&loop, "tcp", &uri, &dialcb, &state)!;

	for (ev::dispatch(&loop, -1)!) void;

	os::exit(state.exit);
};

fn error(state: *state, details: str) void = {
	fmt::errorfln("Error: {}", details)!;
	state.exit = os::status::FAILURE;
	ev::stop(state.loop);
};

fn dialcb(user: nullable *opaque, r: (*ev::file | dial::error)) void = {
	let state = user: *state;
	const file = match (r) {
	case let file: *ev::file =>
		yield file;
	case let err: dial::error =>
		error(state, dial::strerror(err));
		return;
	};
	ev::setuser(file, state);
	state.buf = strings::toutf8("GET / HTTP/1.1\r\n"
		"Host: example.org\r\n"
		"Connection: close\r\n\r\n");
	ev::write(file, &writecb, state.buf);
	const s = fmt::bsprintf(state.buf, "GET {} HTTP/1.1\r\n"
		"Host: {}\r\n"
		"Connection: close\r\n\r\n",
		if (state.uri.path == "") "/" else state.uri.path,
		match (state.uri.host) {
		case let s: str =>
			yield s;
		case let ip: ip::addr =>
			yield ip::string(ip);
		});

	ev::write(file, &writecb, state.buf[..len(s)]);
};

fn writecb(file: *ev::file, r: (size | io::error)) void = {
	const state = ev::getuser(file): *state;
	const z = match (r) {
	case let z: size =>
		yield z;
	case let err: io::error =>
		error(state, io::strerror(err));
		return;
	};
	assert(z == len(state.buf));
	ev::read(file, &readcb, state.buf);
};

fn readcb(file: *ev::file, r: (size | io::EOF | io::error)) void = {
	const state = ev::getuser(file): *state;
	const z = match (r) {
	case let z: size =>
		yield z;
	case io::EOF =>
		ev::stop(state.loop);
		return;
	case let err: io::error =>
		error(state, io::strerror(err));
		return;
	};
	io::writeall(os::stdout, state.buf[..z])!;
	ev::read(file, &readcb, state.buf);
};