dialog.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005 puts "- dialog (coserv-based)"
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 namespace ::dialog {
00018 variable dtrace {}
00019 }
00020
00021
00022
00023
00024 ret ::dialog::setup (type type , type cookie) {
00025 variable id
00026 variable port
00027
00028 switch -- $type {
00029 server {set server 1}
00030 client {set server 0}
00031 default {return -code error "Bad dialog type \"$type\", expected server, or client"}
00032 }
00033
00034 set id [::coserv::start "$type: $cookie"]
00035 ::coserv::run $id {
00036 set responses {}
00037 set strace {}
00038 set received {}
00039 set conn {}
00040 set ilog {}
00041
00042 proc Log {text} {
00043 global ilog ; lappend ilog $text
00044 }
00045 proc Strace {text} {
00046 global strace ; lappend strace $text
00047 }
00048 proc Exit {sock reason} {
00049 Strace $reason
00050 Log [list $reason $sock]
00051 close $sock
00052 Done
00053 }
00054 proc Done {} {
00055 global main strace ilog
00056 comm::comm send $main [list dialog::done [list $strace $ilog]]
00057 return
00058 }
00059 proc ClearTraces {} {
00060 global strace ; set strace {}
00061 global ilog ; set ilog {}
00062 return
00063 }
00064 proc Step {sock} {
00065 global responses trace
00066
00067 if {![llength $responses]} {
00068 Exit $sock empty
00069 return
00070 }
00071
00072 set now [lindex $responses 0]
00073 set responses [lrange $responses 1 end]
00074
00075 Log [list ** $sock $now]
00076 eval [linsert $now end $sock]
00077 return
00078 }
00079
00080 # Step commands ...
00081
00082 proc .Crlf {sock} {
00083 Strace crlf
00084 Log crlf
00085 fconfigure $sock -translation crlf
00086 Step $sock
00087 return
00088 }
00089 proc .Binary {sock} {
00090 Strace bin
00091 Log binary
00092 fconfigure $sock -translation binary
00093 Step $sock
00094 return
00095 }
00096 proc .HaltKeep {sock} {
00097 Log halt.keep
00098 Done
00099 global responses
00100 set responses {}
00101 # No further stepping.
00102 # This keeps the socket open.
00103 # Needs external reset/cleanup
00104 return
00105 }
00106 proc .Send {line sock} {
00107 Strace [list >> $line]
00108 Log [list >> $line]
00109
00110 if {[catch {
00111 puts $sock $line
00112 flush $sock
00113 } msg]} {
00114 Exit $sock broken
00115 return
00116 }
00117 Step $sock
00118 return
00119 }
00120 proc .Geval {script sock} {
00121 Log geval
00122 uplevel #0 $script
00123 Step $sock
00124 return
00125 }
00126 proc .Eval {script sock} {
00127 Log eval
00128 eval $script
00129 Step $sock
00130 return
00131 }
00132 proc .SendGvar {vname sock} {
00133 upvar #0 $vname line
00134 .Send $line $sock
00135 return
00136 }
00137 proc .Receive {sock} {
00138 set aid [after 10000 [list Timeout $sock]]
00139 fileevent $sock readable [list Input $aid $sock]
00140 # No "Step" here. Comes through input.
00141 Log " Waiting \[$aid\]"
00142 return
00143 }
00144 proc Input {aid sock} {
00145 global received
00146 if {[eof $sock]} {
00147 # Clean the timer up
00148 after cancel $aid
00149 Exit $sock close
00150 return
00151 }
00152 if {[gets $sock line] < 0} {
00153 Log " **|////|**"
00154 return
00155 }
00156
00157 Log "-- -v-"
00158 Log " Events off \[$aid, $sock\]"
00159 fileevent $sock readable {}
00160 after cancel $aid
00161
00162 Strace [list << $line]
00163 Log [list << $line]
00164 lappend received $line
00165
00166 # Now we can step further
00167 Step $sock
00168 return
00169 }
00170 proc Timeout {sock} {
00171 Exit $sock timeout
00172 return
00173 }
00174 proc Accept {sock host port} {
00175 fconfigure $sock -blocking 0
00176 ClearTraces
00177 Step $sock
00178 return
00179 }
00180
00181 proc Server {} {
00182 global port
00183 # Start listener for dialog
00184 set listener [socket -server Accept 0]
00185 set port [lindex [fconfigure $listener -sockname] 2]
00186 # implied return of <port>
00187 }
00188
00189 proc Client {port} {
00190 global conn
00191 catch {close $conn}
00192
00193 set conn [set sock [socket localhost $port]]
00194 fconfigure $sock -blocking 0
00195 ClearTraces
00196 Log [list Client @ $port = $sock]
00197 Log [list Channels $port = [lsort [file channels]]]
00198 Step $sock
00199 return
00200 }
00201 }
00202
00203 if {$server} {
00204 set port [coserv::run $id {Server}]
00205 }
00206 }
00207
00208 ret ::dialog::runclient (type port) {
00209 variable id
00210 variable dtrace {}
00211 coserv::task $id [list Client $port]
00212 return
00213 }
00214
00215 ret ::dialog::dialog_set (type response_, type script) {
00216 begin
00217 uplevel 1 $response_script
00218 end
00219 return
00220 }
00221
00222 ret ::dialog::begin (optional cookie ={)} {
00223 variable id
00224 ::coserv::task $id [list set responses {}]
00225 log::log debug "+============================================ $cookie \\\\"
00226 return
00227 }
00228
00229 ret ::dialog::cmd (type command) {
00230 variable id
00231 ::coserv::task $id [list lappend responses $command]
00232 return
00233 }
00234
00235 ret ::dialog::end () {
00236 # This implicitly waits for all preceding commands (which are async) to complete.
00237 variable id
00238 set responses [::coserv::run $id [list set responses]]
00239 ::coserv::run $id {set received {}}
00240 log::log debug |\t[join $responses \n|\t]
00241 log::log debug +---------------------------------------------
00242 return
00243 }
00244
00245 ret ::dialog::crlf. () {cmd .Crlf}
00246 ret ::dialog::binary. () {cmd .Binary}
00247 ret ::dialog::send. (type line) {cmd [list .Send $line]}
00248 ret ::dialog::receive. () {cmd .Receive}
00249 ret ::dialog::respond. (type line) {receive. ; send. $line}
00250 ret ::dialog::request. (type line) {send. $line ; receive.}
00251 ret ::dialog::halt.keep. () {cmd .HaltKeep}
00252 ret ::dialog::sendgvar. (type vname) {cmd [list .SendGvar $vname]}
00253 ret ::dialog::reqgvar. (type vname) {sendgvar. $vname ; receive.}
00254 ret ::dialog::geval. (type script) {cmd [list .Geval $script]}
00255 ret ::dialog::eval. (type script) {cmd [list .Eval $script]}
00256
00257 ret ::dialog::done (type traces) {
00258 variable dtrace $traces
00259 return
00260 }
00261
00262 ret ::dialog::waitdone () {
00263 variable dtrace
00264
00265 # Loop until we have data from the dialog subprocess.
00266 # IOW writes which do not create data are ignored.
00267 while {![llength $dtrace]} {
00268 vwait ::dialog::dtrace
00269 }
00270
00271 foreach {strace ilog} $dtrace break
00272 set dtrace {}
00273
00274 log::log debug +---------------------------------------------
00275 log::log debug |\t[join $strace \n|\t]
00276 log::log debug +---------------------------------------------
00277 log::log debug /\t[join $ilog \n/\t]
00278 log::log debug "+============================================ //"
00279 return $strace
00280 }
00281
00282 ret ::dialog::received () {
00283 # Wait for all preceding commands to complete.
00284 variable id
00285 set received [::coserv::run $id [list set received]]
00286 ::coserv::run $id [list set received {}]
00287 return $received
00288 }
00289
00290 ret ::dialog::listener () {
00291 variable port
00292 return $port
00293 }
00294
00295 ret ::dialog::shutdown () {
00296 variable id
00297 variable port
00298 variable dtrace
00299
00300 ::coserv::shutdown $id
00301
00302 set id {}
00303 set port {}
00304 set dtrace {}
00305 return
00306 }
00307
00308
00309