Add activitypub collection support

Julien LepillerSat May 09 00:59:38+0200 2020

2a0abce

Add activitypub collection support

Makefile.am

44
godir=$(libdir)/guile/$(GUILE_EFFECTIVE_VERSION)/site-ccache
55
66
SOURCES= \
7+
  activitypub/collection.scm \
78
  activitypub/vocabulary.scm \
89
  activitystreams/ontology.scm \
910
  activitystreams/predicates.scm \

activitypub/collection.scm unknown status 1

1+
;;;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu>
2+
;;;; 
3+
;;;; This library is free software; you can redistribute it and/or
4+
;;;; modify it under the terms of the GNU Lesser General Public
5+
;;;; License as published by the Free Software Foundation; either
6+
;;;; version 3 of the License, or (at your option) any later version.
7+
;;;; 
8+
;;;; This library is distributed in the hope that it will be useful,
9+
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11+
;;;; Lesser General Public License for more details.
12+
;;;; 
13+
;;;; You should have received a copy of the GNU Lesser General Public
14+
;;;; License along with this library; if not, write to the Free Software
15+
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16+
17+
(define-module (activitypub collection)
18+
  #:use-module ((activitystreams vocabulary) #:prefix as:)
19+
  #:use-module ((activitypub vocabulary) #:prefix as:)
20+
  #:use-module (activitystreams ontology)
21+
  #:use-module (ice-9 match)
22+
  #:use-module (srfi srfi-9)
23+
  #:export (alist->collection
24+
            make-collection
25+
            collection?
26+
            collection-element-ref
27+
            collection-first
28+
            collection-last
29+
            collection-size
30+
31+
            collection
32+
            collection-page))
33+
34+
(define-record-type <collection>
35+
  (make-collection element-ref first last size)
36+
  collection?
37+
  (element-ref collection-element-ref)
38+
  (first       collection-first)
39+
  (last        collection-last)
40+
  (size        collection-size))
41+
42+
(define (delimited-collection-ref collection start number)
43+
  (let loop ((result '()) (id (or start (collection-first collection))))
44+
    (let ((element ((collection-element-ref collection) id)))
45+
      (if (or (not element) (= (length result) number))
46+
          (reverse result)
47+
          (loop (cons id result) (assoc-ref element "next"))))))
48+
49+
(define (previous-page collection start number)
50+
  (let loop ((id start) (num 0))
51+
    (let ((prev (assoc-ref ((collection-element-ref collection) id) "prev")))
52+
      (if (or (not prev) (= num number))
53+
          id
54+
          (loop prev (+ num 1))))))
55+
56+
(define (collection-ref collection id)
57+
  ((collection-element-ref collection) id))
58+
59+
(define (page-id collection-id start-id)
60+
  (string-append collection-id "?page=true&min_id=" start-id))
61+
62+
(define (collection-page collection start size collection-id)
63+
  (let* ((result (delimited-collection-ref collection start size))
64+
         (content (map (lambda (el) (assoc-ref el "content"))
65+
                       (map (collection-element-ref collection) result))))
66+
    (if (null? result)
67+
        (make-as-document
68+
          (list as:OrderedCollectionPage)
69+
          (list (cons as:id (page-id collection-id start))
70+
                (cons as:partOf collection-id)
71+
                (cons as:items '())))
72+
        (let* ((last (pk (car (reverse result))))
73+
               (prev-id (previous-page collection start size))
74+
               (next-id (assoc-ref ((collection-element-ref collection) last) "next")))
75+
          (make-as-document
76+
            (list as:OrderedCollectionPage)
77+
            (append
78+
              (list (cons as:id (page-id collection-id start))
79+
                    (cons as:partOf collection-id)
80+
                    (cons as:prev (page-id collection-id prev-id))
81+
                    (cons as:items content))
82+
              (if next-id
83+
                (list (cons as:next (page-id collection-id next-id)))
84+
                '())))))))
85+
86+
(define (collection collection collection-id)
87+
  (make-as-document
88+
    (list as:OrderedCollection)
89+
    (list (cons as:id collection-id)
90+
          (cons as:totalItems (collection-size collection))
91+
          (cons as:first (page-id collection-id (collection-first collection)))
92+
          (cons as:last (page-id collection-id (collection-last collection))))))
93+
94+
(define (alist->collection lst)
95+
  (define (alist->collection-alist lst)
96+
    (let loop ((result '()) (lst lst) (prev #f))
97+
      (match lst
98+
        (() result)
99+
        (((id . val) lst ...)
100+
         (loop (cons (cons id `(("content" . ,val) ("prev" . ,prev)))
101+
                     (if prev
102+
                         (cons
103+
                           (cons* prev (cons "next" id) (cdr (car result)))
104+
                           (cdr result))
105+
                         result))
106+
               lst
107+
               id)))))
108+
109+
  (let ((lst (alist->collection-alist lst)))
110+
    (make-collection
111+
      (lambda (id)
112+
        (assoc-ref lst id))
113+
      (car (car (reverse lst)))
114+
      (car (car lst))
115+
      (length lst))))