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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package atprotorepo
import (
"context"
"encoding/json"
"errors"
"strings"
"time"
commonv1 "github.com/johnandersen777/socialweb-computer-kcp/api/common/v1alpha1"
)
const (
CapabilityRead = "repo.read"
CapabilityWrite = "repo.write"
CapabilitySubscribe = "repo.subscribe"
RecordDeleteGiveUp = 24 * time.Hour
)
var (
ErrNotFound = errors.New("atprotorepo: record not found")
ErrRecordNotFound = errors.New("atprotorepo: the PDS answered RecordNotFound")
ErrOutOfScope = errors.New("atprotorepo: the collection is outside the granted scope")
ErrNotBound = errors.New("atprotorepo: the repo has no bound backend")
ErrSwapMismatch = errors.New("atprotorepo: the record is not at the swap cid")
)
type Record struct {
URI string
CID string
Collection string
RKey string
Value json.RawMessage
}
type ListOptions struct {
Limit int
Cursor string
Reverse bool
}
type ListPage struct {
Records []Record
Cursor string
}
type Op struct {
Action string
Collection string
RKey string
CID string
}
type Commit struct {
Seq int64
Repo string
CID string
Rev string
Time time.Time
Ops []Op
}
type SubscribeOptions struct {
Collections []string
Cursor *int64
}
type RecordReader interface {
GetRecord(ctx context.Context, repo, collection, rkey string) (Record, error)
ListRecords(ctx context.Context, repo, collection string, opts ListOptions) (ListPage, error)
Resolve(ctx context.Context, ref commonv1.StrongRef) (Record, error)
}
type RecordWriter interface {
CreateRecord(ctx context.Context, collection, rkey string, value json.RawMessage) (commonv1.StrongRef, error)
PutRecord(ctx context.Context, collection, rkey string, value json.RawMessage) (commonv1.StrongRef, error)
DeleteRecord(ctx context.Context, collection, rkey string) error
}
type SwapDeleter interface {
DeleteRecordSwap(ctx context.Context, collection, rkey, swapCID string) error
}
type SwapPutter interface {
PutRecordSwap(ctx context.Context, collection, rkey string, value json.RawMessage, swapCID string) (commonv1.StrongRef, error)
}
type Subscriber interface {
Subscribe(ctx context.Context, opts SubscribeOptions, fn func(Commit) error) error
}
type Repo interface {
DID() string
RecordReader
RecordWriter
Subscriber
}
func RepoName(did string) string {
raw := strings.ToLower("repo-" + did)
var b strings.Builder
lastDash := false
for _, r := range raw {
if !((r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '.') {
r = '-'
}
if r == '-' {
if lastDash {
continue
}
lastDash = true
} else {
lastDash = false
}
b.WriteRune(r)
}
name := strings.Trim(b.String(), "-.")
if name == "" {
name = "repo"
}
if len(name) > 253 {
name = strings.TrimRight(name[:253], "-.")
}
return name
}