This is an experimental approach to web application development in Tcl. The idea is simple, but seems to be very flexible - create a separate thread (or thread pools in the future) for an application and handle all commands related to an application within that thread.
Another thing which was implemented here is creating Itcl class for the application and creating an instance of the application for each session - so an "object" is bound to a client (there are some open issues with cookie-disabled browsers). This way the object can use variables to store particular data and Iapp framework handles cleanup of the objects as well as it can store some more complex Tcl data structures - like results from database queries. The actual return of the data is done with the original thread so the ''worker'' thread is mainly used for data manipulation and returning the actual HTML. The API will also allow access to query variables (this is subject to many changes at the moment).
'''2006-04-03''' The main issue is the actual performance loss when compared to usual AOLserver approach - because of thread communication etc. A simple job of returning a static data proved that this concept is about '''5 times slower''' - about4000 req/sec vfs 800 req/sec. The tests were executed on the following machine:
vendor_id : AuthenticAMD
cpu family : 15
model : 5
model name : AMD Opteron(tm) Processor 144
stepping : 8
cpu MHz : 1799.998
cache size : 1024 KB
Another test, where 64kB string was to be returned, resulted in 500 req/sec while 200 req/sec were possible using Iapp approach, so when the size of the content increases, the difference actually decreases.
The interesting part of this approach is the actual ease of how things can be implemented. The following is a template for doing a login/logout system:
itcl::clas itcl::class iapp::rh::login {
protected variable loginUserID ""
protected variable loginUserType ""
protected method serializeInt {} {
set serializeData(rh::login::loginUserID) $loginUserID
set serializeData(rh::login::loginUserType) $loginUserType
}
protected method deserializeInt {} {
if {[info exists serializeData(rh::login::loginUserID)]} {
set loginUserID $serializeData(rh::login::loginUserID)
} else {
set loginUserID ""
}
if {[info exists serializeData(rh::login::loginUserType)]} {
set loginUserType $serializeData(rh::login::loginUserType)
} else {
set loginUserType ""
}
}
public method handleLogin {queryprefix type} {
upvar querydata querydata
if {($loginUserID == "")
&&
([info exists querydata(${queryprefix}login)] || [info exists querydata(${queryprefix}login.x)])
&&
([info exists querydata(${queryprefix}username)] && [info exists querydata(${queryprefix}password)])
} {
set loginUserID [loginAuthorize $querydata(${queryprefix}username) $querydata(${queryprefix}password)]
if {$loginUserID != ""} {
set loginUserType $type
}
if {$loginUserID == ""} {
return loginFailed
} else {
return login
}
} elseif {($loginUserID != "")
&&
([info exists querydata(${queryprefix}logout)] || [info exists querydata(${queryprefix}logout.x)])
} {
set loginUserID ""
set loginUserType ""
return logout
} elseif {($loginUserID != "") && (![string equal $type $loginUserType])} {
# do not allow users of different types - logout to be sure
if {[catch {
onLogout $loginUserID
}]} {
# TODO: log error
}
set loginUserID ""
set loginUserType ""
return logout
}
return ""
}
## virtual methods
protected method loginAuthorize {username password} {
return ""
}
}
And the handler class that tests this:
itcl::class ::sessionHandler {
inherit \
::iapp::serialize \
::iapp::requesthandler \
::iapp::rh::login
public method handleRequest {} {
switch -- $suffix {
access {
set cmd [handleLogin iapp_ main]
set html "CMD=$cmd
"
append html "