modal-rb 0.0.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,229 @@
1
+ module Modal
2
+ class SandboxFile
3
+ attr_reader :file_descriptor, :task_id
4
+
5
+ def initialize(file_descriptor, task_id)
6
+ @file_descriptor = file_descriptor
7
+ @task_id = task_id
8
+ end
9
+
10
+ def read
11
+ request = Modal::Client::ContainerFilesystemExecRequest.new(
12
+ file_read_request: Modal::Client::ContainerFileReadRequest.new(
13
+ file_descriptor: @file_descriptor
14
+ ),
15
+ task_id: @task_id
16
+ )
17
+
18
+ resp = Modal.client.call(:container_filesystem_exec, request)
19
+ exec_id = resp.exec_id
20
+
21
+ data = ""
22
+ completed = false
23
+ retries = 20
24
+
25
+ while !completed && retries > 0
26
+ begin
27
+ output_request = Modal::Client::ContainerFilesystemExecGetOutputRequest.new(
28
+ exec_id: exec_id,
29
+ timeout: 10
30
+ )
31
+
32
+ stream = Modal.client.call(:container_filesystem_exec_get_output, output_request)
33
+
34
+ stream.each do |batch|
35
+
36
+ if batch.respond_to?(:output) && batch.output && batch.output.any?
37
+ if batch.output.first.is_a?(String)
38
+ chunk = batch.output.join('')
39
+ elsif batch.output.first.is_a?(Integer)
40
+ chunk = batch.output.pack('C*')
41
+ else
42
+ chunk = batch.output.map(&:to_s).join('')
43
+ end
44
+
45
+ data += chunk.force_encoding('UTF-8')
46
+ end
47
+
48
+ if batch.respond_to?(:error) && batch.error
49
+ raise SandboxFilesystemError.new("Read failed: #{batch.error.error_message}")
50
+ end
51
+
52
+ if batch.respond_to?(:eof) && batch.eof
53
+ completed = true
54
+ break
55
+ end
56
+ end
57
+
58
+ unless completed
59
+ retries -= 1
60
+ sleep(0.1)
61
+ end
62
+
63
+ rescue GRPC::BadStatus => e
64
+ if e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
65
+ retries -= 1
66
+ sleep(0.1)
67
+ next
68
+ else
69
+ raise e
70
+ end
71
+ end
72
+ end
73
+
74
+ data
75
+ end
76
+
77
+ def write(data)
78
+ binary_data = if data.is_a?(String)
79
+ data.force_encoding('BINARY')
80
+ else
81
+ data.to_s.force_encoding('BINARY')
82
+ end
83
+
84
+ request = Modal::Client::ContainerFilesystemExecRequest.new(
85
+ file_write_request: Modal::Client::ContainerFileWriteRequest.new(
86
+ file_descriptor: @file_descriptor,
87
+ data: binary_data
88
+ ),
89
+ task_id: @task_id
90
+ )
91
+
92
+
93
+ resp = Modal.client.call(:container_filesystem_exec, request)
94
+ exec_id = resp.exec_id
95
+
96
+
97
+ completed = false
98
+ retries = 20
99
+
100
+ while !completed && retries > 0
101
+ begin
102
+ output_request = Modal::Client::ContainerFilesystemExecGetOutputRequest.new(
103
+ exec_id: exec_id,
104
+ timeout: 10
105
+ )
106
+
107
+ stream = Modal.client.call(:container_filesystem_exec_get_output, output_request)
108
+
109
+ stream.each do |batch|
110
+ if batch.respond_to?(:error) && batch.error
111
+ raise SandboxFilesystemError.new("Write failed: #{batch.error.error_message}")
112
+ end
113
+ if batch.respond_to?(:eof) && batch.eof
114
+ completed = true
115
+ break
116
+ end
117
+ end
118
+
119
+ unless completed
120
+ retries -= 1
121
+ sleep(0.1)
122
+ end
123
+
124
+ rescue GRPC::BadStatus => e
125
+ if e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
126
+ retries -= 1
127
+ sleep(0.1)
128
+ next
129
+ else
130
+ raise e
131
+ end
132
+ end
133
+ end
134
+
135
+ unless completed
136
+ end
137
+
138
+ data.length
139
+ end
140
+
141
+ def flush
142
+ request = Modal::Client::ContainerFilesystemExecRequest.new(
143
+ file_flush_request: Modal::Client::ContainerFileFlushRequest.new(
144
+ file_descriptor: @file_descriptor
145
+ ),
146
+ task_id: @task_id
147
+ )
148
+
149
+ resp = Modal.client.call(:container_filesystem_exec, request)
150
+ exec_id = resp.exec_id
151
+
152
+ retries = 10
153
+
154
+ while retries > 0
155
+ begin
156
+ output_request = Modal::Client::ContainerFilesystemExecGetOutputRequest.new(
157
+ exec_id: exec_id,
158
+ timeout: 5
159
+ )
160
+
161
+ stream = Modal.client.call(:container_filesystem_exec_get_output, output_request)
162
+ stream.each do |batch|
163
+ if batch.respond_to?(:error) && batch.error
164
+ raise SandboxFilesystemError.new("Flush failed: #{batch.error.error_message}")
165
+ end
166
+ if batch.respond_to?(:eof) && batch.eof
167
+ return
168
+ end
169
+ end
170
+
171
+ retries -= 1
172
+ sleep(0.1)
173
+
174
+ rescue GRPC::BadStatus => e
175
+ if e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
176
+ retries -= 1
177
+ next
178
+ else
179
+ raise e
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ def close
186
+ request = Modal::Client::ContainerFilesystemExecRequest.new(
187
+ file_close_request: Modal::Client::ContainerFileCloseRequest.new(
188
+ file_descriptor: @file_descriptor
189
+ ),
190
+ task_id: @task_id
191
+ )
192
+
193
+ resp = Modal.client.call(:container_filesystem_exec, request)
194
+ exec_id = resp.exec_id
195
+
196
+ retries = 10
197
+
198
+ while retries > 0
199
+ begin
200
+ output_request = Modal::Client::ContainerFilesystemExecGetOutputRequest.new(
201
+ exec_id: exec_id,
202
+ timeout: 5
203
+ )
204
+
205
+ stream = Modal.client.call(:container_filesystem_exec_get_output, output_request)
206
+ stream.each do |batch|
207
+ if batch.respond_to?(:error) && batch.error
208
+ raise SandboxFilesystemError.new("Close failed: #{batch.error.error_message}")
209
+ end
210
+ if batch.respond_to?(:eof) && batch.eof
211
+ return
212
+ end
213
+ end
214
+
215
+ retries -= 1
216
+ sleep(0.1)
217
+
218
+ rescue GRPC::BadStatus => e
219
+ if e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
220
+ retries -= 1
221
+ next
222
+ else
223
+ raise e
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,73 @@
1
+ require 'stringio'
2
+
3
+ module Modal
4
+ class ModalReadStream
5
+ def initialize(source_iterable)
6
+ @source_iterable = source_iterable
7
+ end
8
+
9
+ def read
10
+ read_text
11
+ end
12
+
13
+ def read_text
14
+ chunks = []
15
+ @source_iterable.each do |bytes|
16
+ chunks << bytes.dup.force_encoding('UTF-8')
17
+ end
18
+ chunks.join('')
19
+ end
20
+
21
+ def read_bytes
22
+ chunks = []
23
+ @source_iterable.each do |bytes|
24
+ chunks << bytes.dup
25
+ end
26
+ chunks.join('').bytes.pack('C*')
27
+ end
28
+
29
+ def each(&block)
30
+ @source_iterable.each(&block)
31
+ end
32
+
33
+ def close
34
+ @source_iterable.close if @source_iterable.respond_to?(:close)
35
+ end
36
+ end
37
+
38
+ class ModalWriteStream
39
+ def initialize(sink_writable)
40
+ @sink_writable = sink_writable
41
+ end
42
+
43
+
44
+ def write(data)
45
+ if data.is_a?(String)
46
+ if data.encoding == Encoding::BINARY
47
+ write_bytes(data)
48
+ else
49
+ write_text(data)
50
+ end
51
+ else
52
+
53
+ write_bytes(data.to_s)
54
+ end
55
+ end
56
+
57
+ def write_text(text)
58
+ @sink_writable.write(text)
59
+ end
60
+
61
+ def write_bytes(bytes)
62
+ @sink_writable.write(bytes)
63
+ end
64
+
65
+ def close
66
+ @sink_writable.close if @sink_writable.respond_to?(:close)
67
+ end
68
+
69
+ def flush
70
+ @sink_writable.flush if @sink_writable.respond_to?(:flush)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module Modal
2
+ VERSION = "0.0.0"
3
+ end
data/lib/modal.rb ADDED
@@ -0,0 +1,15 @@
1
+ module Modal
2
+ require 'modal_proto/api_services_pb'
3
+
4
+ require 'modal/version'
5
+ require 'modal/errors'
6
+ require 'modal/config'
7
+ require 'modal/api_client'
8
+ require 'modal/app'
9
+ require 'modal/cls'
10
+ require 'modal/image'
11
+ require 'modal/function'
12
+ require 'modal/function_call'
13
+ require 'modal/sandbox'
14
+ require 'modal/streams'
15
+ end