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
|
/*
Copyright (c) 2019 Ben Morrison (gbmor)
This file is part of Registry.
Registry is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Registry is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Registry. If not, see <https://www.gnu.org/licenses/>.
*/
// Package registry implements functions and types that assist
// in the creation and management of a twtxt registry.
package registry // import "git.sr.ht/~gbmor/getwtxt/registry"
import (
"net"
"net/http"
"sync"
"time"
)
// Registrar implements the minimum amount of methods
// for a functioning Registry.
type Registrar interface {
Put(user *User) error
Get(urlKey string) (*User, error)
DelUser(urlKey string) error
UpdateUser(urlKey string) error
GetUserStatuses(urlKey string) (TimeMap, error)
GetStatuses() (TimeMap, error)
}
// User holds a given user's information
// and statuses.
type User struct {
// Provided to aid in concurrency-safe
// reads and writes. In most cases, the
// mutex in the associated Index should be
// used instead. This mutex is provided
// should the library user need to access
// a User independently of an Index.
Mu sync.RWMutex
// Nick is the user-specified nickname.
Nick string
// The URL of the user's twtxt file
URL string
// The reported last modification date
// of the user's twtxt.txt file.
LastModified string
// The IP address of the user is optionally
// recorded when submitted via POST.
IP net.IP
// The timestamp, in RFC3339 format,
// reflecting when the user was added.
Date string
// A TimeMap of the user's statuses
// from their twtxt file.
Status TimeMap
}
// Registry enables the bulk of a registry's
// user data storage and access.
type Registry struct {
// Provided to aid in concurrency-safe
// reads and writes to a given registry
// Users map.
Mu sync.RWMutex
// The registry's user data is contained
// in this map. The functions within this
// library expect the key to be the URL of
// a given user's twtxt file.
Users map[string]*User
// The client to use for HTTP requests.
// If nil is passed to NewIndex(), a
// client with a 10 second timeout
// and all other values as default is
// used.
HTTPClient *http.Client
}
// TimeMap holds extracted and processed user data as a
// string. A time.Time value is used as the key.
type TimeMap map[time.Time]string
// TimeSlice is a slice of time.Time used for sorting
// a TimeMap by timestamp.
type TimeSlice []time.Time
// NewUser returns a pointer to an initialized User
func NewUser() *User {
return &User{
Mu: sync.RWMutex{},
Status: NewTimeMap(),
}
}
// New returns an initialized Registry instance.
func New(client *http.Client) *Registry {
return &Registry{
Mu: sync.RWMutex{},
Users: make(map[string]*User),
HTTPClient: client,
}
}
// NewTimeMap returns an initialized TimeMap.
func NewTimeMap() TimeMap {
return make(TimeMap)
}
// Len returns the length of the TimeSlice to be sorted.
// This helps satisfy sort.Interface.
func (t TimeSlice) Len() int {
return len(t)
}
// Less returns true if the timestamp at index i is after
// the timestamp at index j in a given TimeSlice. This results
// in a descending (reversed) sort order for timestamps rather
// than ascending.
// This helps satisfy sort.Interface.
func (t TimeSlice) Less(i, j int) bool {
return t[i].After(t[j])
}
// Swap transposes the timestamps at the two given indices
// for the TimeSlice receiver.
// This helps satisfy sort.Interface.
func (t TimeSlice) Swap(i, j int) {
t[i], t[j] = t[j], t[i]
}
|