upfluence-utils 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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