TIP #411: IMPROVED CHANNEL INTROSPECTION VIA "CHAN INFO" ========================================================== Version: $Revision: 1.4 $ Author: Pawel Salawa State: Draft Type: Project Tcl-Version: 8.7 Vote: Pending Created: Friday, 31 August 2012 URL: https://tip.tcl-lang.org411.html Post-History: ------------------------------------------------------------------------- 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 ========================== Patch made against 8.6.0 (just before final release). COPYRIGHT =========== This document has been placed in the public domain. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows