Index: commonmod.scm ================================================================== --- commonmod.scm +++ commonmod.scm @@ -1436,11 +1436,11 @@ csv->test-data ;; MISC sync-inmem->db - ;; TESTMETA + ;; TESTMETAl testmeta-add-record testmeta-update-field ;; TASKS tasks-add Index: rmtmod.scm ================================================================== --- rmtmod.scm +++ rmtmod.scm @@ -70,21 +70,27 @@ cinfo (if (server:check-if-running areapath) (client:setup areapath) #f)))) -(define *send-receive-mutex* (make-mutex)) ;; should have separate mutex per run-id - +;; return the handle struct for sending queries to a specific database +;; - initializes the connection object if this is the first access +;; - finds the "captain" and asks who to talk to for the given dbfname +;; - establishes the connection to the current dbowner +;; (define (rmt:connect alldat dbfname) (let* ((ulexdat (let ((uconn (alldat-ulexdat alldat))) (if uconn uconn (let* ((new-ulexdat (ulex:setup))) ;; establish connection to ulex (alldat-ulexdat-set! alldat new-ulexdat) new-ulexdat))))) (ulex:connect ulexdat dbfname))) +;; set up a connection to the current owner of the dbfile associated with rid +;; then send the query to that dbfile owner and wait for a response. +;; (define (rmt:send-receive cmd rid params #!key (attemptnum 1)(area-dat #f)) ;; start attemptnum at 1 so the modulo below works as expected (let* ((alldat *alldat*) (areapath (alldat-areapath alldat)) (dbfname (if (or (not rid)(< rid 1)) ;; this is the criteria for "main.db" "main.db" Index: ulex/ulex.scm ================================================================== --- ulex/ulex.scm +++ ulex/ulex.scm @@ -24,21 +24,66 @@ ;; Why sql-de-lite and not say, dbi? - performance mostly, then simplicity. ;; ;;====================================================================== ;; (use rpc pkts mailbox sqlite3) - + (module ulex * (import scheme posix chicken data-structures ports extras files mailbox) -(import rpc srfi-18 pkts matchable regex +(import srfi-18 pkts matchable regex typed-records srfi-69 srfi-1 srfi-4 regex-case (prefix sqlite3 sqlite3:) foreign - tcp) ;; ulex-netutil) + tcp6 + ;; ulex-netutil + hostinfo) + +;;====================================================================== +;; network utilities +;;====================================================================== + +(define (rate-ip ipaddr) + (regex-case ipaddr + ( "^127\\..*" _ 0 ) + ( "^(10\\.0|192\\.168)\\..*" _ 1 ) + ( else 2 ) )) + +;; Change this to bias for addresses with a reasonable broadcast value? +;; +(define (ip-pref-less? a b) + (> (rate-ip a) (rate-ip b))) + + +(define (get-my-best-address) + (let ((all-my-addresses (get-all-ips)) + ;;(all-my-addresses-old (vector->list (hostinfo-addresses (hostname->hostinfo (get-host-name))))) + ) + (cond + ((null? all-my-addresses) + (get-host-name)) ;; no interfaces? + ((eq? (length all-my-addresses) 1) + (car all-my-addresses)) ;; only one to choose from, just go with it + + (else + (car (sort all-my-addresses ip-pref-less?))) + ;; (else + ;; (ip->string (car (filter (lambda (x) ;; take any but 127. + ;; (not (eq? (u8vector-ref x 0) 127))) + ;; all-my-addresses)))) + + ))) + +(define (get-all-ips-sorted) + (sort (get-all-ips) ip-pref-less?)) + +(define (get-all-ips) + (map ip->string (vector->list + (hostinfo-addresses + (host-information (current-hostname)))))) ;; make it a global? Well, it is local to area module (define *captain-pktspec* `((captain (host . h) @@ -59,11 +104,22 @@ (captain-address #f) (captain-host #f) (captain-port #f) (captain-pid #f) (cpkts-dir (conc (get-environment-variable "HOME") "/.ulex/pkts")) - (cpkt-spec *captain-pktspec*)) + (cpkt-spec *captain-pktspec*) + (my-cpkt-key #f) ;; put Z card here when I create a pkt for myself as captain + (my-address #f) + (my-hostname #f) + (my-port #f) + (my-pid (current-process-id)) + (serv-listener #f) + ) + +;;====================================================================== +;; Captain pkt functions +;;====================================================================== ;; given a pkts dir read ;; (define (get-all-captain-pkts udata) (let* ((pktsdir (let ((d (udat-cpkts-dir udata))) @@ -76,23 +132,76 @@ (pkt-spec (udat-cpkt-spec udata))) (map (lambda (pkt-file) (read-pkt->alist pkt-file pktspec: pkt-spec)) all-pkt-files))) -;; sort by D then Z, return one +;; sort by D then Z, return one, choose the oldest then +;; differentiate if needed using the Z key +;; (define (get-winning-pkt pkts) (if (null? pkts) #f (car (sort pkts (lambda (a b) - (let ((ad (alist-ref 'D a)) - (bd (alist-ref 'D b))) + (let ((ad (string->number (alist-ref 'D a))) + (bd (string->number (alist-ref 'D b)))) (if (eq? a b) (let ((az (alist-ref 'Z a)) (bz (alist-ref 'Z b))) (string>=? az bz)) (> ad bd)))))))) +;; 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. +;; +(define (start-server-find-port udata #!optional (port 9999)) + (handle-exceptions + exn + (if (< port 65535)(start-server-find-port (+ port 1)) #f) + (start-server udata port))) + +(define (start-server udata 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-my-address-set! udata addr) + (udat-my-port-set! udata port) + (udat-my-hostname-set! udata (get-host-name)) + (udat-serv-listener-set! udata tlsn) + udata)) + +;; put the host, ip, port and pid into a pkt in +;; the captain pkts dir +;; - assumes user has already fired up a server +;; which will be in the udata struct +;; +(define (create-captain-pkt udata) + (if (not (udat-serv-listener udata)) + (begin + (print "ERROR: create-captain-pkt called with out a listener") + #f) + (let* ((pktdat `((port . ,(udat-my-port udata)) + (host . ,(udat-my-hostname udata)) + (ipaddr . ,(udat-my-address udata)) + (pid . ,(udat-my-pid udata)))) + (pktdir (udat-cpkts-dir udata)) + (pktspec (udat-cpkt-spec udata)) + ) + (udat-my-cpkt-key-set! + udata + (write-alist->pkt + pktdir + pktdat + pktspec: pktspec + ptype: 'captain)) + (udat-my-cpkt-key udata)))) + +;;====================================================================== +;; connection setup and management functions +;;====================================================================== + ;; find or become the captain, return a ulex object ;; (define (setup) (let* ((udata (make-udat)) (cpkts (get-all-captain-pkts udata)) ;; read captain pkts @@ -115,10 +224,13 @@ udata ))) (define (connect udata dbfname) udata) + +) ;; END OF ULEX + ;;; ;;====================================================================== ;;; ;; D E B U G H E L P E R S ;;; ;;====================================================================== ;;; @@ -160,29 +272,29 @@ ;; Syntax for defining macros in a simple style similar to function definiton, ;; when there is a single pattern for the argument list and there are no keywords. ;; ;; (define-simple-syntax (name arg ...) body ...) ;; - -(define-syntax define-simple-syntax - (syntax-rules () - ((_ (name arg ...) body ...) - (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) - -(define-simple-syntax (catch-and-dump proc procname) - (handle-exceptions - exn - (begin - (print-call-chain (current-error-port)) - (with-output-to-port (current-error-port) - (lambda () - (print ((condition-property-accessor 'exn 'message) exn)) - (print "Callback error in " procname) - (print "Full condition info:\n" (condition->list exn))))) - (proc))) - - +;; +;; (define-syntax define-simple-syntax +;; (syntax-rules () +;; ((_ (name arg ...) body ...) +;; (define-syntax name (syntax-rules () ((name arg ...) (begin body ...))))))) +;; +;; (define-simple-syntax (catch-and-dump proc procname) +;; (handle-exceptions +;; exn +;; (begin +;; (print-call-chain (current-error-port)) +;; (with-output-to-port (current-error-port) +;; (lambda () +;; (print ((condition-property-accessor 'exn 'message) exn)) +;; (print "Callback error in " procname) +;; (print "Full condition info:\n" (condition->list exn))))) +;; (proc))) +;; +;; ;;====================================================================== ;; R E C O R D S ;;====================================================================== ;;; ;; information about me as a server @@ -1497,6 +1609,6 @@ ;;; ;;; (define (get-all-ips-sorted) ;;; (sort (get-all-ips) ip-pref-less?)) ;;; ;;; -) +