Index: openacs-4/packages/xotcl-core/xotcl-core.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-core/xotcl-core.info,v
diff -u -N -r1.106 -r1.106.2.1
--- openacs-4/packages/xotcl-core/xotcl-core.info 31 Jan 2019 14:32:23 -0000 1.106
+++ openacs-4/packages/xotcl-core/xotcl-core.info 23 Feb 2019 19:02:55 -0000 1.106.2.1
@@ -10,7 +10,7 @@
t
xotcl
-
+
Gustaf Neumann
XOTcl library functionality (e.g. thread handling, online documentation, Generic Form and List Classes)
2017-08-06
@@ -43,7 +43,7 @@
BSD-Style
2
-
+
Index: openacs-4/packages/xotcl-core/tcl/bgdelivery-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-core/tcl/bgdelivery-procs.tcl,v
diff -u -N -r1.68 -r1.68.2.1
--- openacs-4/packages/xotcl-core/tcl/bgdelivery-procs.tcl 16 Nov 2018 18:39:51 -0000 1.68
+++ openacs-4/packages/xotcl-core/tcl/bgdelivery-procs.tcl 23 Feb 2019 19:02:55 -0000 1.68.2.1
@@ -287,7 +287,7 @@
set ::subscription_count 0
set ::message_count 0
- ::xotcl::Class create Subscriber -parameter {key channel user_id mode}
+ ::xotcl::Class create Subscriber -parameter {key channel user_id mode {start_of_page ""}}
Subscriber proc current {-key } {
set result [list]
if {[info exists key]} {
@@ -338,16 +338,8 @@
Subscriber instproc send {msg} {
#ns_log notice "SEND <$msg> [:mode]"
:log ""
- if {[:mode] eq "scripted"} {
- ::sec_handler_reset
- set emsg [encoding convertto utf-8 $msg]
- #ns_log notice "SEND data <$msg> encoded <$emsg>"
- set smsg "\n"
- set smsg [format %x [string length $smsg]]\r\n$smsg\r\n
- } else {
- set smsg $msg
- }
+ ::sec_handler_reset
+ set smsg [::xo::mr::bgdelivery encode_message [:mode] $msg]
#my log "-- sending to subscriber for [:key] $smsg ch=[:channel] \
# mode=[:mode], user_id [:user_id]"
try {
@@ -362,7 +354,7 @@
"POSIX ECONNRESET {connection reset by peer}"
}
if {$::errorCode in $ok_errors} {
- throw {CLIENTDISCONNECT} {client disconnected}
+ throw {AD_CLIENTDISCONNECT} {client disconnected}
} else {
throw $::errorCode $errorMsg
}
@@ -376,7 +368,7 @@
foreach s [set :subscriptions($key)] {
try {
$s $method $argument
- } trap {CLIENTDISCONNECT} {errMsg} {
+ } trap {AD_CLIENTDISCONNECT} {errMsg} {
ns_log warning "$method to subscriber $s (key=$key): $errMsg"
$s destroy
} on error {errMsg} {
@@ -411,22 +403,8 @@
#my log "-- cl=[:info class], subscriptions([:key]) = $subscriptions([:key])"
fconfigure [:channel] -translation binary
- if {[:mode] eq "scripted"} {
- set content_type "text/html;charset=utf-8"
- set encoding "Cache-Control: no-cache\r\nTransfer-Encoding: chunked\r\n"
- set body "[string repeat { } 1024]\r\n"
- set body [format %x [string length $body]]\r\n$body\r\n
- } else {
- # Chrome refuses to expose partial response to ajax unless we
- # set content_type to octet stream. Drawback is we have to
- # force the translation on the channel.
- set content_type "application/octet-stream"
- set encoding ""
- fconfigure [:channel] -encoding utf-8
- set body ""
- }
-
- puts -nonewline [:channel] "HTTP/1.1 200 OK\r\nContent-type: $content_type\r\n$encoding\r\n$body"
+ fconfigure [:channel] -encoding utf-8
+ puts -nonewline [:channel] ${:start_of_page}
flush [:channel]
}
@@ -769,14 +747,14 @@
}
#####################################
-bgdelivery proc subscribe {key {initmsg ""} {mode default} } {
+bgdelivery proc -deprecated subscribe {key {initmsg ""} {mode default} } {
set ch [ns_conn channel]
thread::transfer [:get_tid] $ch
#my do ::Subscriber sweep $key
:do ::Subscriber new -channel $ch -key $key -user_id [ad_conn user_id] -mode $mode
}
-bgdelivery proc send_to_subscriber {key msg} {
+bgdelivery proc -deprecated send_to_subscriber {key msg} {
:do -async ::Subscriber broadcast $key $msg
}
#####################################
Index: openacs-4/packages/xotcl-core/tcl/message-relay-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xotcl-core/tcl/Attic/message-relay-procs.tcl,v
diff -u -N
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/xotcl-core/tcl/message-relay-procs.tcl 23 Feb 2019 19:02:55 -0000 1.1.2.1
@@ -0,0 +1,225 @@
+xo::library doc {
+ GenericMessageRelay procs
+
+ Provide means to publish a subscription key and let clients write to
+ these keys. These functions are used e.g. by the chat.
+
+ @creation-date 2019-02-23
+ @author Gustaf Neumann
+}
+
+namespace eval ::xo {
+
+ nx::Class create ::xo::MessageRelay {
+ :public method subscribe {key {-initmsg ""} {-mode default}} {
+ #
+ # Subscribe to a service identified by a key.
+ #
+ # @param key unique id for a (potentially new communication hub)
+ # @param initmsg optional message to be sent, when subscription happens
+ # @param mode optional mode
+ #
+ }
+
+ :public method send_to_subscriber {key msg} {
+ #
+ # Send a message to a service identified by the key
+ # (communication hub).
+ #
+ # @param key id for an existing communication hub
+ # @param msg message to be sent
+ #
+ }
+
+ :public method sweep {key} {
+ #
+ # Check existing subscriptions and clean stale ones.
+ #
+ # @param key key of the communication hub
+ #
+ }
+
+ :public method can_be_used {} {
+ #
+ # Check, if a message relay can be used in the current
+ # configuration.
+ #
+
+ return 1
+ }
+
+ :method start_of_page {mode} {
+ #
+ # Compose reply header.
+ #
+ if {$mode eq "scripted"} {
+ set content_type "text/html;charset=utf-8"
+ set encoding "Cache-Control: no-cache\r\nTransfer-Encoding: chunked\r\n"
+ set body "[string repeat { } 1024]\r\n"
+ set body [format %x [string length $body]]\r\n$body\r\n
+ } else {
+ #
+ # Chrome refuses to expose partial response to ajax unless we
+ # set content_type to octet stream. Drawback is we have to
+ # force the translation on the channel.
+ #
+ set content_type "application/octet-stream"
+ set encoding ""
+ set body ""
+ }
+ return "HTTP/1.1 200 OK\r\nContent-type: $content_type\r\n$encoding\r\n$body"
+ }
+
+ :public method encode_message {mode msg} {
+ #
+ # Provide different "encoding" depending on the mode. Notice
+ # that for one chat, multiple clients might have difference
+ # modes, since the modes are determined at also by the
+ # capabilities of the client browser. So the incoming message
+ # has to be recoded multiple times.
+ #
+ if {$mode eq "scripted"} {
+ #::sec_handler_reset
+ set emsg [encoding convertto utf-8 $msg]
+ #ns_log notice "SEND data <$msg> encoded <$emsg>"
+ set jsMsg "\n"
+ set msg [format %x [string length $jsMsg]]\r\n$jsMsg\r\n
+ }
+ #ns_log notice "#### [self] encode_message <$mode> returns <$msg>"
+ return $msg
+ }
+
+ }
+}
+
+namespace eval ::xo::mr {
+ #
+ # Create a dummy message relay (which can be always used)
+ #
+ xo::MessageRelay create ::xo::mr::none
+
+ #
+ # Message Relay based on bgdelivery. This interface works directly
+ # on the socket and is therefore only useful for plain HTTP
+ # connections.
+ #
+ xo::MessageRelay create ::xo::mr::bgdelivery {
+
+ :public object method subscribe {key {-initmsg ""} {-mode default} } {
+ ns_log notice "#### [self] subscribe <$key> mode <$mode>"
+ set ch [ns_conn channel]
+ thread::transfer [::bgdelivery get_tid] $ch
+ # ::bgdelivery do ::Subscriber sweep $key
+ ::bgdelivery do ::Subscriber new \
+ -channel $ch -key $key \
+ -user_id [ad_conn user_id] -mode $mode \
+ -start_of_page [:start_of_page $mode]
+ }
+
+ :public object method send_to_subscriber {key msg} {
+ ns_log notice "#### [self] send_to_subscriber $key $msg"
+ ::bgdelivery do -async ::Subscriber broadcast $key $msg
+ }
+
+ :public object method can_be_used {} {
+ #
+ # We require support from the web server, an installed
+ # bgdelivery. This method does not work on HTTPS, since this
+ # method writes to the raw sockets.
+ #
+ return [expr {
+ [info commands ::thread::mutex] ne ""
+ && [info commands ::bgdelivery] ne ""
+ && ![security::secure_conn_p]
+ }]
+ }
+
+ :public object method sweep {key} {
+ ::bgdelivery do ::Subscriber sweep chat-[:chat_id]}
+ }
+
+ #
+ # Message Relay based on ns_connchan. This interface works on the
+ # full connection structure and can therefore be used for HTTP and
+ # HTTPS connections.
+ #
+ xo::MessageRelay create ::xo::mr::connchan {
+
+ :object method cleanup {key handle} {
+
+ catch {ns_connchan close $handle}
+ catch {nsv_unset mr_connchan_$key $handle}
+ }
+
+ :public object method subscribe {key {-initmsg ""} {-mode ""} } {
+ #ns_log notice "#### [self] subscribe $key mode $mode"
+ #
+ # Unplug the connection channel from the current connection
+ # thread. The currently unplugged channels can be queried via
+ # "ns_connchan list"
+ #
+ set handle [ns_connchan detach]
+
+ #
+ # should check and append
+ #
+ if {![nsv_exists mr_connchan_$key $handle]} {
+ nsv_set mr_connchan_$key $handle $mode
+ try {
+ ns_connchan write $handle [:start_of_page $mode]
+ } on error {errorMsg} {
+ ns_log warning "message relay: write on <$key> failed: $errorMsg"
+ :cleanup $key $handle
+ }
+ } else {
+ ns_log warning "message relay: duplicate registration for <$key> attempted"
+ }
+
+ #::bgdelivery do ::Subscriber new \
+ # -channel $ch -key $key \
+ # -user_id [ad_conn user_id] -mode $mode
+ }
+
+ :public object method send_to_subscriber {key msg} {
+ #
+ # Write directly to the subscribers from the connection
+ # thread. It would be possible, to perform asynchronous
+ # operations via "ns_connchan callback", which would be handled
+ # in the background. Not sure, this is necessary.
+ #
+
+ #ns_log notice "#### [self] send_to_subscriber <[nsv_array names mr_connchan_$key]>"
+
+ foreach handle [nsv_array names mr_connchan_$key] {
+ try {
+ ns_connchan write $handle [:encode_message [nsv_array names mr_connchan_$key $handle] $msg]
+ } on error {errorMsg} {
+ ns_log warning "message relay: duplicate registration for <$key> attempted"
+ :cleanup $key $handle
+ }
+ }
+ }
+
+ :public object method can_be_used {} {
+ return [expr {[info commands ::ns_connchan] ne ""}]
+ }
+
+ :public object method sweep {key} {
+ #
+ # For the time being, do nothing. Since the chat is verbose on
+ # logins/logouts, write operations will fail, in which case the
+ # array is cleaned up. If this is not sufficient, probably a
+ # "ns_connchan eof" operation would be useful.
+ #
+ }
+ }
+}
+
+::xo::library source_dependent
+#
+# Local variables:
+# mode: tcl
+# tcl-indent-level: 2
+# indent-tabs-mode: nil
+# End:
Index: openacs-4/packages/xowiki/xowiki.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/xowiki.info,v
diff -u -N -r1.180 -r1.180.2.1
--- openacs-4/packages/xowiki/xowiki.info 9 Feb 2019 00:18:28 -0000 1.180
+++ openacs-4/packages/xowiki/xowiki.info 23 Feb 2019 19:02:55 -0000 1.180.2.1
@@ -10,7 +10,7 @@
t
xowiki
-
+
Gustaf Neumann
A xotcl-based enterprise wiki system with multiple object types
2017-08-06
@@ -55,8 +55,8 @@
BSD-Style
2
-
-
+
+
Index: openacs-4/packages/xowiki/tcl/chat-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/chat-procs.tcl,v
diff -u -N -r1.54 -r1.54.2.1
--- openacs-4/packages/xowiki/tcl/chat-procs.tcl 18 Jan 2019 16:39:36 -0000 1.54
+++ openacs-4/packages/xowiki/tcl/chat-procs.tcl 23 Feb 2019 19:02:55 -0000 1.54.2.1
@@ -16,14 +16,28 @@
{mode default}
{encoder noencode}
{timewindow 600}
- {sweepinterval 5}
+ {sweepinterval 60}
{login_messages_p t}
{logout_messages_p t}
{conf {}}
+ {message_relay {bgdelivery connchan none}}
}
Chat instproc init {} {
# :log "-- "
+
+ #
+ # Work through the list of provided message_relays an select a
+ # usable one.
+ #
+ set :mr ::xo::mr::none
+ foreach mr ${:message_relay} {
+ if {[::xo::mr::$mr can_be_used]} {
+ set :mr ::xo::mr::$mr
+ break
+ }
+ }
+
set :now [clock clicks -milliseconds]
if {![info exists :user_id]} {
set :user_id [ad_conn user_id]
@@ -79,17 +93,19 @@
set user_id [expr {$uid ne "" ? $uid : ${:user_id}}]
set color [:user_color $user_id]
set msg [ns_quotehtml $msg]
+
# :log "-- msg=$msg"
+ :broadcast_msg [Message new -volatile -time [clock seconds] \
+ -user_id $user_id -color $color [list -msg $msg]]
- if {[info commands ::thread::mutex] ne "" &&
- [info commands ::bgdelivery] ne ""} {
- # we could use the streaming interface
- :broadcast_msg [Message new -volatile -time [clock seconds] \
- -user_id $user_id -color $color [list -msg $msg]]
- }
:register_nsvs ${:now}.$user_id $user_id $msg $color [clock seconds]
- # this in any case a valid result, but only needed for the polling interface
- if {$get_new} {:get_new}
+ #
+ # This in any case a valid result, but only needed for the polling
+ # interface
+ #
+ if {$get_new} {
+ :get_new
+ }
}
Chat instproc current_message_valid {} {
@@ -134,9 +150,9 @@
}
}
::xo::clusterwide nsv_set ${:array}-seen ${:session_id} ${:now}
- # :log "--c setting session_id ${:session_id}: ${:now}"
+ # :log "--chat setting session_id ${:session_id}: ${:now}"
} else {
- # :log "--c nothing new for ${:session_id}"
+ # :log "--chat nothing new for ${:session_id}"
}
:render
}
@@ -148,26 +164,24 @@
:add [Message new -time $secs -user_id $user -msg $msg -color $color]
}
}
- #my log "--c setting session_id ${:session_id}: ${:now}"
+ #my log "--chat setting session_id ${:session_id}: ${:now}"
::xo::clusterwide nsv_set ${:array}-seen ${:session_id} ${:now}
:render
}
Chat instproc sweeper {} {
#:log "--core-chat starting"
foreach {user timestamp} [nsv_array get ${:array}-last-activity] {
- #ns_log notice "--core-chat at user $user with $timestamp"
set ago [expr {(${:now} - $timestamp) / 1000}]
#ns_log notice "--core-chat Checking: now=${:now}, timestamp=$timestamp, ago=$ago"
- # was 1200
if {$ago > 300} {
:logout -user_id $user -msg "auto logout"
# ns_log warning "-user_id $user auto logout"
- try {::bgdelivery do ::Subscriber sweep chat-[:chat_id]}
+ ${:mr} sweep chat-[:chat_id]
}
}
:broadcast_msg [Message new -volatile -type "users" -time [clock seconds]]
- :log "-- ending"
+ #:log "-- ending"
}
Chat instproc logout {{-user_id ""} {-msg ""}} {
@@ -209,12 +223,12 @@
Chat instproc user_active {user_id} {
# was the user already active?
- :log "--chat login already avtive? [nsv_exists ${:array}-last-activity $user_id]"
+ #:log "--chat login already avtive? [nsv_exists ${:array}-last-activity $user_id]"
return [nsv_exists ${:array}-last-activity $user_id]
}
Chat instproc login {} {
- :log "--chat login"
+ :log "--chat login mode=${:mode}"
if {${:login_messages_p} && ![:user_active ${:user_id}]} {
:add_msg -uid ${:user_id} -get_new false [_ xotcl-core.has_entered_the_room]
} elseif {${:user_id} > 0 && ![nsv_exists ${:array}-login ${:user_id}]} {
@@ -224,7 +238,7 @@
::xo::clusterwide nsv_set ${:array}-last-activity ${:user_id} ${:now}
}
:encoder noencode
- :log "--c setting session_id ${:session_id}: ${:now}"
+ #:log "--chat setting session_id ${:session_id}: ${:now} mode=${:mode}"
return [:get_all]
}
@@ -305,14 +319,14 @@
Chat instproc broadcast_msg {msg} {
#:log "--chat broadcast_msg"
- ::xo::clusterwide \
- bgdelivery send_to_subscriber chat-[:chat_id] [:json_encode_msg $msg]
+ ${:mr} send_to_subscriber chat-[:chat_id] [:json_encode_msg $msg]
}
Chat instproc subscribe {-uid} {
set user_id [expr {[info exists uid] ? $uid : ${:user_id}}]
set color [:user_color $user_id]
- bgdelivery subscribe chat-[:chat_id] "" [:mode]
+ #ns_log notice "--CHAT [self] subscribe chat-${:chat_id} -mode ${:mode} via <${:mr}>"
+ ${:mr} subscribe chat-${:chat_id} -mode ${:mode}
}
Chat instproc render {} {
@@ -339,7 +353,7 @@
:new -volatile -chat_id $chat_id -user_id 0 -session_id 0 -init -sweeper
}
}
- :log "-- ending"
+ #:log "-- ending"
}
ChatClass method initialize_nsvs {} {
@@ -394,7 +408,7 @@
set mode polling
#
# Check, whether we have the tcllibthread and a sufficiently new
- # aolserver/NaviServer supporting bgdelivery transfers.
+ # AOLserver/NaviServer supporting bgdelivery transfers.
#
if {[info commands ::thread::mutex] ne "" &&
![catch {ns_conn contentsentlength}]} {
@@ -403,10 +417,12 @@
#
set mode scripted-streaming
if {![regexp msie|opera [string tolower [ns_set get [ns_conn headers] User-Agent]]]} {
- # Explorer doesn't expose partial response until request state != 4, while Opera fires
- # onreadystateevent only once. For this reason, for every browser except them, we could
- # use the nice mode without the spinning load indicator.
#
+ # Explorer doesn't expose partial response until request state
+ # != 4, while Opera fires onreadystateevent only once. For
+ # this reason, for every browser except them, we could use the
+ # nice mode without the spinning load indicator.
+ #
set mode streaming
}
}
@@ -473,11 +489,11 @@
switch -- $mode {
polling {
set jspath /resources/xowiki/chat.js
- set subscribe_url ${base_url}&m=get_new
+ set subscribe_url ${base_url}&m=get_new&=polling
}
streaming {
set jspath /resources/xowiki/streaming-chat.js
- set subscribe_url ${base_url}&m=subscribe
+ set subscribe_url ${base_url}&m=subscribe&mode=streaming
}
scripted-streaming {
set jspath /resources/xowiki/scripted-streaming-chat.js
@@ -551,6 +567,7 @@
-session_id $session_id \
-mode $mode \
-conf $conf
+ #:log "--CHAT created c1 with mode=$mode"
set data [c1 login]
if {$data ne ""} {
@@ -584,6 +601,8 @@
}]
+ #:log "--CHAT create HTML for mode=$mode"
+
switch -- $mode {
"polling" {
append html [subst -nocommands {
Index: openacs-4/packages/xowiki/www/chat.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/www/chat.tcl,v
diff -u -N -r1.2 -r1.2.2.1
--- openacs-4/packages/xowiki/www/chat.tcl 20 Nov 2018 18:41:05 -0000 1.2
+++ openacs-4/packages/xowiki/www/chat.tcl 23 Feb 2019 19:02:55 -0000 1.2.2.1
@@ -1,9 +1,10 @@
ad_page_contract {
- a tiny chat client
+ A tiny chat client
@author Gustaf Neumann (gustaf.neumann@wu-wien.ac.at)
@creation-date Jan 31, 2006
@cvs-id $Id$
+
} -query {
m:word
id:integer
@@ -15,32 +16,37 @@
if {![::xo::ChatClass is_chat_p $class]} {
ns_returnnotfound
- ad_script_abort
-}
-#ns_log notice "--chat m=$m session_id=$s [clock format [lindex [split $s .] 1] -format %H:%M:%S] mode=$mode"
-$class create c1 -destroy_on_cleanup -chat_id $id -session_id $s -mode $mode
-switch -- $m {
- add_msg {
- #ns_log notice "--c call c1 $m '$msg'"
- ns_return 200 application/json [c1 $m $msg]
- ad_script_abort
- #ns_log notice "--c add_msg returns '$_'"
+} else {
+
+ #ns_log notice "### chat.tcl mode <$mode> class <$class>"
+ #ns_log notice "--chat m=$m session_id=$s [clock format [lindex [split $s .] 1] -format %H:%M:%S] mode=$mode"
+
+ $class create c1 -destroy_on_cleanup -chat_id $id -session_id $s -mode $mode
+ switch -- $m {
+ add_msg {
+ #ns_log notice "--c call c1 $m '$msg'"
+ ns_return 200 application/json [c1 $m $msg]
+ }
+ get_new {
+ ns_return 200 application/json [c1 $m]
+ }
+ login -
+ subscribe -
+ get_all {
+ set _ [c1 $m]
+ ns_return 200 text/html [subst {$_}]
+ }
+ default {
+ ns_log error "--c unknown method $m called."
+ }
}
- get_new {
- ns_return 200 application/json [c1 $m]
- ad_script_abort
- }
- login -
- subscribe -
- get_all {set _ [c1 $m]}
- default {ns_log error "--c unknown method $m called."}
}
+ad_script_abort
+
#ns_log notice "--chat.tcl $m: returns '$_'"
-ns_return 200 text/html [subst {$_}]
-
# Local variables:
# mode: tcl
# tcl-indent-level: 2