upfluence-utils 0.1.2 → 0.2.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.
- checksums.yaml +4 -4
- data/lib/upfluence/endpoint/api_endpoint.rb +2 -72
- data/lib/upfluence/error_logger/null.rb +7 -0
- data/lib/upfluence/http/builder.rb +19 -0
- data/lib/upfluence/http/endpoint/api_endpoint.rb +83 -0
- data/lib/upfluence/http/endpoint/healthcheck.rb +11 -0
- data/lib/upfluence/http/middleware/application_headers.rb +34 -0
- data/lib/upfluence/http/middleware/handle_exception.rb +17 -0
- data/lib/upfluence/http/middleware/logger.rb +39 -0
- data/lib/upfluence/http/server.rb +73 -0
- data/lib/upfluence/mixin/strong_parameters.rb +1 -5
- data/lib/upfluence/utils.rb +0 -1
- data/lib/upfluence/utils/version.rb +1 -1
- data/rbutils.gemspec +2 -0
- metadata +37 -3
- data/lib/upfluence/utils/http/middleware/logger.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4162426d70b7a8ac73a57eaa83dabb1984e9d59c
|
4
|
+
data.tar.gz: fc37016f0ae7d50d8a0e25af7ab4729d707596f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 08424881e4d05ad873a82ff8ebf52994fd43a215e6d36908bd1cdafa92aba71b8438e5866ffbd84eca416fa593767475f3617ad7d0e05c7b85e0210f4ca8252f
|
7
|
+
data.tar.gz: b086601b01b55e85162f208c672b021c7d788fccdeb91f64e85d6644cef8e3ae0dbedaec8d2ae34b1c30a8da82392156aacc833eb8ba53e1e46d9d9d29558b3f
|
@@ -1,78 +1,8 @@
|
|
1
1
|
require 'sinatra'
|
2
|
+
require 'upfluence/http/endpoint/api_endpoint'
|
2
3
|
|
3
4
|
module Upfluence
|
4
5
|
module Endpoint
|
5
|
-
|
6
|
-
class ApiEndpoint < Sinatra::Base
|
7
|
-
disable :show_exceptions
|
8
|
-
|
9
|
-
configure :development do
|
10
|
-
require 'sinatra/reloader'
|
11
|
-
register Sinatra::Reloader
|
12
|
-
end
|
13
|
-
|
14
|
-
configure :test do
|
15
|
-
enable :raise_errors
|
16
|
-
end
|
17
|
-
|
18
|
-
helpers do
|
19
|
-
def ok
|
20
|
-
content_type :json
|
21
|
-
[200, { status: 'OK' }.to_json]
|
22
|
-
end
|
23
|
-
|
24
|
-
def access_token
|
25
|
-
token = params[:access_token]
|
26
|
-
|
27
|
-
unless token
|
28
|
-
pattern = /^Bearer /
|
29
|
-
header = request.env['HTTP_AUTHORIZATION']
|
30
|
-
token = header.gsub(pattern, '') if header && header.match(pattern)
|
31
|
-
end
|
32
|
-
|
33
|
-
token
|
34
|
-
end
|
35
|
-
|
36
|
-
def respond_with(resource, *args)
|
37
|
-
if resource.respond_to?(:errors) && resource.errors.any?
|
38
|
-
status = 422
|
39
|
-
result = Base::Exceptions::ValidationError.from_model(
|
40
|
-
resource
|
41
|
-
).to_json
|
42
|
-
else
|
43
|
-
status = 200
|
44
|
-
result = if resource.is_a? Enumerable
|
45
|
-
ActiveModel::ArraySerializer.new(
|
46
|
-
resource, *args
|
47
|
-
).to_json
|
48
|
-
elsif resource.respond_to?(:serialize)
|
49
|
-
resource.serialize(*args).to_json
|
50
|
-
else
|
51
|
-
ActiveModel::Serializer.serializer_for(resource).new(resource, *args).to_json
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
halt [status, result]
|
56
|
-
end
|
57
|
-
|
58
|
-
def json_params
|
59
|
-
ActiveSupport::HashWithIndifferentAccess.new(JSON.parse(request_body))
|
60
|
-
end
|
61
|
-
|
62
|
-
def request_body
|
63
|
-
@request_body ||= request.body.read
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
Sinatra::Base.error BadRequest do
|
69
|
-
status 400
|
70
|
-
{ error: 'Bad request' }.to_json
|
71
|
-
end
|
72
|
-
|
73
|
-
Sinatra::Base.error JSON::ParserError do
|
74
|
-
status 400
|
75
|
-
{ message: 'Invalid JSON' }.to_json
|
76
|
-
end
|
6
|
+
ApiEndpoint = HTTP::Endpoint::APIEndpoint
|
77
7
|
end
|
78
8
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rack/builder'
|
2
|
+
require 'thrift/server/rack_application'
|
3
|
+
require 'upfluence/utils'
|
4
|
+
|
5
|
+
module Upfluence
|
6
|
+
module HTTP
|
7
|
+
class Builder < Rack::Builder
|
8
|
+
def run_thrift(processor, handler, timeout = 30)
|
9
|
+
run Thrift::RackApplication.for(
|
10
|
+
'/',
|
11
|
+
processor.new(
|
12
|
+
Upfluence::Utils::Thrift::Middleware.setup(handler, timeout)
|
13
|
+
),
|
14
|
+
Thrift::BinaryProtocolFactory.new
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
|
3
|
+
module Upfluence
|
4
|
+
module HTTP
|
5
|
+
module Endpoint
|
6
|
+
class BadRequest < StandardError; end
|
7
|
+
class APIEndpoint < Sinatra::Base
|
8
|
+
disable :show_exceptions
|
9
|
+
disable :logging
|
10
|
+
|
11
|
+
configure :development do
|
12
|
+
require 'sinatra/reloader'
|
13
|
+
register Sinatra::Reloader
|
14
|
+
end
|
15
|
+
|
16
|
+
configure :test do
|
17
|
+
enable :raise_errors
|
18
|
+
end
|
19
|
+
|
20
|
+
helpers do
|
21
|
+
def ok
|
22
|
+
content_type :json
|
23
|
+
[200, { status: 'OK' }.to_json]
|
24
|
+
end
|
25
|
+
|
26
|
+
def access_token
|
27
|
+
token = params[:access_token]
|
28
|
+
|
29
|
+
unless token
|
30
|
+
pattern = /^Bearer /
|
31
|
+
header = request.env['HTTP_AUTHORIZATION']
|
32
|
+
token = header.gsub(pattern, '') if header && header.match(pattern)
|
33
|
+
end
|
34
|
+
|
35
|
+
token
|
36
|
+
end
|
37
|
+
|
38
|
+
def respond_with(resource, *args)
|
39
|
+
if resource.respond_to?(:errors) && resource.errors.any?
|
40
|
+
status = 422
|
41
|
+
result = Base::Exceptions::ValidationError.from_model(
|
42
|
+
resource
|
43
|
+
).to_json
|
44
|
+
else
|
45
|
+
status = 200
|
46
|
+
result = if resource.is_a? Enumerable
|
47
|
+
ActiveModel::ArraySerializer.new(
|
48
|
+
resource, *args
|
49
|
+
).to_json
|
50
|
+
elsif resource.respond_to?(:serialize)
|
51
|
+
resource.serialize(*args).to_json
|
52
|
+
else
|
53
|
+
ActiveModel::Serializer.serializer_for(resource).new(resource, *args).to_json
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
halt [status, result]
|
58
|
+
end
|
59
|
+
|
60
|
+
def json_params
|
61
|
+
ActiveSupport::HashWithIndifferentAccess.new(JSON.parse(request_body))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def request_body
|
66
|
+
@request_body ||= request.body.read
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Sinatra::Base.error BadRequest do
|
71
|
+
[400, {}, { error: 'bad_request' }.to_json]
|
72
|
+
end
|
73
|
+
|
74
|
+
Sinatra::Base.error JSON::ParserError do
|
75
|
+
[400, {}, { message: 'invalid_json' }.to_json]
|
76
|
+
end
|
77
|
+
|
78
|
+
Sinatra::Base.not_found do
|
79
|
+
[404, {}, { error: 'not_found' }.to_json]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Upfluence
|
2
|
+
module HTTP
|
3
|
+
module Middleware
|
4
|
+
class ApplicationHeaders
|
5
|
+
def initialize(app, handler)
|
6
|
+
@app = app
|
7
|
+
@headers = {
|
8
|
+
"X-Upfluence-Unit-Name" => handler.getName,
|
9
|
+
"X-Upfluence-Version" => build_version(handler.getVersion)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
status, header, body = @app.call(env)
|
15
|
+
[status, header.merge(@headers), body]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_version(thrift_version)
|
21
|
+
if v = thrift_version.semantic_version
|
22
|
+
return "v#{v.major}.#{v.minor}.#{v.patch}"
|
23
|
+
end
|
24
|
+
|
25
|
+
if v = thrift_version.git_version
|
26
|
+
return "v0.0.0-#{v.commit}"
|
27
|
+
end
|
28
|
+
|
29
|
+
'undefined'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Upfluence
|
2
|
+
module HTTP
|
3
|
+
module Middleware
|
4
|
+
class HandleException
|
5
|
+
def initialize(app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
@app.call(env)
|
11
|
+
rescue StandardError, LoadError, SyntaxError => e
|
12
|
+
[500, {}, ["{\"error\": \"#{e.class.name}\"}"]]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rack/body_proxy'
|
2
|
+
|
3
|
+
module Upfluence
|
4
|
+
module HTTP
|
5
|
+
module Middleware
|
6
|
+
class Logger
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
began_at = Time.now
|
13
|
+
status, header, body = @app.call(env)
|
14
|
+
header = Rack::Utils::HeaderHash.new(header)
|
15
|
+
body = Rack::BodyProxy.new(body) do
|
16
|
+
log(env, status, header, began_at)
|
17
|
+
end
|
18
|
+
[status, header, body]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def log(env, status, _header, began_at)
|
24
|
+
now = Time.now
|
25
|
+
|
26
|
+
Upfluence.logger.info(
|
27
|
+
"%d %s %s%s (%s) %.2fms" % [
|
28
|
+
status, env[Rack::REQUEST_METHOD],
|
29
|
+
env[Rack::PATH_INFO],
|
30
|
+
env[Rack::QUERY_STRING].empty? ? "" : "?"+env[Rack::QUERY_STRING],
|
31
|
+
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
32
|
+
(now - began_at) * 1000
|
33
|
+
]
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rack/handler'
|
2
|
+
require 'rack/etag'
|
3
|
+
|
4
|
+
require 'upfluence/environment'
|
5
|
+
require 'upfluence/error_logger'
|
6
|
+
|
7
|
+
require 'upfluence/http/builder'
|
8
|
+
require 'upfluence/http/endpoint/healthcheck'
|
9
|
+
require 'upfluence/http/middleware/logger'
|
10
|
+
require 'upfluence/http/middleware/application_headers'
|
11
|
+
require 'upfluence/http/middleware/handle_exception'
|
12
|
+
require 'upfluence/handler/base'
|
13
|
+
|
14
|
+
module Upfluence
|
15
|
+
module HTTP
|
16
|
+
class Server
|
17
|
+
DEFAULT_OPTIONS = {
|
18
|
+
server: :thin,
|
19
|
+
Port: ENV['PORT'] || 8080,
|
20
|
+
Host: '0.0.0.0',
|
21
|
+
threaded: true,
|
22
|
+
interfaces: []
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
def initialize(options = {}, &block)
|
26
|
+
@options = DEFAULT_OPTIONS.dup.merge(options)
|
27
|
+
opts = @options
|
28
|
+
base_handler = Handler::Base.new(opts[:interfaces])
|
29
|
+
|
30
|
+
@builder = Builder.new do
|
31
|
+
use Middleware::Logger
|
32
|
+
use Middleware::ApplicationHeaders, base_handler
|
33
|
+
use Middleware::HandleException
|
34
|
+
use Upfluence.error_logger.middleware
|
35
|
+
use Rack::ContentLength
|
36
|
+
use Rack::Chunked
|
37
|
+
use Rack::Lint if Upfluence.env.development?
|
38
|
+
use Rack::TempfileReaper
|
39
|
+
use Rack::ETag
|
40
|
+
|
41
|
+
map '/healthcheck' do
|
42
|
+
run(opts[:healthcheck_endpoint] || Endpoint::Healthcheck.new)
|
43
|
+
end
|
44
|
+
|
45
|
+
map '/base' do
|
46
|
+
run_thrift Base::BaseService::Processor, base_handler
|
47
|
+
end
|
48
|
+
|
49
|
+
instance_eval(&block)
|
50
|
+
end
|
51
|
+
|
52
|
+
@handler = Rack::Handler.get(@options[:server])
|
53
|
+
|
54
|
+
if @options[:server] == :thin
|
55
|
+
require 'thin/logging'
|
56
|
+
|
57
|
+
Thin::Logging.silent = true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def serve
|
62
|
+
ENV['RACK_ENV'] = Upfluence.env.to_s
|
63
|
+
@handler.run(@builder, @options) do |server|
|
64
|
+
server.threaded = @options[:threaded] if server.respond_to? :threaded=
|
65
|
+
|
66
|
+
if server.respond_to?(:threadpool_size=) && @options[:threadpool_size]
|
67
|
+
server.threadpool_size = @options[:threadpool_size]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -254,11 +254,7 @@ module Upfluence
|
|
254
254
|
end
|
255
255
|
|
256
256
|
def json_params
|
257
|
-
|
258
|
-
@_json_params ||= Parameters.new(super)
|
259
|
-
rescue
|
260
|
-
raise "You must extend Upfluence::Endpoint::ApiEndpoint to use json_params"
|
261
|
-
end
|
257
|
+
@_json_params ||= Parameters.new(super)
|
262
258
|
end
|
263
259
|
|
264
260
|
def json_params=(val)
|
data/lib/upfluence/utils.rb
CHANGED
data/rbutils.gemspec
CHANGED
@@ -26,5 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_runtime_dependency 'sentry-raven'
|
27
27
|
spec.add_runtime_dependency 'sinatra-contrib'
|
28
28
|
spec.add_runtime_dependency 'activesupport'
|
29
|
+
spec.add_runtime_dependency 'thin'
|
30
|
+
spec.add_runtime_dependency 'rack'
|
29
31
|
spec.add_runtime_dependency 'active_model_serializers', '~> 0.9.0'
|
30
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: upfluence-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Upfluence
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -156,6 +156,34 @@ dependencies:
|
|
156
156
|
- - ">="
|
157
157
|
- !ruby/object:Gem::Version
|
158
158
|
version: '0'
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: thin
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :runtime
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - ">="
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: rack
|
175
|
+
requirement: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
type: :runtime
|
181
|
+
prerelease: false
|
182
|
+
version_requirements: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
159
187
|
- !ruby/object:Gem::Dependency
|
160
188
|
name: active_model_serializers
|
161
189
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,10 +220,16 @@ files:
|
|
192
220
|
- lib/upfluence/error_logger/null.rb
|
193
221
|
- lib/upfluence/error_logger/sentry.rb
|
194
222
|
- lib/upfluence/handler/base.rb
|
223
|
+
- lib/upfluence/http/builder.rb
|
224
|
+
- lib/upfluence/http/endpoint/api_endpoint.rb
|
225
|
+
- lib/upfluence/http/endpoint/healthcheck.rb
|
226
|
+
- lib/upfluence/http/middleware/application_headers.rb
|
227
|
+
- lib/upfluence/http/middleware/handle_exception.rb
|
228
|
+
- lib/upfluence/http/middleware/logger.rb
|
229
|
+
- lib/upfluence/http/server.rb
|
195
230
|
- lib/upfluence/logger.rb
|
196
231
|
- lib/upfluence/mixin/strong_parameters.rb
|
197
232
|
- lib/upfluence/utils.rb
|
198
|
-
- lib/upfluence/utils/http/middleware/logger.rb
|
199
233
|
- lib/upfluence/utils/http/middleware/null.rb
|
200
234
|
- lib/upfluence/utils/thrift.rb
|
201
235
|
- lib/upfluence/utils/thrift/middleware.rb
|
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'rack/body_proxy'
|
2
|
-
|
3
|
-
module Upfluence
|
4
|
-
module Utils
|
5
|
-
module HTTP
|
6
|
-
module Middleware
|
7
|
-
class Logger
|
8
|
-
def initialize(app)
|
9
|
-
@app = app
|
10
|
-
end
|
11
|
-
|
12
|
-
def call(env)
|
13
|
-
began_at = Time.now
|
14
|
-
status, header, body = @app.call(env)
|
15
|
-
header = Rack::Utils::HeaderHash.new(header)
|
16
|
-
body = Rack::BodyProxy.new(body) { log(env, status, header, began_at) }
|
17
|
-
[status, header, body]
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def log(env, status, header, began_at)
|
23
|
-
now = Time.now
|
24
|
-
|
25
|
-
Upfluence.logger.info(
|
26
|
-
"%d %s %s%s (%s) %.2fms\n" % [
|
27
|
-
status, env[Rack::REQUEST_METHOD],
|
28
|
-
env[Rack::PATH_INFO],
|
29
|
-
env[Rack::QUERY_STRING].empty? ? "" : "?"+env[Rack::QUERY_STRING],
|
30
|
-
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
31
|
-
(now - began_at) * 1000
|
32
|
-
]
|
33
|
-
)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|