distributed-press-api-client 0.4.0rc3 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee95dc9deb3cb19084a66ee33ee4970906619c6489ce0bf29b0aa9f90ae99d93
4
- data.tar.gz: abcb6a90f1e16ad51aac21f15b79067c141f4cdc45edfbddc69704dd235adac7
3
+ metadata.gz: 6a5f4b33d4222028ca00dfe7e4a3f9e0fd5a4e4c620068e8ae094df84e4d4a2c
4
+ data.tar.gz: ba21a56decb67357d65243ea5f7a12f92e705f689a2501fe3419921d6ffeea0f
5
5
  SHA512:
6
- metadata.gz: 5d3e98400b29ee2258a29beb1c47fab70a07d1cbdd43a96df9842a507d2ee3f3aaf9d3eeef1dee381967363227fb8af68b0b9f080861feac67595b1a081c43b0
7
- data.tar.gz: 55291cec6e026520a3e9f111fd80e55b4762aa551f1dcae12015951a01d9d6dd55bbda07394f5f36566e3500abed7673e2a71c90feaf2f4092ef838361d3c8e8
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
- 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
- })
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, cache_key: public_key_url }
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 fragment [HTTParty::ResponseFragment]
286
+ # @param body [String]
279
287
  # @param append_to [String]
280
- def inflate_fragment!(fragment, append_to)
281
- fragment_io = StringIO.new(fragment)
288
+ def inflate_body!(body, append_to)
289
+ body_io = StringIO.new(body)
282
290
 
283
- BRS::Stream::Reader.new(fragment_io, source_buffer_length: 256,
284
- destination_buffer_length: 1024).each_char do |char|
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
- raise ContentTooLargeError if append_to.bytesize > 1_000_000
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
- case fragment.http_response['content-encoding']
298
- when 'br'
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
- raise ContentTooLargeError if append_to.bytesize > 1_000_000
311
- rescue ContentTooLargeError
312
- raise ContentTooLargeError, "Content too large #{append_to.bytesize} bytes!"
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]
@@ -3,5 +3,5 @@
3
3
  # API client
4
4
  class DistributedPress
5
5
  # Version
6
- VERSION = '0.4.0rc3'
6
+ VERSION = '0.4.1'
7
7
  end
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.0rc3
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-01 00:00:00.000000000 Z
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/dereferencer.rb.orig
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: 1.3.1
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