code: 9ferno

ref: f1eaa84bca784511be2b98c4f82a858c42110b4d
dir: /appl/alphabet/auxi/endpoints.b/

View raw version
implement Endpoints;
include "sys.m";
	sys: Sys;
include "draw.m";
include "string.m";
	str: String;
include "sh.m";
	sh: Sh;
include "alphabet/endpoints.m";

init()
{
	sys = load Sys Sys->PATH;
	sh = load Sh Sh->PATH;
	sh->initialise();
	str = load String String->PATH;
}

DIR: con "/n/endpoint";

new(nil, addr: string, force: int): string		# XXX don't ignore net directory
{
	if(!force && sys->stat(DIR+"/"+addr+"/clone").t0 != -1)
		return nil;
	if((e := sh->run(nil, "mount"::"{mntgen}"::DIR::nil)) != nil)
		return "mount mntgen failed: "+e;
	if((e = sh->run(nil, "endpointsrv"::addr::DIR+"/"+addr::nil)) != nil)
		return "endpoint failed: "+e;
	if((e = sh->run(nil, "listen"::addr::"export"::DIR+"/"+addr::nil)) != nil){
		sys->unmount(nil, DIR+"/"+addr);
		return "listen failed: "+e;
	}
	return nil;
}

err(e: string): Endpoint
{
	return (nil, nil, e);
}

create(addr: string): (ref Sys->FD, Endpoint)
{
	d := DIR+"/"+addr;
	fd := sys->open(d+"/clone", Sys->OREAD);
	if(fd == nil)
		return (nil, err(sys->sprint("cannot open %s/clone: %r", d)));

	buf := array[1024] of byte;
	n := sys->read(fd, buf, len buf);
	if(n <= 0)
		return (nil, err("read id failed"));
	s := string buf[0:n];
	(nt, toks) := sys->tokenize(s, " ");
	if(nt != 2)
		return (nil, err(sys->sprint("invalid id read %q", s)));
	id: string;
	(addr, id) = (hd toks, hd tl toks);
	fd = sys->open(d+"/"+id+".in", Sys->OWRITE);
	if(fd == nil)
		return (nil, err(sys->sprint("cannot write to %s/%s: %r", d, id)));
	return (fd, Endpoint(addr, id, nil));
}

open(net: string, ep: Endpoint): (ref Sys->FD, string)
{
	if(hasslash(ep.addr))
		return (nil, "bad address");
	if(hasslash(ep.id))
		return (nil, "bad id");
	d := DIR+"/"+ep.addr;
	fd := sys->open(d+"/"+ep.id, Sys->OREAD);
	if(fd != nil)
		return (fd, nil);
	e := sys->sprint("%r");
	if(sys->stat(d+"/clone").t0 != -1)
		return (nil, sys->sprint("endpoint does not exist: %s", e));
	if((e = sh->run(nil, "mount"::"-A"::net+ep.addr::d::nil)) != nil)
		return (nil, e);
	fd = sys->open(d+"/"+ep.id, Sys->OREAD);
	if(fd == nil)
		return (nil, sys->sprint("endpoint does not exist: %r"));
	return (fd, nil);
}

Endpoint.text(ep: self Endpoint): string
{
	return sys->sprint("%q %q %q", ep.addr, ep.id, ep.about);
}

Endpoint.mk(s: string): Endpoint
{
	t := str->unquoted(s);
	if(len t != 3)
		return err("invalid endpoint string");
	# XXX could do more validation than this.
	return (hd t, hd tl t, hd tl tl t);
}

hasslash(s: string): int
{
	for(i := 0; i < len s; i++)
		if(s[i] == '/')
			return 1;
	return 0;
}