funnel_http 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,78 @@
1
+ github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
2
+ github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
3
+ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
4
+ github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
5
+ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
6
+ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
7
+ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
8
+ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
9
+ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10
+ github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
11
+ github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
12
+ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
13
+ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
14
+ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
15
+ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
16
+ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
17
+ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
18
+ github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
19
+ github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
20
+ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
21
+ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
22
+ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
23
+ github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
24
+ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
25
+ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
26
+ github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
27
+ github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
28
+ github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
29
+ github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
30
+ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
31
+ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
32
+ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
33
+ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
34
+ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
35
+ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
36
+ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
37
+ github.com/ruby-go-gem/go-gem-wrapper v0.5.1 h1:TFGH/eOJl0uYzYMwrcLbZxXNQiQbQjCq/VLXyRk1HRM=
38
+ github.com/ruby-go-gem/go-gem-wrapper v0.5.1/go.mod h1:k2k+LziSCMxNYP4J9/9v90xdU6zlU1DJpJDTU6oJhHE=
39
+ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
40
+ github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
41
+ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
42
+ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
43
+ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
44
+ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
45
+ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
46
+ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
47
+ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
48
+ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
49
+ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
50
+ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
51
+ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
52
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
53
+ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
54
+ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
55
+ golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
56
+ golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
57
+ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
58
+ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
59
+ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
60
+ golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
61
+ golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
62
+ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
63
+ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
64
+ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
65
+ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
66
+ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
67
+ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
68
+ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
69
+ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
70
+ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
71
+ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
72
+ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
73
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
74
+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
75
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
76
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
77
+ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
78
+ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -0,0 +1,77 @@
1
+ package main
2
+
3
+ import (
4
+ "bytes"
5
+ "github.com/cockroachdb/errors"
6
+ "golang.org/x/sync/errgroup"
7
+ "io"
8
+ "net/http"
9
+ )
10
+
11
+ // Request is proxy between CRuby and Go
12
+ type Request struct {
13
+ Method string
14
+ URL string
15
+ Header map[string][]string
16
+ }
17
+
18
+ // Response is proxy between CRuby and Go
19
+ type Response struct {
20
+ StatusCode int
21
+ Header map[string][]string
22
+ Body []byte
23
+ }
24
+
25
+ // RunRequests perform HTTP requests in parallel
26
+ func RunRequests(httpClient *http.Client, requests []Request) ([]Response, error) {
27
+ g := new(errgroup.Group)
28
+ responses := make([]Response, len(requests))
29
+
30
+ for i, request := range requests {
31
+ // https://golang.org/doc/faq#closures_and_goroutines
32
+ i := i
33
+ request := request
34
+
35
+ g.Go(func() error {
36
+ var body []byte
37
+ httpReq, err := http.NewRequest(request.Method, request.URL, bytes.NewBuffer(body))
38
+ if err != nil {
39
+ return errors.WithStack(err)
40
+ }
41
+
42
+ for key, values := range request.Header {
43
+ for _, value := range values {
44
+ httpReq.Header.Add(key, value)
45
+ }
46
+ }
47
+
48
+ httpResp, err := httpClient.Do(httpReq)
49
+ if err != nil {
50
+ return errors.WithStack(err)
51
+ }
52
+ defer httpResp.Body.Close()
53
+
54
+ responses[i].StatusCode = httpResp.StatusCode
55
+
56
+ buf, err := io.ReadAll(httpResp.Body)
57
+ if err != nil {
58
+ return errors.WithStack(err)
59
+ }
60
+
61
+ responses[i].Body = buf
62
+ responses[i].Header = map[string][]string{}
63
+
64
+ for key, values := range httpResp.Header {
65
+ responses[i].Header[key] = append(responses[i].Header[key], values...)
66
+ }
67
+
68
+ return nil
69
+ })
70
+ }
71
+
72
+ if err := g.Wait(); err != nil {
73
+ return []Response{}, errors.WithStack(err)
74
+ }
75
+
76
+ return responses, nil
77
+ }
@@ -0,0 +1,120 @@
1
+ package main_test
2
+
3
+ import (
4
+ "github.com/jarcoal/httpmock"
5
+ "github.com/stretchr/testify/assert"
6
+ "github.com/sue445/funnel_http"
7
+ "net/http"
8
+ "testing"
9
+ )
10
+
11
+ func TestRunRequests(t *testing.T) {
12
+ httpmock.Activate()
13
+ t.Cleanup(httpmock.DeactivateAndReset)
14
+
15
+ httpmock.RegisterResponder("GET", "http://example.com/1",
16
+ func(req *http.Request) (*http.Response, error) {
17
+ resp := httpmock.NewStringResponse(200, "GET http://example.com/1")
18
+
19
+ resp.Header.Set("Content-Type", "text/plain")
20
+
21
+ for key, values := range req.Header {
22
+ for _, value := range values {
23
+ resp.Header.Add(key, value)
24
+ }
25
+ }
26
+
27
+ return resp, nil
28
+ })
29
+
30
+ httpmock.RegisterResponder("GET", "http://example.com/2",
31
+ func(req *http.Request) (*http.Response, error) {
32
+ resp := httpmock.NewStringResponse(200, "GET http://example.com/2")
33
+
34
+ resp.Header.Set("Content-Type", "text/plain")
35
+
36
+ for key, values := range req.Header {
37
+ for _, value := range values {
38
+ resp.Header.Add(key, value)
39
+ }
40
+ }
41
+
42
+ return resp, nil
43
+ })
44
+
45
+ tests := []struct {
46
+ name string
47
+ requests []main.Request
48
+ expected []main.Response
49
+ }{
50
+ {
51
+ name: "1 request",
52
+ requests: []main.Request{
53
+ {
54
+ Method: "GET",
55
+ URL: "http://example.com/1",
56
+ Header: map[string][]string{
57
+ "X-My-Request-Header": {"a", "b"},
58
+ },
59
+ },
60
+ },
61
+ expected: []main.Response{
62
+ {
63
+ StatusCode: 200,
64
+ Body: []byte("GET http://example.com/1"),
65
+ Header: map[string][]string{
66
+ "Content-Type": {"text/plain"},
67
+ "X-My-Request-Header": {"a", "b"},
68
+ },
69
+ },
70
+ },
71
+ },
72
+ {
73
+ name: "multiple requests",
74
+ requests: []main.Request{
75
+ {
76
+ Method: "GET",
77
+ URL: "http://example.com/1",
78
+ Header: map[string][]string{
79
+ "X-My-Request-Header": {"a", "b"},
80
+ },
81
+ },
82
+ {
83
+ Method: "GET",
84
+ URL: "http://example.com/2",
85
+ Header: map[string][]string{
86
+ "X-My-Request-Header": {"c", "d"},
87
+ },
88
+ },
89
+ },
90
+ expected: []main.Response{
91
+ {
92
+ StatusCode: 200,
93
+ Body: []byte("GET http://example.com/1"),
94
+ Header: map[string][]string{
95
+ "Content-Type": {"text/plain"},
96
+ "X-My-Request-Header": {"a", "b"},
97
+ },
98
+ },
99
+ {
100
+ StatusCode: 200,
101
+ Body: []byte("GET http://example.com/2"),
102
+ Header: map[string][]string{
103
+ "Content-Type": {"text/plain"},
104
+ "X-My-Request-Header": {"c", "d"},
105
+ },
106
+ },
107
+ },
108
+ },
109
+ }
110
+
111
+ httpClient := http.Client{}
112
+ for _, tt := range tests {
113
+ t.Run(tt.name, func(t *testing.T) {
114
+ actual, err := main.RunRequests(&httpClient, tt.requests)
115
+ if assert.NoError(t, err) {
116
+ assert.Equal(t, tt.expected, actual)
117
+ }
118
+ })
119
+ }
120
+ }
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunnelHttp
4
+ class Client
5
+ # @!attribute default_request_header
6
+ # @return [Hash{String => String, Array<String>}]
7
+ attr_accessor :default_request_header
8
+
9
+ # @param default_request_header [Hash{String => String, Array<String>}]
10
+ def initialize(default_request_header: {})
11
+ @default_request_header = {"User-Agent" => USER_AGENT}.merge(default_request_header)
12
+ end
13
+
14
+ # Add header to {default_request_header}
15
+ # @param name [String] Header name
16
+ # @param value [String, Array<String>] Header value
17
+ #
18
+ # @return [Hash{String => String, Array<String>}] {default_request_header} after adding header
19
+ def add_default_request_header(name, value)
20
+ default_request_header.merge!(name => value)
21
+ end
22
+
23
+ # perform HTTP requests in parallel
24
+ #
25
+ # @overload perform(requests)
26
+ # @param requests [Array<Hash{Symbol => Object}>] `Array` of following `Hash`
27
+ # @option requests :method [String, Symbol] **[required]** Request method (e.g. `:get`, `"POST"`)
28
+ # @option requests :url [String] **[required]** Request url
29
+ # @option requests :header [Hash{String => String, Array<String>}, nil] Request header
30
+ #
31
+ # @overload perform(request)
32
+ # @param request [Hash{Symbol => Object}]
33
+ # @option request :method [String, Symbol] **[required]** Request method (e.g. `:get`, `"POST"`)
34
+ # @option request :url [String] **[required]** Request url
35
+ # @option request :header [Hash{String => String, Array<String>}, nil] Request header
36
+ #
37
+ # @return [Array<Hash<Symbol => Object>>] `Array` of following `Hash`
38
+ # @return [Integer] `:status_code`
39
+ # @return [String] `:body` Response body
40
+ # @return [Hash{String => Array<String>}] `:header` Response header
41
+ def perform(requests)
42
+ ext_client.run_requests(normalize_requests(requests))
43
+ end
44
+
45
+ # @overload normalize_requests(requests)
46
+ # @param requests [Array<Hash{Symbol => Object}>] `Array` of following `Hash`
47
+ # @option requests :method [String, Symbol] **[required]** Request method (e.g. `:get`, `"POST"`)
48
+ # @option requests :url [String] **[required]** Request url
49
+ # @option requests :header [Hash{String => String, Array<String>}, nil] Request header
50
+ #
51
+ # @overload normalize_requests(request)
52
+ # @param request [Hash{Symbol => Object}]
53
+ # @option request :method [String, Symbol] **[required]** Request method (e.g. `:get`, `"POST"`)
54
+ # @option request :url [String] **[required]** Request url
55
+ # @option request :header [Hash{String => String, Array<String>}, nil] Request header
56
+ #
57
+ # @return [Array<Hash{Symbol => Object}>] `Array` of following `Hash`
58
+ # @return [String] `:method` Request method (e.g. `"POST"`)
59
+ # @return [String] `:url` Request url
60
+ # @return [Hash{String => Array<String>}] `:header` Request header
61
+ def normalize_requests(arg)
62
+ requests =
63
+ case arg
64
+ when Array
65
+ arg
66
+ when Hash
67
+ [arg]
68
+ else
69
+ raise ArgumentError, "#{arg} must be Array or Hash"
70
+ end
71
+
72
+ requests.map do |request|
73
+ raise ArgumentError, "#{arg} contains something other than Hash" unless request.is_a?(Hash)
74
+
75
+ raise ArgumentError, "#{arg} key does not contain all :method and :url" if !request.key?(:method) || !request.key?(:url)
76
+
77
+ {
78
+ url: request[:url].to_s,
79
+ method: request[:method].to_s.upcase,
80
+ header: normalize_header(request[:header]),
81
+ }
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ # @param header [Hash{String => String, Array<String>}, nil] Request header
88
+ # @return [Hash{String => Array<String>}] Request header
89
+ def normalize_header(header)
90
+ full_header =
91
+ if header
92
+ default_request_header.dup.merge(header)
93
+ else
94
+ default_request_header.dup
95
+ end
96
+
97
+ # Workaround for Ruby::UnannotatedEmptyCollection on steep 1.9.0+
98
+ result = {} #: strict_header
99
+
100
+ full_header.each_with_object(result) do |(k, v), hash|
101
+ # FIXME: Fails `steep check` when use Array(v)...
102
+ # hash[k] = Array(v)
103
+ hash[k] = v.is_a?(Array) ? v : Array(v)
104
+ end
105
+ end
106
+
107
+ # @return [FunnelHttp::Ext::Client]
108
+ def ext_client
109
+ @ext_client ||= FunnelHttp::Ext::Client.new
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunnelHttp
4
+ module Ext
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FunnelHttp
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "funnel_http/version"
4
+ require_relative "funnel_http/client"
5
+ require_relative "funnel_http/ext"
6
+ require_relative "funnel_http/funnel_http"
7
+
8
+ module FunnelHttp
9
+ class Error < StandardError; end
10
+
11
+ USER_AGENT = "funnel_http/#{FunnelHttp::VERSION} (+https://github.com/sue445/funnel_http)"
12
+
13
+ # Your code goes here...
14
+ end
@@ -0,0 +1,68 @@
1
+ ---
2
+ path: ".gem_rbs_collection"
3
+ gems:
4
+ - name: base64
5
+ version: '0'
6
+ source:
7
+ type: stdlib
8
+ - name: cgi
9
+ version: '0'
10
+ source:
11
+ type: stdlib
12
+ - name: diff-lcs
13
+ version: '1.5'
14
+ source:
15
+ type: git
16
+ name: ruby/gem_rbs_collection
17
+ revision: 0a6ea105a0afc7eaee4494585a7775f47eea6145
18
+ remote: https://github.com/ruby/gem_rbs_collection.git
19
+ repo_dir: gems
20
+ - name: fileutils
21
+ version: '0'
22
+ source:
23
+ type: stdlib
24
+ - name: logger
25
+ version: '0'
26
+ source:
27
+ type: stdlib
28
+ - name: monitor
29
+ version: '0'
30
+ source:
31
+ type: stdlib
32
+ - name: rack
33
+ version: '2.2'
34
+ source:
35
+ type: git
36
+ name: ruby/gem_rbs_collection
37
+ revision: 0a6ea105a0afc7eaee4494585a7775f47eea6145
38
+ remote: https://github.com/ruby/gem_rbs_collection.git
39
+ repo_dir: gems
40
+ - name: rake
41
+ version: '13.0'
42
+ source:
43
+ type: git
44
+ name: ruby/gem_rbs_collection
45
+ revision: 0a6ea105a0afc7eaee4494585a7775f47eea6145
46
+ remote: https://github.com/ruby/gem_rbs_collection.git
47
+ repo_dir: gems
48
+ - name: sinatra
49
+ version: '4.0'
50
+ source:
51
+ type: git
52
+ name: ruby/gem_rbs_collection
53
+ revision: 0a6ea105a0afc7eaee4494585a7775f47eea6145
54
+ remote: https://github.com/ruby/gem_rbs_collection.git
55
+ repo_dir: gems
56
+ - name: stringio
57
+ version: '0'
58
+ source:
59
+ type: stdlib
60
+ - name: tempfile
61
+ version: '0'
62
+ source:
63
+ type: stdlib
64
+ - name: uri
65
+ version: '0'
66
+ source:
67
+ type: stdlib
68
+ gemfile_lock_path: Gemfile.lock
@@ -0,0 +1,24 @@
1
+ # Download sources
2
+ sources:
3
+ - type: git
4
+ name: ruby/gem_rbs_collection
5
+ remote: https://github.com/ruby/gem_rbs_collection.git
6
+ revision: main
7
+ repo_dir: gems
8
+
9
+ # You can specify local directories as sources also.
10
+ # - type: local
11
+ # path: path/to/your/local/repository
12
+
13
+ # A directory to install the downloaded RBSs
14
+ path: .gem_rbs_collection
15
+
16
+ gems:
17
+ - name: rbs
18
+ ignore: true
19
+ - name: steep
20
+ ignore: true
21
+ - name: yard
22
+ ignore: true
23
+ - name: funnel_http
24
+ ignore: true
@@ -0,0 +1,21 @@
1
+ module FunnelHttp
2
+ class Client
3
+ @ext_client: FunnelHttp::Ext::Client
4
+
5
+ attr_accessor default_request_header: fuzzy_header
6
+
7
+ def initialize: (?default_request_header: fuzzy_header) -> void
8
+
9
+ def add_default_request_header: (String name, String | Array[String] value) -> fuzzy_header
10
+
11
+ def perform: (fuzzy_request | Array[fuzzy_request] requests) -> Array[response]
12
+
13
+ def normalize_requests: (fuzzy_request | Array[fuzzy_request] arg) -> Array[strict_request]
14
+
15
+ private
16
+
17
+ def normalize_header: (fuzzy_header? header) -> strict_header
18
+
19
+ def ext_client: () -> FunnelHttp::Ext::Client
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module FunnelHttp
2
+ module Ext
3
+ # defined in ext/funnel_http/funnel_http.go
4
+ class Client
5
+ def run_requests: (Array[strict_request] requests) -> Array[response]
6
+ end
7
+
8
+ class GoData
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ module FunnelHttp
2
+ VERSION: String
3
+ USER_AGENT: String
4
+
5
+ class Error < StandardError
6
+ end
7
+
8
+ type fuzzy_header = Hash[String, String | Array[String]]
9
+
10
+ type fuzzy_request = {
11
+ method: String | Symbol,
12
+ url: String,
13
+ header: fuzzy_header?
14
+ }
15
+
16
+ type strict_header = Hash[String, Array[String]]
17
+
18
+ type strict_request = {
19
+ method: String,
20
+ url: String,
21
+ header: strict_header
22
+ }
23
+
24
+ type response = {
25
+ status_code: Integer,
26
+ body: String,
27
+ header: strict_header
28
+ }
29
+
30
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
31
+ end