Version 10 of Wikit run in a Slave Interpreter on TclHttpd

Updated 2004-11-21 21:33:49 by BAJ

"WhipIt" - Wikit run in a Slave Interpreter on TclHttpd

Since I read the comments below this became an itch I just had to scratch! Jeff Smith

Extracted from the How to grow your own Wiki page.

MDD: What would be really nice would be if someone would create a Starkit that combines tclhttpd and the wikit into one turnkey wiki server. Performance should be better, since you wouldn't have to use CGI.

11apr03 jcw - Yes, that would be cool, but it may need some work (either to make it properly keep state with repeated requests, or to make it work in a slave interp which gets re-inited on each access).

To try "WhipIt" place the following whipit.tcl code into the custom directory of your TclHttpd Starkit or get a ready made starkit, whipit.kit, from [L1 ]. This starkit has a copy of wikit.kit inside and copies it to the outside directory at startup if the wikit.kit file does not exist.

To launch on unix

 # ./tclkit whipit.kit

On Windows

from a dos window

 C:\tclkitsh whipit.kit

from windows explorer

 drag and release whipit.kit on tclkit

Point your browser to

 http://yourhost:8015/wikit/

This provides a nice wrapper around Wikit to allow you to dynamically control it. For example the WIKIT_BASE environment variable is dynamically set per request in the code below. Some ideas for the future

  • A readonly wiki with a seperate database that allows certain pages to be edited by dynamically removing "-readonly" flag for those pages.
  • A database which registers users and allows them to only edit the pages they created or edit pages of people in their group.

BAJ uses whipit and finds it very useful, but just discovered that the history feature of wikit (enabled with "WIKI_HIST" is broken by whipit (the puts that should write to a disk file ends up being remapped to the WktCGI_Puts command in script below).

************* whipit.tcl ****************************

 #Mount the wikit startkit
 vfs::mk4::Mount [file dir $starkit::topdir]/wikit.kit [file dir $starkit::topdir]/wikit.kit

 set WktDir [file dir $starkit::topdir]/wikit.kit

 # Append wikit library from the mounted wikit starkit to the auto_path
 lappend auto_path [file dir $starkit::topdir]/wikit.kit/lib

 Url_PrefixInstall /wikit [list wikitProc /wikit]

 proc wikitProc {prefix sock suffix} {
         upvar #0 Httpd$sock data
         global env auto_path

      # Set the CGI environment variables

      Cgi_SetEnv $sock $prefix
      set env(PATH_INFO) $suffix
      set env(SCRIPT_NAME) $prefix

      # This sets the WIKIT_BASE environment vaiable dynamically based on
      # the host portion of the url typed in the browser.

      set env(WIKIT_BASE) http://$env(HTTP_HOST)$prefix/

      append data(query) ""

      # Use the Session Module in TclHttpd to create a slave interpreter.
      # A session state array is also created but we don't use it. This
      # maybe of some use if you have a need for a session based wiki.
      #
      # To emulate a CGI environment for Wikit, a slave interpreter is created
      # and then destroyed per request.

      # Destroy any old sessions that are laying around. Interpreters that have
      # been created but for some reason not destroyed. In this instance
      # 2 minutes is the setting.

      Session_Reap 120 Wkt

      # Create a new session.

      set session [Session_Create Wkt 0]

      set html [WktProcess $session $data(query)]

      Httpd_ReturnData $sock text/html $html
      Session_Destroy $session
 }

 proc WktProcess {session query} {
      upvar #0 Session:$session state
      set interp $state(interp)
      global auto_path WktDir

      set WktCGI_LineNumber 0

      set html ""

      # Redirect the read and puts in the slave interpreter
      # that runs Wikit.

      interp eval  $interp {rename puts real_puts}
      interp alias $interp puts {} WktCGI_Puts
      interp hidden $interp
      interp eval $interp {rename read real_read}
      interp alias $interp read {} WktCGI_Read $interp $query

      # Fool wikit to think it is running in it own Starkit so we can copy
      # the first ten pages from wikidoc.tkd

      interp eval $interp [list namespace eval starkit set topdir $WktDir]

      # Following taken from httpd.tcl for getting these variables into
      # a slave interpreter.
      #
      # Transfer the scalar global variables

      foreach var {::v ::auto_path} {
         $interp eval [list set $var [set $var]]
      }

      # Procedure that is run when the slave interpreter does a read.

      proc WktCGI_Read {interp query args} {

            if { [llength $args] == 2 && [lindex $args 0] == "stdin" } {
                return [$interp eval subst $query]
            } else {
                return [$interp eval real_read $args]
            }
      }

      # Precedure that is run when the slave interpreter does a puts.

      proc WktCGI_Puts {args} {
            upvar 1 WktCGI_LineNumber WktCGI_LineNumber
            upvar 1 html html

            incr WktCGI_LineNumber
            if {$WktCGI_LineNumber <= 4} {
                return ""
            } else {
                 append html [lindex $args end]
            }
      }


      # Setup and run Wikit.

      $interp eval {
                    set argv0 tclkit
                    set argv {}
                    set argc 0

                    package require cgi
                    #cgi_debug -on

                    # Work around for getting lassign into the slave interpreter.
                    # From "Practical Programming in Tcl and Tk" Third Edition
                    # by Brent B. Welch page 131.

                    proc lassign {valueList args} {
                         if {[llength $args] == 0 } {
                             error "wrong # args: lassign list varname ?varname ..?"
                         }
                         if {[llength $valueList] == 0} {
                             #Ensure one trip through the foreach loop
                              set valueList [list {}]
                         }
                         uplevel 1 [list foreach $args $valueList {break}]
                         return [lrange $valueList [llength $args] end]
                    }

                    # Source the starkit
                    package require app-wikit
       }
       return $html
 }

**********************************************************************************


Category Wikit - Category TclHttpd