shithub: wired

Download patch

ref: 5a9e919a0872f18fd39b62ab3c74216f0666e2e6
parent: 1abb9736d43ec046c91975abedadce884ecc98a6
author: james palmer <james@biobuf.link>
date: Tue Jun 15 08:33:48 EDT 2021

rewired. toggleable grep window soon™

--- a/main.c
+++ b/main.c
@@ -1,202 +1,291 @@
 #include <u.h>
 #include <libc.h>
-#include <bio.h>
 #include <thread.h>
 #include <acme.h>
 
-typedef struct Session Session;
-struct Session {
-	AWin *cwin;
-	AWin *iwin;
-	
+typedef struct Server Server;
+typedef struct Chan Chan;
+typedef struct Ctl Ctl;
+
+struct Server {
+	char *addr;
 	char *mtpt;
-	char *chan;
-	char *usr;
+	char *user;
 	
+	char *sep;
+	char *actsep;
+
+	Chan *channels;
+};
+
+struct Chan {
+	char *name;
+	
+	Channel *logc;
+	Channel *inputc;
+	Channel *readc;
+	
 	Channel *ctl;
 	
+	int logproc;
+	int inputproc;
+	int readproc;
+
 	int fd;
+
+	Server *srv;
 };
 
-enum { Stack = 4*1024, };
+struct Ctl {
+	int type;
+	void *aux;
+};
 
-void
-chatcatproc(void *aux)
+enum {
+	MExit,
+	MMessage,
+	MSend,
+	MAct,
+
+	Stack = 4*1024,
+	Buf = 8*1024,
+};
+
+int
+sendctl(Channel *chan, int type, void *aux)
 {
-	Session *s;
-	AWin *w;
+	Ctl ctl;
 	
-	w = aux;
-	s = w->aux;
+	ctl.type = type;
+	ctl.aux = aux;
 	
-	awincat(w, s->fd);
+	return send(chan, &ctl);
 }
 
 void
-wineventproc(void *aux)
+handleevent(Chan *chan, AWin *win, AEvent *ev)
 {
-	AWin *w;
+	switch(ev->type) {
+	case 'x':
+	case 'X':
+		if(strcmp(ev->text, "Del") == 0)
+			sendctl(chan->ctl, MExit, nil);
+		else if(strcmp(ev->text, "Send") == 0)
+			sendctl(chan->inputc, MSend, nil);
+		else if(strcmp(ev->text, "Action") == 0)
+			sendctl(chan->inputc, MAct, nil);
+		else
+			aeventsend(win, ev);
+			
+		break;
+	case 'I':
+		if(strchr(ev->text, '') != 0)
+			sendctl(chan->ctl, MSend, nil);
+			
+		break;
+	case 'l':
+	case 'L':
+		aeventsend(win, ev);
+		break;
+	}
+}
+
+void
+eventproc(void *aux)
+{
+	AWin *win;
 	AEvent ev;
-	Session *s;
-	Channel *ctl;
-	Channel *eventc;
+
+	threadsetname("event");
+		
+	win = aux;
+	win->eventfd = awinfsopen(win, "event", ORDWR);
 	
-	w = aux;
-	s = w->aux;
-	ctl = s->ctl;
-	eventc = aeventlisten(w);
-	
-	while(recv(eventc, &ev)) {
-		switch(ev.type) {
-		case 'x':
-			if(strcmp(ev.text, "Del") == 0)
-				sendp(ctl, "quit");
-			if(strcmp(ev.text, "Send") == 0)
-				sendp(ctl, "send");
-			if(strcmp(ev.text, "Action") == 0)
-				sendp(ctl, "act");
-				
-			break;
-		case 'I':
-			if(strchr(ev.text, '') != 0)
-				sendp(ctl, "send");
+	while(aeventnext(win, &ev) > 0)
+		handleevent(win->aux, win, &ev);
 
-			break;
-		case 'l':
-		case 'L':
-			aeventsend(w, &ev);
-		}
-	}	
+	threadexits(nil);
 }
 
-char *
-readbody(AWin *w)
+void
+logproc(void *aux)
 {
-	Biobuf *fd;
-	int addr;
-	char *buf;
-	int i;
-	
-	sleep(10);
-	
-	addr = awinfsopen(w, "addr", OWRITE);
-	fd = awinfsbopen(w, "data", OREAD);
+	Chan *chan;
+	Ctl ctl;
+	AWin *win;
 
-	fprint(addr, ",");
-	buf = Brdstr(fd, '\0', 0);
+	threadsetname("log");
 	
-	if(!buf)
-		return nil;
+	chan = aux;
+	win = awincreate();
+	fprint(win->ctlfd, "name /wired/%s/log\n"
+		"scratch\n" "nomenu\n", chan->name);
+	win->aux = chan;
 	
-	for(i = strlen(buf)-1; i >= 0; i--) {
-		if(buf[i] == '' || buf[i] == '\n')
-			buf[i] = '\0';
-		else
+	proccreate(eventproc, win, Stack);
+	
+	while(recv(chan->logc, &ctl)) {
+		switch(ctl.type) {
+		case MMessage:
+			fprint(win->bodyfd, "%s", ctl.aux);
+			free(ctl.aux);
 			break;
+		case MExit:
+			goto exit;
+		}
 	}
+
+exit:
+	close(win->eventfd);
+	chanfree(chan->logc);
+	awinclose(win);
+	threadexits(nil);
+}
+
+void
+sendmessage(AWin *win, char *fmt, ...)
+{
+	Chan *chan;
+	char *prefix;
+	char *message;
+	va_list args;
 	
-	if(buf[0] == '\0') {
-		awinclear(w);
-		return nil;
-	}
+	chan = win->aux;
+
+	va_start(args, fmt);
+	prefix = vsmprint(fmt, args);
+	va_end(args);
 	
-	awinclear(w);
-	Bterm(fd);
-	close(addr);
-	return buf;
+	message = mallocz(Buf, 1);
+	fprint(win->addrfd, ",");
+	if(read(win->datafd, message, Buf-1) < 0)
+		return;
+	
+	fprint(chan->fd, "%s %s\n", prefix, message);
+	free(prefix);
+	free(message);
 }
 
 void
-domessage(Session *s, char *msg)
+inputproc(void *aux)
 {
-	char *buf;
+	Server *srv;
+	Chan *chan;
+	Ctl ctl;
+	AWin *win;
+
+	threadsetname("input");
 	
-	if(!msg)
-		return;
+	chan = aux;
+	srv = chan->srv;
+	win = awincreate();
+	fprint(win->ctlfd, "name /wired/%s/input\n"
+		"scratch\n" "nomenu\n", chan->name);
+	awinsettag(win, " Send Action ");
+	win->aux = chan;
 	
-	buf = smprint("%s • %s\n", s->usr, msg);
-	write(s->fd, buf, strlen(buf));
+	proccreate(eventproc, win, Stack);
 	
-	free(buf);
-	free(msg);
+	while(recv(chan->inputc, &ctl)) {
+		switch(ctl.type) {
+		case MSend:
+			sendmessage(win, "%s %s", srv->user, srv->sep);
+			break;
+		case MAct:
+			sendmessage(win, "%s %s", srv->actsep, srv->user);
+			break;
+		case MExit:
+			goto exit;
+		}
+	}
+
+exit:
+	close(win->eventfd);
+	chanfree(chan->inputc);
+	awinclose(win);
+	threadexits(nil);
 }
 
 void
-doaction(Session *s, char *msg)
+readproc(void *aux)
 {
+	Chan *chan;
 	char *buf;
+	long n;
+	Ctl ctl;
+
+	threadsetname("read");
 	
-	if(!msg)
-		return;
+	chan = aux;
+	buf = mallocz(Buf, 1);
 	
-	buf = smprint("* %s %s\n", s->usr, msg);
-	write(s->fd, buf, strlen(buf));
+	while((n = read(chan->fd, buf, Buf-1)) > 0) {
+		buf[n] = '\0';
+		sendctl(chan->logc, MMessage, strdup(buf));
+		
+		if(nbrecv(chan->readc, &ctl))
+			if(ctl.type == MExit)
+				break;
+	}
 	
 	free(buf);
-	free(msg);
+	chanfree(chan->readc);
+	threadexits(nil);
 }
 
 void
-dochat(char *mtpt, char *chan, char *usr)
+connectchan(Server *srv, char *name)
 {
-	Session *s;
-	char buf[128];
-	char *ctl;
+	Chan *chan;
+	char *buf;
+	Ctl ctl;
 	
-	s = mallocz(sizeof(Session), 1);
-
-	s->mtpt = strdup(mtpt);
-	s->chan = strdup(chan);
-	s->usr = strdup(usr);
+	chan = mallocz(sizeof(Chan), 1);
+	chan->name = name;
+	chan->srv = srv;
 	
-	snprint(buf, sizeof(buf), "%s/%s", s->mtpt, s->chan);
-	s->fd = open(buf, ORDWR);
-	if(s->fd < 0) {
-		free(s->mtpt);
-		free(s->chan);
-		free(s->usr);
-		free(s);
-		
-		sysfatal("couldn't read channel: %r");
-	};
-		
-	s->cwin = awincreate();
-	awinctl(s->cwin, "name /wired/chat\n");
-	awinctl(s->cwin, "scratch\n");
-	awinctl(s->cwin, "nomenu\n");
-	s->cwin->aux = s;
+	buf = smprint("%s/%s", srv->mtpt, name);
+	chan->fd = open(buf, ORDWR);
+	if(chan->fd < 0) {
+		fprint(2, "channel %s not found\n", name);
+		free(chan);
+		return;
+	}
 	
-	s->iwin = awincreate();
-	awinctl(s->iwin, "name /wired/input\n");
-	awinctl(s->iwin, "scratch\n");
-	awinctl(s->iwin, "nomenu\n");
-	awinsettag(s->iwin, " Send Action ");
-	s->iwin->aux = s;
+	chan->logc = chancreate(sizeof(Ctl), 0);
+	chan->inputc = chancreate(sizeof(Ctl), 0);
+	chan->readc = chancreate(sizeof(Ctl), 0);
 	
-	s->ctl = chancreate(sizeof(char*), 0);
+	chan->ctl = chancreate(sizeof(Ctl), 0);
 	
-	proccreate(chatcatproc, s->cwin, Stack);
-	proccreate(wineventproc, s->cwin, Stack);
-	proccreate(wineventproc, s->iwin, Stack);
+	chan->logproc = proccreate(logproc, chan, Stack);
+	chan->inputproc = proccreate(inputproc, chan, Stack);
+	chan->readproc = proccreate(readproc, chan, Stack);
 	
-	while(ctl = recvp(s->ctl)) {
-		if(strcmp(ctl, "send") == 0)
-			domessage(s, readbody(s->iwin));
-		if(strcmp(ctl, "act") == 0)
-			doaction(s, readbody(s->iwin));
-		if(strcmp(ctl, "quit") == 0)
+	while(recv(chan->ctl, &ctl)) {
+		if(ctl.type == MExit) {
+			threadint(chan->readproc); /* try to interrupt the read */
+			sendctl(chan->logc, MExit, nil);
+			sendctl(chan->inputc, MExit, nil);
 			break;
+		}
 	}
+
+
+	chanfree(chan->ctl);
+	free(chan);
+	free(buf);
+	return;
 }
 
 void
-dialchat(char *srv, char *mtpt)
+connectsrv(Server *srv)
 {
 	int fd;
 	
-	if((fd = dial(srv, nil, nil, nil)) < 0)
+	if((fd = dial(srv->addr, nil, nil, nil)) < 0)
 		sysfatal("couldn't dial chat server: %r");
-	if(mount(fd, -1, mtpt, MREPL, "") == -1)
+	if(mount(fd, -1, srv->mtpt, MREPL, "") < 0)
 		sysfatal("couldn't mount chat server: %r");
 }
 
@@ -203,40 +292,53 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-s srv] [-c chan] [-u user]\n", argv0);
-	exits(nil);
+	fprint(2, "usage: %s [-s srv] [-m mtpt] [-u user] "
+		"[-S sep] [-A actsep]\n", argv0);
+	threadexitsall("usage");
 }
 
 void
 threadmain(int argc, char *argv[])
 {
-	char *srv, *mtpt, *user, *chan;
+	Server *srv;
+	char *channel;
 	
-	srv = "tcp!chat.9p.zone!9990";
-	mtpt = "/n/chat";
-	chan = "chat";
-	user = getuser();
+	srv = mallocz(sizeof(Server), 1);
+	srv->addr = "tcp!9p.zone!9990";
+	srv->mtpt = "/n/wired";
+	srv->sep = "•";
+	srv->actsep = "*";
+	srv->user = getuser();
+
+	channel = "chat";
 	
 	ARGBEGIN {
 	case 's':
-		srv = EARGF(usage());
+		srv->addr = EARGF(usage());
 		break;
 	case 'm':
-		mtpt = EARGF(usage());
+		srv->mtpt = EARGF(usage());
 		break;
-	case 'c':
-		chan = EARGF(usage());
-		break;
 	case 'u':
-		user = EARGF(usage());
+		srv->user = EARGF(usage());
 		break;
+	case 'S':
+		srv->sep = EARGF(usage());
+		break;
+	case 'A':
+		srv->actsep = EARGF(usage());
+		break;
+	case 'c':
+		channel = EARGF(usage());
+		break;
 	default:
 		usage();
 	} ARGEND
 	
-	dialchat(srv, mtpt);
-	dochat(mtpt, chan, user);
-	
-	awincloseall();
-	threadexitsall(nil);
+	connectsrv(srv);
+	connectchan(srv, channel);
+	unmount(nil, srv->mtpt);
+
+	free(srv);
+	threadexits(nil);
 }