Plan 9 from Bell Labs’s /usr/web/sources/contrib/rog/sh-examples/chat.sh

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#!/dis/sh
# distributed chat application.
# not fully debugged...
load std file2chan tk
run net.sh
nl='
'
fn debug {
	echo $* > /dev/cons
}

fn startwindow {
	wid = ${tk window $"*}
	fn x { a := $*; or {tk $wid $a} {echo error on tk cmd $"a':' $status }}
	x entry .e
	x frame .f
	x scrollbar .f.s -orient vertical -command {.f.t yview}
	x text .f.t -yscrollcommand {.f.s set}
	x pack .f.s -side left -fill y
	x pack .f.t -side top -fill both -expand 1
	x pack .e -side top -fill x
	x pack .f -side top -fill both -expand 1
	x pack propagate . 0
	x bind .e '<Key-'^$nl^'>' {send event enter}
	x update
	while {} {tk winctl $wid ${recv $wid}} &	# default window handling
	chan event
	tk namechan $wid event
	fn addtext {
		x .f.t insert end ''''^$"*
		x update
	}
	subfn enteredtext {
		debug waiting for entered text
		{} ${recv event}
		debug got entered text
		result = ${tk $wid .e get}
	}
}

fn chatserver {
	addr:=$1
	name:=$2
	memfs -r /tmp
	mkdir /tmp/^(local remote)
	blocked := fidl := ()
	(file2chan /tmp/local/chatlocal
		# pendFID: list of pending chat messages for FID
		# blocked: list of tags of blocked read requests
		# blockedFID: "true" if fid currently has a tag blocked.
		# nameFID: name associated with FID
		{
			fid := ${rget fid}
			p := pend^$fid
			r := ${hd $$p}
			(if {~ $#r 1}
				{rread $r}
				{
					rblock
					blocked=$tag $blocked
					blocked^$fid=true
				}
			)
		}
		{
			rq := ${unquote ${rget data}}
			debug 'chatlocal got write:' ${quote $rq}
			cmd := ${hd $rq}
			fid := ${rget fid}
			(if
				{~ $cmd announce} {debug processing announce; name^$fid = ${tl $rq}; fidl=$fid $fidl; blocked^$fid=''}
				{~ $cmd msg} {
					# reply to any blocked requests; add to the pending
					# lists of those that aren't
					debug process message. blocked ${quote $blocked}
					debug fidl ${quote $fidl}
					msg := $(name^$fid)^': '^${tl $rq}^$nl
					for i in $blocked {rread $i $msg}
					blocked=()
					for i in $fidl {
						(if {~ $(blocked^$i) ''}
							{debug adding to pending for fid $i; pend^$i = $msg $(pend^$i)}
							{blocked^$i = ''}
						)
					}
					addtext $msg
				}
			)
			debug done chatlocal write
		}
		{
			fid := ${rget fid}
			blocked^$fid=()
			name^$fid=()
			pend^$fid=()
		}
	)

	{
		echo -n announce ${quote $name}
		while {} {
			txt := ${enteredtext}
			echo -n msg ${quote $txt}
		}
	} <>[1] /tmp/local/chatlocal &

	debug announcing on $addr
	announce $addr {
		while {} {
			debug server awaiting connection on $net
			listen {
				debug got connection in dir $net from `{cat $net/remote}
				name := ${pid}		# was "{read}
				debug name is $name
				{
					pctl forkns
					echo -n ${quote announce $name} >[1=3]
					debug about to do file2chan
					or {(file2chan /tmp/remote/chat
						{debug chat read; rblock; {read <>[0=3] | putrdata} &}
						{debug chat write; echo ${quote msg ${rget data}} >[1=3]}
						{debug chat close; echo $name exiting; exit}
					)} {debug file2chan for remote failed}
					debug done file2chan
					ls -l /tmp/remote
					export /tmp/remote &
					debug export finished
					pause
				} <>[3] /tmp/local/chatlocal
			}
			echo after listen net is $net
		}
	}
}

fn chatclient {
	addr := $1
	name := $2
	mkdir /tmp/chatdir >[2] /dev/null
	chmod 755 /tmp/chatdir
	dial $addr {
		debug 'connected to chat server'
#		echo -n $name >[1=0]
		imount $net/data /tmp/chatdir
		debug done imount
		ls -l /tmp/chatdir
		debug done ls
		{
			while {} {
				txt := ${enteredtext}
				debug got entered text ${quote $txt}
				echo -n $txt >[1=0]
			} &
			eof:=''
			while {} {
				txt := "{read; eof=$status}
				debug got remote ${quote $txt}
				if {! ~ $eof ''} {echo eof is $eof; raise break}
				addtext $"txt
			}
		} <> /tmp/chatdir/chat
	}
}

args:=$*
port:=18981
if {! ~ $#args 1 2} {echo 'usage: chat [address] name' >[1=2]; raise usage}
pctl newpgrp forkns
startwindow $args
(if {~ $#args 1}
	{chatserver 'tcp!*!'^$port $args}
	{chatclient 'tcp!'^${hd $args}^'!'^$port ${tl $args}}
)
echo bye bye...

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.