async-matrix 2.1.0-arm-linux → 3.0.0-arm-linux

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -58
  3. data/lib/async/matrix/3.3/async_matrix_e2ee.so +0 -0
  4. data/lib/async/matrix/3.4/async_matrix_e2ee.so +0 -0
  5. data/lib/async/matrix/4.0/async_matrix_e2ee.so +0 -0
  6. data/lib/async/matrix/api/chain.rb +120 -94
  7. data/lib/async/matrix/api/concat.rb +28 -22
  8. data/lib/async/matrix/api/path_tree.rb +71 -44
  9. data/lib/async/matrix/api.rb +6 -1
  10. data/lib/async/matrix/auth_error.rb +20 -0
  11. data/lib/async/matrix/bad_json_error.rb +20 -0
  12. data/lib/async/matrix/client.rb +142 -110
  13. data/lib/async/matrix/config/vivify.rb +107 -0
  14. data/lib/async/matrix/config.rb +184 -0
  15. data/lib/async/matrix/content.rb +106 -0
  16. data/lib/async/matrix/double_puppet_client.rb +1 -1
  17. data/lib/async/matrix/error.rb +0 -27
  18. data/lib/async/matrix/{application_service/error_response.rb → error_response.rb} +10 -10
  19. data/lib/async/matrix/event.rb +197 -0
  20. data/lib/async/matrix/homeserver_error.rb +20 -0
  21. data/lib/async/matrix/invalid_endpoint_error.rb +20 -0
  22. data/lib/async/matrix/media_client.rb +46 -35
  23. data/lib/async/matrix/not_found_error.rb +20 -0
  24. data/lib/async/matrix/notifier.rb +7 -3
  25. data/lib/async/matrix/response_too_large_error.rb +20 -0
  26. data/lib/async/matrix/schema/registry.rb +367 -340
  27. data/lib/async/matrix/schema/validation_error.rb +221 -214
  28. data/lib/async/matrix/schema.rb +161 -161
  29. data/lib/async/matrix/version.rb +3 -3
  30. data/lib/async/matrix.rb +0 -7
  31. metadata +25 -133
  32. data/lib/async/discord/api/path_tree.rb +0 -127
  33. data/lib/async/discord/api.rb +0 -151
  34. data/lib/async/discord/client.rb +0 -283
  35. data/lib/async/discord/error.rb +0 -84
  36. data/lib/async/discord/gateway.rb +0 -359
  37. data/lib/async/discord.rb +0 -15
  38. data/lib/async/matrix/application_service/bot.rb +0 -232
  39. data/lib/async/matrix/application_service/config/schema/analytics.json +0 -21
  40. data/lib/async/matrix/application_service/config/schema/appservice.json +0 -82
  41. data/lib/async/matrix/application_service/config/schema/backfill.json +0 -91
  42. data/lib/async/matrix/application_service/config/schema/bridge.json +0 -209
  43. data/lib/async/matrix/application_service/config/schema/config.json +0 -61
  44. data/lib/async/matrix/application_service/config/schema/database.json +0 -38
  45. data/lib/async/matrix/application_service/config/schema/direct_media.json +0 -35
  46. data/lib/async/matrix/application_service/config/schema/double_puppet.json +0 -24
  47. data/lib/async/matrix/application_service/config/schema/encryption.json +0 -164
  48. data/lib/async/matrix/application_service/config/schema/homeserver.json +0 -58
  49. data/lib/async/matrix/application_service/config/schema/logging.json +0 -50
  50. data/lib/async/matrix/application_service/config/schema/management_room_texts.json +0 -25
  51. data/lib/async/matrix/application_service/config/schema/matrix.json +0 -45
  52. data/lib/async/matrix/application_service/config/schema/permissions.json +0 -54
  53. data/lib/async/matrix/application_service/config/schema/provisioning.json +0 -23
  54. data/lib/async/matrix/application_service/config/schema/public_media.json +0 -39
  55. data/lib/async/matrix/application_service/config/schema/relay.json +0 -43
  56. data/lib/async/matrix/application_service/config/vivify.rb +0 -109
  57. data/lib/async/matrix/application_service/config.rb +0 -225
  58. data/lib/async/matrix/application_service/dispatcher.rb +0 -185
  59. data/lib/async/matrix/application_service/event.rb +0 -285
  60. data/lib/async/matrix/application_service/server.rb +0 -430
  61. data/lib/async/matrix/application_service/transaction.rb +0 -66
  62. data/lib/async/matrix/application_service/transaction_handler.rb +0 -185
  63. data/lib/async/matrix/application_service/transaction_store.rb +0 -80
  64. data/lib/async/matrix/bridge/discord/db/connection.rb +0 -141
  65. data/lib/async/matrix/bridge/discord/db/file.rb +0 -118
  66. data/lib/async/matrix/bridge/discord/db/guild.rb +0 -120
  67. data/lib/async/matrix/bridge/discord/db/message.rb +0 -160
  68. data/lib/async/matrix/bridge/discord/db/migrations/001_create_users.rb +0 -14
  69. data/lib/async/matrix/bridge/discord/db/migrations/002_create_guilds.rb +0 -14
  70. data/lib/async/matrix/bridge/discord/db/migrations/003_create_portals.rb +0 -23
  71. data/lib/async/matrix/bridge/discord/db/migrations/004_create_puppets.rb +0 -19
  72. data/lib/async/matrix/bridge/discord/db/migrations/005_create_messages.rb +0 -20
  73. data/lib/async/matrix/bridge/discord/db/migrations/006_create_reactions.rb +0 -19
  74. data/lib/async/matrix/bridge/discord/db/migrations/007_create_files.rb +0 -18
  75. data/lib/async/matrix/bridge/discord/db/portal.rb +0 -150
  76. data/lib/async/matrix/bridge/discord/db/puppet.rb +0 -128
  77. data/lib/async/matrix/bridge/discord/db/reaction.rb +0 -165
  78. data/lib/async/matrix/bridge/discord/db/schema.rb +0 -18
  79. data/lib/async/matrix/bridge/discord/db/user.rb +0 -112
  80. data/lib/async/matrix/bridge/discord/db.rb +0 -138
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ module Async
7
+ module Matrix
8
+ # Wraps the content object of a Matrix event, providing typed access to
9
+ # schema-defined properties via method_missing.
10
+ #
11
+ # Common fields like `msgtype`, `body`, and `membership` have dedicated
12
+ # accessors for convenience. Any other field defined in the event's schema
13
+ # (or present in the raw hash) is accessible as a method call:
14
+ #
15
+ # content.msgtype # => "m.text"
16
+ # content.body # => "hello"
17
+ # content.membership # => "join"
18
+ # content.avatar_url # => "mxc://example.org/abc"
19
+ # content["custom"] # => direct hash access for non-standard fields
20
+ #
21
+ class Content
22
+ attr_reader :msgtype, :body, :membership
23
+
24
+ def initialize(data)
25
+ @data = data
26
+ @msgtype = data["msgtype"]
27
+ @body = data["body"]
28
+ @membership = data["membership"]
29
+ end
30
+
31
+ def to_h = @data
32
+ def to_s = @body.to_s
33
+ def to_str = to_s
34
+
35
+ # Direct hash access for any content field.
36
+ def [](key) = @data[key.to_s]
37
+
38
+ # Dynamic access to any content field present in the raw data.
39
+ def method_missing(name, *args)
40
+ key = name.to_s
41
+
42
+ if @data.key?(key)
43
+ @data[key]
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def respond_to_missing?(name, include_private = false)
50
+ @data.key?(name.to_s) || super
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ __END__
57
+ describe "Async::Matrix::Content" do
58
+ it "parses msgtype, body, and membership" do
59
+ content = Async::Matrix::Content.new({
60
+ "msgtype" => "m.text",
61
+ "body" => "hello",
62
+ "membership" => "join"
63
+ })
64
+ content.msgtype.should == "m.text"
65
+ content.body.should == "hello"
66
+ content.membership.should == "join"
67
+ end
68
+
69
+ it "handles missing fields gracefully" do
70
+ content = Async::Matrix::Content.new({})
71
+ content.msgtype.should.be.nil
72
+ content.body.should.be.nil
73
+ content.membership.should.be.nil
74
+ end
75
+
76
+ it "provides hash access via []" do
77
+ content = Async::Matrix::Content.new({"custom_field" => "value"})
78
+ content["custom_field"].should == "value"
79
+ end
80
+
81
+ it "provides dynamic access via method_missing" do
82
+ content = Async::Matrix::Content.new({
83
+ "avatar_url" => "mxc://example.org/abc",
84
+ "displayname" => "Alice"
85
+ })
86
+ content.avatar_url.should == "mxc://example.org/abc"
87
+ content.displayname.should == "Alice"
88
+ end
89
+
90
+ it "returns nil for unknown fields via method_missing" do
91
+ content = Async::Matrix::Content.new({})
92
+ content.nonexistent.should.be.nil
93
+ end
94
+
95
+ it "returns the raw hash via to_h" do
96
+ data = {"msgtype" => "m.text", "body" => "hi"}
97
+ content = Async::Matrix::Content.new(data)
98
+ content.to_h.should == data
99
+ end
100
+
101
+ it "responds to keys present in the data" do
102
+ content = Async::Matrix::Content.new({"avatar_url" => "mxc://x/y"})
103
+ content.respond_to?(:avatar_url).should == true
104
+ content.respond_to?(:nonexistent).should == false
105
+ end
106
+ end
@@ -29,7 +29,7 @@ end
29
29
  __END__
30
30
  describe "Async::Matrix::DoublePuppetClient" do
31
31
  def make_config
32
- Async::Matrix::ApplicationService::Config.new({
32
+ Async::Matrix::Config.new({
33
33
  "homeserver" => { "address" => "http://localhost:8008", "domain" => "localhost" },
34
34
  "appservice" => { "as_token" => "as_token_value", "hs_token" => "hs_secret", "bot" => { "username" => "bot" } }
35
35
  })
@@ -14,13 +14,6 @@ module Async
14
14
  super(message)
15
15
  end
16
16
  end
17
-
18
- class NotFoundError < Error; end
19
- class BadJsonError < Error; end
20
- class AuthError < Error; end
21
- class HomeserverError < Error; end
22
- class InvalidEndpointError < Error; end
23
- class ResponseTooLargeError < Error; end
24
17
  end
25
18
  end
26
19
 
@@ -45,23 +38,3 @@ __END__
45
38
  Async::Matrix::Error.new("M_UNKNOWN", "bad").should.be.kind_of StandardError
46
39
  end
47
40
  end
48
-
49
- it "NotFoundError inherits from Error" do
50
- Async::Matrix::NotFoundError.new("M_NOT_FOUND", "gone").should.be.kind_of Async::Matrix::Error
51
- end
52
-
53
- it "BadJsonError inherits from Error" do
54
- Async::Matrix::BadJsonError.new("M_BAD_JSON", "invalid").should.be.kind_of Async::Matrix::Error
55
- end
56
-
57
- it "AuthError inherits from Error" do
58
- Async::Matrix::AuthError.new("M_FORBIDDEN", "denied").should.be.kind_of Async::Matrix::Error
59
- end
60
-
61
- it "HomeserverError inherits from Error" do
62
- Async::Matrix::HomeserverError.new("M_UNKNOWN", "upstream").should.be.kind_of Async::Matrix::Error
63
- end
64
-
65
- it "ResponseTooLargeError inherits from Error" do
66
- Async::Matrix::ResponseTooLargeError.new("M_TOO_LARGE", "too big").should.be.kind_of Async::Matrix::Error
67
- end
@@ -5,23 +5,23 @@
5
5
 
6
6
  module Async
7
7
  module Matrix
8
- module ApplicationService
9
- class ErrorResponse
10
- attr_reader :errcode, :error
8
+ # A Matrix standard error response body: `{"errcode": ..., "error": ...}`.
9
+ # Both {Client} and {MediaClient} parse failed responses into one of these.
10
+ class ErrorResponse
11
+ attr_reader :errcode, :error
11
12
 
12
- def initialize(data)
13
- @errcode = data["errcode"]
14
- @error = data["error"]
15
- end
13
+ def initialize(data)
14
+ @errcode = data["errcode"]
15
+ @error = data["error"]
16
16
  end
17
17
  end
18
18
  end
19
19
  end
20
20
 
21
21
  __END__
22
- describe "Async::Matrix::ApplicationService::ErrorResponse" do
22
+ describe "Async::Matrix::ErrorResponse" do
23
23
  it "parses errcode and error" do
24
- resp = Async::Matrix::ApplicationService::ErrorResponse.new({
24
+ resp = Async::Matrix::ErrorResponse.new({
25
25
  "errcode" => "M_FORBIDDEN",
26
26
  "error" => "Access denied"
27
27
  })
@@ -30,7 +30,7 @@ __END__
30
30
  end
31
31
 
32
32
  it "handles missing fields" do
33
- resp = Async::Matrix::ApplicationService::ErrorResponse.new({})
33
+ resp = Async::Matrix::ErrorResponse.new({})
34
34
  resp.errcode.should.be.nil
35
35
  resp.error.should.be.nil
36
36
  end
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ module Async
7
+ module Matrix
8
+ # Represents a Matrix event, however it arrived — a /sync response, an
9
+ # application service transaction, or a hash you built yourself.
10
+ #
11
+ # Provides typed accessors for all envelope fields plus schema-driven
12
+ # validation using the official Matrix spec YAML schemas.
13
+ #
14
+ # event = Event.new(raw_hash)
15
+ # event.type # => "m.room.message"
16
+ # event.sender # => "@alice:example.org"
17
+ # event.content.body # => "hello"
18
+ # event.valid? # => true
19
+ # event.valid! # => true (or raises Schema::ValidationError)
20
+ #
21
+ class Event
22
+ attr_reader :type,
23
+ :sender,
24
+ :room_id,
25
+ :state_key,
26
+ :content,
27
+ :event_id,
28
+ :origin_server_ts,
29
+ :unsigned,
30
+ :raw
31
+
32
+ def initialize(data)
33
+ @raw = data
34
+ @type = data["type"]
35
+ @sender = data["sender"]
36
+ @room_id = data["room_id"]
37
+ @state_key = data["state_key"]
38
+ @event_id = data["event_id"]
39
+ @origin_server_ts = data["origin_server_ts"]
40
+ @unsigned = data["unsigned"]
41
+ @content = Content.new(data["content"] || {})
42
+ end
43
+
44
+ # The JSONSchemer::Schema for this event's type, or nil if unknown.
45
+ def schema = Schema[@type]
46
+
47
+ # Validate this event against its schema.
48
+ # Returns true if valid or if no schema exists (lenient).
49
+ def valid? = Schema.valid?(@raw)
50
+
51
+ # Validate this event against its schema.
52
+ # Raises Schema::ValidationError with detailed errors on failure.
53
+ # Returns true if valid or if no schema exists.
54
+ def valid!
55
+ errors = Schema.validate(@raw)
56
+
57
+ unless errors.empty?
58
+ raise Schema::ValidationError.new(
59
+ errors,
60
+ event_type: @type,
61
+ event_id: @event_id,
62
+ )
63
+ end
64
+
65
+ true
66
+ end
67
+
68
+ # Content property names defined by the schema for this event type.
69
+ # @return [Array<String>]
70
+ def content_properties = Schema.content_properties(@type)
71
+
72
+ # Is this a state event? (has a state_key)
73
+ def state_event? = !@state_key.nil?
74
+ end
75
+ end
76
+ end
77
+
78
+ __END__
79
+ describe "Async::Matrix::Event" do
80
+ it "parses all event fields" do
81
+ event = Async::Matrix::Event.new({
82
+ "type" => "m.room.message",
83
+ "sender" => "@alice:example.com",
84
+ "room_id" => "!abc:example.com",
85
+ "state_key" => "",
86
+ "event_id" => "$evt1",
87
+ "origin_server_ts" => 1234567890,
88
+ "unsigned" => {"age" => 1000},
89
+ "content" => {"msgtype" => "m.text", "body" => "hi"}
90
+ })
91
+ event.type.should == "m.room.message"
92
+ event.sender.should == "@alice:example.com"
93
+ event.room_id.should == "!abc:example.com"
94
+ event.state_key.should == ""
95
+ event.event_id.should == "$evt1"
96
+ event.origin_server_ts.should == 1234567890
97
+ event.unsigned.should == {"age" => 1000}
98
+ event.content.should.be.kind_of Async::Matrix::Content
99
+ event.content.body.should == "hi"
100
+ end
101
+
102
+ it "defaults content to empty Content when missing" do
103
+ event = Async::Matrix::Event.new({"type" => "m.room.message"})
104
+ event.content.should.be.kind_of Async::Matrix::Content
105
+ event.content.body.should.be.nil
106
+ end
107
+
108
+ it "exposes the raw hash" do
109
+ data = {"type" => "m.room.message", "content" => {"body" => "hi", "msgtype" => "m.text"}}
110
+ event = Async::Matrix::Event.new(data)
111
+ event.raw.should.equal data
112
+ end
113
+
114
+ it "detects state events" do
115
+ state = Async::Matrix::Event.new({"type" => "m.room.member", "state_key" => "@a:b"})
116
+ state.state_event?.should == true
117
+
118
+ msg = Async::Matrix::Event.new({"type" => "m.room.message"})
119
+ msg.state_event?.should == false
120
+ end
121
+
122
+ it "returns the schema for known event types" do
123
+ event = Async::Matrix::Event.new({"type" => "m.room.message", "content" => {}})
124
+ event.schema.should.not.be.nil
125
+ event.schema.should.be.kind_of JSONSchemer::Schema
126
+ end
127
+
128
+ it "returns nil schema for unknown event types" do
129
+ event = Async::Matrix::Event.new({"type" => "m.custom.event", "content" => {}})
130
+ event.schema.should.be.nil
131
+ end
132
+
133
+ it "validates a correct event" do
134
+ event = Async::Matrix::Event.new({
135
+ "type" => "m.room.message",
136
+ "content" => {"msgtype" => "m.text", "body" => "hello"},
137
+ "event_id" => "$abc123",
138
+ "sender" => "@alice:example.org",
139
+ "origin_server_ts" => 1234567890,
140
+ "room_id" => "!room:example.org"
141
+ })
142
+ event.valid?.should == true
143
+ event.valid!.should == true
144
+ end
145
+
146
+ it "rejects an invalid event" do
147
+ event = Async::Matrix::Event.new({
148
+ "type" => "m.room.message",
149
+ "content" => {"msgtype" => "m.text"},
150
+ "event_id" => "$abc123",
151
+ "sender" => "@alice:example.org",
152
+ "origin_server_ts" => 1234567890,
153
+ "room_id" => "!room:example.org"
154
+ })
155
+ event.valid?.should == false
156
+ end
157
+
158
+ it "raises ValidationError from valid!" do
159
+ event = Async::Matrix::Event.new({
160
+ "type" => "m.room.member",
161
+ "content" => {"membership" => "invalid_state"},
162
+ "state_key" => "@alice:example.org",
163
+ "event_id" => "$abc123",
164
+ "sender" => "@alice:example.org",
165
+ "origin_server_ts" => 1234567890,
166
+ "room_id" => "!room:example.org"
167
+ })
168
+ begin
169
+ event.valid!
170
+ raise "should have raised"
171
+ rescue Async::Matrix::Schema::ValidationError => e
172
+ e.message.should.include "m.room.member"
173
+ e.message.should.include "$abc123"
174
+ e.errors.should.not.be.empty
175
+ end
176
+ end
177
+
178
+ it "is lenient with unknown event types" do
179
+ event = Async::Matrix::Event.new({
180
+ "type" => "com.custom.event",
181
+ "content" => {"anything" => "goes"},
182
+ "event_id" => "$x",
183
+ "sender" => "@a:b"
184
+ })
185
+ event.valid?.should == true
186
+ event.valid!.should == true
187
+ end
188
+
189
+ it "returns content properties for known types" do
190
+ event = Async::Matrix::Event.new({
191
+ "type" => "m.room.member",
192
+ "content" => {"membership" => "join"}
193
+ })
194
+ props = event.content_properties
195
+ props.should.include "membership"
196
+ end
197
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ # Async::Matrix::Error is this class's superclass, so it has to exist before
7
+ # this file finishes loading — the glob in async/matrix.rb sorts
8
+ # alphabetically and would otherwise get here first.
9
+ require_relative "error"
10
+
11
+ module Async
12
+ module Matrix
13
+ class HomeserverError < Error; end
14
+ end
15
+ end
16
+
17
+ __END__
18
+ it "HomeserverError inherits from Error" do
19
+ Async::Matrix::HomeserverError.new("M_UNKNOWN", "upstream").should.be.kind_of Async::Matrix::Error
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ # Async::Matrix::Error is this class's superclass, so it has to exist before
7
+ # this file finishes loading — the glob in async/matrix.rb sorts
8
+ # alphabetically and would otherwise get here first.
9
+ require_relative "error"
10
+
11
+ module Async
12
+ module Matrix
13
+ class InvalidEndpointError < Error; end
14
+ end
15
+ end
16
+
17
+ __END__
18
+ it "InvalidEndpointError inherits from Error" do
19
+ Async::Matrix::InvalidEndpointError.new("M_UNRECOGNIZED", "no such route").should.be.kind_of Async::Matrix::Error
20
+ end
@@ -49,19 +49,24 @@ module Async
49
49
 
50
50
  Console.debug(self) { "UPLOAD #{method} #{path} (#{content_type}, #{body.bytesize} bytes)" }
51
51
 
52
- response = internet.call(method, url, headers, body)
52
+ response = internet.call(
53
+ method,
54
+ url,
55
+ headers,
56
+ body,
57
+ )
53
58
  status = response.status
54
59
 
55
60
  unless (200..299).cover?(status)
56
61
  payload = read_limited(response, ERROR_RESPONSE_SIZE_LIMIT)
57
- parsed = ApplicationService::ErrorResponse.new(
58
- begin; JSON.parse(payload); rescue; {} end
62
+ parsed = ErrorResponse.new(
63
+ begin; JSON.parse(payload); rescue; {} end,
59
64
  )
60
65
  Console.error(self) { "Matrix media upload #{status}: #{parsed.errcode} — #{parsed.error}" }
61
66
  raise HomeserverError.new(
62
67
  parsed.errcode || "UNKNOWN",
63
68
  parsed.error || payload.to_s[0..200],
64
- status: status
69
+ status: status,
65
70
  )
66
71
  end
67
72
 
@@ -87,19 +92,24 @@ module Async
87
92
 
88
93
  Console.debug(self) { "DOWNLOAD #{path}" }
89
94
 
90
- response = internet.call("GET", url, @auth_headers, nil)
95
+ response = internet.call(
96
+ "GET",
97
+ url,
98
+ @auth_headers,
99
+ nil,
100
+ )
91
101
  status = response.status
92
102
 
93
103
  unless (200..299).cover?(status)
94
104
  payload = response.read
95
- parsed = ApplicationService::ErrorResponse.new(
96
- begin; JSON.parse(payload); rescue; {} end
105
+ parsed = ErrorResponse.new(
106
+ begin; JSON.parse(payload); rescue; {} end,
97
107
  )
98
108
  Console.error(self) { "Matrix media download #{status}: #{parsed.errcode} — #{parsed.error}" }
99
109
  raise HomeserverError.new(
100
110
  parsed.errcode || "UNKNOWN",
101
111
  parsed.error || payload.to_s[0..200],
102
- status: status
112
+ status: status,
103
113
  )
104
114
  end
105
115
 
@@ -113,37 +123,38 @@ module Async
113
123
 
114
124
  private
115
125
 
116
- def internet
117
- @internet ||= Async::HTTP::Internet.new
118
- end
126
+ def internet
127
+ @internet ||= Async::HTTP::Internet.new
128
+ end
119
129
 
120
130
  # Read response body with a size limit. Raises ResponseTooLargeError
121
131
  # if the body exceeds the limit.
122
- def read_limited(response, limit)
123
- body = response.body
124
- return nil unless body
125
-
126
- if body.respond_to?(:length) && body.length && body.length > limit
127
- body.close
128
- raise ResponseTooLargeError.new(
129
- "M_TOO_LARGE",
130
- "Response Content-Length #{body.length} bytes exceeds limit of #{limit} bytes"
131
- )
132
- end
133
-
134
- buffer = String.new(encoding: Encoding::BINARY)
135
- body.each do |chunk|
136
- buffer << chunk
137
- if buffer.bytesize > limit
138
- body.close
139
- raise ResponseTooLargeError.new(
140
- "M_TOO_LARGE",
141
- "Response body exceeds limit of #{limit} bytes"
142
- )
132
+ def read_limited(response, limit)
133
+ body = response.body
134
+ if body
135
+ if body.respond_to?(:length) && body.length && body.length > limit
136
+ body.close
137
+ raise ResponseTooLargeError.new(
138
+ "M_TOO_LARGE",
139
+ "Response Content-Length #{body.length} bytes exceeds limit of #{limit} bytes",
140
+ )
141
+ end
142
+ buffer = String.new(encoding: Encoding::BINARY)
143
+ body.each do |chunk|
144
+ buffer << chunk
145
+ if buffer.bytesize > limit
146
+ body.close
147
+ raise ResponseTooLargeError.new(
148
+ "M_TOO_LARGE",
149
+ "Response body exceeds limit of #{limit} bytes",
150
+ )
151
+ end
152
+ end
153
+ buffer.empty? ? nil : buffer
154
+ else
155
+ nil
143
156
  end
144
157
  end
145
- buffer.empty? ? nil : buffer
146
- end
147
158
  end
148
159
  end
149
160
  end
@@ -151,7 +162,7 @@ end
151
162
  __END__
152
163
  describe "Async::Matrix::MediaClient" do
153
164
  def make_config
154
- Async::Matrix::ApplicationService::Config.new({
165
+ Async::Matrix::Config.new({
155
166
  "homeserver" => { "address" => "http://localhost:8008", "domain" => "localhost" },
156
167
  "appservice" => { "as_token" => "test_token", "hs_token" => "hs_secret", "bot" => { "username" => "bot" } }
157
168
  })
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ # Async::Matrix::Error is this class's superclass, so it has to exist before
7
+ # this file finishes loading — the glob in async/matrix.rb sorts
8
+ # alphabetically and would otherwise get here first.
9
+ require_relative "error"
10
+
11
+ module Async
12
+ module Matrix
13
+ class NotFoundError < Error; end
14
+ end
15
+ end
16
+
17
+ __END__
18
+ it "NotFoundError inherits from Error" do
19
+ Async::Matrix::NotFoundError.new("M_NOT_FOUND", "gone").should.be.kind_of Async::Matrix::Error
20
+ end
@@ -37,17 +37,21 @@ module Async
37
37
 
38
38
  loop do
39
39
  result = yield
40
- return result if result
40
+ if result
41
+ break result
42
+ end
41
43
 
42
44
  remaining = deadline - Time.now
43
- return result if remaining <= 0
45
+ if remaining <= 0
46
+ break result
47
+ end
44
48
 
45
49
  begin
46
50
  Async::Task.current.with_timeout(remaining) do
47
51
  @condition.wait
48
52
  end
49
53
  rescue Async::TimeoutError
50
- return yield
54
+ break yield
51
55
  end
52
56
  end
53
57
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the Apache License, Version 2.0.
4
+ # Copyright, 2026, by General Intelligence Systems.
5
+
6
+ # Async::Matrix::Error is this class's superclass, so it has to exist before
7
+ # this file finishes loading — the glob in async/matrix.rb sorts
8
+ # alphabetically and would otherwise get here first.
9
+ require_relative "error"
10
+
11
+ module Async
12
+ module Matrix
13
+ class ResponseTooLargeError < Error; end
14
+ end
15
+ end
16
+
17
+ __END__
18
+ it "ResponseTooLargeError inherits from Error" do
19
+ Async::Matrix::ResponseTooLargeError.new("M_TOO_LARGE", "too big").should.be.kind_of Async::Matrix::Error
20
+ end