distributed-press-api-client 0.4.0rc3 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/distributed_press/v1/social/client.rb +32 -27
- data/lib/distributed_press/v1/social/followers.rb +48 -0
- data/lib/distributed_press/v1/social/inbox.rb +17 -0
- data/lib/distributed_press/version.rb +1 -1
- metadata +5 -5
- data/lib/distributed_press/v1/social/dereferencer.rb.orig +0 -132
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a5f4b33d4222028ca00dfe7e4a3f9e0fd5a4e4c620068e8ae094df84e4d4a2c
|
4
|
+
data.tar.gz: ba21a56decb67357d65243ea5f7a12f92e705f689a2501fe3419921d6ffeea0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a8f016d1fba233cf4e106b6f114fa82b34949af8b88cde9c252d4c33bb440c30c233eadee120205d4ff9c019327f44d9f9e4971abc8733c4e2c5856ec2a5986
|
7
|
+
data.tar.gz: 43019f74c34831fa3a9164db342e971307ab8c76e225445a7a95cf82f025e2496af8cfa0c1264fcd620ad2126f1066093280bbcfa5d113705c658247583c7aec
|
@@ -86,12 +86,12 @@ class DistributedPress
|
|
86
86
|
|
87
87
|
def _dump(_)
|
88
88
|
Marshal.dump({
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
89
|
+
public_key_url: public_key_url,
|
90
|
+
url: url,
|
91
|
+
private_key_pem: @private_key_pem,
|
92
|
+
key_size: key_size,
|
93
|
+
cache_store: self.class.cache_store
|
94
|
+
})
|
95
95
|
end
|
96
96
|
|
97
97
|
def self._load(hash)
|
@@ -202,7 +202,7 @@ class DistributedPress
|
|
202
202
|
# after the request is instantiated. No need to process
|
203
203
|
# cookies for now. Uses the public key URL as a caching key so
|
204
204
|
# we revalidate access on shared caches.
|
205
|
-
options = { body: body, headers: headers, base_uri: url, parser: parser, stream_body: true
|
205
|
+
options = { body: body, headers: headers, base_uri: url, parser: parser, stream_body: true }
|
206
206
|
options = HTTParty::ModuleInheritableAttributes.hash_deep_dup(self.class.default_options).merge(options)
|
207
207
|
response_body = ''.dup
|
208
208
|
|
@@ -211,6 +211,14 @@ class DistributedPress
|
|
211
211
|
end.perform do |fragment|
|
212
212
|
fragment_to_body!(fragment, response_body)
|
213
213
|
end.tap do |response|
|
214
|
+
# Brotli decompression is delayed until after full download
|
215
|
+
if response.headers['content-encoding'] == 'br'
|
216
|
+
''.dup.tap do |inflated_response_body|
|
217
|
+
inflate_body!(response_body, inflated_response_body)
|
218
|
+
response_body = inflated_response_body
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
214
222
|
next if response_body.empty?
|
215
223
|
|
216
224
|
fix_response!(response, response_body)
|
@@ -275,16 +283,19 @@ class DistributedPress
|
|
275
283
|
# tests, 2GB of zeroes were compressed to a 1.6KB fragment.
|
276
284
|
#
|
277
285
|
# @todo Maybe each_char is too slow?
|
278
|
-
# @param
|
286
|
+
# @param body [String]
|
279
287
|
# @param append_to [String]
|
280
|
-
def
|
281
|
-
|
288
|
+
def inflate_body!(body, append_to)
|
289
|
+
body_io = StringIO.new(body)
|
282
290
|
|
283
|
-
BRS::Stream::Reader.new(
|
284
|
-
|
291
|
+
BRS::Stream::Reader.new(body_io, source_buffer_length: 256,
|
292
|
+
destination_buffer_length: 1024).each_char do |char|
|
285
293
|
append_to << char
|
286
294
|
|
287
|
-
|
295
|
+
if append_to.bytesize > 1_000_000
|
296
|
+
raise ContentTooLargeError,
|
297
|
+
"Content too large after inflating, stopped at #{append_to.bytesize} bytes!"
|
298
|
+
end
|
288
299
|
end
|
289
300
|
end
|
290
301
|
|
@@ -294,22 +305,16 @@ class DistributedPress
|
|
294
305
|
# @param :fragment [HTTParty::ResponseFragment]
|
295
306
|
# @param :append_to [String]
|
296
307
|
def fragment_to_body!(fragment, append_to)
|
297
|
-
|
298
|
-
|
299
|
-
# Raise an error rather than returning an empty body
|
300
|
-
unless brotli?
|
301
|
-
raise BrotliUnsupportedError,
|
302
|
-
'Server sent brotli-encoded response but ruby-brs gem is missing'
|
303
|
-
end
|
304
|
-
|
305
|
-
inflate_fragment!(fragment, append_to)
|
306
|
-
else
|
307
|
-
append_to << fragment
|
308
|
+
if fragment.http_response['content-encoding'] == 'br' && !brotli?
|
309
|
+
raise BrotliUnsupportedError, 'Server sent brotli-encoded response but ruby-brs gem is missing'
|
308
310
|
end
|
309
311
|
|
310
|
-
|
311
|
-
|
312
|
-
|
312
|
+
append_to << fragment
|
313
|
+
|
314
|
+
return unless append_to.bytesize > 1_000_000
|
315
|
+
|
316
|
+
raise ContentTooLargeError,
|
317
|
+
"Content too large, stopped at #{append_to.bytesize} bytes!"
|
313
318
|
end
|
314
319
|
|
315
320
|
# Re-adds a streamed body to the response and caches it again so
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require_relative 'client'
|
5
|
+
|
6
|
+
class DistributedPress
|
7
|
+
module V1
|
8
|
+
module Social
|
9
|
+
# Manages the actor's followers on the Social Inbox
|
10
|
+
class Followers
|
11
|
+
# @return [DistributedPress::V1::Social::Client]
|
12
|
+
attr_reader :client
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
attr_reader :actor
|
16
|
+
|
17
|
+
# @param :client [DistributedPress::V1::Social::Client]
|
18
|
+
# @param :actor [String]
|
19
|
+
def initialize(client:, actor:)
|
20
|
+
@client = client
|
21
|
+
@actor = actor
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get the actor's inbox
|
25
|
+
#
|
26
|
+
# @return [HTTParty::Response]
|
27
|
+
def get
|
28
|
+
client.get(endpoint: endpoint)
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
#
|
33
|
+
# @param :id [String] Activity ID
|
34
|
+
# @return [HTTParty::Response]
|
35
|
+
def remove(id:)
|
36
|
+
client.delete(endpoint: "#{endpoint}/#{URI.encode_uri_component(id)}")
|
37
|
+
end
|
38
|
+
|
39
|
+
# Followers
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
def endpoint
|
43
|
+
@endpoint ||= "/v1/#{actor}/followers"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -21,6 +21,23 @@ class DistributedPress
|
|
21
21
|
@actor = actor
|
22
22
|
end
|
23
23
|
|
24
|
+
# Creates a Social Inbox by uploading the keypair to it.
|
25
|
+
#
|
26
|
+
# @param actor_url [String] The URL where the Actor profile is hosted
|
27
|
+
# @return [HTTParty::Response]
|
28
|
+
def create(actor_url)
|
29
|
+
inbox_body = {
|
30
|
+
'actorUrl' => actor_url,
|
31
|
+
'publicKeyId' => "#{actor_url}#main-key",
|
32
|
+
'keypair' => {
|
33
|
+
'publicKeyPem' => client.public_key.public_to_pem,
|
34
|
+
'privateKeyPem' => client.private_key.export
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
client.post(endpoint: "/v1/#{actor}", body: inbox_body)
|
39
|
+
end
|
40
|
+
|
24
41
|
# Get the actor's inbox
|
25
42
|
#
|
26
43
|
# @return [HTTParty::Response]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: distributed-press-api-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- f
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -311,7 +311,7 @@ files:
|
|
311
311
|
- lib/distributed_press/v1/social/blocklist.rb
|
312
312
|
- lib/distributed_press/v1/social/client.rb
|
313
313
|
- lib/distributed_press/v1/social/dereferencer.rb
|
314
|
-
- lib/distributed_press/v1/social/
|
314
|
+
- lib/distributed_press/v1/social/followers.rb
|
315
315
|
- lib/distributed_press/v1/social/hook.rb
|
316
316
|
- lib/distributed_press/v1/social/inbox.rb
|
317
317
|
- lib/distributed_press/v1/social/outbox.rb
|
@@ -351,9 +351,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
351
351
|
version: '2.7'
|
352
352
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
353
353
|
requirements:
|
354
|
-
- - "
|
354
|
+
- - ">="
|
355
355
|
- !ruby/object:Gem::Version
|
356
|
-
version:
|
356
|
+
version: '0'
|
357
357
|
requirements: []
|
358
358
|
rubygems_version: 3.3.26
|
359
359
|
signing_key:
|
@@ -1,132 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'addressable'
|
4
|
-
require_relative 'reference'
|
5
|
-
|
6
|
-
class DistributedPress
|
7
|
-
module V1
|
8
|
-
module Social
|
9
|
-
# Fetches ActivityStreams from different instances by
|
10
|
-
# instantiating clients.
|
11
|
-
class Dereferencer
|
12
|
-
# @return [DistributedPress::V1::Social::Client]
|
13
|
-
attr_reader :client
|
14
|
-
|
15
|
-
REFERENTIABLE_ATTRIBUTES =
|
16
|
-
%w[
|
17
|
-
actor
|
18
|
-
owner
|
19
|
-
attributedTo
|
20
|
-
cc
|
21
|
-
inReplyTo
|
22
|
-
object
|
23
|
-
replies
|
24
|
-
to
|
25
|
-
publicKey
|
26
|
-
|
27
|
-
alsoKnownAs
|
28
|
-
devices
|
29
|
-
featured
|
30
|
-
featuredTags
|
31
|
-
followers
|
32
|
-
following
|
33
|
-
inbox
|
34
|
-
movedTo
|
35
|
-
outbox
|
36
|
-
|
37
|
-
first
|
38
|
-
items
|
39
|
-
next
|
40
|
-
orderedItems
|
41
|
-
partOf
|
42
|
-
prev
|
43
|
-
].freeze
|
44
|
-
|
45
|
-
# @param :client [DistributedPress::V1::Social::Client]
|
46
|
-
def initialize(client:)
|
47
|
-
@client = client
|
48
|
-
@parser =
|
49
|
-
proc do |body, format|
|
50
|
-
next HTTParty::Parser.call(body, format || :plain) unless body&.starts_with? '{'
|
51
|
-
|
52
|
-
HTTParty::Parser.call(body, :json).tap do |object|
|
53
|
-
reference_object! object
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Fetch a URI
|
59
|
-
#
|
60
|
-
# @param :uri [String, Addressable::URI]
|
61
|
-
# @return [HTTParty::Response]
|
62
|
-
def get(uri:)
|
63
|
-
uri = uris(uri)
|
64
|
-
|
65
|
-
clients(uri).get(endpoint: uri.path, parser: @parser)
|
66
|
-
end
|
67
|
-
|
68
|
-
# Gets a client for a URI
|
69
|
-
#
|
70
|
-
# @param :uri [Addressable::URI]
|
71
|
-
# @return [DistributedPress::V1::Social::Client]
|
72
|
-
def clients(uri)
|
73
|
-
@clients ||= {}
|
74
|
-
@clients[uri.origin] ||=
|
75
|
-
client.class.new(
|
76
|
-
url: uri.origin,
|
77
|
-
public_key_url: client.public_key_url,
|
78
|
-
private_key_pem: client.private_key.to_s,
|
79
|
-
logger: client.logger,
|
80
|
-
cache_store: client.class.cache_store
|
81
|
-
)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Gets a reference for a URI and indexes it by the complete
|
85
|
-
# and normalized URI
|
86
|
-
#
|
87
|
-
# @param :uri [String, Addressable::URI]
|
88
|
-
# @return [DistributedPress::V1::Social::Reference]
|
89
|
-
def references(uri)
|
90
|
-
@references ||= {}
|
91
|
-
@references[uri.to_s] ||= Reference.new(uri: uri.to_s, dereferencer: self)
|
92
|
-
end
|
93
|
-
|
94
|
-
# Make sure we're getting a normalized Addressable::URI
|
95
|
-
#
|
96
|
-
# @param :uri [String, Addressable::URI]
|
97
|
-
# @return [Addressable::URI]
|
98
|
-
def uris(uri)
|
99
|
-
@uris ||= {}
|
100
|
-
@uris[uri.to_s] ||=
|
101
|
-
(if uri.is_a? Addressable::URI
|
102
|
-
uri
|
103
|
-
else
|
104
|
-
Addressable::URI.parse(uri)
|
105
|
-
end).normalize
|
106
|
-
end
|
107
|
-
|
108
|
-
def reference_object!(object)
|
109
|
-
REFERENTIABLE_ATTRIBUTES.each do |attribute|
|
110
|
-
next unless object.key? attribute
|
111
|
-
|
112
|
-
case object[attribute]
|
113
|
-
when Array
|
114
|
-
object[attribute].map! do |o|
|
115
|
-
case o
|
116
|
-
when Hash
|
117
|
-
reference_object!(o)
|
118
|
-
o
|
119
|
-
when String then references(uris(o))
|
120
|
-
end
|
121
|
-
end
|
122
|
-
when Hash
|
123
|
-
reference_object!(object[attribute])
|
124
|
-
when String
|
125
|
-
object[attribute] = references(uris(object[attribute]))
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|