|(require xiden/source)||package: xiden|
A source is a value that implements gen:source. When used with fetch, a source produces an input port and an estimate of how many bytes that port can produce. Xiden uses sources to read data with safety limits. To tap a source means gaining a reference to the input port and estimate. To exhaust a source means gaining a reference to a contextual error value. We can also say a source is tapped or exhausted.
Note that these terms are linguistic conveniences. There is no value representing a tapped or exhausted state. The only difference is where control ends up in the program, and what references become available as a result of using fetch on a source.
The procedure is given an input port, and an estimate of the maximum number of bytes the port can produce. This estimate could be +inf.0 to allow unlimited reading, provided the user allows this in their configuration.
The sole argument to the procedure depends on the source type.
Otherwise, fetch calls exhaust in tail position using a source-dependent argument.
The log will gain a ($fetch id errors) message, where errors is empty if the fetch is successful.
(define-source (id [field field-contract] ...) body ...)
define-source injects several bindings into the lexical context of body:
%src, %tap, and %fail are each bound to their respective formal argument of fetch.
%fetch is (bind-recursive-fetch %tap %fail).
Each field identifier is bound to a respective value for an instance of the structure type.
To understand how these injected bindings work together, let’s go through a few examples.
Use %tap to fulfil data with an input port and an estimated data length. In the simplest case, you can return constant data.
byte-source uses %tap like so:
(define-source (byte-source [data bytes?]) (%tap (open-input-bytes data) (bytes-length data)))
Use %fail in tail position with error information to indicate a source was exhausted.
file-source uses %fail like so:
(define-source (file-source [path path-string?]) (with-handlers ([exn:fail:filesystem? %fail]) (%tap (open-input-file path) (+ (* 20 1024) (file-size path)))))
Note that %fail is an exhaust/c procedure, so it does not have to be given an exception as an argument.
first-available-source uses a resursive fetch to iterate on available sources until it has none left to check.
(define-source (first-available-source [available (listof source?)] [errors list?]) (if (null? available) (%fail (reverse errors)) (%fetch (car available) (λ (e) (%fetch (first-available-source (cdr available) (cons e errors)) %fail)))))
Finally, %src is just a reference to an instance of the structure containing each field.
If all sources for an instance are exhausted, then the instance is exhausted. As sources are visited, errors are functionally accumulated in errors.
The value produced for an exhausted first-available-source is the longest possible list bound to errors.
(define src (lines-source "\r\n" '("#lang racket/base" "(provide a)" "(define a 1)"))) ; "#lang racket/base (provide a) (define a 1) " (fetch src consume void)
(struct http-source (request-url) #:extra-constructor-name make-http-source) request-url : (or/c url? url-string?)
If the source is exhausted, it yields a relevant exception.
The behavior of the source is impacted by XIDEN_DOWNLOAD_MAX_REDIRECTS.
(struct http-mirrors-source (request-urls) #:extra-constructor-name make-http-mirrors-source) request-urls : (listof (or/c url-string? url?))
The following procedures are useful for declaring sources in a package input.
Otherwise, returns (string->source variant) in terms of the plugin.
(from-catalogs query-string [url-templates])
→ (listof url-string?) query-string : string? url-templates : (listof string?) = (XIDEN_CATALOGS)
Due to this behavior, from-file will return different results when the containing source file changes location on disk.
reason : (or/c 'security 'invariant) datum : any/c
datum : any/c ns : namespace? = (current-namespace)
|(require xiden/port)||package: xiden|
bytes-source : input-port? bytes-sink : output-port? on-status : (-> $transfer? any) max-size : (or/c +inf.0 exact-positive-integer?) buffer-size : exact-positive-integer? transfer-name : non-empty-string? est-size : (or/c +inf.0 real?) timeout-ms : (>=/c 0)
transfer reads no more than N bytes from bytes-source, and will wait no longer than timeout-ms for the next available byte.
The value of N is computed using est-size and max-size. max-size is the prescribed upper limit for total bytes to copy. est-size is an estimated for the number of bytes that bytes-source will actually produce (this is typically not decided by the user). If (> est-size max-size), then the transfer will not start. Otherwise N is bound to est-size to hold bytes-source accountable for the estimate.
(struct $transfer:scope $transfer (name message) #:prefab) name : string? message : (and/c $transfer? (not/c $transfer:scope?))
(struct $transfer:progress $transfer ( bytes-read max-size timestamp) #:prefab) bytes-read : exact-nonnegative-integer? max-size : (or/c +inf.0 exact-positive-integer?) timestamp : exact-positive-integer?
Unless max-size is +inf.0, (/ bytes-read max-size) approaches 1. You can use this along with the timestamp (in seconds) to reactively compute an estimated time to complete.
(struct $transfer:budget:rejected $message ( proposed-max-size allowed-max-size) #:prefab) proposed-max-size : (or/c +inf.0 exact-positive-integer?) allowed-max-size : exact-positive-integer?
(struct $transfer:timeout $message (bytes-read wait-time) #:prefab) bytes-read : exact-nonnegative-integer? wait-time : (>=/c 0)