Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -30,11 +30,12 @@ # server.scm http-transport.scm client.scm rmt.scm # module source files MSRCFILES = dbfile.scm debugprint.scm mtargs.scm commonmod.scm dbmod.scm \ - servermod.scm clientmod.scm rmtmod.scm + configfmod.scm servermod.scm clientmod.scm rmtmod.scm \ + artifacts.scm all : $(PREFIX)/bin/.$(ARCHSTR) mtest dboard mtut # dbmod.import.o is just a hack here mofiles/dbfile.o : mofiles/debugprint.o mofiles/commonmod.o dbmod.import.o Index: api.scm ================================================================== --- api.scm +++ api.scm @@ -395,43 +395,5 @@ #;(common:telemetry-log (conc "api-out:"(->string cmd)) payload: `((params . ,params) (ok-res . #f))) (vector #t res)))))))) -;; http-server send-response -;; api:process-request -;; db:* -;; -;; NB// Runs on the server as part of the server loop -;; -(define (api:process-request dbstruct $) ;; the $ is the request vars proc - (debug:print 4 *default-log-port* "server-id:" *server-id*) - (let* ((cmd ($ 'cmd)) - (paramsj ($ 'params)) - (key ($ 'key)) - (params (db:string->obj paramsj transport: 'http))) ;; incoming data from the POST (or is it a GET?) - (debug:print 4 *default-log-port* "cmd:" cmd " with params " params "key " key) - (if (equal? key *server-id*) - (begin - (set! *api-process-request-count* (+ *api-process-request-count* 1)) - (let* ((resdat (api:execute-requests dbstruct (vector cmd params))) ;; process the request, resdat = #( flag result ) - (success (vector-ref resdat 0)) - (res (vector-ref resdat 1))) ;; (vector flag payload), get the payload, ignore the flag (why?) - (debug:print 4 *default-log-port* "res:" res) - (if (not success) - (debug:print 0 *default-log-port* "ERROR: success flag is #f for " cmd " with params " params)) - (if (> *api-process-request-count* *max-api-process-requests*) - (set! *max-api-process-requests* *api-process-request-count*)) - (set! *api-process-request-count* (- *api-process-request-count* 1)) - ;; This can be here but needs controls to ensure it doesn't run more than every 4 seconds - ;; (rmt:dat->json-str - ;; (if (or (string? res) - ;; (list? res) - ;; (number? res) - ;; (boolean? res)) - ;; res - ;; (list "ERROR, not string, list, number or boolean" 1 cmd params res))))) - (db:obj->string res transport: 'http))) - (begin - (debug:print 0 *default-log-port* "Server refused to process request. Server id mismatch. recived " key " expected: " *server-id* ".\nOther arguments recived: cmd=" cmd " params = " params) - (db:obj->string (conc "Server refused to process request server-id mismatch: " key ", " *server-id*) transport: 'http))))) - Index: artifacts/artifacts.scm ================================================================== --- artifacts/artifacts.scm +++ artifacts/artifacts.scm @@ -199,22 +199,41 @@ ;; new artifacts db with-todays-adb get-all-artifacts refresh-artifacts-db - ) -(import (chicken base) scheme (chicken process) (chicken time posix) +(import scheme) + +(cond-expand + (chicken-5 + (import (chicken base) + (chicken process) (chicken time posix) (chicken io) (chicken file) (chicken pathname) chicken.process-context.posix (chicken string) - (chicken time) (chicken sort) (chicken file posix) (chicken condition) srfi-1 - regex srfi-13 srfi-69 (chicken port) (chicken process-context) - crypt sha1 matchable message-digest sqlite3 typed-records - directory-utils - scsh-process) + (chicken time) (chicken sort) (chicken file posix) (chicken condition) + (chicken port) (chicken process-context) + )) + (chicken-4 + (import chicken + posix + data-structures + extras + ports + files + setup-api + ) + (define file-executable? file-execute-access?)) + (else)) + (import srfi-69 srfi-1 + regex srfi-13 srfi-69 + crypt sha1 matchable message-digest sqlite3 typed-records + directory-utils + scsh-process) + ;;====================================================================== ;; DATA MANIPULATION UTILS ;;====================================================================== (define-inline (unescape-data data) Index: http-transport.scm ================================================================== --- http-transport.scm +++ http-transport.scm @@ -688,6 +688,45 @@ ;; (map (lambda (stat) ;; (conc "" (car stat) "" (cadr stat) "")) ;; stats) ;; " ") ;; ""))) +;; +;; ;; http-server send-response +;; ;; api:process-request +;; ;; db:* +;; ;; +;; ;; NB// Runs on the server as part of the server loop +;; ;; +;; (define (api:process-request dbstruct $) ;; the $ is the request vars proc +;; (debug:print 4 *default-log-port* "server-id:" *server-id*) +;; (let* ((cmd ($ 'cmd)) +;; (paramsj ($ 'params)) +;; (key ($ 'key)) +;; (params (db:string->obj paramsj transport: 'http))) ;; incoming data from the POST (or is it a GET?) +;; (debug:print 4 *default-log-port* "cmd:" cmd " with params " params "key " key) +;; (if (equal? key *server-id*) +;; (begin +;; (set! *api-process-request-count* (+ *api-process-request-count* 1)) +;; (let* ((resdat (api:execute-requests dbstruct (vector cmd params))) ;; process the request, resdat = #( flag result ) +;; (success (vector-ref resdat 0)) +;; (res (vector-ref resdat 1))) ;; (vector flag payload), get the payload, ignore the flag (why?) +;; (debug:print 4 *default-log-port* "res:" res) +;; (if (not success) +;; (debug:print 0 *default-log-port* "ERROR: success flag is #f for " cmd " with params " params)) +;; (if (> *api-process-request-count* *max-api-process-requests*) +;; (set! *max-api-process-requests* *api-process-request-count*)) +;; (set! *api-process-request-count* (- *api-process-request-count* 1)) +;; ;; This can be here but needs controls to ensure it doesn't run more than every 4 seconds +;; ;; (rmt:dat->json-str +;; ;; (if (or (string? res) +;; ;; (list? res) +;; ;; (number? res) +;; ;; (boolean? res)) +;; ;; res +;; ;; (list "ERROR, not string, list, number or boolean" 1 cmd params res))))) +;; (db:obj->string res transport: 'http))) +;; (begin +;; (debug:print 0 *default-log-port* "Server refused to process request. Server id mismatch. recived " key " expected: " *server-id* ".\nOther arguments recived: cmd=" cmd " params = " params) +;; (db:obj->string (conc "Server refused to process request server-id mismatch: " key ", " *server-id*) transport: 'http))))) +;; ;; Index: mtserv.scm ================================================================== --- mtserv.scm +++ mtserv.scm @@ -21,34 +21,38 @@ ;; fake out readline usage of toplevel-command (define (toplevel-command . a) #f) (use srfi-1 posix srfi-69 readline ;; regex regex-case srfi-69 apropos json http-client directory-utils rpc typed-records;; (srfi 18) extras) - srfi-19 srfi-18 extras format pkts regex regex-case + srfi-19 srfi-18 extras format regex regex-case (prefix dbi dbi:) + matchable ) ;; (declare (uses common)) (declare (uses margs)) -(declare (uses configf)) -;; (declare (uses rmt)) +(declare (uses configfmod)) +(declare (uses servermod)) -;; (use ducttape-lib) (include "megatest-version.scm") (include "megatest-fossil-hash.scm") -;; (require-library stml) - (define help (conc " -mtutil, part of the Megatest tool suite, documentation at http://www.kiatoa.com/fossils/megatest +mtserv, part of the Megatest tool suite, documentation at http://www.kiatoa.com/fossils/megatest version " megatest-version " license GPL, Copyright Matt Welland 2006-2017 -Usage: mtutil action [options] +Usage: mtserv action [options] -h : this help -manual : show the Megatest user manual -version : print megatest version (currently " megatest-version ") + -start-dir path : switch to dir at start + +actions: + + server : start server + repl : start repl Examples: Called as " (string-intersperse (argv) " ") " Version " megatest-version ", built from " megatest-fossil-hash )) @@ -59,36 +63,55 @@ (cadr (argv)) #f)) (define *remargs* (args:get-args - (if *action* (cdr (argv)) (argv)) - '("-log") - '("-h") - args:arg-hash - 0)) + (if *action* (cdr (argv)) (argv)) + '("-log") + '("-h" + ) + args:arg-hash + 0)) (if (args:get-arg "-h") (begin (print help) (exit))) -(if (or (args:get-arg "-repl") - (args:get-arg "-load")) +(if (args:get-arg "-start-dir") + (let* ((start-dir (args:get-arg "-start-dir"))) + (if (and (file-exists? start-dir) + (directory? start-dir)) + (change-directory start-dir) + (begin + (print "FATAL: cannot find or access "start-dir) + (exit 1))))) + +(if *action* + (case (string->symbol *action*) + ((server) (server:run)) + ((repl) + (import extras) ;; might not be needed + ;; (import csi) + (import readline) + (import apropos) + ;; (import (prefix sqlite3 sqlite3:)) ;; doesn't work ... + + (install-history-file (get-environment-variable "HOME") ".mtserv_history") ;; [homedir] [filename] [nlines]) + (current-input-port (make-readline-port "mtserv> ")) + (print "Starting repl...") + (repl)) + ;; (if (args:get-arg "-load") + ;; (load (args:get-arg "-load")) + ;; (repl))) + (else + (print "Action \""*action*"\" not recognised.") + (print help))) (begin - (import extras) ;; might not be needed - ;; (import csi) - (import readline) - (import apropos) - ;; (import (prefix sqlite3 sqlite3:)) ;; doesn't work ... - - (install-history-file (get-environment-variable "HOME") ".mtutil_history") ;; [homedir] [filename] [nlines]) - (current-input-port (make-readline-port "mtutil> ")) - (if (args:get-arg "-repl") - (repl) - (load (args:get-arg "-load"))))) + (print "No action provided.") + (print help))) #| (define mtconf (car (simple-setup #f))) (define dat (common:with-queue-db mtconf (lambda (conn)(get-pkts conn '())))) (pp (pkts#flatten-all dat '((cmd . ((parent . P)(url . M)))(runtype . ((parent . P)))) 'id 'group-id 'uuid 'parent 'pkt-type 'pkt 'processed)) |# Index: servermod.scm ================================================================== --- servermod.scm +++ servermod.scm @@ -16,24 +16,37 @@ ;; along with Megatest. If not, see . ;; (declare (unit servermod)) +(use md5 message-digest posix typed-records extras) + (module servermod * (import scheme chicken + extras md5 message-digest ports posix + + typed-records + data-structures ) (define *client-server-id* #f) +(defstruct srv + (areapath #f) + (host #f) + (pid #f) + (type #f) + (dir #f) + ) ;;====================================================================== ;; S E R V E R U T I L I T I E S ;;====================================================================== ;; Generate a unique signature for this server @@ -49,10 +62,65 @@ (if *client-server-id* *client-server-id* (let ((sig (mk-signature))) ;; clients re-use the server:mk-signature logic (set! *client-server-id* sig) *client-server-id*))) +;; if srvdat is #f calculate host.pid +(define (get-host.pid srvdat) + (if srvdat + (conc (srv-host srvdat)"."(srv-pid srvdat)) + (conc (get-host-name)"."(current-process-id)))) + +;; nearly every process in Megatest (if write access) starts a server so it +;; can receive messages to exit on request + +;; one server per run db file would be ideal. + +;; servers have a type, mtserve, dboard, runner, execute + +;; mtrah/.servers//./incoming/*.artifact +;; | `attic +;; | +;; (note: not needed? (i)) `outgoing/./*.artifact +;; | `attic +;; `.host:port + +;; (i) Not needed if it is expected that all processes run a server + +;; on exit processes clean up. only mtserv or dboard clean up abandoned records? + +;; server:setup - setup the directory +;; server:launch - start a new mtserve process, possibly +;; using a launcher +;; server:run - run the long running thread that monitors +;; the .server area +;; server:exit - shutdown the server and exit +;; server:handle-request - take incoming request, process it, send response +;; back via best or fastest available transport + +;; set up the server area and return a server struct +;; NOTE: This will need to be gated by write-access +;; +(define (server:setup srvtype areapath) + (let* ((srvdat (make-srv + areapath: areapath + host: (get-host-name) ;; likely need to replace with ip address + pid: (current-process-id) + type: srvtype)) + (srvdir (conc areapath"/"srvtype"/"(get-host.pid srvdat)))) + (srv-dir-set! srvdat srvdir) + (create-directory srvdir #t) + srvdat)) + +;; maybe check load before calling this? +(define (server:launch areapath) + (let* ((logd (conc areapath"/logs")) + (logf (conc logd"/from-"(get-host.pid #f)".log"))) + (if (not (file-exists? logd))(create-directory logd #t)) + (setenv "NBFAKE_LOG" logf) + (system (conc "nbfake mtserve -start-dir "areapath)))) + ;; ;; When using zmq this would send the message back (two step process) ;; ;; with spiffy or rpc this simply returns the return data to be returned ;; ;; ;; (define (server:reply return-addr query-sig success/fail result) ;; (debug:print-info 11 *default-log-port* "server:reply return-addr=" return-addr ", result=" result)