This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch

[PATCH v2] Implement trick-local storage

Message ID
DKIM signature
Download raw message
Patch: +67 -6
From: Alwinfy <20421383+Alwinfy@users.noreply.github.com>

Same as last time, but rebased and formatted.
 main.rkt              | 41 +++++++++++++++++++++++++++++++++++++++--
 scribblings/r16.scrbl | 32 ++++++++++++++++++++++++++++----
 2 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/main.rkt b/main.rkt
index 302c66a..3bed30e 100755
--- a/main.rkt
+++ b/main.rkt
@@ -32,6 +32,7 @@
   [storage #:mutable]
   [invocations #:mutable]))

(define (can-modify? message trick)
@@ -100,12 +101,13 @@
  (trick (if parent (trick-author parent) (message-author-id message))
         (strip-backticks body)
         (if parent (trick-created parent) (rc:message-timestamp message))
         (if parent (trick-storage parent) (make-hash))
         (if parent (trick-invocations parent) 0)))

(define (run-snippet client db message code)
  (let ([code (strip-backticks code)])
    (with-typing-indicator client message
      (thunk (ev:run code (evaluation-ctx client message db (context-id message) "" #f))))))
      (thunk (ev:run code (evaluation-ctx #f client message db (context-id message) "" #f))))))

(define (register-trick client db message text)
@@ -131,6 +133,7 @@
             (thunk (ev:run
                     (trick-body trick)
@@ -255,6 +258,7 @@
               (thunk (ev:run
                       (trick-body trick)
@@ -267,6 +271,35 @@
          (apply values vals))
        (raise (make-exn:fail:contract (~a "Trick " name " doesn't exist!"))))))

(define (storage-info message type)
  (match type
    ['guild   (cons 65536 'global)]
    ['channel (cons 8192  (rc:message-channel-id message))]
    ['user    (cons 2048  (message-author-id message))]
    [_        (cons 0     #f)]))

(define/contract (read-storage trick message type)
  (-> (or/c trick? #f) rc:message? (or/c 'guild 'channel 'user) any/c)
  (let ([datum (and~> trick
                 (hash-ref (cdr (storage-info message type)) #f)
                 (with-input-from-bytes read)
                 (with-handlers ([exn:fail:read? (const #f)]) _))])
    (and (not (eof-object? datum)) datum)))
(define/contract (write-storage trick message type data)
  (-> (or/c trick? #f) rc:message? (or/c 'guild 'channel 'user) any/c boolean?)
    (match-let ([(cons limit key) (storage-info message type)])
        (let ([data (with-output-to-bytes (curry write data))])
            (<= (bytes-length data) limit)
              (hash-set! (trick-storage trick) key data)

; client -> (emote name -> emote id)
(define emote-lookup-cache (make-hash))

@@ -309,7 +342,7 @@
         ; If empty byte string returned, return #f
         (and data (positive? (bytes-length data)) data)))))))

(define (evaluation-ctx client message db context-id args parent-ctx)
(define (evaluation-ctx trick client message db context-id args parent-ctx)
  (let* ([placeholder (make-placeholder #f)]
          `((message-contents . ,(rc:message-content message))
@@ -328,6 +361,9 @@
            (delete-caller    . ,(thunk (thread-send deleter-thread (cons client message))))
            (make-attachment  . ,make-attachment)
            (call-trick       . ,(call-subtrick client db context-id message placeholder))
            (message-author   . ,(message-author-id message))
            (read-storage     . ,(curry read-storage trick message))
            (write-storage    . ,(curry write-storage trick message))
            (parent-context   . ,parent-ctx))])
    (placeholder-set! placeholder (make-hash ctx))
    (cons (make-reader-graph ctx) '(threading))))
@@ -343,6 +379,7 @@
   (hash-ref json 'author)
   (hash-ref json 'body)
   (hash-ref json 'created)
   (make-hash) ; We purposefully don't save the trick storage due to space limits
   (hash-ref json 'invocations)))

(define command-table
diff --git a/scribblings/r16.scrbl b/scribblings/r16.scrbl
index 2052f3c..7d90487 100644
--- a/scribblings/r16.scrbl
+++ b/scribblings/r16.scrbl
@@ -19,8 +19,8 @@ All symbols from the @racket[threading-lib] package are available for convenienc
                          [mime (or/c symbol? string? bytes?)]) any/c]{
Creates an attachment with payload @racket[payload], filename @racket[name], and MIME-type @racket[mime].
This opaque object must be returned from the trick to be sent to Discord.
If more than one attachment is returned, an unspecified one is sent.                      
If more than one attachment is returned, an unspecified one is sent.

@defproc[(call-trick [name (or/c symbol? string?)]
                     [argument any/c]) any/c]{
@@ -48,10 +48,34 @@ Function that returns the ID for emote with name @racket[name], or @racket[#f] i
Function that returns the PNG data of the emote with ID @racket[id], or @racket[#f] if it doesn't exist.

@defproc[(read-storage [type (or/c 'guild 'channel 'user)]) any/c]{
Reads "trick-local storage" @racket[name] and return its result, or @racket[#f] if the result is uninitialized.

A trick's "trick-local storage" can be per-guild, per-channel, or per-user.

This will always return @racket[#f] for the eval command.

@defproc[(write-storage [type (or/c 'guild 'channel 'user)]
                        [data any/c]) boolean?]{
Writes @racket[data] to the trick's "trick-local storage," overwriting any existing value, and returns whether the write succeeded. All data supported by @racket[write] can be written.

Note that "trick-local storage" is transient and does not currently persist across bot restarts.

A trick's "trick-local storage" can be per-guild, per-channel, or per-user; each type of storage has its own limitation on size:
@tabular[#:sep @hspace[1]
  `(,(list @bold{Type} @bold{Size Limit})
          ("guild"     "64kb")
          ("channel"   "8kb")
          ("user"      "2kb"))]

This will always be a no-op when invoked from the eval command.

@defproc[(delete-caller) void?]{
Thunk that deletes the message that invoked this sandbox.

@defthing[parent-context (or/c (hash/c symbol? any/c) #f)]{
Mapping of all the above symbols for the trick calling this one, or @racket[#f] if this trick is the top level invocation.
Reply to thread Export thread (mbox)