tcl-libraries - NaviServer Tcl Libraries
A Tcl library is simply a directory containing Tcl scripts that are sourced at startup by a virtual server. You can create private libraries for individual virtual servers and public libraries that affect all or some of an installation's virtual servers.
Each Tcl file in a library often contains one or more calls to ns_register_proc, ns_schedule_proc, or ns_register_filter to bind a script to a specific URL or URL hierarchy, plus the Tcl scripts that will handle the URL(s). This example shows the ns_register_proc function being used to bind the Tcl procedure hello to handle a GET request for /example/hello, plus the hello procedure itself:
ns_register_proc GET /example/hello hello proc hello {} { ns_return 200 text/plain "Hello World" }
After the function is loaded (typically from a Tcl library directory) and the server is started, one can test the function by visiting the URL
http://yourserver/example/hello
When NaviServer processes a method/URL request, it checks to see if there is a Tcl script in the virtual server's private or shared library to handle the method and URL. A private Tcl script registered to handle a URL overrides a shared Tcl script registered to handle the same URL.
Tcl libraries can also be created that contain no registration functions; they may just contain Tcl functions that are called from ADPs or from scheduled procedures.
The alternative to embedding Tcl scripts in HTML pages using ADPs (see Chapter 2), is to store Tcl scripts in Tcl libraries. The situations listed below are well-suited to the Tcl libraries approach.
If you want one Tcl script to handle a URL and all of its sub-URLs, it is better to store the script in a Tcl library and register it using ns_register_proc to handle a URL hierarchy. For example, you may want to manage a server domain name change by redirecting every response to the corresponding domain name on another server.
If you want one Tcl script to handle all files with a specific extension, like /*.csv, you would register the script with ns_register_proc to handle those files.
If you want a Tcl script to be run at specific intervals, you can use the ns_schedule_* functions to run a script from the Tcl library at scheduled intervals. These procedures do not normally involve returning HTML pages and so are not well suited to ADPs.
If you want a Tcl script to be called at pre-authorization, post-authorization, or trace time for a group of URLs, you would register a filter using the ns_register_filter function.
If there are Tcl scripts that you want to use in multiple situations, you can store them in a Tcl library and invoke them from within any ADP or Tcl script.
Tcl libraries contain Tcl files, which are loaded at startup time. The functions defined in these Tcl files are available at run time without any function loading overhead. NaviServer distinguishes between global (shared) and per-server (private) library directories.
The global (shared) Tcl library directory is specified by the parameter tcllibrary in the ns/parameters section and it defaults to tcl under NaviServer home directory.
# # Global parameters # ns_section ns/parameters { ns_param home /usr/local/ns ;# usual place ns_param tcllibrary tcl ;# default, full path: /usr/local/ns/tcl }
The per-server (private) Tcl library directory is specified by the parameter library in the ns/server/$server/tcl section. It defaults to modules/tcl under NaviServer home. One can specify a different Tcl library directory for each server.
# # Global parameters # ns_section ns/parameters { ns_param home /usr/local/ns ;# usual place } # # Parameters of the "tcl" section of the server "myserver" # ns_section ns/server/myserver/tcl { ns_param library modules/tcl ;# default, full path: /usr/local/ns/modules/tcl }
Note that the specified directories need not reside under home (the NaviServer installation directory). Using a different directory tree allows you to keep site-specific scripts physically separate from the system-specific scripts supplied by NaviServer. For example, OpenACS uses the per-server library directory to start the server with the OpenACS specific packages and request/templating processing.
In general, the global (shared) Tcl libraries are loaded before the per-server (private) libraries. This is true for the Tcl files placed directly in the library directories as for the Tcl modules (more details follow). The Tcl library directories are a flat structure, from which all contained Tcl files are loaded. Sometimes several Tcl files should be handled together and might not be necessary for all managed servers. For these purpose, Tcl-only modules can be used.
At server startup time, NaviServer initializes first the Tcl library directories and then the specified Tcl-only modules:
For the specified Tcl library directories, the init.tcl file in that directory is sourced first (if it exists), and then all the remaining .tcl files are sourced in an alphabetical order.
For each module (including any Tcl-only modules) in the server: If a private Tcl directory is specified, the init.tcl file in the module-name subdirectory of the private directory is sourced first (if it exists), and then all the remaining .tcl files are sourced alphabetically.
If the tcl section of the server configuration contains the parameter initcmds then these commands are executed after the initialization of the Tcl-only modules. This feature is useful e.g. for simple server configurations, where the full code of the server-initialization can be put into the configuration file. So only one file has to be maintained
# # Parameters of the "tcl" section of the server "myserver" # ns_section ns/server/myserver/tcl { ns_param initcmds { ns_log notice "=== Hello World === server: [ns_info server]" } }
NaviServer supports C-based modules and Tcl-only modules. Tcl-only modules are directories, containing potentially multiple Tcl source files. When a Tcl-only module mymodule is configured to be loaded, during starutp NaviServer searches in the subdirectory of the global (shared) library directory, and if not found the per-server (privated) library directory for a directory with that name. When it is found the subdirectory mymodule is initialized (as described above). To load a Tcl-only module named mymodule, add the following line to the per-server modules section in the configuration file:
# # Parameters of the "modules" section of the server "myserver" # ns_section ns/server/myserver/modules { ns_param mymodule Tcl }
Note that when Tcl modules are specified, only the named subdirectories of the Tcl library directory are initialized (loaded). Otherwise, all subdirectories of the Tcl library directories are ignored. For example, if a server named myserver has a Tcl library directory defined as /home/mydir/tcl/myserver-lib, and the modules foo and bar are loaded,
# # Parameters of the "tcl" section of the server "myserver" # ns_section ns/server/myserver/tcl { ns_param library /home/mydir/tcl/myserver-lib } # # Parameters of the "modules" section of the server "myserver" # ns_section ns/server/myserver/modules { ns_param foo tcl ns_param bar tcl }
... then the following directories will be initialized as server start-up:
/home/mydir/tcl/myserver-lib /home/mydir/tcl/myserver-lib/foo /home/mydir/tcl/myserver-lib/bar
Assume the library directory for module foo contains these files:
init.tcl aa.tcl zz.tcl
The Tcl files will be sourced in this order:
/home/mydir/tcl/myserver-lib/... /home/mydir/tcl/myserver-lib/foo/init.tcl /home/mydir/tcl/myserver-lib/foo/aa.tcl /home/mydir/tcl/myserver-lib/foo/zz.tcl
For a loaded Tcl-only module foo the paths of the actual files can by queried via ns_library as shown in the following example.
set shared [ns_library shared foo] set priv [ns_library private foo]
ns_config, ns_library