Related
When I send messages via a faye-websocket server as middleware, I find the message doesn't send until after the block finishes.
Here's a few examples I've tried:
No threading
require 'faye/websocket'
require 'eventmachine'
require 'json'
Faye::WebSocket.load_adapter('thin')
module SocketTest
class Websocket
def initialize(app)
#app = app
end
def long_function()
sleep 20
"foo"
end
def call(env)
EM.run {
if Faye::WebSocket.websocket?(env)
ws = Faye::WebSocket.new(env, nil, {ping: 15 })
ws.on :open do |event|
response = {
:responseCode => 100,
:message => "Connection opened"
}
$logger.info "< #{response.to_json}"
ws.send(response.to_json)
end
ws.on :message do |event|
response = {
:responseCode => 100,
:message => "Received request, running slow function"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
long_function_result = long_function()
response = {
:responseCode => 200,
:message => "Long function ran, result is #{long_function_result}"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
ws.close()
end
ws.on :close do |event|
$logger.info "< CLOSE"
ws = nil
end
# Return async Rack response
ws.rack_response
else
#app.call(env)
end
}
end
end
end
Chrome output
5:25:09pm WebSocket Connection Established
5:25:09pm {"request":"test"}
5:25:09pm {"responseCode":100,"message":"Connection opened"}
5:25:30pm {"responseCode":100,"message":"Received request, running slow function"}
5:25:30pm {"responseCode":200,"message":"Long function ran, result is foo"}
5:25:30pm Connection Close Frame
5:25:30pm Connection Close Frame
Console output
I, [2020-01-15T17:25:10.006006 #25394] INFO -- : < {"responseCode":100,"message":"Connection opened"}
I, [2020-01-15T17:25:10.024170 #25394] INFO -- : < {"responseCode":100,"message":"Received request, running slow function"}
I, [2020-01-15T17:25:30.034885 #25394] INFO -- : < {"responseCode":200,"message":"Long function ran, result is foo"}I, [2020-01-15T06:25:30.189606 #25394] INFO -- : < CLOSE
As we can see above, the logger output is is immediate (17:25:09) for "Received request, running slow function", however the additional 20 seconds are taken for the response to be sent to the client. I've noticed the same thing with PING/PONG messages - nothing comes from the WebSocket server until the blocking sleep finishes.
I've also tried a modified version like this:
Threading off
# Just the call function, all other parts are the same
def call(env)
EM.run {
if Faye::WebSocket.websocket?(env)
ws = Faye::WebSocket.new(env, nil, {ping: 15 })
ws.on :open do |event|
response = {
:responseCode => 100,
:message => "Connection opened"
}
$logger.info "< #{response.to_json}"
ws.send(response.to_json)
end
ws.on :message do |event|
response = {
:responseCode => 100,
:message => "Received request, running slow function"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
long_function = Thread.new { long_function() }
until (long_function.alive? == false) do
response = {
:responseCode => 100,
:message => "Waiting for long function to complete"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
sleep 5
end
response = {
:responseCode => 200,
:message => "Long function ran, result is #{long_function.value}"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
ws.close()
end
ws.on :close do |event|
$logger.info "< CLOSE"
ws = nil
end
# Return async Rack response
ws.rack_response
else
#app.call(env)
end
}
end
Chrome output
5:34:33pm WebSocket Connection Established
5:34:33pm {"request":"test"}
5:34:33pm {"responseCode":100,"message":"Connection opened"}
5:34:53pm {"responseCode":100,"message":"Received request, running slow function"}
5:34:53pm {"responseCode":100,"message":"Waiting for long function to complete"}
5:34:53pm {"responseCode":100,"message":"Waiting for long function to complete"}
5:34:53pm {"responseCode":100,"message":"Waiting for long function to complete"}
5:34:53pm {"responseCode":100,"message":"Waiting for long function to complete"}
5:34:53pm {"responseCode":200,"message":"Long function ran, result is foo"}
5:34:53pm Connection Close Frame
5:34:53pm Connection Close Frame
Console output
I, [2020-01-15T17:34:33.473295 #25729] INFO -- : < {"responseCode":100,"message":"Connection opened"}
I, [2020-01-15T17:34:33.489433 #25729] INFO -- : < {"responseCode":100,"message":"Received request, running slow function"}
I, [2020-01-15T17:34:33.489638 #25729] INFO -- : < {"responseCode":100,"message":"Waiting for long function to complete"}
I, [2020-01-15T17:34:38.490995 #25729] INFO -- : < {"responseCode":100,"message":"Waiting for long function to complete"}
I, [2020-01-15T17:34:43.491927 #25729] INFO -- : < {"responseCode":100,"message":"Waiting for long function to complete"}
I, [2020-01-15T17:34:48.497281 #25729] INFO -- : < {"responseCode":100,"message":"Waiting for long function to complete"}
I, [2020-01-15T17:34:53.499446 #25729] INFO -- : < {"responseCode":200,"message":"Long function ran, result is foo"}
I, [2020-01-15T17:34:53.632997 #25729] INFO -- : < CLOSE
The result is the same again, although the $logger object continues to operate whilst waiting for the thread result (indicating to me we are no longer blocking), it appears the WebSocket is still holding and waiting for its buffer. How can I force this buffer out?
Using the add_timer EventMachine function that #max_pleaner suggested I was able to build a working version of the code with internal callbacks to the function to create a loop:
require 'faye/websocket'
require 'eventmachine'
require 'json'
Faye::WebSocket.load_adapter('thin')
module SocketTest
class Websocket
def initialize(app)
#app = app
end
def call(env)
EM.run {
if Faye::WebSocket.websocket?(env)
ws = Faye::WebSocket.new(env, nil, {ping: 15 })
ws.on :open do |event|
response = {
:responseCode => 100,
:message => "Connection opened"
}
$logger.info "< #{response.to_json}"
ws.send(response.to_json)
end
ws.on :message do |event|
response = {
:responseCode => 100,
:message => "Received request, running slow function"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
total_runs = 4
def long_function(ws, count, total_runs)
if count > total_runs then
# Error out
puts "Reached full count, exiting"
ws.close()
return
end
# Logic here
if count == 3 then
response = {
:responseCode => 200,
:message => "Long function ran"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
ws.close()
else
response = {
:responseCode => 100,
:message => "Waiting for long function to complete"
}
ws.send(response.to_json)
$logger.info "< #{response.to_json}"
EventMachine.add_timer(5) {
long_function(ws, count + 1, total_runs)
}
end
end
long_function(ws, 1, total_runs)
end
ws.on :close do |event|
$logger.info "< CLOSE"
ws = nil
end
# Return async Rack response
ws.rack_response
else
#app.call(env)
end
}
end
end
end
I create a sample project in Golang:
sampleapp/
sampleapp/main.go
which has the following code:
package main
import (
"flag"
"fmt"
)
func main() {
var name = flag.String("name", "user1", "user name")
var age = flag.Int("age", 20, "user age")
fmt.Println(*name)
fmt.Println(*age)
}
I followed https://code.visualstudio.com/docs/editor/debugging and created the following launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch file",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/main.go",
"env": {},
"args": []
},
{
"name": "Launch exec",
"type": "go",
"request": "launch",
"mode": "exec",
"program": "${workspaceFolder}/sampleapp",
"env": {},
"args": []
}
]
}
When I use Launch File debug mode setting breakpoints on main - I am able to single step through the program and can see the values of username and age as follows:
But when I use Launch exec debug mode after building the app like so:
go build
I can single step through the code but the Local section hangs with a spinner going on continuously and doesn't show any local variables as per the following:
I have to do a Reload window to get rid of the hanging Local vars spinner. I checked vscode issues and saw https://github.com/microsoft/vscode-go/issues/2444 but in that case the variables are not shown when there is a panic. But in my case, I am just printing 2 variables.
I thought it might be an issue with my dlv installation but when I debugged using dlv with the executable, I was able to get the values (deleting unnecessary lines from dlv output):
dlv exec sampleapp
Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x109e1f3 for main.main() ./main.go:8
(dlv) s
> main.main() ./main.go:8 (hits goroutine(1):1 total:1) (PC: 0x109e1f3)
Warning: debugging optimized function
3: import (
4: "flag"
5: "fmt"
6: )
7:
=> 8: func main() {
9: var name = flag.String("name", "user1", "user name")
10: var age = flag.Int("age", 20, "user age")
11: fmt.Println(*name)
12: fmt.Println(*age)
13: }
(dlv) s
> main.main() ./main.go:9 (PC: 0x109e202)
Warning: debugging optimized function
4: "flag"
5: "fmt"
6: )
7:
8: func main() {
=> 9: var name = flag.String("name", "user1", "user name")
10: var age = flag.Int("age", 20, "user age")
11: fmt.Println(*name)
12: fmt.Println(*age)
13: }
(dlv) s
> main.main() ./main.go:11 (PC: 0x109e29f)
Warning: debugging optimized function
6: )
7:
8: func main() {
9: var name = flag.String("name", "user1", "user name")
10: var age = flag.Int("age", 20, "user age")
=> 11: fmt.Println(*name)
12: fmt.Println(*age)
13: }
(dlv) stepout
user1
> main.main() ./main.go:12 (PC: 0x109e31a)
Warning: debugging optimized function
7:
8: func main() {
9: var name = flag.String("name", "user1", "user name")
10: var age = flag.Int("age", 20, "user age")
11: fmt.Println(*name)
=> 12: fmt.Println(*age)
13: }
(dlv) p name
*"user1"
(dlv) p age
*20
Is there something very basic that I am missing here?
I could reproduce your issue initially but after I upgrade to VSCode Version 1.35.1 (I am on MacOSX), the issue is gone. I can see the variable values during debug with "Launch exec"
I think the compiler optimisation made it problematic. Should works fine for executable built with
go build -gcflags=all="-N -l"
-N: disable optimization
-l: disable inlining
Golang officially suggested it as well: https://golang.org/doc/gdb
I am trying to setup a simple password encryption using mongoid-bcrypt-ruby mongoid and sinatra i am also developing on a windows machine
unfortunately whenever I try to persist a new user i get an error from my User.create!() call saying invalid hash
# gemfile
ruby "2.2.4"
source "http://rubygems.org"
gem "sinatra", require: "sinatra/base"
gem "sinatra-contrib", require: "sinatra/namespace"
gem "rack"
gem "thin"
gem "mongoid"
gem "mongoid-bcrypt-ruby"
user model
class User
include Mongoid::Document
include Mongoid::Timestamps
store_in collection: :users
field :first_name, type: String
field :last_name, type: String
field :email, type: String
field :phone_number, type: String
field :password, type: BCrypt::Password
field :is_active, type: Boolean, default: false
field :is_admin, type: Boolean, default: false
# ....
end
class Routes
# ....
post '/submit' do
User.create!(
first_name: params['first_name'],
last_name: params['last_name'],
email: params['email'],
phone_number: params['phone_number'],
password: params['password']
)
end
end
Trace from Sinatra's error page:
BCrypt::Errors::InvalidHash at /api/v1/new_user
invalid hash
file: password.rb location: initialize line: 60
Full Backtrace from Sinatra's error page:
C:/Ruby22/lib/ruby/gems/2.2.0/gems/bcrypt-3.1.11-x86-mingw32/lib/bcrypt/password.rb in initialize
raise Errors::InvalidHash.new("invalid hash")
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-bcrypt-ruby-0.0.2/lib/mongoid/bcrypt/ruby.rb in new
when String then self.new(password)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-bcrypt-ruby-0.0.2/lib/mongoid/bcrypt/ruby.rb in demongoize
when String then self.new(password)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/fields/standard.rb in demongoize
delegate :demongoize, :evolve, :mongoize, to: :type
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/fields.rb in block (2 levels) in create_field_getter
value = field.demongoize(raw)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/validatable.rb in read_attribute_for_validation
send(attr)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validator.rb in block in validate
value = record.read_attribute_for_validation(attribute)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validator.rb in each
attributes.each do |attribute|
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validator.rb in validate
attributes.each do |attribute|
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in public_send
filter.public_send method_to_call, target, &blk
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in block in make_lambda
filter.public_send method_to_call, target, &blk
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in call
result_lambda = -> { user_callback.call target, value }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in block (2 levels) in halting
result_lambda = -> { user_callback.call target, value }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in call
result_lambda.call if result_lambda.is_a?(Proc)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in block (2 levels) in default_terminator
result_lambda.call if result_lambda.is_a?(Proc)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in catch
catch(:abort) do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in block in default_terminator
catch(:abort) do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in call
env.halted = halted_lambda.call(target, result_lambda)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in block in halting
env.halted = halted_lambda.call(target, result_lambda)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in call
#before.each { |b| b.call(arg) }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in block in call
#before.each { |b| b.call(arg) }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in each
#before.each { |b| b.call(arg) }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in call
#before.each { |b| b.call(arg) }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in __run_callbacks__
runner.call(e).value
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in _run_validate_callbacks
__run_callbacks__(_#{name}_callbacks, &block)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validations.rb in run_validations!
_run_validate_callbacks
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validations/callbacks.rb in block in run_validations!
_run_validation_callbacks { super }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in __run_callbacks__
yield if block_given?
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activesupport-5.0.0.1/lib/active_support/callbacks.rb in _run_validation_callbacks
__run_callbacks__(_#{name}_callbacks, &block)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validations/callbacks.rb in run_validations!
_run_validation_callbacks { super }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validations.rb in valid?
run_validations!
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/validatable.rb in valid?
super context ? context : (new_record? ? :create : :update)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/activemodel-5.0.0.1/lib/active_model/validations.rb in invalid?
!valid?(context)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/persistable/creatable.rb in prepare_insert
invalid?(options[:context] || :create)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/persistable/creatable.rb in insert
prepare_insert(options) do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/persistable/creatable.rb in block in create!
doc.fail_due_to_validation! unless doc.insert.errors.empty?
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/threaded/lifecycle.rb in _creating
yield
C:/Ruby22/lib/ruby/gems/2.2.0/gems/mongoid-6.0.2/lib/mongoid/persistable/creatable.rb in create!
_creating do
C:/Users/ALilland/Documents/macros/experiments/mongoid/mongoid_heroku/db_core_app/models/user.rb in block (2 levels) in <class:Routes>
User.create!(
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call
proc { |a,p| unbound_method.bind(a).call }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in compile!
proc { |a,p| unbound_method.bind(a).call }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in []
route_eval { block[*args] }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block (3 levels) in route!
route_eval { block[*args] }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in route_eval
throw :halt, yield
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block (2 levels) in route!
route_eval { block[*args] }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in process_route
block ? block[self, values] : yield(self, values)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in catch
catch(:pass) do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in process_route
catch(:pass) do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in route!
returned_pass_block = process_route(pattern, keys, conditions) do |*args|
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in each
routes.each do |pattern, keys, conditions, block|
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in route!
routes.each do |pattern, keys, conditions, block|
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in dispatch!
route!
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in invoke
res = catch(:halt) { yield }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in catch
res = catch(:halt) { yield }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in invoke
res = catch(:halt) { yield }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in dispatch!
invoke do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in call!
invoke { dispatch! }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in invoke
res = catch(:halt) { yield }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in catch
res = catch(:halt) { yield }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in invoke
res = catch(:halt) { yield }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call!
invoke { dispatch! }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call
dup.call!(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb in call
status, headers, body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
result or app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
result or app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/path_traversal.rb in call
app.call env
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb in call
status, headers, body = app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
result or app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
result or app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb in call
status, headers, body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/session/abstract/id.rb in context
status, headers, body = app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/session/abstract/id.rb in call
context(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/logger.rb in call
#app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call
env['sinatra.commonlogger'] ? #app.call(env) : super
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/head.rb in call
status, headers, body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/show_exceptions.rb in call
#app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call
result, callback = app.call(env), env['async.callback']
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call
#stack.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in block in call
synchronize { prototype.call(env) }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in synchronize
yield
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call
synchronize { prototype.call(env) }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/cascade.rb in block in call
result = app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/cascade.rb in each
#apps.each do |app|
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/cascade.rb in call
#apps.each do |app|
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/tempfile_reaper.rb in call
status, headers, body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/lint.rb in _call
status, headers, #body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/lint.rb in call
dup._call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/showexceptions.rb in call
#app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/commonlogger.rb in call
status, header, body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/sinatra-1.4.7/lib/sinatra/base.rb in call
call_without_check(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/chunked.rb in call
status, headers, body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/content_length.rb in call
status, headers, body = #app.call(env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/thin-1.7.0/lib/thin/connection.rb in block in pre_process
response = #app.call(#request.env)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/thin-1.7.0/lib/thin/connection.rb in catch
catch(:async) do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/thin-1.7.0/lib/thin/connection.rb in pre_process
catch(:async) do
C:/Ruby22/lib/ruby/gems/2.2.0/gems/thin-1.7.0/lib/thin/connection.rb in process
post_process(pre_process)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/thin-1.7.0/lib/thin/connection.rb in receive_data
process if #request.parse(data)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/eventmachine-1.2.1-x86-mingw32/lib/eventmachine.rb in run_machine
run_machine
C:/Ruby22/lib/ruby/gems/2.2.0/gems/eventmachine-1.2.1-x86-mingw32/lib/eventmachine.rb in run
run_machine
C:/Ruby22/lib/ruby/gems/2.2.0/gems/thin-1.7.0/lib/thin/backends/base.rb in start
EventMachine.run(&starter)
C:/Ruby22/lib/ruby/gems/2.2.0/gems/thin-1.7.0/lib/thin/server.rb in start
#backend.start { setup_signals if #setup_signals }
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/handler/thin.rb in run
server.start
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/server.rb in start
server.run wrapped_app, options, &blk
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/lib/rack/server.rb in start
new(options).start
C:/Ruby22/lib/ruby/gems/2.2.0/gems/rack-1.6.5/bin/rackup in <top (required)>
Rack::Server.start
C:/Ruby22/bin/rackup in load
load Gem.bin_path('rack', 'rackup', version)
C:/Ruby22/bin/rackup in <main>
load Gem.bin_path('rack', 'rackup', version)
I had this problem myself. The below worked for me.
You can see from the trace that the problem is the line:
when String then self.new(password)
Change that line to the following:
when String then self.create(password)
I am trying to compress an image before sending a request to an API using this code:
require 'sinatra'
require 'unirest'
require 'mini_magick'
require 'json'
require 'open-uri'
get '/' do
File.read('public/views/index.erb')
end
post '/' do
Unirest.timeout(5)
image = MiniMagick::Image.open(params['user_image'][:tempfile])
image.resize "600x400"
response = Unirest.post 'https://search.craftar.net/v1/search',
parameters: {
token: "703eb042371c49f0",
image: image
}
body = response.body
url = body['results'][0]['item']['url']
redirect url
end
When it runs to get the result, I get the following error:
ArgumentError at /
wrong number of arguments (1 for 0)
/usr/local/Cellar/ruby/2.2.3/lib/ruby/2.2.0/tempfile.rb in open
def open
/usr/local/Cellar/ruby/2.2.3/lib/ruby/2.2.0/open-uri.rb in open
name.open(*rest, &block)
/usr/local/lib/ruby/gems/2.2.0/gems/mini_magick-4.3.6/lib/mini_magick/image.rb in open
Kernel.open(path_or_url, "rb") do |file|
server.rb in block in <main>
image = MiniMagick::Image.open(params['user_image'][:tempfile])
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
proc { |a,p| unbound_method.bind(a).call }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in compile!
proc { |a,p| unbound_method.bind(a).call }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in []
route_eval { block[*args] }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block (3 levels) in route!
route_eval { block[*args] }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in route_eval
throw :halt, yield
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block (2 levels) in route!
route_eval { block[*args] }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in process_route
block ? block[self, values] : yield(self, values)
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in catch
catch(:pass) do
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in process_route
catch(:pass) do
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in route!
returned_pass_block = process_route(pattern, keys, conditions) do |*args|
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in each
routes.each do |pattern, keys, conditions, block|
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in route!
routes.each do |pattern, keys, conditions, block|
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in dispatch!
route!
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in invoke
res = catch(:halt) { yield }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in catch
res = catch(:halt) { yield }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in invoke
res = catch(:halt) { yield }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in dispatch!
invoke do
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in call!
invoke { dispatch! }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in invoke
res = catch(:halt) { yield }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in catch
res = catch(:halt) { yield }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in invoke
res = catch(:halt) { yield }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call!
invoke { dispatch! }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
dup.call!(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb in call
status, headers, body = #app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/path_traversal.rb in call
app.call env
/usr/local/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb in call
status, headers, body = app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
result or app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
result or app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb in call
status, headers, body = #app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/logger.rb in call
#app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/commonlogger.rb in call
status, header, body = #app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
call_without_check(env)
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
env['sinatra.commonlogger'] ? #app.call(env) : super
/usr/local/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/head.rb in call
status, headers, body = #app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/methodoverride.rb in call
#app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/show_exceptions.rb in call
#app.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
result, callback = app.call(env), env['async.callback']
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
#stack.call(env)
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in call
synchronize { prototype.call(env) }
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in synchronize
yield
/usr/local/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
synchronize { prototype.call(env) }
/usr/local/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/handler/webrick.rb in service
status, headers, body = #app.call(env)
/usr/local/Cellar/ruby/2.2.3/lib/ruby/2.2.0/webrick/httpserver.rb in service
si.service(req, res)
/usr/local/Cellar/ruby/2.2.3/lib/ruby/2.2.0/webrick/httpserver.rb in run
server.service(req, res)
/usr/local/Cellar/ruby/2.2.3/lib/ruby/2.2.0/webrick/server.rb in block in start_thread
block ? block.call(sock) : run(sock)
If this doesn't work, how can I extract an image uploaded by a user that is temporarily stored and compress it to the specific requirements that the API needs.
Would appreciate any help!
The code in image.rb is calling Kernel.open on the tempfile. This calls open from open-uri.rb, which calls open on it if the object responds to that. A tempfile responds to open, but does not accept the 'rb' param open-uri delegates from image.rb to it.
I think the easiest solution is to wrap the tempfile into a normal file and to go from there:
image = MiniMagick::Image.open(File.new(params[:user_image][:tempfile]))
The code still fails, but the error (unrecognized option -to-ary') in MiniMagick I think is unrelated.
I want to wrap OptionParser in another function that defines some defaults, but allows
me to overwrite the banner, add separators, and add new options. I am having a hard time passing the relevant information to the on method.
Any advice on how to fix the line options.each { |o, p| opts.on(o, &p) }?
def my_opts (banner: "Usage: ruby #{File::basename($0)} [options]", separators: [], options: {})
option_parser = OptionParser.new do |opts|
opts.banner = banner
separators.each {|s| opts.separator s }
opts.separator ''
opts.separator 'Options:'
opts.on('-u', '--user USER', 'Username for authentication.') { |user| #user = user }
options.each { |o, p| opts.on(o, &p) }
opts.on_tail('--help', 'Print this help message.') { puts opts; exit }
end
return option_parser
end
opts = {['-f', '--file FILE', 'File to read']=>Proc.new { |f| #f=file } }
stdopts = my_opts( options: opts)
HA! figured it out! the line in question needs to be: options.each { |o,p| opts.on(*o, &p) }