prusalink 0.1.0

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.
@@ -0,0 +1,191 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ # The printer's current job.
6
+ #
7
+ # @example Inspect and control the current job
8
+ # job = Prusalink::Job.get # => nil when the printer is idle
9
+ # job.state # => "PRINTING"
10
+ # job.progress # => 42.0
11
+ # job.file.full_path # => "/usb/SPICE~1.gco"
12
+ # job.pause
13
+ #
14
+ # @example Control a job by id
15
+ # Prusalink::Job.stop(420)
16
+ class Job < BaseResource
17
+ extend T::Sig
18
+ include AutoInitializable
19
+ include Deserializable
20
+
21
+ resource_path("/api/v1/job")
22
+
23
+ # @!attribute [r] id
24
+ # @return [Integer] The job's id
25
+ auto_attr :id, type: Integer
26
+
27
+ # @!attribute [r] state
28
+ # @return [String] One of "PRINTING", "PAUSED", "FINISHED", "STOPPED" or "ERROR"
29
+ auto_attr :state, type: String
30
+
31
+ # @!attribute [r] progress
32
+ # @return [Float] Completion, in percent
33
+ auto_attr :progress, type: Float
34
+
35
+ # @!attribute [r] time_remaining
36
+ # @return [Integer, nil] Estimated time left, in seconds
37
+ auto_attr :time_remaining, type: Integer
38
+
39
+ # @!attribute [r] time_printing
40
+ # @return [Integer] Time spent printing, in seconds
41
+ auto_attr :time_printing, type: Integer
42
+
43
+ # @!attribute [r] inaccurate_estimates
44
+ # @return [Boolean, nil] Whether the time estimates are inaccurate
45
+ auto_attr :inaccurate_estimates, type: T::Boolean
46
+
47
+ # @!attribute [r] serial_print
48
+ # @return [Boolean, nil] Whether the printer is printing from the serial line (no file is then available)
49
+ auto_attr :serial_print, type: T::Boolean
50
+
51
+ # @!attribute [r] file
52
+ # @return [Job::File, nil] The file being printed, absent for serial prints
53
+ auto_attr :file, type: File
54
+
55
+ # @!attribute [r] extra
56
+ # @return [Hash] Any additional fields returned by the API
57
+ auto_attr :extra, type: Hash
58
+
59
+ auto_initialize!
60
+
61
+ deserialize_config do
62
+ nested :file, File
63
+ end
64
+
65
+ class << self
66
+ extend T::Sig
67
+
68
+ # Retrieve the current job.
69
+ #
70
+ # @return [Job, nil] nil when there is no job (the printer answers 204 No Content)
71
+ # @raise [Prusalink::Exceptions::Error] if the request fails
72
+ sig { returns(T.nilable(Job)) }
73
+ def get
74
+ fetch_resource
75
+ end
76
+
77
+ # Stop the job with the given id.
78
+ #
79
+ # @param id [Integer] The job's id
80
+ # @return [Boolean] true on success
81
+ # @raise [Prusalink::Exceptions::NotFoundError] if no job has this id
82
+ # @raise [Prusalink::Exceptions::ConflictError] if the job can't be stopped in its current state
83
+ sig { params(id: Integer).returns(T::Boolean) }
84
+ def stop(id)
85
+ delete(path: job_path(id))
86
+ end
87
+
88
+ # Pause the job with the given id.
89
+ #
90
+ # @param id [Integer] The job's id
91
+ # @return [Boolean] true on success
92
+ # @raise [Prusalink::Exceptions::NotFoundError] if no job has this id
93
+ # @raise [Prusalink::Exceptions::ConflictError] if the job can't be paused in its current state
94
+ sig { params(id: Integer).returns(T::Boolean) }
95
+ def pause(id)
96
+ put(path: job_path(id, "pause"))
97
+ end
98
+
99
+ # Resume the paused job with the given id.
100
+ #
101
+ # @param id [Integer] The job's id
102
+ # @return [Boolean] true on success
103
+ # @raise [Prusalink::Exceptions::NotFoundError] if no job has this id
104
+ # @raise [Prusalink::Exceptions::ConflictError] if the job isn't paused
105
+ sig { params(id: Integer).returns(T::Boolean) }
106
+ def resume(id)
107
+ put(path: job_path(id, "resume"))
108
+ end
109
+
110
+ # Continue the job with the given id after a timelapse capture.
111
+ #
112
+ # @param id [Integer] The job's id
113
+ # @return [Boolean] true on success
114
+ # @raise [Prusalink::Exceptions::NotFoundError] if no job has this id
115
+ # @raise [Prusalink::Exceptions::ConflictError] if the job isn't waiting to continue
116
+ sig { params(id: Integer).returns(T::Boolean) }
117
+ def continue(id)
118
+ put(path: job_path(id, "continue"))
119
+ end
120
+
121
+ private
122
+
123
+ sig { params(id: Integer, action: T.nilable(String)).returns(String) }
124
+ def job_path(id, action = nil)
125
+ ["/api/v1/job", id, action].compact.join("/")
126
+ end
127
+ end
128
+
129
+ # Stop this job. See {Job.stop}.
130
+ #
131
+ # @return [Boolean] true on success
132
+ sig { returns(T::Boolean) }
133
+ def stop
134
+ self.class.stop(T.must(id))
135
+ end
136
+
137
+ # Pause this job. See {Job.pause}.
138
+ #
139
+ # @return [Boolean] true on success
140
+ sig { returns(T::Boolean) }
141
+ def pause
142
+ self.class.pause(T.must(id))
143
+ end
144
+
145
+ # Resume this job. See {Job.resume}.
146
+ #
147
+ # @return [Boolean] true on success
148
+ sig { returns(T::Boolean) }
149
+ def resume
150
+ self.class.resume(T.must(id))
151
+ end
152
+
153
+ # Continue this job after a timelapse capture. See {Job.continue}.
154
+ #
155
+ # @return [Boolean] true on success
156
+ sig { returns(T::Boolean) }
157
+ def continue
158
+ self.class.continue(T.must(id))
159
+ end
160
+
161
+ # @return [Boolean] whether the job is printing
162
+ sig { returns(T::Boolean) }
163
+ def printing?
164
+ state == "PRINTING"
165
+ end
166
+
167
+ # @return [Boolean] whether the job is paused
168
+ sig { returns(T::Boolean) }
169
+ def paused?
170
+ state == "PAUSED"
171
+ end
172
+
173
+ # @return [Boolean] whether the job has finished
174
+ sig { returns(T::Boolean) }
175
+ def finished?
176
+ state == "FINISHED"
177
+ end
178
+
179
+ # @return [Boolean] whether the job was stopped
180
+ sig { returns(T::Boolean) }
181
+ def stopped?
182
+ state == "STOPPED"
183
+ end
184
+
185
+ # @return [Boolean] whether the job ended in error
186
+ sig { returns(T::Boolean) }
187
+ def error?
188
+ state == "ERROR"
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,70 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ # Version information about the PrusaLink server and the printer's firmware.
6
+ #
7
+ # @example
8
+ # version = Prusalink::ServerVersion.get
9
+ # version.text # => "PrusaLink 0.7.0"
10
+ # version.firmware # => "6.1.3+8098"
11
+ # version.upload_by_put? # => true
12
+ class ServerVersion < BaseResource
13
+ extend T::Sig
14
+ include AutoInitializable
15
+ include Deserializable
16
+
17
+ resource_path("/api/version")
18
+
19
+ # @!attribute [r] api
20
+ # @return [String] The API version
21
+ auto_attr :api, type: String
22
+
23
+ # @!attribute [r] version
24
+ # @return [String] The PrusaLink version
25
+ auto_attr :version, type: String
26
+
27
+ # @!attribute [r] printer
28
+ # @return [String] The printer's version
29
+ auto_attr :printer, type: String
30
+
31
+ # @!attribute [r] text
32
+ # @return [String] Server version including the "PrusaLink" prefix
33
+ auto_attr :text, type: String
34
+
35
+ # @!attribute [r] firmware
36
+ # @return [String] The printer's firmware version
37
+ auto_attr :firmware, type: String
38
+
39
+ # @!attribute [r] sdk
40
+ # @return [String] The PrusaLink SDK version
41
+ auto_attr :sdk, type: String
42
+
43
+ # @!attribute [r] capabilities
44
+ # @return [Hash] Optional capabilities, e.g. { upload_by_put: true }
45
+ auto_attr :capabilities, type: Hash
46
+
47
+ # @!attribute [r] extra
48
+ # @return [Hash] Any additional fields returned by the API
49
+ auto_attr :extra, type: Hash
50
+
51
+ auto_initialize!
52
+
53
+ # Retrieve information regarding server and API version.
54
+ #
55
+ # @return [ServerVersion]
56
+ # @raise [Prusalink::Exceptions::Error] if the request fails
57
+ sig { returns(ServerVersion) }
58
+ def self.get
59
+ fetch_resource
60
+ end
61
+
62
+ # Whether the printer accepts uploads with PUT /api/v1/files (see {Files.upload})
63
+ #
64
+ # @return [Boolean]
65
+ sig { returns(T::Boolean) }
66
+ def upload_by_put?
67
+ capabilities&.fetch(:upload_by_put, false) == true
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,26 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ class Status
6
+ # The default working camera, if available.
7
+ #
8
+ # @example
9
+ # Prusalink::Status.get.camera&.id # => "Ba1kmCbifTa8X"
10
+ class Camera
11
+ extend T::Sig
12
+ include AutoInitializable
13
+ include Deserializable
14
+
15
+ # @!attribute [r] id
16
+ # @return [String] The camera's id
17
+ auto_attr :id, type: String
18
+
19
+ # @!attribute [r] extra
20
+ # @return [Hash] Any additional fields returned by the API
21
+ auto_attr :extra, type: Hash
22
+
23
+ auto_initialize!
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,41 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ class Status
6
+ # Telemetry about the current job. All values are optional.
7
+ # See {Prusalink::Job} for the full job details.
8
+ #
9
+ # @example
10
+ # job = Prusalink::Status.get.job
11
+ # job.progress # => 42.0
12
+ # job.time_remaining # => 520
13
+ class Job
14
+ extend T::Sig
15
+ include AutoInitializable
16
+ include Deserializable
17
+
18
+ # @!attribute [r] id
19
+ # @return [Integer] The job's id
20
+ auto_attr :id, type: Integer
21
+
22
+ # @!attribute [r] progress
23
+ # @return [Float] Job progress, in percent
24
+ auto_attr :progress, type: Float
25
+
26
+ # @!attribute [r] time_remaining
27
+ # @return [Integer] Estimated time remaining, in seconds
28
+ auto_attr :time_remaining, type: Integer
29
+
30
+ # @!attribute [r] time_printing
31
+ # @return [Integer] Time spent printing, in seconds
32
+ auto_attr :time_printing, type: Integer
33
+
34
+ # @!attribute [r] extra
35
+ # @return [Hash] Any additional fields returned by the API
36
+ auto_attr :extra, type: Hash
37
+
38
+ auto_initialize!
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,136 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ class Status
6
+ # Telemetry about the printer. All values except {#state} are optional.
7
+ #
8
+ # @example
9
+ # printer = Prusalink::Status.get.printer
10
+ # printer.state # => "PRINTING"
11
+ # printer.printing? # => true
12
+ # printer.temp_bed # => 59.5
13
+ class Printer
14
+ extend T::Sig
15
+ include AutoInitializable
16
+ include Deserializable
17
+
18
+ # @!attribute [r] state
19
+ # @return [String] The printer's state: "IDLE", "BUSY", "PRINTING", "PAUSED", "FINISHED", "STOPPED",
20
+ # "ERROR", "ATTENTION" or "READY"
21
+ auto_attr :state, type: String
22
+
23
+ # @!attribute [r] temp_nozzle
24
+ # @return [Float] Current nozzle temperature, in °C
25
+ auto_attr :temp_nozzle, type: Float
26
+
27
+ # @!attribute [r] target_nozzle
28
+ # @return [Float] Target nozzle temperature, in °C
29
+ auto_attr :target_nozzle, type: Float
30
+
31
+ # @!attribute [r] temp_bed
32
+ # @return [Float] Current bed temperature, in °C
33
+ auto_attr :temp_bed, type: Float
34
+
35
+ # @!attribute [r] target_bed
36
+ # @return [Float] Target bed temperature, in °C
37
+ auto_attr :target_bed, type: Float
38
+
39
+ # @!attribute [r] axis_x
40
+ # @return [Float, nil] X axis position, in mm. Only available when the printer is not moving
41
+ auto_attr :axis_x, type: Float
42
+
43
+ # @!attribute [r] axis_y
44
+ # @return [Float, nil] Y axis position, in mm. Only available when the printer is not moving
45
+ auto_attr :axis_y, type: Float
46
+
47
+ # @!attribute [r] axis_z
48
+ # @return [Float] Z axis position, in mm
49
+ auto_attr :axis_z, type: Float
50
+
51
+ # @!attribute [r] flow
52
+ # @return [Integer] Flow rate factor, in percent
53
+ auto_attr :flow, type: Integer
54
+
55
+ # @!attribute [r] speed
56
+ # @return [Integer] Print speed factor, in percent
57
+ auto_attr :speed, type: Integer
58
+
59
+ # @!attribute [r] fan_hotend
60
+ # @return [Integer] Hotend fan speed, in RPM
61
+ auto_attr :fan_hotend, type: Integer
62
+
63
+ # @!attribute [r] fan_print
64
+ # @return [Integer] Print fan speed, in RPM
65
+ auto_attr :fan_print, type: Integer
66
+
67
+ # @!attribute [r] status_printer
68
+ # @return [Hash] Printer health, e.g. { ok: true, message: "OK" }
69
+ auto_attr :status_printer, type: Hash
70
+
71
+ # @!attribute [r] status_connect
72
+ # @return [Hash] Prusa Connect health, e.g. { ok: true, message: "OK" }
73
+ auto_attr :status_connect, type: Hash
74
+
75
+ # @!attribute [r] extra
76
+ # @return [Hash] Any additional fields returned by the API
77
+ auto_attr :extra, type: Hash
78
+
79
+ auto_initialize!
80
+
81
+ # @return [Boolean] true when the state is "IDLE"
82
+ sig { returns(T::Boolean) }
83
+ def idle?
84
+ state == "IDLE"
85
+ end
86
+
87
+ # @return [Boolean] true when the state is "BUSY"
88
+ sig { returns(T::Boolean) }
89
+ def busy?
90
+ state == "BUSY"
91
+ end
92
+
93
+ # @return [Boolean] true when the state is "PRINTING"
94
+ sig { returns(T::Boolean) }
95
+ def printing?
96
+ state == "PRINTING"
97
+ end
98
+
99
+ # @return [Boolean] true when the state is "PAUSED"
100
+ sig { returns(T::Boolean) }
101
+ def paused?
102
+ state == "PAUSED"
103
+ end
104
+
105
+ # @return [Boolean] true when the state is "FINISHED"
106
+ sig { returns(T::Boolean) }
107
+ def finished?
108
+ state == "FINISHED"
109
+ end
110
+
111
+ # @return [Boolean] true when the state is "STOPPED"
112
+ sig { returns(T::Boolean) }
113
+ def stopped?
114
+ state == "STOPPED"
115
+ end
116
+
117
+ # @return [Boolean] true when the state is "ERROR"
118
+ sig { returns(T::Boolean) }
119
+ def error?
120
+ state == "ERROR"
121
+ end
122
+
123
+ # @return [Boolean] true when the state is "ATTENTION" (the printer waits for user input)
124
+ sig { returns(T::Boolean) }
125
+ def attention?
126
+ state == "ATTENTION"
127
+ end
128
+
129
+ # @return [Boolean] true when the state is "READY"
130
+ sig { returns(T::Boolean) }
131
+ def ready?
132
+ state == "READY"
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,40 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ class Status
6
+ # Telemetry about the current storage.
7
+ #
8
+ # @example
9
+ # storage = Prusalink::Status.get.storage
10
+ # storage.name # => "LOCAL"
11
+ # storage.free_space # => 4202335
12
+ class Storage
13
+ extend T::Sig
14
+ include AutoInitializable
15
+ include Deserializable
16
+
17
+ # @!attribute [r] name
18
+ # @return [String] The storage's name, e.g. "LOCAL"
19
+ auto_attr :name, type: String
20
+
21
+ # @!attribute [r] path
22
+ # @return [String] The storage's path, e.g. "/local"
23
+ auto_attr :path, type: String
24
+
25
+ # @!attribute [r] read_only
26
+ # @return [Boolean] Whether the storage is read-only
27
+ auto_attr :read_only, type: T::Boolean
28
+
29
+ # @!attribute [r] free_space
30
+ # @return [Integer] Free space, in bytes
31
+ auto_attr :free_space, type: Integer
32
+
33
+ # @!attribute [r] extra
34
+ # @return [Hash] Any additional fields returned by the API
35
+ auto_attr :extra, type: Hash
36
+
37
+ auto_initialize!
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ class Status
6
+ # Telemetry about the current file transfer. All values except {#id} and {#time_transferring} are optional.
7
+ #
8
+ # @example
9
+ # transfer = Prusalink::Status.get.transfer
10
+ # transfer.progress # => 65.82
11
+ # transfer.data_transferred # => 123084800
12
+ class Transfer
13
+ extend T::Sig
14
+ include AutoInitializable
15
+ include Deserializable
16
+
17
+ # @!attribute [r] id
18
+ # @return [Integer] The transfer's id
19
+ auto_attr :id, type: Integer
20
+
21
+ # @!attribute [r] time_transferring
22
+ # @return [Integer] Time spent transferring, in seconds
23
+ auto_attr :time_transferring, type: Integer
24
+
25
+ # @!attribute [r] progress
26
+ # @return [Float] Transfer progress, in percent
27
+ auto_attr :progress, type: Float
28
+
29
+ # @!attribute [r] data_transferred
30
+ # @return [Integer] Amount of data transferred, in bytes
31
+ auto_attr :data_transferred, type: Integer
32
+
33
+ # @!attribute [r] extra
34
+ # @return [Hash] Any additional fields returned by the API
35
+ auto_attr :extra, type: Hash
36
+
37
+ auto_initialize!
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,64 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ # Telemetry about the printer, the current job, the current transfer, the storage and the camera.
6
+ # Everything except {#printer} is optional and is nil when the printer doesn't report it.
7
+ #
8
+ # @example
9
+ # status = Prusalink::Status.get
10
+ # status.printer.state # => "PRINTING"
11
+ # status.printer.printing? # => true
12
+ # status.job&.progress # => 42.0
13
+ # status.transfer # => nil when nothing is being transferred
14
+ class Status < BaseResource
15
+ extend T::Sig
16
+ include AutoInitializable
17
+ include Deserializable
18
+
19
+ resource_path("/api/v1/status")
20
+
21
+ # @!attribute [r] printer
22
+ # @return [Status::Printer] Telemetry about the printer (always present)
23
+ auto_attr :printer, type: Status::Printer
24
+
25
+ # @!attribute [r] job
26
+ # @return [Status::Job, nil] Telemetry about the current job
27
+ auto_attr :job, type: Status::Job
28
+
29
+ # @!attribute [r] transfer
30
+ # @return [Status::Transfer, nil] Telemetry about the current file transfer
31
+ auto_attr :transfer, type: Status::Transfer
32
+
33
+ # @!attribute [r] storage
34
+ # @return [Status::Storage, nil] Telemetry about the current storage
35
+ auto_attr :storage, type: Status::Storage
36
+
37
+ # @!attribute [r] camera
38
+ # @return [Status::Camera, nil] The default working camera, if available
39
+ auto_attr :camera, type: Status::Camera
40
+
41
+ # @!attribute [r] extra
42
+ # @return [Hash] Any additional fields returned by the API
43
+ auto_attr :extra, type: Hash
44
+
45
+ auto_initialize!
46
+
47
+ deserialize_config do
48
+ nested :printer, Status::Printer
49
+ nested :job, Status::Job
50
+ nested :transfer, Status::Transfer
51
+ nested :storage, Status::Storage
52
+ nested :camera, Status::Camera
53
+ end
54
+
55
+ # Retrieve the printer, job, transfer, storage and camera telemetry.
56
+ #
57
+ # @return [Status, nil] nil when the printer answers 204 No Content
58
+ # @raise [Prusalink::Exceptions::Error] if the request fails
59
+ sig { returns(T.nilable(Status)) }
60
+ def self.get
61
+ fetch_resource
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,87 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Prusalink
5
+ # A file storage of the printer, such as the local storage, an SD card or a USB drive.
6
+ #
7
+ # @example
8
+ # storages = Prusalink::Storage.list
9
+ # usb = storages.find { |storage| storage.storage_type == "USB" }
10
+ # usb.available? # => true
11
+ # usb.free_space # => 1921681142
12
+ class Storage < BaseResource
13
+ extend T::Sig
14
+ include AutoInitializable
15
+ include Deserializable
16
+
17
+ resource_path("/api/v1/storage")
18
+
19
+ # @!attribute [r] name
20
+ # @return [String, nil] Name of the storage, in the printer's language, e.g. "PrusaLink gcodes"
21
+ auto_attr :name, type: String
22
+
23
+ # @!attribute [r] storage_type
24
+ # @return [String] The storage's source: "LOCAL", "SDCARD" or "USB". Renamed from the API's `type` field.
25
+ auto_attr :storage_type, type: String
26
+
27
+ # @!attribute [r] path
28
+ # @return [String] Path of the storage (not the display path), e.g. "/local"
29
+ auto_attr :path, type: String
30
+
31
+ # @!attribute [r] print_files
32
+ # @return [Integer, nil] Size of all print files, in bytes
33
+ auto_attr :print_files, type: Integer
34
+
35
+ # @!attribute [r] system_files
36
+ # @return [Integer, nil] Size of all system files, in bytes
37
+ auto_attr :system_files, type: Integer
38
+
39
+ # @!attribute [r] free_space
40
+ # @return [Integer, nil] Free space, in bytes
41
+ auto_attr :free_space, type: Integer
42
+
43
+ # @!attribute [r] total_space
44
+ # @return [Integer, nil] Total space, in bytes
45
+ auto_attr :total_space, type: Integer
46
+
47
+ # @!attribute [r] available
48
+ # @return [Boolean] Whether the storage is available. See {#available?}
49
+ auto_attr :available, type: T::Boolean
50
+
51
+ # @!attribute [r] read_only
52
+ # @return [Boolean, nil] Whether the storage is read only. See {#read_only?}
53
+ auto_attr :read_only, type: T::Boolean
54
+
55
+ # @!attribute [r] extra
56
+ # @return [Hash] Any additional fields returned by the API
57
+ auto_attr :extra, type: Hash
58
+
59
+ auto_initialize!
60
+
61
+ deserialize_config do
62
+ rename type: :storage_type
63
+ end
64
+
65
+ # Retrieve every file storage of the printer.
66
+ #
67
+ # @return [Array<Storage>]
68
+ # @raise [Prusalink::Exceptions::Error] if the request fails
69
+ sig { returns(T::Array[Storage]) }
70
+ def self.list
71
+ response = fetch_resource(deserialize: false)
72
+ Array(response&.fetch(:storage_list, nil)).map { |storage| deserialize(storage) }
73
+ end
74
+
75
+ # @return [Boolean] whether the storage is available
76
+ sig { returns(T::Boolean) }
77
+ def available?
78
+ available == true
79
+ end
80
+
81
+ # @return [Boolean] whether the storage is read only
82
+ sig { returns(T::Boolean) }
83
+ def read_only?
84
+ read_only == true
85
+ end
86
+ end
87
+ end