TIP #411: Improved Channel Introspection via "chan info"
_____________________________________________________________________________
TIP:	411
Title:	Improved Channel Introspection via "chan info"
Version:	$Revision: 1.4 $
Authors:	Pawel Salawa <pawelsalawa@gmail.com>
State:	Draft
Type:	Project
Tcl-Version:	8.7
Vote:	Pending
Created:	Fri Aug 31 00:00:00 UTC 2012
Abstract
This document describes new subcommand for chan, chan info, that provides a unified interface to deeper introspection of information about a particular channel.
Rationale
When working with Tcl channels sometimes it happens that we got the channel, but we don't know if it's a file channel, socket, or reflected channel. This information can be very useful. Also some additional information, depending of the channel type, like file path for file channel, host and port for sockets (it's already available, but could get unified within new chan subcommand), or any metadata provided by reflected channels.
An example where it could be used is the package with an API that accepts just a channel on input call and the inside routines need to do something with the file (in file system), so they have to learn the name of the file related to given channel.
Specification
A new subcommand for chan is introduced:
chan info channelId
Also a new optional command is introduced for reflected channels API:
cmdPrefix chaninfo channelId
The info Subcommand of chan
The chan info command will take a single mandatory argument, channelId, which will be the name of a channel to retrieve information about. This operation will always fail in a safe interpreter. The result of the new chan info command would be a dictionary with following keys always present:
type	indicating a type of channel. Possible values are "file", "socket", "process" (result of [[open "|..."]]), empty string (in case of channel that doesn't support this information), or any custom type, depending of refchan implementations. This is a mandatory key.
The remainder of the keys are optional and depend on the type.
For file channels, the dictionary shall include these:
path	full, normalized path to the file, including the file name.
new	boolean value indicating whether file already existed while opening, or it was created.
For socket channels, the dictionary shall include these:
host	peer hostname, or local hostname for listening socket. This is partially equivalent to getting the first value returned by [[chan configure channelId -peername]] for connected sockets.
port	peer port, or listening port (for listening socket). This is partially equivalent to getting the third value returned by [[chan configure channelId -peername]] for connected sockets.
side	one of the following: "client", "accepted", or "listening".
For process channels, the dictionary shall include these:
cmdline	copy of the command passed to open.
pid	PID of a spawned process, as produced by pid.
Any key could be produced by other channel types, notably including reflected channels.
The chaninfo Operation of Reflected Channel Implementations
The chaninfo subcommand of a reflected channel implementation command returns a dict that is provided in response to a chan info request. If the dictionary does not include the mandatory type member, the reflected channel baseline implementation will add it and set it to refchan. It is an error to return a non-dictionary.
Since reflected channels are free to set the type to anything, they can simulate standard channels, like "file", as well as create completely new types.
If the operation is not supported, the baseline implementation will treat it the same as if the operation returned an empty dictionary.
Internals
Channel structure in Tcl core would require another API level indicating channels that have a function returning an "info" dict. All core channels are expected to migrate to this level, although it's possible to stay at current API version - it will just cause the type in chan info dict to be the typeName field of the channel's Tcl_ChannelType structure, with no additional keys in the dict.
Examples
This is a a pure Tcl implementation of file type channel, so it supports new information in chan info:
oo::class create filechan 
    variable path fd created filemode
    constructor fpath mode 
        set filemode $mode
        set path $fpath

    method initialize ch mode 
        set exists [file exists $path]
        set fd [open $path $filemode]
        set created [expr  [file exists $path] && !$exists]
        return "initialize finalize watch read seek chaninfo"
    
    method finalize ch 
        ::close $fd
        my destroy
    
    method watch ch events 
        foreach event [list read write] method [list readable writable] 
            if $event in $events 
                fileevent $fd $method [list chan postevent $ch $event]

    

    # Must be present on a readable channel
    method read ch count 
        ::read $fd $count

    # This method is optional, but useful for the example below
    method seek ch offset base 
        ::seek $fd $offset $base

    method chaninfo ch 
        dict create type file path $path new $created

proc openfile file mode 
    # lets not bother of what modes should be passed to [chan create],
    # it's just an example...
    chan create [list read write] [filechan new $file $mode]

set fd [openfile "myfile.txt" r]
puts [chan info $fd]
close $fd
Reference Implementation
http://sqlitestudio.pl/tcl/patches/tip-411-chan_info.patch
Patch made against 8.6.0 (just before final release).
Copyright
This document has been placed in the public domain.
_____________________________________________________________________________
Colophon
TIP AutoGenerator - written by Donal K. Fellows