Overview
Comment: | ulex compiles |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | v2.001 |
Files: | files | file ages | folders |
SHA1: |
8860d05092be6bb7c097e611e94ffc37 |
User & Date: | matt on 2021-12-23 16:33:47 |
Other Links: | branch diff | manifest | tags |
Context
2021-12-23
| ||
18:46 | Loop back test passes for ulex check-in: bd0896dbd6 user: matt tags: v2.001 | |
16:33 | ulex compiles check-in: 8860d05092 user: matt tags: v2.001 | |
2021-12-22
| ||
19:51 | Looking a resurecting ulex - but without all the stuff beyond a transport layer. check-in: f88b668106 user: matt tags: v2.001 | |
Changes
Modified build-assist/ck5-eggs.list from [6d7e206485] to [339d250117].
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | filepath fmt format http-client itemsmod json linenoise md5 message-digest nanomsg postgresql queues regex regex-case | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | filepath fmt format http-client itemsmod json linenoise mailbox md5 message-digest nanomsg postgresql queues regex regex-case |
︙ | ︙ | |||
36 37 38 39 40 41 42 43 44 45 46 | srfi-1 srfi-13 srfi-19 sxml-modifications sxml-serializer sxml-transforms system-information test typed-records uri-common z3 | > | 37 38 39 40 41 42 43 44 45 46 47 48 | srfi-1 srfi-13 srfi-19 sxml-modifications sxml-serializer sxml-transforms system-information tcp6 test typed-records uri-common z3 |
Modified ulex/ulex.scm from [c344faad69] to [b7f1e11e85].
︙ | ︙ | |||
21 22 23 24 25 26 27 | ;; ABOUT: ;; See README in the distribution at https://www.kiatoa.com/fossils/ulex ;; NOTES: ;; Why sql-de-lite and not say, dbi? - performance mostly, then simplicity. ;; ;;====================================================================== | < < | > > | | | | | | < > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | ;; ABOUT: ;; See README in the distribution at https://www.kiatoa.com/fossils/ulex ;; NOTES: ;; Why sql-de-lite and not say, dbi? - performance mostly, then simplicity. ;; ;;====================================================================== (module ulex * (import scheme chicken.base chicken.file chicken.time chicken.condition chicken.string chicken.sort address-info mailbox matchable queues regex regex-case srfi-1 srfi-18 srfi-4 srfi-69 system-information tcp6 typed-records ) ;; udat struct, used by both caller and callee ;; instantiated as uconn by convention ;; (defstruct udat ;; the listener side (port #f) (host-port #f) (socket #f) ;; the peers (peers (make-hash-table)) ;; host:port->peer ;; work handling (work-queue (make-queue)) (work-proc #f) ;; set by user (cnum 0) ;; cookie number (mboxes (make-hash-table)) (avail-cmboxes '()) ;; list of (<cookie> . <mbox>) for re-use ) ;; struct for keeping track of others we are talking to ;; (defstruct pdat (host-port #f) (conns '()) ;; list of pcon structs, pop one off when calling the peer ) ;; struct for peer connections, keep track of expiration etc. ;; (defstruct pcon (inp #f) (oup #f) (exp (+ (current-seconds) 59)) ;; expires at this time, set to (+ (current-seconds) 59) (lifetime (+ (current-seconds) 600)) ;; throw away and create new after five minutes ) ;;====================================================================== ;; listener ;;====================================================================== ;; create a tcp listener and return a populated udat struct with ;; my port, address, hostname, pid etc. ;; return #f if fail to find a port to allocate. ;; |
︙ | ︙ | |||
156 157 158 159 160 161 162 | (connect-listener uconn port))) (define (connect-listener uconn port) ;; (tcp-listener-socket LISTENER)(socket-name so) ;; sockaddr-address, sockaddr-port, sockaddr->string (let* ((tlsn (tcp-listen port 1000 #f)) ;; (tcp-listen TCPPORT [BACKLOG [HOST]]) (addr (get-my-best-address))) ;; (hostinfo-addresses (host-information (current-hostname))) | < | | | < < < < < | < | | < > | < < < < < > | | | < < < < < | | < < < | < | | | < < < | | > > | | < < | | < | > > > > > | > > | | | | < | | | < < < < < < < < < < < | > > | | < < < < < < < < < | < < < < < < | < < | | | | | | < > > > | | < < < | < | | > | > > > > > > > > > > | > > > > | | < < < < < | > > > | > > > > > > > > | | | < | < > | < | > | | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | (connect-listener uconn port))) (define (connect-listener uconn port) ;; (tcp-listener-socket LISTENER)(socket-name so) ;; sockaddr-address, sockaddr-port, sockaddr->string (let* ((tlsn (tcp-listen port 1000 #f)) ;; (tcp-listen TCPPORT [BACKLOG [HOST]]) (addr (get-my-best-address))) ;; (hostinfo-addresses (host-information (current-hostname))) (udat-port-set! uconn port) (udat-host-port-set! uconn (conc addr":"port)) (udat-socket-set! uconn tlsn) uconn)) ;;====================================================================== ;; peers and connections ;;====================================================================== ;; send structured data to recipient ;; ;; NOTE: qrykey is what was called the "cookie" previously ;; ;; retval tells send to expect and wait for return data (one line) and return it or time out ;; this is for ping where we don't want to necessarily have set up our own server yet. ;; ;; NOTE: see below for beginnings of code to allow re-use of tcp connections ;; - I believe (without substantial evidence) that re-using connections will ;; be beneficial ... ;; (define (send udata host-port qrykey cmd params) (let* ((my-host-port (udat-host-port udata)) ;; remote will return to this (isme (equal? host-port my-host-port)) ;; calling myself? ;; dat is a self-contained work block that can be sent or handled locally (dat (list my-host-port qrykey cmd params)) ) (if isme (ulex-handler udata dat) ;; no transmission needed (handle-exceptions ;; TODO - MAKE THIS EXCEPTION CMD SPECIFIC? exn #f (let-values (((inp oup)(tcp-connect host-port))) (let ((res (if (and inp oup) (begin (write dat oup) (read inp)) ;; yes, we always want an ack (begin (print "ERROR: send called but no receiver has been setup. Please call setup first!") #f)))) (close-input-port inp) (close-output-port oup) res)))))) ;; res will always be 'ack ;; send a request to the given host-port and register a mailbox in udata ;; wait for the mailbox data and return it ;; (define (send-receive uconn host-port cmd data) (let* ((cmbox (get-cmbox uconn)) ;; would it be better to keep a stack of mboxes to reuse? (qrykey (car cmbox)) (mbox (cdr cmbox)) (mbox-time (current-milliseconds))) (if (eq? (send uconn host-port qrykey cmd data) 'ack) (let* ((mbox-timeout-secs 120) ;; timeout) (mbox-timeout-result 'MBOX_TIMEOUT) (res (mailbox-receive! mbox mbox-timeout-secs mbox-timeout-result)) (mbox-receive-time (current-milliseconds))) (if (eq? res 'MBOX_TIMEOUT) #f ;; convert to raising exception? res)) #f))) ;; #f means failed to communicate ;;====================================================================== ;; responder side ;;====================================================================== ;; take a request, rdata, and if not immediate put it in the work queue ;; ;; Reserved cmds; ack ping goodbye response ;; (define (ulex-handler uconn rdata) (print "ulex-handler received data: "rdata) (match rdata ;; (string-split controldat) ((rem-host-port qrykey cmd params) ;; cmdkey host-port pid qrykey params ...) (case cmd ((ack )(print "Got ack! But why? Should NOT get here.") 'ack) ((ping) 'ack) ;; special case - return result immediately on the same connection ((goodbye) ;; just clear out references to the caller 'ack) ((response) ;; this is a result from remote processing, send it as mail ... (let ((mbox (hash-table-ref/default (udat-mboxes uconn) qrykey #f))) (if mbox (mailbox-send! mbox params) ;; params here is our result (begin (print "ERROR: received result but no associated mbox for cookie "qrykey) #f)))) ((else (add-to-work-queue uconn rdata) 'ack)))) (else (print "BAD DATA? controldat=" rdata) 'ack) ;; send ack anyway? )) ;; given an already set up uconn start the cmd-loop ;; (define (ulex-cmd-loop uconn) (let* ((serv-listener (udat-socket uconn))) (let loop ((state 'start)) (let-values (((inp oup)(tcp-accept serv-listener))) (let* ((rdat (read inp)) (resp (ulex-handler uconn rdat))) (if resp (write resp oup)) (close-input-port inp) (close-output-port oup)) (loop state))))) ;; add a proc to the cmd list, these are done symetrically (i.e. in all instances) ;; so that the proc can be dereferenced remotely ;; (define (set-work-handler uconn proc) (udat-work-proc-set! uconn proc)) ;; run-listener does all the work of starting a listener in a thread ;; it then returns control ;; (define (run-listener handler-proc) (let* ((uconn (make-udat))) (if (setup-listener uconn) (let* ((th1 (make-thread (lambda ()(ulex-cmd-loop uconn)) "Ulex command loop")) (th2 (make-thread (lambda ()(process-work-queue uconn)) "Ulex work queue processor"))) (thread-start! th1) (thread-start! th2) ) (begin (print "ERROR: run-listener called without proper setup.") (exit))))) ;;====================================================================== ;; work queues - this is all happening on the listener side ;;====================================================================== ;; rdata is (rem-host-port qrykey cmd params) (define (add-to-work-queue uconn rdata) (queue-add! (udat-work-queue uconn) rdata)) (define (do-work uconn rdata) (let* ((proc (udat-work-proc uconn))) ;; get it each time - conceivebly it could change ;; put this following into a do-work procedure (match rdata ((rem-host-port qrykey cmd params) (let* ((result (proc rem-host-port qrykey cmd params))) (send uconn rem-host-port qrykey result))) ;; could check for ack (else (print "ERROR: rdata "rdata", did not match rem-host-port qrykey cmd params"))))) (define (process-work-queue uconn) (let ((wqueue (udat-work-queue uconn)) (proc (udat-work-proc uconn))) (let loop () (if (queue-empty? wqueue) (thread-sleep! 0.1) (let ((rdata (queue-remove! wqueue))) (do-work uconn rdata))) (loop)))) ;; below was to enable re-use of connections. This seems non-trivial so for ;; now lets open on each call ;; ;; ;; given host-port get or create peer struct ;; ;; ;; (define (udat-get-peer uconn host-port) |
︙ | ︙ | |||
377 378 379 380 381 382 383 | ;;====================================================================== ;; misc utils ;;====================================================================== (define (make-cookie uconn) (let ((newcnum (+ (udat-cnum uconn) 1))) (udat-cnum-set! uconn newcnum) | | < > > > > > > > > > > > > > > > > > > > > | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | ;;====================================================================== ;; misc utils ;;====================================================================== (define (make-cookie uconn) (let ((newcnum (+ (udat-cnum uconn) 1))) (udat-cnum-set! uconn newcnum) (conc (udat-host-port uconn) ":" newcnum))) ;; cookie/mboxes ;; we store each mbox with a cookie (<cookie> . <mbox>) ;; (define (get-cmbox uconn) (if (null? (udat-avail-cmboxes uconn)) (let ((cookie (make-cookie)) (mbox (make-mailbox))) (hash-table-set! (udat-mboxes uconn) cookie mbox) `(cookie . mbox)) (let ((cmbox (car (udat-avail-cmboxes uconn)))) (udat-avail-cmboxes-set! uconn (cdr (udat-avail-cmboxes uconn))) cmbox))) (define (put-cmbox uconn cmbox) (udat-avail-cmboxes-set! uconn (cons cmbox (udat-avail-cmboxes uconn)))) ;; peers ;;====================================================================== ;; network utilities ;;====================================================================== ;; NOTE: Look at address-info egg as alternative to some of this (define (rate-ip ipaddr) |
︙ | ︙ | |||
412 413 414 415 416 417 418 | (else (car (sort all-my-addresses ip-pref-less?)))))) (define (get-all-ips-sorted) (sort (get-all-ips) ip-pref-less?)) (define (get-all-ips) | > > > > > | | | > > | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | (else (car (sort all-my-addresses ip-pref-less?)))))) (define (get-all-ips-sorted) (sort (get-all-ips) ip-pref-less?)) (define (get-all-ips) (map address-info-host (filter (lambda (x) (equal? (address-info-type x) "tcp")) (address-infos (get-host-name))))) ;; (map ip->string (vector->list ;; (hostinfo-addresses ;; (host-information (current-hostname)))))) ) (import ulex) |