;; -*- lexical-binding: t; -*- (defun parse-request (line) (if (string-match "\\`\\([^=]*\\)=\\(.*\\)\\'" line) (cons (match-string 1 line) (match-string 2 line)) line)) (defvar kvstore (make-hash-table :test #'equal)) (defun server-filter (process string) (message "Received string (%s): %S" process string) (let ((request (parse-request string))) (if (stringp request) (if (equal request "version") (progn (message "(%s) GET version=UDP 1.0" (float-time)) (process-send-string process "version=UDP 1.0")) (let ((value (gethash request kvstore))) (message "(%s) GET %S -> %S" (float-time) request value) (when (and value (not (zerop (length value)))) (process-send-string process (format "%s=%s" request value))))) (let ((key (car request)) (value (cdr request))) (message "(%s) SET %S <- %S" (float-time) key value) (when (not (equal key "version")) (puthash key value kvstore)))))) (defun server-sentinel (process event) (message "(%s) Event (%s): %S" (float-time) (process-status process) event) (when (not (process-buffer process)) (set-process-buffer process (generate-new-buffer "unusual-database"))) ;; FIXME: upon receiving an empty packet, this code is triggered ;; NOTE: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=62990 (when (string-match-p "^connection broken by remote peer" event) (setq server (make-server)) (process-send-string server (format "%s=%s" "" (gethash "" kvstore)))) (when (eq (process-status process) 'closed) (delete-process process) (kill-buffer (process-buffer process)))) ;; (defun server-log (server connection message) ;; (message "(%s) LOG: %s (%s): %s" (float-time) server connection message)) (defun make-server () (make-network-process :name "unusual-database" :type 'datagram :server t :host "0.0.0.0" :service 10000 :family 'ipv4 :coding 'utf-8 :filter #'server-filter :sentinel #'server-sentinel ;; :log #'server-log )) (defvar server (make-server)) (while t (accept-process-output nil 0.01))