shithub: mc

ref: bd25454011010946b91c21e8af737d86505c4041
dir: /lib/std/listen+plan9.myr/

View raw version
use sys

use "alloc"
use "die"
use "dirname"
use "fmt"
use "option"
use "result"
use "strfind"
use "syswrap"
use "cstrconv"
use "utf"

pkg std =
	const announce	: (ds : byte[:] -> result(fd, byte[:]))
	const accept	: (lfd : fd -> result(fd, byte[:]))
;;

const Maxpath = 256

const announce = {ds
	var a, abuf : byte[Maxpath]
	var f, fbuf : byte[Maxpath]
	var l, lbuf : byte[Maxpath]
	var nbuf : byte[32]
	var dir, ctl, lfd, n

	/* announce */
	match translate(ds, abuf[:], fbuf[:])
	| `Err _:	-> `Err "invalid dial string"
	| `Ok (addr, file):
		put("addr: {}, file: {}\n", addr, file)
		a = addr
		f = file
		match strrfind(f, "/")
		| `Some i:	dir = i
		| `None:	-> `Err "invalid net dir"
		;;
	;;

	match open(f, Ordwr)
	| `Ok fd:	ctl = fd
	| `Err e:	-> `Err "could not open ctl fd"
	;;

	match read(ctl, nbuf[:])
	| `Err e:	->`Err "unable to read ctl fd"
	| `Ok nn:	l = bfmt(lbuf[:], "{}/{}/listen", f[:dir], nbuf[:nn])
	;;

	put("announce {}\n", a)
	n = fput(ctl, "announce {}", a)
	if n <= 0
		close(ctl)
		-> `Err "writing announce"
	;;

	/* listen */
	match open(l, Ordwr)
	| `Err e:
		close(ctl)
		-> `Err "could not open ctl"
	| `Ok fd:
		lfd = fd
	;;
	close(ctl)

	-> `Ok lfd
}

const accept = {lfd -> result(fd, byte[:])
	var dir, dirbuf : byte[40]
	var num, numbuf : byte[40]
	var dat, datbuf : byte[Maxpath]



	match read(lfd, numbuf[:])
	| `Ok n:	num = numbuf[:n]
	| `Err e:	-> `Err "could not accept"
	;;
	fput(lfd, "accept {}", num)

	sys.fd2path((lfd : sys.fd), dirbuf[:])
	dir = dirname(cstrconv(dirbuf[:]))
	match strrfind(dir, "/")
	| `None:	dat = bfmt(datbuf[:], "{}/{}/data", dir, num)
	| `Some i:	dat = bfmt(datbuf[:], "{}/{}/data", dir[:i], num)
	;;

	put("data fd: {}\n", dat)
	match open(dat, Ordwr)
	| `Ok fd:	-> `Ok fd
	| `Err e:	-> `Err "could not open data fd"
	;;
}

const translate = {ds, addrbuf, filebuf
	var cs, csbuf : byte[Maxpath]
	var r, rbuf : byte[Maxpath]
	var netdir, rest
	var addr, file

	match strfind(ds, "!")
	| `None:	-> `Err void
	| `Some sep:
		if decode(ds[:sep]) == '#' || decode(ds[:sep]) == '/'
			match strrfind(ds[:sep], "/")
			| `None:	-> `Err void
			| `Some idx:
				netdir = ds[:idx]
				rest = ds[idx+1:]
			;;
		else
			netdir = "/net"
			addr = ds
		;;
	;;

	cs = bfmt(csbuf[:], "{}/cs", netdir)
	match open(cs, Ordwr)
	| `Err e:	-> identtrans(rest, netdir, addrbuf, filebuf)
	| `Ok fd:
		match write(fd, addr)
		| `Err e:
			close(fd)
			-> `Err void
		| `Ok _:
		;;

		seek(fd, 0, Seekset)
		match read(fd, rbuf[:])
		| `Err e:
			close(fd)
			-> `Err void
		| `Ok n:
			r = rbuf[:n]
		;;
		close(fd)
	;;

	put("cs returned: {}\n", r)
	match strfind(r, " ")
	| `None:	-> `Err void
	| `Some i:
		addr = bfmt(addrbuf, "{}", r[i+1:])
		if decode(r) == '/'
			match strfind(r[:i], "/")
			| `None:	-> `Err void
			| `Some 0:	file = bfmt(filebuf, "{}{}", netdir, r[:i])
			| `Some n:	file = bfmt(filebuf, "{}{}", netdir, r[n+1:])
			;;
		else
			file = bfmt(filebuf, "{}/{}", netdir, r[:i])
		;;
	;;
	-> `Ok (addr, file) 
}

const identtrans = {ds, netdir, addrbuf, filebuf
	var a, f

	match strfind(ds, "!")
	| `None:
		-> `Err void
	| `Some sep:
		a = bfmt(addrbuf, "{}", ds[sep + 1:])
		f = bfmt(filebuf, "{}/{}/clone", netdir, ds[:sep])
		-> `Ok (a, f)
	;;
}