tep 0.11.3 → 0.11.5
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 +4 -4
- data/Makefile +42 -2
- data/README.md +4 -4
- data/SINATRA_COMPAT.md +20 -20
- data/bin/tep +47 -10
- data/examples/api_gateway/app.rb +1 -1
- data/examples/blog/app.rb +17 -17
- data/examples/chat/app.rb +12 -12
- data/examples/chatbot/README.md +2 -2
- data/examples/chatbot/app.rb +24 -24
- data/examples/llm_gateway/app.rb +4 -4
- data/examples/pg_hello.rb +11 -1
- data/lib/spinel_kit/hex.rb +65 -0
- data/lib/spinel_kit/json.rb +151 -0
- data/lib/spinel_kit/json_decoder.rb +396 -0
- data/lib/{tep/logger.rb → spinel_kit/log.rb} +25 -21
- data/lib/spinel_kit/url.rb +166 -0
- data/lib/tep/auth_bearer_token.rb +6 -6
- data/lib/tep/auth_oauth2.rb +4 -4
- data/lib/tep/broadcast.rb +18 -80
- data/lib/tep/events.rb +37 -37
- data/lib/tep/http.rb +3 -3
- data/lib/tep/job.rb +2 -2
- data/lib/tep/jwt.rb +4 -4
- data/lib/tep/live_view.rb +4 -4
- data/lib/tep/llm.rb +13 -45
- data/lib/tep/mcp.rb +12 -12
- data/lib/tep/multipart.rb +1 -1
- data/lib/tep/net.rb +8 -3
- data/lib/tep/openai_server.rb +102 -94
- data/lib/tep/parser.rb +2 -2
- data/lib/tep/pg.rb +468 -14
- data/lib/tep/presence.rb +33 -329
- data/lib/tep/proxy.rb +7 -7
- data/lib/tep/request.rb +1 -1
- data/lib/tep/response.rb +1 -1
- data/lib/tep/router.rb +1 -1
- data/lib/tep/session.rb +2 -2
- data/lib/tep/version.rb +1 -1
- data/lib/tep.rb +57 -137
- data/spinel-ext.json +6 -0
- data/test/helper.rb +95 -8
- data/test/run_parallel.rb +44 -7
- data/test/test_auth.rb +17 -17
- data/test/test_auth_oauth2.rb +5 -5
- data/test/test_broadcast_pg.rb +1 -0
- data/test/test_http_pool.rb +4 -4
- data/test/test_http_pool_send.rb +3 -3
- data/test/test_json.rb +12 -12
- data/test/test_jwt.rb +4 -4
- data/test/test_live_view.rb +3 -3
- data/test/test_llm.rb +12 -9
- data/test/test_llm_gateway.rb +2 -2
- data/test/test_logger.rb +2 -2
- data/test/test_openai_server.rb +10 -1
- data/test/test_password.rb +3 -3
- data/test/test_pg.rb +1 -0
- data/test/test_presence_pg.rb +1 -0
- data/test/test_real_world.rb +6 -1
- data/test/test_shutdown.rb +40 -0
- metadata +23 -8
- data/lib/tep/json.rb +0 -572
- data/lib/tep/url.rb +0 -161
data/lib/tep/url.rb
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# Percent-decoding + form-urlencoded query parser.
|
|
2
|
-
module Tep
|
|
3
|
-
class Url
|
|
4
|
-
# "%41+b" -> "A b"
|
|
5
|
-
def self.unescape(s)
|
|
6
|
-
out = ""
|
|
7
|
-
i = 0
|
|
8
|
-
n = s.length
|
|
9
|
-
while i < n
|
|
10
|
-
c = s[i]
|
|
11
|
-
if c == "+"
|
|
12
|
-
out = out + " "
|
|
13
|
-
i += 1
|
|
14
|
-
elsif c == "%" && i + 2 < n
|
|
15
|
-
hi = Url.hex_nibble(s[i + 1])
|
|
16
|
-
lo = Url.hex_nibble(s[i + 2])
|
|
17
|
-
if hi >= 0 && lo >= 0
|
|
18
|
-
out = out + ((hi * 16 + lo).chr)
|
|
19
|
-
i += 3
|
|
20
|
-
else
|
|
21
|
-
out = out + c
|
|
22
|
-
i += 1
|
|
23
|
-
end
|
|
24
|
-
else
|
|
25
|
-
out = out + c
|
|
26
|
-
i += 1
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
out
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Percent-encode the bytes that are unsafe in cookie values, query
|
|
33
|
-
# strings, and similar contexts. RFC 3986 unreserved set:
|
|
34
|
-
# ALPHA / DIGIT / `-._~`. Everything else gets `%XX` (uppercase hex).
|
|
35
|
-
def self.escape(s)
|
|
36
|
-
out = ""
|
|
37
|
-
i = 0
|
|
38
|
-
while i < s.length
|
|
39
|
-
c = s[i]
|
|
40
|
-
if (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") ||
|
|
41
|
-
(c >= "0" && c <= "9") || c == "-" || c == "." ||
|
|
42
|
-
c == "_" || c == "~"
|
|
43
|
-
out = out + c
|
|
44
|
-
else
|
|
45
|
-
b = c.getbyte(0)
|
|
46
|
-
hi = b / 16
|
|
47
|
-
lo = b % 16
|
|
48
|
-
out = out + "%" + Url.hex_char(hi) + Url.hex_char(lo)
|
|
49
|
-
end
|
|
50
|
-
i += 1
|
|
51
|
-
end
|
|
52
|
-
out
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def self.hex_char(n)
|
|
56
|
-
if n < 10
|
|
57
|
-
return ("0".getbyte(0) + n).chr
|
|
58
|
-
end
|
|
59
|
-
("A".getbyte(0) + n - 10).chr
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def self.hex_nibble(c)
|
|
63
|
-
if c >= "0" && c <= "9"
|
|
64
|
-
return c.getbyte(0) - "0".getbyte(0)
|
|
65
|
-
end
|
|
66
|
-
if c >= "a" && c <= "f"
|
|
67
|
-
return c.getbyte(0) - "a".getbyte(0) + 10
|
|
68
|
-
end
|
|
69
|
-
if c >= "A" && c <= "F"
|
|
70
|
-
return c.getbyte(0) - "A".getbyte(0) + 10
|
|
71
|
-
end
|
|
72
|
-
-1
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Split a URL into a Hash with str=>str entries:
|
|
76
|
-
# "scheme" "host" "port" "path" "query"
|
|
77
|
-
#
|
|
78
|
-
# Recognises `http://host[:port]/path?query` and the same shape
|
|
79
|
-
# with `https://`. Without a scheme, the input is treated as a
|
|
80
|
-
# path (host stays empty); useful for routing relative paths
|
|
81
|
-
# through the same parser. Default ports follow the scheme:
|
|
82
|
-
# 80 for http, 443 for https. Path defaults to "/". `query` is
|
|
83
|
-
# the raw substring after `?`, no further decoding.
|
|
84
|
-
#
|
|
85
|
-
# Inlined as one method on purpose: spinel's analyzer widens
|
|
86
|
-
# Hash-typed parameters when a helper mutates them and the
|
|
87
|
-
# caller then keeps reading; sticking to a single body keeps
|
|
88
|
-
# `out` narrowed to StrStrHash throughout.
|
|
89
|
-
def self.split_url(u)
|
|
90
|
-
out = Tep.str_hash
|
|
91
|
-
out["scheme"] = ""
|
|
92
|
-
out["host"] = ""
|
|
93
|
-
out["port"] = ""
|
|
94
|
-
out["path"] = "/"
|
|
95
|
-
out["query"] = ""
|
|
96
|
-
|
|
97
|
-
rest = u
|
|
98
|
-
if rest.length >= 7 && rest[0, 7] == "http://"
|
|
99
|
-
out["scheme"] = "http"
|
|
100
|
-
out["port"] = "80"
|
|
101
|
-
rest = rest[7, rest.length - 7]
|
|
102
|
-
elsif rest.length >= 8 && rest[0, 8] == "https://"
|
|
103
|
-
out["scheme"] = "https"
|
|
104
|
-
out["port"] = "443"
|
|
105
|
-
rest = rest[8, rest.length - 8]
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
if out["scheme"].length > 0
|
|
109
|
-
slash = Tep.str_find(rest, "/", 0)
|
|
110
|
-
hostport = rest
|
|
111
|
-
tail = "/"
|
|
112
|
-
if slash >= 0
|
|
113
|
-
hostport = rest[0, slash]
|
|
114
|
-
tail = rest[slash, rest.length - slash]
|
|
115
|
-
end
|
|
116
|
-
colon = Tep.str_find(hostport, ":", 0)
|
|
117
|
-
if colon >= 0
|
|
118
|
-
out["host"] = hostport[0, colon]
|
|
119
|
-
out["port"] = hostport[colon + 1, hostport.length - colon - 1]
|
|
120
|
-
else
|
|
121
|
-
out["host"] = hostport
|
|
122
|
-
end
|
|
123
|
-
rest = tail
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
qi = Tep.str_find(rest, "?", 0)
|
|
127
|
-
if qi >= 0
|
|
128
|
-
out["path"] = rest[0, qi]
|
|
129
|
-
out["query"] = rest[qi + 1, rest.length - qi - 1]
|
|
130
|
-
else
|
|
131
|
-
out["path"] = rest
|
|
132
|
-
end
|
|
133
|
-
if out["path"].length == 0
|
|
134
|
-
out["path"] = "/"
|
|
135
|
-
end
|
|
136
|
-
out
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# "a=1&b=2&c" -> Hash {"a"=>"1","b"=>"2","c"=>""}
|
|
140
|
-
def self.parse_query(s)
|
|
141
|
-
h = Tep.str_hash
|
|
142
|
-
if s.length == 0
|
|
143
|
-
return h
|
|
144
|
-
end
|
|
145
|
-
pairs = s.split("&")
|
|
146
|
-
pairs.each do |pair|
|
|
147
|
-
if pair.length > 0
|
|
148
|
-
eq = Tep.str_find(pair, "=", 0)
|
|
149
|
-
if eq < 0
|
|
150
|
-
h[Url.unescape(pair)] = ""
|
|
151
|
-
else
|
|
152
|
-
k = pair[0, eq]
|
|
153
|
-
v = pair[eq + 1, pair.length - eq - 1]
|
|
154
|
-
h[Url.unescape(k)] = Url.unescape(v)
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
h
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|