head	1.4;
access;
symbols
	tcllib-1-13:1.4
	tcllib-1-12:1.4
	tklib-0-5:1.4
	tcllib-1-11-1:1.4
	tcllib-1-11:1.4
	tcllib-1-10:1.2;
locks; strict;
comment	@# @;


1.4
date	2008.05.06.03.52.17;	author andreas_kupries;	state Exp;
branches;
next	1.3;

1.3
date	2008.05.01.07.06.32;	author andreas_kupries;	state Exp;
branches;
next	1.2;

1.2
date	2007.07.18.22.37.37;	author andreas_kupries;	state Exp;
branches;
next	1.1;

1.1
date	2007.05.08.22.03.56;	author andreas_kupries;	state Exp;
branches;
next	;


desc
@@


1.4
log
@
	* ../../apps/nns: Switched to use of nameserv::auto to handle the
	* ../../apps/nnslog: loss and restoration of the server
	  automatically. Got rid of the colorization frills.

	* server.tcl (::nameserv::server::bind): Small extension of log
	* pkgIndex.tcl: output for failure case of bind. Added log output
	* nns_server.man: to trace searches. Bumped package version to 0.3.2.

	* nns_auto.tcl: Refactored the bind and restore code, put the
	* nns_auto.man: commonalities into shared commands. Extended the
	* pkgIndex.tcl: API to become a full drop-in replacement for
	  'nameserv', just with the persistence feature. Extended the
	  persistence to continuous and unfulfilled async searches. Now
	  exporting the API commands. Bumped package version to 0.3.

	* nns.tcl: Factored the argument processing for searches into a
	* pkgIndex.tcl: separate command. Pseudo-public. Undocumented, but
	* nns_client.man: can be used by other nameserver packages. Fixed
	  leak when encountering a missing name server during creation of
	  a continuous or async search. Fixed async destruction of a
	  continous search from receiver object. Now exporting the API
	  commands. Bumped package version to 0.4.
@
text
@#! /bin/sh
# -*- tcl -*- \
exec tclsh "$0" ${1+"$@@"}

# @@@@ Meta Begin
# Application nns 1.2
# Meta platform     tcl
# Meta summary      Nano Name Service Client
# Meta description  This application connects to a name service demon
# Meta description  and either registers a name with associated data
# Meta description  (until exit) or searches for entries matching a
# Meta description  glob pattern. Operations to identify client and
# Meta description  server are made available as well. It will survive
# Meta description  the loss of the nameserver and automatically reconnect
# Meta description  and continue when it comes back (bind and search).
# Meta description  
# Meta subject      {name service} client
# Meta require      {Tcl 8.4}
# Meta require      logger
# Meta require      nameserv::auto
# Meta require      struct::matrix
# Meta author       Andreas Kupries
# Meta license      BSD
# @@@@ Meta End

package provide nns 1.2

# nns - Nano Name Service Client
# === = ========================
#
# Use cases
# ---------
# 
# (1)	Register something at a nano name service
# (2)   Query protocol and feature information.
# (3)   Provide application version, and protocol information
# (4)   Search service for entries matching a glob-pattern
#	
# Command syntax
# --------------
#
# (Ad 1) nns bind  ?-host NAME|IP? ?-port PORT? name data
# (Ad 2) nns ident ?-host NAME|IP? ?-port PORT?
# (Ad 3) nns who
# (Ad 4) nns search ?-host NAME|IP? ?-port PORT? ?-continuous? ?pattern?
#
#       Register a name with data. If no port is specified the default
# 	port 38573 is used to connect to it. If no host is specified
# 	the default (localhost) is used to connect to it.

# ### ### ### ######### ######### #########
## Requirements

lappend auto_path [file join [file dirname [file dirname \
			[file normalize [info script]]]] modules]

package require nameserv::auto 0.3 ;# Need auto-restoring search.
package require struct::matrix

logger::initNamespace ::nns
namespace eval        ::nns { log::setlevel info }

# ### ### ### ######### ######### #########
## Process application command line

proc ::nns::ProcessCommandLine {} {
    global argv
    variable xcmd
    variable xname
    variable xdata
    variable xpat   *
    variable xwatch 0

    # Process the options, perform basic validation.

    if {[llength $argv] < 1} Usage

    set cmd  [lindex $argv 0]
    set argv [lrange $argv 1 end]

    switch -exact -- $cmd {
	bind - ident - who - search {set xcmd $cmd}
	default Usage
    }

    while {[llength $argv]} {
	set opt [lindex $argv 0]
	if {![string match "-*" $opt]} break

	switch -exact -- $opt {
	    -host {
		if {$xcmd == "who"} Usage
		if {[llength $argv] < 2} Usage

		set host [lindex $argv 1]
		set argv [lrange $argv 2 end]

		nameserv::auto::configure -host $host
	    }
	    -port {
		if {$xcmd == "who"} Usage
		if {[llength $argv] < 2} Usage

		# Todo: Check non-zero unsigned short integer
		set port [lindex $argv 1]
		set argv [lrange $argv 2 end]

		nameserv::auto::configure -port $port
	    }
	    -continuous {
		set xwatch 1
		set argv [lrange $argv 1 end]
	    }
	    -debug {
		# Undocumented. Activate the logger services provided
		# by various packages.
		logger::setlevel debug
		set argv [lrange $argv 1 end]
	    }
	    default Usage
	}
    }

    # Additional validation, and extraction of the non-option
    # arguments. Of which this application has none.

    switch -exact -- $xcmd {
	bind {
	    if {[llength $argv] != 2} Usage
	    foreach {xname xdata} $argv break
	}
	search {
	    if {[llength $argv] > 1} Usage
	    if {[llength $argv] == 1} {
		set xpat [lindex $argv 0]
	    }
	}
	who - ident {
	    if {[llength $argv] != 0} Usage
	}
    }
    return
}

proc ::nns::Usage {{sfx {}}} {
    global argv0 ; append argv0 $sfx
    set    blank [blank $argv0]
    puts stderr "$argv0 wrong#args, expected: bind   ?-host NAME|IP? ?-port PORT? NAME DATA"
    puts stderr "$blank                       ident  ?-host NAME|IP? ?-port PORT?"
    puts stderr "$blank                       search ?-host NAME|IP? ?-port PORT? ?-continuous? ?PATTERN?"
    puts stderr "$blank                       who"
    exit 1
}

proc ::nns::ArgError {text} {
    global argv0
    puts stderr "$argv0: $text"
    #puts $::errorInfo
    exit 1
}

proc ::nns::blank {s} {
    regsub -all -- {[^	]} $s { } s
    return $s
}

# ### ### ### ######### ######### #########

proc ::nns::My {} {
    # Quick access to format the identity of the name service the
    # client talks to.
    return "[nameserv::auto::cget -host] @@[nameserv::auto::cget -port]"
}

proc ::nns::Connection {message args} {
    # args = tag event details, ignored
    log::info $message
    return
}

proc ::nns::MonitorConnection {} {
    uevent::bind nameserv lost-connection [list ::nns::Connection "Disconnected name service at [My]"]
    uevent::bind nameserv re-connection   [list ::nns::Connection "Reconnected2 name service at [My]"]
    return
}

# ### ### ### ######### ######### #########
## Main

proc ::nns::Do.bind {} {
    global argv0
    variable xname
    variable xdata

    MonitorConnection
    log::info "Binding with name service at [My]: $xname = $xdata"
    nameserv::auto::bind $xname $xdata

    vwait ::forever
    # Not reached.
    return
}

proc ::nns::Do.ident {} {
    set sp [nameserv::auto::server_protocol]
    set sf [join [nameserv::auto::server_features] {, }]

    if {[llength $sf] > 1} {
	set sf [linsert $sf end-1 and]
    }

    puts "Server [My]"
    puts "  Protocol: $sp"
    puts "  Features: $sf"
    return
}

proc ::nns::Do.search {} {
    variable xpat
    variable xwatch

    struct::matrix M
    M add columns 2

    if {$xwatch} {
	MonitorConnection
	set contents [nameserv::auto::search -continuous $xpat]
	$contents configure -command [list ::nns::Do.search.change $contents]

	vwait ::forever
	# Not reached.
    } else {
	Do.search.print [nameserv::auto::search $xpat]
    }
    return
}

proc ::nns::Do.search.change {res type response} {
    # Ignoring the arguments, we simply print the full results every
    # time.

    if {$type eq "stop"} {
	# Cannot happen for nameserv::auto client, we are free to panic.
	$res destroy
	log::critical {Bad event 'stop' <=> Lost connection, search closed}
	return
    }

    # Clear screen ...
    puts -nonewline stdout "\033\[H\033\[J"; # Home + Erase Down
    flush           stdout

    ::nns::Do.search.print [$res getall]
    return
}

proc ::nns::Do.search.print {contents} {
    log::info "Searching at name service at [My]"

    if {![llength $contents]} {
	log info "Nothing found..."
	return
    }

    catch {M delete rows [M rows]}
    foreach {name data} $contents {
	M add row [list $name $data]
    }

    foreach line [split [M format 2string] \n] { log::info $line }
    return
}

proc ::nns::Do.who {} {
    # FUTURE: access and print the metadata contained in ourselves.
    global argv0
    puts "$argv0 [package require nns] (Client Protocol [nameserv::auto::protocol])"
    return
}

# ### ### ### ######### ######### #########
## Invoking the functionality.

::nns::ProcessCommandLine
if {[catch {
    ::nns::Do.$::nns::xcmd
} msg]} {
    ::nns::ArgError $msg
}

# ### ### ### ######### ######### #########
exit
@


1.3
log
@
	* ../../apps/nns (::nns::ProcessCommandLine): Fixed inccorrect
	* ../../apps/nns.man: checking for wrong#args in the code handling
	* ../../apps/nnsd.man: the options -host and -port. Reworked
	  the descriptiond of the applications a bit.

	* ../../apps/nnslog: New application and its documentation, a
	* ../../apps/nnslog.man: stripped down form of 'nns search
	  -continuous *' with different output (log of events).
@
text
@d6 1
a6 1
# Application nnst 1.1
d13 3
a15 1
# Meta description  server are made available as well.
a18 1
# Meta require      comm
d20 1
a20 3
# Meta require      nameserv
# Meta require      nameserv::common
# Meta require      snit
d26 1
a26 1
package provide nns 1.1
d51 3
d57 1
a57 1
package require nameserv
d60 5
a64 1
namespace eval ::nns {}
d98 1
a98 1
		nameserv::configure -host $host
d108 1
a108 1
		nameserv::configure -port $port
a161 3
# ### ### ### ######### ######### #########
## Setup a text|graphical report

d167 18
a184 3
proc ::nns::Exit {args} {
    puts {Exiting client due to loss of connection with service}
    exit 0
d195 3
a197 1
    nameserv::bind $xname $xdata
d199 2
a200 2
    uevent::bind nameserv lost-connection ::nns::Exit
    vwait forever
d205 2
a206 2
    set sp [nameserv::server_protocol]
    set sf [join [nameserv::server_features] {, }]
d212 1
a212 1
    puts "Server [nameserv::cget -host] @@[nameserv::cget -port]"
d226 2
a227 1
	set contents [nameserv::search -continuous $xpat]
d230 1
a230 2
	uevent::bind nameserv lost-connection ::nns::Exit
	vwait forever
d233 1
a233 1
	Do.search.print [nameserv::search $xpat]
d243 1
d245 1
a245 1
	puts {Lost connection, search closed}
d258 2
d261 1
a261 1
	puts "Nothing found..."
d270 1
a270 2
    M format 2chan
    puts ""
d277 1
a277 1
    puts "$argv0 [package require nns] (Client Protocol [nameserv::protocol])"
@


1.2
log
@
	* ../../apps/nnsd: Fixed option bug. Bumped version to 1.0.1.

	* ../../apps/nns: Extended example client application with
	* ../../apps/nns.man: continuous search. Further extended to
	  detect and handle loss of connection with service, by exiting.
	  Bumped version to 1.1

	* server.tcl: Implemented asynchronous and continuous searches.
	* nns.tcl: Ditto in client. Documented this feature, and the
	* nns_client.man: extensions to the protocol it needs.
	* nns_server.man: Bumped both server and client to version 0.3.
	* nns_protocol.man:
	* pkgIndex.tcl:
@
text
@d87 1
a87 1
		if {[llength $argv] % 2 == 1} Usage
d96 1
a96 1
		if {[llength $argv] % 2 == 1} Usage
@


1.1
log
@
	* nns_client.man: New name for nns.man, to avoid clashing with the
	* nns.tcl: nns.man of the command line client, and removed unwanted
	  log output from the client package.

	* ../../apps/nnsl: Merged nnsl and nnst into one command line client
	* ../../apps/nnst: application, nns. Added documentation for that
	* ../../apps/nns: application.
	* ../../apps/nns.man

	* ../../apps/nnsd.man: Added documentation for the command line
	  server application.

	* nns_server.man: Changed configuration -local to -localonly
	* server.tcl: for better understanding. Bumped to version 0.2
	* pkgIndex.tcl: Removed unwanted log output.
@
text
@d6 1
a6 1
# Application nnst 1.0
d19 3
a22 2
# Meta require      nameserv::common
# Meta require      nameserv
d27 1
a27 1
package provide nns 1.0
d43 4
a46 3
# Ad 1) nns bind  ?-host NAME|IP? ?-port PORT? name data
# Ad 2) nns ident ?-host NAME|IP? ?-port PORT?
# Ad 3) nns who
d52 2
a53 2
#lappend auto_path [file join [file dirname [file dirname \
#			[file normalize [info script]]]] modules]
d65 2
a66 1
    variable xpat  *
d104 4
d144 1
a144 1
    puts stderr "$blank                       search ?-host NAME|IP? ?-port PORT? ?PATTERN?"
d164 5
d178 2
d200 1
d202 2
a203 1
    set contents [nameserv::search $xpat]
d205 32
d242 1
a242 3
    struct::matrix M
    M add columns 2

@

