ok now it's an MVP (some features still missing,,)

This commit is contained in:
xenia 2020-12-29 01:28:15 -05:00
parent 18381a5e01
commit 05b3e97a66
6 changed files with 197 additions and 32 deletions

View File

@ -16,10 +16,10 @@
;; You should have received a copy of the GNU Affero General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(require file/tar racket/bool racket/file racket/function racket/list racket/match racket/path
racket/string racket/unit racket/vector syntax/parse/define
(require file/tar racket/bool racket/contract racket/file racket/format racket/function racket/list
racket/match racket/path racket/string racket/unit racket/vector syntax/parse/define
(only-in file/sha1 bytes->hex-string)
(for-syntax racket/base racket/syntax)
(for-syntax racket/base racket/list racket/syntax)
"codegen.rkt" "comms.rkt" "info.rkt" "manifest.rkt" "not-crypto.rkt" "protocol.rkt")
(define *program* (format "~a-client" (#%info-lookup 'collection)))
@ -34,6 +34,43 @@
(define *cf-private-cache* (build-path ".crossfire" "cache.rktd"))
(define *cf-tmp-targz* (build-path ".crossfire" "project.tgz"))
(define server-wrapper@ (make-rpc-wrapper-unit server^))
(define (call-with-server-connection func)
(match-define (list client-node server-node) (call-with-input-file *client-key-file* read))
(define (noshutdown)
(current-to-node server-node)
(current-comms (make-comms client-node))
(current-tm (make-transaction-manager client-node (current-comms)))
(comms-set-node-info (current-comms) server-node)
(comms-connect (current-comms) (node-id server-node)))
(define (shutdown)
(tm-shutdown (current-tm))
(comms-shutdown (current-comms)))
(dynamic-wind noshutdown func shutdown))
(define-simple-macro (with-server-connection body ...+)
#:with no-hygiene
(datum->syntax (first (syntax-e #'(body ...)))
'(define-values/invoke-unit server-wrapper@ (import) (export server^)))
(call-with-server-connection
(lambda ()
no-hygiene
body ...)))
(define (read-manifest project-dir)
(define (report-contract-error ex)
(error "failed to parse manifest! make sure it matches the example formats"))
(with-handlers ([exn:fail:contract? report-contract-error])
(parse-manifest (call-with-input-file (build-path project-dir "manifest.rktd") read))))
;; command functions
(define (cmd-new project-name mode)
(define project-root (build-path project-name))
(when (or (file-exists? project-root) (directory-exists? project-root)
@ -90,7 +127,7 @@
(define (cmd-check project-dir)
(define messages '())
(define mf (parse-manifest (call-with-input-file (build-path project-dir "manifest.rktd") read)))
(define mf (read-manifest project-dir))
(define mode (first (manifest-data-ref mf 'mode)))
(when (and (symbol=? mode 'stdio)
@ -106,13 +143,11 @@
(define (cmd-submit project-dir)
(define mf (parse-manifest (call-with-input-file (build-path project-dir "manifest.rktd") read)))
(match-define (list client-node server-node) (call-with-input-file *client-key-file* read))
(define mf (read-manifest project-dir))
;; create targz
(define tmp-targz (build-path project-dir *cf-tmp-targz*))
(parameterize ([current-directory project-dir])
(define out (current-output-port))
(tar-gzip tmp-targz "."
#:exists-ok? #t
#:path-filter (lambda (p)
@ -122,21 +157,55 @@
[(list 'same) #t]
[_ (error "not shonks...")]))))
;; connect to server
(define server-wrapper@ (make-rpc-wrapper-unit server^))
(define-values/invoke-unit server-wrapper@ (import) (export server^))
(with-server-connection
(new-project (serialize-manifest mf) (file->bytes tmp-targz))))
(current-to-node server-node)
(current-comms (make-comms client-node))
(current-tm (make-transaction-manager client-node (current-comms)))
(comms-set-node-info (current-comms) server-node)
(comms-connect (current-comms) (node-id server-node))
(new-project (serialize-manifest mf) (file->bytes tmp-targz))
(define (cmd-delete id)
(with-server-connection
(delete-project id)))
(tm-shutdown (current-tm))
(comms-shutdown (current-comms))
(void))
(define (cmd-status)
(define projects
(with-server-connection
(get-projects)))
(cons '("project id" "name" "progress" "matches")
(let ([body (for/list ([proj (in-list projects)])
(list (~a (project-info-id proj))
(project-info-name proj)
(format "~a%" (inexact->exact (* 100 (project-info-progress proj))))
(~a (project-info-matches proj))))])
(if (empty? body)
'(("" " - no projects - " ""))
body))))
(define all-printable? (listof (integer-in 32 126)))
(define all-byte? (listof (integer-in 0 255)))
(define (cmd-show id)
;; if it's all printable, make it a string
;; if it's all bytes, make it a bytes
;; otherwise, ....
(define (format-match m)
(define fmt-width
;; determine the number of digits needed to print in hex
(let ([max-size (ceiling (log (apply max m) 16))])
;; adjust the digit count to the nearest power of 2 (4 digits, 8 digits, 16 digits, etc)
(expt 2 (inexact->exact (ceiling (log max-size 2))))))
(cond
[(all-printable? m) (~s (list->string (map integer->char m)))]
[(all-byte? m) (~s (apply bytes m))]
[else (string-join (map (lambda (x) (~r x #:base 16 #:min-width fmt-width #:pad-string "0"))
m))]))
(define matches
(with-server-connection
(get-project-matches id)))
(if (empty? matches)
(list "no matches... :(")
(for/list ([m (in-list matches)] [i (in-naturals)])
(format "match ~a: ~a" i (format-match m)))))
(define (cmd-setup config)
@ -144,6 +213,8 @@
(with-output-to-file *client-key-file* (lambda () (write config)) #:exists 'replace))
;; command parsing / UI
(module+ main
(require racket/cmdline)
@ -171,6 +242,19 @@
(report-status "error: ~a" warning))
(report-fatal-error "check was not successful due to above messages")]))
(define (interactive-status)
(define status-tbl (cmd-status))
(define max-widths (for/list ([_ (in-list (first status-tbl))] [i (in-naturals)])
(apply max (map (lambda (x) (string-length (list-ref x i))) status-tbl))))
(for ([row (in-list status-tbl)])
(for ([item (in-list row)] [width (in-list max-widths)])
(write-string (~a item #:width (+ 2 width))))
(write-string "\n")))
(define (interactive-show id)
(for ([line (in-list (cmd-show id))])
(displayln line)))
(define-simple-macro (subcommand (name:id description:str) body ...)
#:with name-str (datum->syntax #'name (symbol->string (syntax-e #'name)))
(list name-str
@ -218,6 +302,23 @@
(cmd-submit (current-directory))
(report-status "project submitted!! time for crab"))
(subcommand (delete "Delete an executed or completed project")
#:args (id-str)
(define id (or (string->number id-str)
(error "must provide numeric ID")))
(cmd-delete id)
(report-status "project ~a deleted" id))
(subcommand (status "Summary of project status on server")
#:args ()
(interactive-status))
(subcommand (show "Show information about a project on the server")
#:args (id-str)
(define id (or (string->number id-str)
(error "must provide numeric ID")))
(interactive-show id))
(subcommand (setup "Set up access to a crossfire server")
#:args (config-file)
(unless (file-exists? config-file)

View File

@ -44,14 +44,22 @@
;; ok gamer move time
(define-runtime-path codegen-template "templates/codegen.rktc")
(define-runtime-path header-template "templates/header.rktc")
(define-runtime-path makefile-template "templates/Makefile.rkt")
(define-runtime-path manifest-template "templates/manifest.rktrktd")
;; TODO : make configurable
(define c-type "uint64_t")
(define c-type-fmt "%lx")
(define (generate-support-code mf)
(define vars (hash 'pattern (vector-map integer-set-contents (manifest-pattern mf))
'mode (first (manifest-data-ref mf 'mode))))
'mode (first (manifest-data-ref mf 'mode))
'c-type c-type
'c-type-fmt c-type-fmt))
(hash
"crossfire.c" (eval-template codegen-template vars)
"crossfire.h" (eval-template header-template vars)
"Makefile" (eval-template makefile-template vars)))
(define (generate-manifest mode)

View File

@ -30,6 +30,7 @@
new-project
get-projects
get-project-file
get-project-matches
delete-project
agent-report-state])
@ -40,3 +41,8 @@
(define-signature client^
[todo])
(struct node-info [id name arch type resources online?] #:prefab)
;; manifest is the raw source format
(struct project-info [id name manifest progress matches] #:prefab)
(provide (struct-out node-info) (struct-out project-info))

View File

@ -109,7 +109,6 @@
(define-stmt q-get-tasks "select id, name, manifest, complete from task")
(define-stmt q-set-task-complete "update task set complete=1 where id=?")
(define-stmt q-task-exists "select 1 from task where id=?")
(define-stmt q-delete-task "delete from task where id=?")
(define-stmt q-get-task-log
"select worker, time_wall_start, duration, pattern from task_log where taskid=?")
@ -118,6 +117,10 @@
values (?, ?, ?, ?, ?)")
(define-stmt q-add-task-match
"insert into task_match (taskid, worker, time_wall, match) values (?, ?, ?, ?)")
(define-stmt q-get-task-matches
"select worker, time_wall, match from task_match where taskid=?")
(define-stmt q-count-task-match
"select count(*) from task_match where taskid=?")
;; utils
@ -172,9 +175,7 @@
(file->bytes path))
(struct node-info [id name arch type resources online?] #:prefab)
;; manifest is the raw source format
(struct project-info [id name manifest complete?] #:prefab)
;; rpc helpers
(define (get-nodes type)
(define type-str (symbol->string type))
@ -312,8 +313,26 @@
(define (get-projects)
(enforce-subject 'client)
(define (get-progress id mf)
(define parsed-mf (parse-manifest mf))
(define total-size (manifest-psize parsed-mf))
(define completed-size
(for/sum ([(_1 _2 _3 pat-fasl) (in-query (current-db) q-get-task-log id)])
(define sub (make-integer-set (fasl->s-exp pat-fasl)))
(integer-set-count sub)))
(/ completed-size total-size))
(for/list ([(id name manifest complete?) (in-query (current-db) q-get-tasks)])
(project-info id name (fasl->s-exp manifest) complete?)))
(define mf (fasl->s-exp manifest))
;; XXX this should be a join t b h
(define matches (query-value (current-db) q-count-task-match id))
(define progress
(if (zero? complete?)
;; XXX this could also _maybe_ be a join but idk
(get-progress id mf)
1.0))
(project-info id name mf progress matches)))
(define/contract (get-project-file taskid)
(-> integer? bytes?)
@ -321,7 +340,12 @@
(with-handlers ([exn:fail? (lambda (ex) (error "unable to fetch the requested file"))])
(server-get-file taskid)))
(define/contract (cancel-project taskid)
(define/contract (get-project-matches taskid)
(-> integer? (listof (listof integer?)))
(for/list ([(worker time-wall match-fasl) (in-query (current-db) q-get-task-matches taskid)])
(fasl->s-exp match-fasl)))
(define/contract (delete-project taskid)
(-> integer? void?)
(enforce-subject 'client)
(call-with-transaction (current-db) (lambda ()

View File

@ -23,12 +23,7 @@
#include <stdint.h>
#include <stdbool.h>
@;; TODO : make configurable
@(define c-type "uint64_t")
@(define c-type-fmt "%lx")
typedef @c-type vartype;
typedef bool (*callback)( @(add-between (for/list ([_ (in-vector pattern)]) "vartype") ",") );
#include "crossfire.h"
typedef struct {
vartype start;

View File

@ -0,0 +1,31 @@
@;; crossfire: distributed brute force infrastructure
@;;
@;; Copyright (C) 2020 haskal
@;;
@;; This program is free software: you can redistribute it and/or modify
@;; it under the terms of the GNU Affero General Public License as published by
@;; the Free Software Foundation, either version 3 of the License, or
@;; (at your option) any later version.
@;;
@;; This program is distributed in the hope that it will be useful,
@;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
@;; GNU Affero General Public License for more details.
@;;
@;; You should have received a copy of the GNU Affero General Public License
@;; along with this program. If not, see <https://www.gnu.org/licenses/>.
@;; vim: ft=c
#pragma once
#include <stdbool.h>
#include <stdint.h>
typedef @c-type vartype;
@(define args (add-between (for/list ([_ (in-vector pattern)]) "vartype") ","))
typedef bool (*callback)( @args );
int crossfire_main(int argc, char* argv[], callback cb);
void cf_report_success( @args );