diff options
Diffstat (limited to 'appl/demo/whiteboard/wbsrv.b')
| -rw-r--r-- | appl/demo/whiteboard/wbsrv.b | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/appl/demo/whiteboard/wbsrv.b b/appl/demo/whiteboard/wbsrv.b new file mode 100644 index 00000000..9bec955b --- /dev/null +++ b/appl/demo/whiteboard/wbsrv.b @@ -0,0 +1,268 @@ +implement Wbserve; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + draw: Draw; + Chans, Display, Image, Rect, Point : import draw; + +Wbserve : module { + init : fn (ctxt : ref Draw->Context, args : list of string); +}; + +WBW : con 600; +WBH : con 400; + +savefile := ""; + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + if (draw == nil) + badmod(Draw->PATH); + + if (args == nil || tl args == nil) + error("usage: wbsrv mntpt [savefile]"); + args = tl args; + mntpt := hd args; + args = tl args; + + display := Display.allocate(nil); + if (display == nil) + error(sys->sprint("cannot allocate display: %r")); + + bg: ref Draw->Image; + if (args != nil) { + savefile = hd args; + bg = display.open(savefile); + } + r := Rect(Point(0,0), Point(WBW, WBH)); + wb := display.newimage(r, Draw->CMAP8, 0, Draw->White); + if (wb == nil) + error(sys->sprint("cannot allocate whiteboard image: %r")); + if (bg != nil) { + wb.draw(bg.r, bg, nil, Point(0,0)); + bg = nil; + } + + nextmsg = ref Msg (nil, nil); + + sys->bind("#s", mntpt, Sys->MBEFORE); + + bit := sys->file2chan(mntpt, "wb.bit"); + strokes := sys->file2chan(mntpt, "strokes"); + + spawn srv(wb, bit, strokes); + if (savefile != nil) + spawn saveit(display, wb); +} + +srv(wb: ref Image, bit, strokes: ref Sys->FileIO) +{ + nwbbytes := draw->bytesperline(wb.r, wb.depth) * wb.r.dy(); + bithdr := sys->aprint("%11s %11d %11d %11d %11d ", wb.chans.text(), 0, 0, WBW, WBH); + + for (;;) alt { + (offset, count, fid, r) := <-bit.read => + if (r == nil) { + closeclient(fid); + continue; + } + c := getclient(fid); + if (c == nil) { + # new client + c = newclient(fid); + data := array [len bithdr + nwbbytes] of byte; + data[0:] = bithdr; + wb.readpixels(wb.r, data[len bithdr:]); + c.bitdata = data; + } + if (offset >= len c.bitdata) { + rreply(r, (nil, nil)); + continue; + } + rreply(r, (c.bitdata[offset:], nil)); + + (offset, data, fid, w) := <-bit.write => + if (w != nil) + wreply(w, (0, "permission denied")); + + (offset, count, fid, r) := <-strokes.read => + if (r == nil) { + closeclient(fid); + continue; + } + c := getclient(fid); + if (c == nil) { + c = newclient(fid); + c.nextmsg = nextmsg; + } + d := c.nextmsg.data; + if (d == nil) { + c.pending = r; + c.pendlen = count; + continue; + } + c.nextmsg = c.nextmsg.next; + rreply(r, (d, nil)); + + (offset, data, fid, w) := <-strokes.write => + if (w == nil) { + closeclient(fid); + continue; + } + err := drawstrokes(wb, data); + if (err != nil) { + wreply(w, (0, err)); + continue; + } + wreply(w, (len data, nil)); + writeclients(data); + } +} + +rreply(rc: chan of (array of byte, string), reply: (array of byte, string)) +{ + alt { + rc <-= reply =>; + * =>; + } +} + +wreply(wc: chan of (int, string), reply: (int, string)) +{ + alt { + wc <-= reply=>; + * =>; + } +} + +export(fd : ref Sys->FD, done : chan of int) +{ + sys->export(fd, "/", Sys->EXPWAIT); + done <-= 1; +} + +Msg : adt { + data : array of byte; + next : cyclic ref Msg; +}; + +Client : adt { + fid : int; + bitdata : array of byte; # bit file client + nextmsg : ref Msg; # strokes file client + pending : Sys->Rread; + pendlen : int; +}; + +nextmsg : ref Msg; +clients : list of ref Client; + +newclient(fid : int) : ref Client +{ + c := ref Client(fid, nil, nil, nil, 0); + clients = c :: clients; + return c; +} + +getclient(fid : int) : ref Client +{ + for(cl := clients; cl != nil; cl = tl cl) + if((c := hd cl).fid == fid) + return c; + return nil; +} + +closeclient(fid : int) +{ + nl: list of ref Client; + for(cl := clients; cl != nil; cl = tl cl) + if((hd cl).fid != fid) + nl = hd cl :: nl; + clients = nl; +} + +writeclients(data : array of byte) +{ + nm := ref Msg(nil, nil); + nextmsg.data = data; + nextmsg.next = nm; + + for(cl := clients; cl != nil; cl = tl cl){ + if ((c := hd cl).pending != nil) { + n := c.pendlen; + if (n > len data) + n = len data; + alt{ + c.pending <-= (data[0:n], nil) => ; + * => ; + } + c.pending = nil; + c.nextmsg = nm; + } + } + nextmsg = nm; +} + +# data: colour width p0 p1 pn* + +pencol: int; +pen: ref Image; + +drawstrokes(wb: ref Image, data : array of byte) : string +{ + (n, toks) := sys->tokenize(string data, " "); + if (n < 6 || n & 1) + return "bad data"; + + colour, width, x, y : int; + (colour, toks) = (int hd toks, tl toks); + (width, toks) = (int hd toks, tl toks); + (x, toks) = (int hd toks, tl toks); + (y, toks) = (int hd toks, tl toks); + if (pen == nil || colour != pencol) { + pencol = colour; + pen = wb.display.newimage(Rect(Point(0,0), Point(1,1)), Draw->CMAP8, 1, pencol); + } + p0 := Point(x, y); + while (toks != nil) { + (x, toks) = (int hd toks, tl toks); + (y, toks) = (int hd toks, tl toks); + p1 := Point(x, y); + # could use poly() instead of line() + wb.line(p0, p1, Draw->Enddisc, Draw->Enddisc, width, pen, pen.r.min); + p0 = p1; + } + return nil; +} + +error(e: string) +{ + sys->fprint(stderr(), "wbsrv: %s\n", e); + raise "fail:error"; +} + +stderr(): ref Sys->FD +{ + return sys->fildes(2); +} + +badmod(path: string) +{ + sys->fprint(stderr(), "wbsrv: cannot load %s: %r\n", path); + exit; +} + +saveit(display: ref Display, img: ref Image) +{ + for (;;) { + sys->sleep(300000); + fd := sys->open(savefile, sys->OWRITE); + if (fd == nil) + exit; + display.writeimage(fd, img); + } +}
\ No newline at end of file |
