ruflet_rails 0.0.14 → 0.0.16
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 92fa7112149cede7ab3ba1dfc0f0c235c662513f83c27a3bea423ef3f68a6664
|
|
4
|
+
data.tar.gz: 9903778b68c3b7fd3596509fd91036b3fc4775308b4d3728fafa93269a5d3bcc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 81f65d75640995d5471a8fcfcb0c7fa99792a9de754978f0dee7f43d7dfb14e8db7a24bb3ff1bc826a060981c114c7caab138f50ba16cb6bcef52514ea56c03d
|
|
7
|
+
data.tar.gz: da622f66688a2f49208b13e5be0290e3fc8e19ed7c150bb135ac5f57b8c0f97ebc4e3de5db2f9901af1e87b96d2650cc1a730745a5535ee52738e1065fd055e0
|
|
@@ -155,7 +155,7 @@ module Ruflet
|
|
|
155
155
|
html.include?("</head>") ? html.sub("</head>", "#{script}</head>") : "#{script}#{html}"
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
-
# Pins
|
|
158
|
+
# Pins Ruflet clients to <mount>/ws (derived from the rewritten
|
|
159
159
|
# <base href>) instead of the origin's /ws. The Ruflet client itself
|
|
160
160
|
# uses the mounted page URL, so Rails needs no separate backend URL.
|
|
161
161
|
def mount_websocket_bootstrap
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruflet
|
|
4
|
+
module Rails
|
|
5
|
+
module Protocol
|
|
6
|
+
class WebSocketConnection
|
|
7
|
+
def initialize(socket)
|
|
8
|
+
@socket = socket
|
|
9
|
+
@write_mutex = Mutex.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def session_key
|
|
13
|
+
@socket.object_id
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def closed?
|
|
17
|
+
@socket.closed?
|
|
18
|
+
rescue IOError
|
|
19
|
+
true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def send_binary(payload)
|
|
23
|
+
send_frame(0x2, payload.to_s.b)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def read_message
|
|
27
|
+
frame = read_frame
|
|
28
|
+
return nil if frame.nil?
|
|
29
|
+
|
|
30
|
+
opcode = frame[:opcode]
|
|
31
|
+
payload = frame[:payload]
|
|
32
|
+
|
|
33
|
+
case opcode
|
|
34
|
+
when 0x8
|
|
35
|
+
close
|
|
36
|
+
nil
|
|
37
|
+
when 0x9
|
|
38
|
+
send_frame(0xA, payload)
|
|
39
|
+
read_message
|
|
40
|
+
when 0xA
|
|
41
|
+
read_message
|
|
42
|
+
when 0x1, 0x2
|
|
43
|
+
payload
|
|
44
|
+
else
|
|
45
|
+
read_message
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def close
|
|
50
|
+
return if closed?
|
|
51
|
+
|
|
52
|
+
@socket.close
|
|
53
|
+
rescue IOError
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def read_frame
|
|
60
|
+
header = read_exact(2)
|
|
61
|
+
return nil if header.nil?
|
|
62
|
+
|
|
63
|
+
b1 = header.getbyte(0)
|
|
64
|
+
b2 = header.getbyte(1)
|
|
65
|
+
|
|
66
|
+
masked = (b2 & 0x80) != 0
|
|
67
|
+
payload_len = b2 & 0x7f
|
|
68
|
+
|
|
69
|
+
payload_len = read_exact(2).unpack1("n") if payload_len == 126
|
|
70
|
+
payload_len = read_exact(8).unpack1("Q>") if payload_len == 127
|
|
71
|
+
|
|
72
|
+
masking_key = masked ? read_exact(4) : nil
|
|
73
|
+
payload = payload_len.zero? ? "".b : read_exact(payload_len)
|
|
74
|
+
return nil if payload.nil?
|
|
75
|
+
|
|
76
|
+
payload = unmask(payload, masking_key) if masked
|
|
77
|
+
|
|
78
|
+
{ opcode: b1 & 0x0f, payload: payload }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def send_frame(opcode, payload)
|
|
82
|
+
bytes = payload.to_s.b
|
|
83
|
+
len = bytes.bytesize
|
|
84
|
+
header = [0x80 | (opcode & 0x0f)].pack("C")
|
|
85
|
+
|
|
86
|
+
header <<
|
|
87
|
+
if len <= 125
|
|
88
|
+
[len].pack("C")
|
|
89
|
+
elsif len <= 0xffff
|
|
90
|
+
[126].pack("C") + [len].pack("n")
|
|
91
|
+
else
|
|
92
|
+
[127].pack("C") + [len].pack("Q>")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
@write_mutex.synchronize do
|
|
96
|
+
@socket.write(header)
|
|
97
|
+
@socket.write(bytes) unless bytes.empty?
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def unmask(payload, mask)
|
|
102
|
+
out = +""
|
|
103
|
+
out.force_encoding(Encoding::BINARY)
|
|
104
|
+
payload.bytes.each_with_index do |byte, idx|
|
|
105
|
+
out << (byte ^ mask.getbyte(idx % 4))
|
|
106
|
+
end
|
|
107
|
+
out
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def read_exact(length)
|
|
111
|
+
chunk = +""
|
|
112
|
+
chunk.force_encoding(Encoding::BINARY)
|
|
113
|
+
|
|
114
|
+
while chunk.bytesize < length
|
|
115
|
+
part = @socket.read(length - chunk.bytesize)
|
|
116
|
+
return nil if part.nil? || part.empty?
|
|
117
|
+
|
|
118
|
+
chunk << part
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
chunk
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ruflet
|
|
4
|
+
module Rails
|
|
5
|
+
module Protocol
|
|
6
|
+
class WireCodec
|
|
7
|
+
class << self
|
|
8
|
+
def pack(value)
|
|
9
|
+
case value
|
|
10
|
+
when ::Ruflet::Protocol::DateTimeValue
|
|
11
|
+
pack_extension(1, value)
|
|
12
|
+
when ::Ruflet::Protocol::TimeOfDayValue
|
|
13
|
+
pack_extension(2, value)
|
|
14
|
+
when ::Ruflet::Protocol::DurationValue
|
|
15
|
+
pack_extension(3, value)
|
|
16
|
+
when NilClass
|
|
17
|
+
"\xc0".b
|
|
18
|
+
when TrueClass
|
|
19
|
+
"\xc3".b
|
|
20
|
+
when FalseClass
|
|
21
|
+
"\xc2".b
|
|
22
|
+
when Integer
|
|
23
|
+
pack_integer(value)
|
|
24
|
+
when Float
|
|
25
|
+
"\xcb".b + [value].pack("G")
|
|
26
|
+
when String
|
|
27
|
+
binary_string?(value) ? pack_binary(value) : pack_string(value)
|
|
28
|
+
when Symbol
|
|
29
|
+
pack_string(value.to_s)
|
|
30
|
+
when Array
|
|
31
|
+
pack_array(value)
|
|
32
|
+
when Hash
|
|
33
|
+
pack_map(value)
|
|
34
|
+
else
|
|
35
|
+
pack_string(value.to_s)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def unpack(bytes)
|
|
40
|
+
reader = ByteReader.new(bytes)
|
|
41
|
+
read_value(reader)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def pack_extension(type, value)
|
|
47
|
+
bytes = value.to_s.b
|
|
48
|
+
length = bytes.bytesize
|
|
49
|
+
header =
|
|
50
|
+
if length <= 0xff
|
|
51
|
+
"\xc7".b + [length].pack("C")
|
|
52
|
+
elsif length <= 0xffff
|
|
53
|
+
"\xc8".b + [length].pack("n")
|
|
54
|
+
else
|
|
55
|
+
"\xc9".b + [length].pack("N")
|
|
56
|
+
end
|
|
57
|
+
header + [type].pack("c") + bytes
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def pack_integer(value)
|
|
61
|
+
if value >= 0
|
|
62
|
+
return [value].pack("C") if value <= 0x7f
|
|
63
|
+
return "\xcc".b + [value].pack("C") if value <= 0xff
|
|
64
|
+
return "\xcd".b + [value].pack("n") if value <= 0xffff
|
|
65
|
+
return "\xce".b + [value].pack("N") if value <= 0xffff_ffff
|
|
66
|
+
|
|
67
|
+
"\xcf".b + [value].pack("Q>")
|
|
68
|
+
else
|
|
69
|
+
return [value & 0xff].pack("C") if value >= -32
|
|
70
|
+
return "\xd0".b + [value].pack("c") if value >= -128
|
|
71
|
+
return "\xd1".b + [value].pack("s>") if value >= -32_768
|
|
72
|
+
return "\xd2".b + [value].pack("l>") if value >= -2_147_483_648
|
|
73
|
+
|
|
74
|
+
"\xd3".b + [value].pack("q>")
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def pack_string(value)
|
|
79
|
+
str = value.to_s.dup.force_encoding("UTF-8")
|
|
80
|
+
bytes = str.b
|
|
81
|
+
len = bytes.bytesize
|
|
82
|
+
|
|
83
|
+
if len <= 31
|
|
84
|
+
[0xA0 | len].pack("C") + bytes
|
|
85
|
+
elsif len <= 0xff
|
|
86
|
+
"\xd9".b + [len].pack("C") + bytes
|
|
87
|
+
elsif len <= 0xffff
|
|
88
|
+
"\xda".b + [len].pack("n") + bytes
|
|
89
|
+
else
|
|
90
|
+
"\xdb".b + [len].pack("N") + bytes
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def pack_binary(value)
|
|
95
|
+
bytes = value.to_s.b
|
|
96
|
+
len = bytes.bytesize
|
|
97
|
+
|
|
98
|
+
if len <= 0xff
|
|
99
|
+
"\xc4".b + [len].pack("C") + bytes
|
|
100
|
+
elsif len <= 0xffff
|
|
101
|
+
"\xc5".b + [len].pack("n") + bytes
|
|
102
|
+
else
|
|
103
|
+
"\xc6".b + [len].pack("N") + bytes
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def binary_string?(value)
|
|
108
|
+
value.encoding == Encoding::BINARY || !value.valid_encoding?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def pack_array(value)
|
|
112
|
+
len = value.length
|
|
113
|
+
head =
|
|
114
|
+
if len <= 15
|
|
115
|
+
[0x90 | len].pack("C")
|
|
116
|
+
elsif len <= 0xffff
|
|
117
|
+
"\xdc".b + [len].pack("n")
|
|
118
|
+
else
|
|
119
|
+
"\xdd".b + [len].pack("N")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
body = +"".b
|
|
123
|
+
value.each { |item| body << pack(item) }
|
|
124
|
+
head + body
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def pack_map(value)
|
|
128
|
+
pairs = value.each_with_object({}) { |(k, v), out| out[k.to_s] = v }
|
|
129
|
+
len = pairs.length
|
|
130
|
+
head =
|
|
131
|
+
if len <= 15
|
|
132
|
+
[0x80 | len].pack("C")
|
|
133
|
+
elsif len <= 0xffff
|
|
134
|
+
"\xde".b + [len].pack("n")
|
|
135
|
+
else
|
|
136
|
+
"\xdf".b + [len].pack("N")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
body = +"".b
|
|
140
|
+
pairs.each do |k, v|
|
|
141
|
+
body << pack(k)
|
|
142
|
+
body << pack(v)
|
|
143
|
+
end
|
|
144
|
+
head + body
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def read_value(reader)
|
|
148
|
+
marker = reader.read_u8
|
|
149
|
+
|
|
150
|
+
return marker if marker <= 0x7f
|
|
151
|
+
return marker - 256 if marker >= 0xe0
|
|
152
|
+
|
|
153
|
+
case marker
|
|
154
|
+
when 0xc0 then nil
|
|
155
|
+
when 0xc2 then false
|
|
156
|
+
when 0xc3 then true
|
|
157
|
+
when 0xcc then reader.read_u8
|
|
158
|
+
when 0xcd then reader.read_u16
|
|
159
|
+
when 0xce then reader.read_u32
|
|
160
|
+
when 0xcf then reader.read_u64
|
|
161
|
+
when 0xd0 then reader.read_i8
|
|
162
|
+
when 0xd1 then reader.read_i16
|
|
163
|
+
when 0xd2 then reader.read_i32
|
|
164
|
+
when 0xd3 then reader.read_i64
|
|
165
|
+
when 0xca then reader.read_f32
|
|
166
|
+
when 0xcb then reader.read_f64
|
|
167
|
+
when 0xd9 then reader.read_string(reader.read_u8)
|
|
168
|
+
when 0xda then reader.read_string(reader.read_u16)
|
|
169
|
+
when 0xdb then reader.read_string(reader.read_u32)
|
|
170
|
+
when 0xc4 then reader.read_binary(reader.read_u8)
|
|
171
|
+
when 0xc5 then reader.read_binary(reader.read_u16)
|
|
172
|
+
when 0xc6 then reader.read_binary(reader.read_u32)
|
|
173
|
+
when 0xdc then read_array(reader, reader.read_u16)
|
|
174
|
+
when 0xdd then read_array(reader, reader.read_u32)
|
|
175
|
+
when 0xde then read_map(reader, reader.read_u16)
|
|
176
|
+
when 0xdf then read_map(reader, reader.read_u32)
|
|
177
|
+
when 0xd4
|
|
178
|
+
read_ext(reader, 1)
|
|
179
|
+
when 0xd5
|
|
180
|
+
read_ext(reader, 2)
|
|
181
|
+
when 0xd6
|
|
182
|
+
read_ext(reader, 4)
|
|
183
|
+
when 0xd7
|
|
184
|
+
read_ext(reader, 8)
|
|
185
|
+
when 0xd8
|
|
186
|
+
read_ext(reader, 16)
|
|
187
|
+
when 0xc7
|
|
188
|
+
read_ext(reader, reader.read_u8)
|
|
189
|
+
when 0xc8
|
|
190
|
+
read_ext(reader, reader.read_u16)
|
|
191
|
+
when 0xc9
|
|
192
|
+
read_ext(reader, reader.read_u32)
|
|
193
|
+
else
|
|
194
|
+
if (marker & 0xf0) == 0x90
|
|
195
|
+
read_array(reader, marker & 0x0f)
|
|
196
|
+
elsif (marker & 0xf0) == 0x80
|
|
197
|
+
read_map(reader, marker & 0x0f)
|
|
198
|
+
elsif (marker & 0xe0) == 0xa0
|
|
199
|
+
reader.read_string(marker & 0x1f)
|
|
200
|
+
else
|
|
201
|
+
raise "Unsupported MessagePack marker: 0x#{marker.to_s(16)}"
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def read_array(reader, size)
|
|
207
|
+
Array.new(size) { read_value(reader) }
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def read_map(reader, size)
|
|
211
|
+
out = {}
|
|
212
|
+
size.times do
|
|
213
|
+
key = read_value(reader)
|
|
214
|
+
out[key.to_s] = read_value(reader)
|
|
215
|
+
end
|
|
216
|
+
out
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def read_ext(reader, size)
|
|
220
|
+
type = reader.read_i8
|
|
221
|
+
value = reader.read_exact(size).force_encoding("UTF-8")
|
|
222
|
+
case type
|
|
223
|
+
when 1 then ::Ruflet::Protocol.date_time(value)
|
|
224
|
+
when 2 then ::Ruflet::Protocol.time_of_day(value)
|
|
225
|
+
when 3 then ::Ruflet::Protocol.duration(value)
|
|
226
|
+
else value
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
class ByteReader
|
|
232
|
+
def initialize(bytes)
|
|
233
|
+
@data = bytes.to_s.b
|
|
234
|
+
@offset = 0
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def read_u8
|
|
238
|
+
value = @data.getbyte(@offset)
|
|
239
|
+
raise "Unexpected EOF" if value.nil?
|
|
240
|
+
|
|
241
|
+
@offset += 1
|
|
242
|
+
value
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def read_exact(size)
|
|
246
|
+
chunk = @data.byteslice(@offset, size)
|
|
247
|
+
raise "Unexpected EOF" if chunk.nil? || chunk.bytesize != size
|
|
248
|
+
|
|
249
|
+
@offset += size
|
|
250
|
+
chunk
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def read_u16 = read_exact(2).unpack1("n")
|
|
254
|
+
def read_u32 = read_exact(4).unpack1("N")
|
|
255
|
+
def read_u64 = read_exact(8).unpack1("Q>")
|
|
256
|
+
def read_i8 = read_exact(1).unpack1("c")
|
|
257
|
+
def read_i16 = read_exact(2).unpack1("s>")
|
|
258
|
+
def read_i32 = read_exact(4).unpack1("l>")
|
|
259
|
+
def read_i64 = read_exact(8).unpack1("q>")
|
|
260
|
+
def read_f32 = read_exact(4).unpack1("g")
|
|
261
|
+
def read_f64 = read_exact(8).unpack1("G")
|
|
262
|
+
def read_string(size) = read_exact(size).force_encoding("UTF-8")
|
|
263
|
+
def read_binary(size) = read_exact(size)
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
data/lib/ruflet/rails/railtie.rb
CHANGED
|
@@ -100,6 +100,25 @@ module Ruflet
|
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
|
+
|
|
104
|
+
rake_tasks do
|
|
105
|
+
namespace :ruflet do
|
|
106
|
+
desc "Build Ruflet client for this Rails app. Usage: rake ruflet:build[web]"
|
|
107
|
+
task :build, [:platform] do |_task, args|
|
|
108
|
+
platform = args[:platform].to_s.strip
|
|
109
|
+
if platform.empty?
|
|
110
|
+
warn "Usage: rake ruflet:build[apk|android|ios|aab|web|macos|windows|linux]"
|
|
111
|
+
next
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
require "ruflet/cli"
|
|
115
|
+
exit_code = Dir.chdir(::Rails.root) do
|
|
116
|
+
Ruflet::CLI.command_build([platform])
|
|
117
|
+
end
|
|
118
|
+
raise SystemExit, exit_code unless exit_code.to_i.zero?
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
103
122
|
end
|
|
104
123
|
end
|
|
105
124
|
end
|
data/lib/ruflet/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruflet_rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.16
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adam Moussa Ali
|
|
@@ -29,42 +29,42 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.0.
|
|
32
|
+
version: 0.0.19
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.0.
|
|
39
|
+
version: 0.0.19
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: ruflet_core
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: 0.0.
|
|
46
|
+
version: 0.0.19
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - ">="
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: 0.0.
|
|
53
|
+
version: 0.0.19
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: ruflet_server
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
58
|
- - ">="
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: 0.0.
|
|
60
|
+
version: 0.0.19
|
|
61
61
|
type: :runtime
|
|
62
62
|
prerelease: false
|
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
65
|
- - ">="
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: 0.0.
|
|
67
|
+
version: 0.0.19
|
|
68
68
|
description: Build cross-platform mobile and desktop apps with Ruby on Rails using
|
|
69
69
|
Ruflet.
|
|
70
70
|
email:
|
|
@@ -94,7 +94,9 @@ files:
|
|
|
94
94
|
- lib/ruflet/rails/protocol/mobile_loader.rb
|
|
95
95
|
- lib/ruflet/rails/protocol/runner.rb
|
|
96
96
|
- lib/ruflet/rails/protocol/web_app.rb
|
|
97
|
+
- lib/ruflet/rails/protocol/web_socket_connection.rb
|
|
97
98
|
- lib/ruflet/rails/protocol/websocket_detection.rb
|
|
99
|
+
- lib/ruflet/rails/protocol/wire_codec.rb
|
|
98
100
|
- lib/ruflet/rails/railtie.rb
|
|
99
101
|
- lib/ruflet/rails/session_registry.rb
|
|
100
102
|
- lib/ruflet/rails/view_helpers.rb
|