aboutsummaryrefslogtreecommitdiff
path: root/eris.scm
blob: 49e8d0c27daf24d569a6029ab809c760d529a509 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
; SPDX-FileCopyrightText: 2020 pukkamustard <pukkamustard@posteo.net>
;
; SPDX-License-Identifier: GPL-3.0-or-later

(define-module (eris)
  #:use-module (eris read-capability)
  #:use-module (eris encode)
  #:use-module (eris decode)
  #:use-module (eris utils rbytevector)

  #:use-module (srfi srfi-11)
  #:use-module (srfi srfi-171)
  #:use-module (rnrs bytevectors)
  #:use-module (rnrs io ports)

  #:export (eris-block-size-small
            eris-block-size-large

            eris-encode
            eris-encode->urn

            eris-decode->bytevector))

(define eris-block-size-small 1024)
(define eris-block-size-large 32768)

(define null-convergence-secret (make-bytevector 32 0))

(define (tstore-blocks block-reducer)
  "Returns a transducer that reduces blocks into @code{block-reducer} and emits a
single pair consisting of the reduced blocks and the read capability"
  (lambda (reducer)
    (let ((read-capability #f)
          (blocks (block-reducer)))
      (case-lambda

        ;; identity
        (() (reducer))

        ;; completion - cons the blocks and read-capability
        ((result)
         (reducer (reducer result (cons read-capability
                                        ;; call the completion arity on the block reducer
                                        (block-reducer blocks)))))

        ;; on input
        ((result input)
         (cond

          ;; input is a block
          ((pair? input)
           ;; reduce block with block reducer
           (set! blocks (block-reducer blocks input))
           result)

          ;; input is the read-capability
          ((read-capability? input)
           (set! read-capability input)
           result)))))))

(define* (rlast #:key (default #f))
  "Returns a reducer that returns the last reduced value or the default value if no values are reduced."
  (case-lambda
    (() default)
    ((result) result)
    ((result input) input)))

(define (->port readable)
  "Helper to read content as port"
  (cond
   ((port? readable) readable)
   ((bytevector? readable) (open-bytevector-input-port readable))
   ((string? readable) (->port (string->utf8 readable)))))

;; Higher-level interfaces for encoding

(define* (eris-encode readable #:key
                      (block-reducer rcons)
                      (convergence-secret null-convergence-secret)
                      (block-size eris-block-size-small))
  "Encode content from a port and reduce blocks into @code{bock-reducer}. Returns the read capability and reduced blocks."
  (let ((read-capability-blocks
         (port-transduce
          (compose (eris-encode-transducer #:convergence-secret convergence-secret
                                           #:block-size block-size)
                   (tstore-blocks block-reducer))
          (rlast)
          (lambda (port) (get-bytevector-n port block-size))
          (->port readable))))
    (values (car read-capability-blocks)
            (cdr read-capability-blocks))))

(define* (eris-encode->urn readable #:key
                           (convergence-secret null-convergence-secret)
                           (block-size eris-block-size-small))
  "Encode content, discard blocks and return the read capability as URN. This is useful for verifying that content is properly encoded."
  (let-values (((read-capability block-count)
                (eris-encode readable #:convergence-secret convergence-secret
                             #:block-size block-size
                             #:block-reducer rcount)))
    (read-capability->string read-capability)))

(let-values
    (((read-capability blocks) (eris-encode (open-bytevector-input-port (string->utf8 "Hello world!")))))
  (eris-decode->bytevector (read-capability->string read-capability)
                           (lambda (ref) (assoc-ref blocks ref))))

(define (eris-decode->bytevector read-capability block-ref)
  "Decode ERIS encoded content into a bytevector."
  (eris-transduce
   (tmap identity)
   (rbytevector)
   #:block-ref block-ref
   #:read-capability (->read-capability read-capability)))