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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f81e3d2290b40407d5ad7dcf745f261499a2952
4
- data.tar.gz: c1dde053901fb782d8863709c711753c61e8c784
3
+ metadata.gz: 4162426d70b7a8ac73a57eaa83dabb1984e9d59c
4
+ data.tar.gz: fc37016f0ae7d50d8a0e25af7ab4729d707596f6
5
5
  SHA512:
6
- metadata.gz: 52ad714f7e763d782d73e71712e69c4261b59291ae6dbb442db23c52f3f6d45206384942d722d3782f86ffaa3d2649cc8f3b81b54c9bc8553fddd2cf2e1fab5e
7
- data.tar.gz: d70bcb3de7d6f27a72d0f69239645cc0ae36adf9b7cbade9d509ab60979fa7461f2c8eb26bb5cdd68fdcf8d0712466b172cb515c1f0987e78f8b9717dbbd1faa
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
- class BadRequest < StandardError; end
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
@@ -8,6 +8,13 @@ module Upfluence
8
8
 
9
9
  def call(env)
10
10
  @app.call(env)
11
+ rescue => e
12
+ Upfluence.logger.error("Error: #{e.class}: #{e.message}")
13
+ e.backtrace.each do |b|
14
+ Upfluence.logger.error("\t#{b}")
15
+ end
16
+
17
+ raise e
11
18
  end
12
19
  end
13
20
 
@@ -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,11 @@
1
+ module Upfluence
2
+ module HTTP
3
+ module Endpoint
4
+ class Healthcheck
5
+ def call(_env)
6
+ [200, {}, ["ok\n"]]
7
+ end
8
+ end
9
+ end
10
+ end
11
+ 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
- begin
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)
@@ -1,6 +1,5 @@
1
1
  require 'upfluence/utils/version'
2
2
  require 'upfluence/utils/thrift'
3
- require 'upfluence/utils/http/middleware/logger'
4
3
  require 'upfluence/logger'
5
4
  require 'upfluence/error_logger'
6
5
  require 'upfluence/environment'
@@ -1,5 +1,5 @@
1
1
  module Upfluence
2
2
  module Utils
3
- VERSION = '0.1.2'.freeze
3
+ VERSION = '0.2.0'.freeze
4
4
  end
5
5
  end
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.1.2
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-07-10 00:00:00.000000000 Z
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