Erc20 tokens deposit/withdraw on ruby - ruby
I use Peatio based exchange. Ethereum deposit/withdraw are working, but Binance coin doesn't work. I can't generate binance coin address. My codes below. Is it wring? I reall need help.
require 'net/http'
require 'uri'
require 'json'
class CoinRPC
class JSONRPCError < RuntimeError; end
class ConnectionRefusedError < StandardError; end
def initialize(uri)
#uri = URI.parse(uri)
end
def self.[](currency)
c = Currency.find_by_code(currency.to_s)
if c && c.rpc
name = c[:handler] || 'BTC'
"::CoinRPC::#{name}".constantize.new(c.rpc)
end
end
def method_missing(name, *args)
handle name, *args
end
def handle
raise "Not implemented"
end
class BTC < self
def handle(name, *args)
post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def safe_getbalance
begin
getbalance
rescue
'N/A'
end
end
end
class ETH < self
def handle(name, *args)
post_body = {"jsonrpc" => "2.0", 'method' => name, 'params' => args, 'id' => '1' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def safe_getbalance
begin
(open(#uri.host + '/cgi-bin/total.cgi').read.rstrip.to_f)
rescue
'N/A'
end
end
end
class BNB < self
def handle(name, *args)
post_body = {"jsonrpc" => "2.0", 'method' => name, 'params' => args, 'id' => '1' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def safe_getbalance
begin
(open(#uri.host + '/cgi-bin/total.cgi').read.rstrip.to_f)
rescue
'N/A'
end
end
end
end
My code is parameterized for Binance currencies, I haven't tested the ETH network system, but I verified that the codes are similar.
It costs nothing to test ...
require 'net/http'
require 'uri'
require 'json'
class CoinRPC
class JSONRPCError < RuntimeError; end
class ConnectionRefusedError < StandardError; end
def initialize(coin)
#uri = URI.parse(coin.rpc)
#rest = coin.rest
#coin = coin
end
def self.[](currency)
c = Currency.find_by_code(currency.to_s)
if c && c.rpc
if c.proto == 'ETH'
name = 'ETH'
elsif c.proto == 'BTC'
name = 'BTC'
elsif c.proto == 'OLD_BTC'
name = 'OLD_BTC'
elsif c.proto == 'WOA_BTC'
name = 'WOA_BTC'
elsif c.proto == 'CNT'
name = 'CNT'
else
name = c[:handler]
end
Rails.logger.info "Making class " + name.to_s + "(" + currency.to_s + ")\n"
"::CoinRPC::#{name.to_s}".constantize.new(c)
end
end
def method_missing(name, *args)
handle name, *args
end
def handle
raise "Not implemented"
end
class BTC < self
def handle(name, *args)
post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
#reply = http.request(request).body
# Rails.logger.info #reply
return #reply
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def getnewaddress(name, digest)
#newaddress = handle("getnewaddress", name)
end
def safe_getblockchaininfo
begin
getblockchaininfo
rescue
'N/A'
end
end
def safe_getbalance
begin
getbalance
rescue
'N/A'
end
end
end
class OLD_BTC < self
def handle(name, *args)
post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def getnewaddress(name, digest)
#newaddress = handle("getnewaddress", name)
end
def getblockchaininfo
#getinfo = getinfo()
{
blocks: Integer(#getinfo[:blocks]),
headers: 0,
mediantime: 0
}
end
def safe_getbalance
begin
getbalance
rescue
'N/A'
end
end
end
class WOA_BTC < self
def handle(name, *args)
post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
Rails.logger.info "WOA_BTC " + post_body
resp = JSON.parse( http_post_request(post_body) )
Rails.logger.info resp
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
#Rails.logger.info post_body
#reply = http.request(request).body
#Rails.logger.info #reply
return #reply
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def sendtoaddress(from, address, amount)
handle("sendtoaddress", address, amount)
end
def getnewaddress(name, digest)
#newaddress = handle("getnewaddress", "")
end
def getblockchaininfo
#getinfo = getinfo()
{
blocks: Integer(#getinfo[:blocks]),
headers: 0,
mediantime: 0
}
end
def safe_getbalance
begin
getbalance
rescue
'N/A'
end
end
end
class ETH < self
def handle(name, *args)
post_body = {"jsonrpc" => "2.0", 'method' => name, 'params' => args, 'id' => '1' }.to_json
resp = JSON.parse( http_post_request(post_body) )
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
http.request(request).body
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def safe_getbalance
begin
(open(#uri.host + '/cgi-bin/total.cgi').read.rstrip.to_f)
rescue
'N/A'
end
end
def getblockchaininfo
#lastBlock = eth_getBlockByNumber("latest", true)
#Rails.logger.info #lastBlock
#Rails.logger.info "number = " + Integer(#lastBlock[:number]).to_s + ", timestamp = " + Integer(#lastBlock[:timestamp]).to_s
{
blocks: Integer(#lastBlock[:number]),
headers: 0,
mediantime: Integer(#lastBlock[:timestamp])
}
end
end
class LISK < self
def handle(name, *args)
post_body = {"jsonrpc" => "2.0", 'method' => name, 'params' => args, 'id' => '1' }.to_json
Rails.logger.info "LISK -> " + post_body
resp = JSON.parse( http_post_request(post_body) )
Rails.logger.info "LISK <- " + resp.to_json
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
#reply = http.request(request).body
return #reply
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def http_post_request_body(post_url, post_body)
Rails.logger.info "LISK -> " + post_url + " / " + post_body
uri = URI.parse(post_url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.basic_auth uri.user, uri.password
request.content_type = 'application/json'
request.body = post_body
reply = JSON.parse(http.request(request).body)
raise JSONRPCError, reply['error'] if reply['error']
Rails.logger.info "LISK <- " + reply.to_json
return reply
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def http_get_request(get_url)
Rails.logger.info "LISK -> " + get_url
uri = URI.parse(get_url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
request.basic_auth uri.user, uri.password
request.content_type = ""
request.body = ""
reply = http.request(request).body
result = JSON.parse(reply)
raise JSONRPCError, result['error'] if result['error']
Rails.logger.info "LISK <- " + result.to_json
return result
end
def http_put_request_body(post_url, post_body)
Rails.logger.info "LISK -> " + post_url + " / " + post_body
uri = URI.parse(post_url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Put.new(uri.request_uri)
request.basic_auth uri.user, uri.password
request.content_type = 'application/json'
request.body = post_body
reply = JSON.parse(http.request(request).body)
raise JSONRPCError, reply['error'] if reply['error']
Rails.logger.info "LISK <- " + reply.to_json
return reply
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def safe_getbalance
begin
getbalance
rescue => ex
Rails.logger.info "[error]: " + ex.message + "\n" + ex.backtrace.join("\n") + "\n"
'N/A'
end
end
def getbalance
result = http_get_request("#{#rest}/api/accounts/getBalance?address=#{#coin.base_account}")
balance = result['balance'].to_f / 100000000.0
return balance
end
def gettransaction(txid)
transaction = http_get_request("#{#rest}/api/transactions/get?id=#{txid}")
{
confirmations: transaction['transaction']['confirmations'],
time: Time.now.to_i,
details:
[
address: transaction['transaction']['recipientId'],
amount: transaction['transaction']['amount'].to_f / 100000000.0,
category: "receive"
]
}
end
def settxfee
end
def sendtoaddress(from, address, amount)
parameters =
{
secret: from,
amount: Integer(amount * 100000000.0),
recipientId: address
}.to_json
result = http_put_request_body("#{#rest}/api/transactions", parameters)
return result['transactionId']
end
# digest - simple form usermail & number
def getnewaddress(base_account, digest)
parameters =
{
secret: digest
}.to_json
result = http_post_request_body("#{#rest}/api/accounts/open", parameters)
return result['account']['address']
end
def getfee(size)
return (12000000.0/100000000.0).to_f
end
def validateaddress(address)
end
def getblockchaininfo
result = http_get_request("#{#rest}/api/blocks/getStatus")
{
blocks: Integer(result['height']),
headers: 0,
mediantime: 0
}
end
end
class CNT < self
def handle(name, *args)
post_body = {"jsonrpc" => "2.0", 'method' => name, 'params' => args, 'id' => '1' }.to_json
Rails.logger.info "CNT -> " + post_body
resp = JSON.parse( http_post_request(post_body) )
Rails.logger.info "CNT <- " + resp.to_json
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
#result.symbolize_keys! if result.is_a? Hash
result
end
def handle_one(name, arg)
post_body = {"jsonrpc" => "2.0", 'method' => name, 'params' => arg, 'id' => '1' }.to_json
Rails.logger.info "CNT -> " + post_body
resp = JSON.parse( http_post_request(post_body) )
Rails.logger.info "CNT <- " + resp.to_json
raise JSONRPCError, resp['error'] if resp['error']
result = resp['result']
#result.symbolize_keys! if result.is_a? Hash
result
end
def http_post_request(post_body)
http = Net::HTTP.new(#uri.host, #uri.port)
request = Net::HTTP::Post.new(#uri.request_uri)
#request.basic_auth #uri.user, #uri.password
request.content_type = 'application/json'
request.body = post_body
#reply = http.request(request).body
return #reply
rescue Errno::ECONNREFUSED => e
raise ConnectionRefusedError
end
def safe_getbalance
begin
getbalance
rescue => ex
Rails.logger.info "[error]: " + ex.message + "\n" + ex.backtrace.join("\n") + "\n"
'N/A'
end
end
def getbalance
result = handle("getbalance")
balance = result['balance'].to_f / 1000000000.0
return balance
end
def gettransaction(txid)
parameters =
{
txid: txid
}
transaction = handle_one("get_transfer_by_txid", parameters)
confirmations = Integer(transaction['transfer']['height'])
if confirmations > 0
result = handle("getheight", "")
confirmations = Integer(result['height']) - confirmations
end
result = {
confirmations: confirmations,
time: Time.now.to_i,
details:[]
}
if transaction['transfer']['destinations'] == nil
return result
end
transaction['transfer']['destinations'].each do |destination|
tx = {
address: destination['address'],
amount: destination['amount'].to_f / 1000000000.0,
category: "receive"
}
result[:details].push(tx)
end
return result
end
def settxfee
end
def sendtoaddress(from, address, amount)
parameters =
{
account_index: 0,
destinations:
[
{
amount: Integer(amount * 1000000000.0),
address: address
}
],
get_tx_key: true
}
result = handle_one("transfer", parameters)
return result['tx_hash']
end
def getnewaddress(name, digest)
parameters =
{
account_index: 0,
label: ""
}.to_json
result = handle_one("create_address", parameters)
return result['address']
end
def getfee(size)
return (30000000.0/1000000000.0).to_f
end
def validateaddress(address)
end
def getblockchaininfo
result = handle("getheight", "")
{
blocks: Integer(result['height']),
headers: 0,
mediantime: 0
}
end
end
end
Related
Ruby error: undefined local variable or method `c'
I am working on a ruby application but getting a strange error that I believe might be caused by activerecord/activemodel. The error is as follows: Error on PaymentTransaction::Normal: undefined local variable or method `c' for #<Deposits::Mobitglobal:0x0055995b000b78> /home/deploy/peatio/vendor/bundle/ruby/2.2.0/gems/activemodel-4.0.12/lib/active_model/attribute_methods.rb:439:in `method_missing' /home/deploy/peatio/vendor/bundle/ruby/2.2.0/gems/activerecord-4.0.12/lib/active_record/attribute_methods.rb:168:in `method_missing' I have tried using ruby-2.3.0 as a suggested solution thinking that activerecord/activemodel in that version handles it differently. But the result is the same. The process starts from the file: coin_rpc.rb require 'net/http' require 'uri' require 'json' class CoinRPC class JSONRPCError < RuntimeError; end class ConnectionRefusedError < StandardError; end def initialize(uri) #uri = URI.parse(uri) end def self.[](currency) c = Currency.find_by_code(currency.to_s) if c && c.rpc name = c.family || 'BTC' "::CoinRPC::#{name}".constantize.new(c.rpc) end end def method_missing(name, *args) handle name, *args end def handle raise "Not implemented" end class BTC < self def handle(name, *args) post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json resp = JSON.parse( http_post_request(post_body) ) raise JSONRPCError, resp['error'] if resp['error'] result = resp['result'] result.symbolize_keys! if result.is_a? Hash result end def http_post_request(post_body) http = Net::HTTP.new(#uri.host, #uri.port) request = Net::HTTP::Post.new(#uri.request_uri) request.basic_auth #uri.user, #uri.password request.content_type = 'application/json' request.body = post_body http.request(request).body rescue Errno::ECONNREFUSED => e raise ConnectionRefusedError end def safe_getbalance begin getbalance rescue 'N/A' end end end class ETH < self def handle(name, *args) post_body = {"jsonrpc" => "2.0", 'method' => name, 'params' => args, 'id' => '1' }.to_json resp = JSON.parse( http_post_request(post_body) ) raise JSONRPCError, resp['error'] if resp['error'] result = resp['result'] result.symbolize_keys! if result.is_a? Hash result end def http_post_request(post_body) http = Net::HTTP.new(#uri.host, #uri.port) request = Net::HTTP::Post.new(#uri.request_uri) request.basic_auth #uri.user, #uri.password request.content_type = 'application/json' request.body = post_body http.request(request).body rescue Errno::ECONNREFUSED => e raise ConnectionRefusedError end def safe_getbalance begin (open(#uri.host + '/cgi-bin/total.cgi').read.rstrip.to_f) rescue 'N/A' end end end end The error seems to come somewhere between the two definitions in the above file: def self.[](currency) c = Currency.find_by_code(currency.to_s) if c && c.rpc name = c.family || 'BTC' "::CoinRPC::#{name}".constantize.new(c.rpc) end end def method_missing(name, *args) handle name, *args end The file about calls the "family" name, in this case "BTC" in the following file: currencies.yml - id: 9 key: mobitglobal code: mbg symbol: "฿" coin: true family: BTC quick_withdraw_max: 1000 rpc: http://username:password#127.0.0.1:11111 blockchain: http://cryptoid.net/explorer/MBGL?txid=#{txid} address_url: http://cryptoid.net/explorer/MBGL?txid=#{address} At that point the call should be looking for "family" and then if set to BTC then continue the operation in coin_rpc.rb: class BTC < self def handle(name, *args) post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json resp = JSON.parse( http_post_request(post_body) ) raise JSONRPCError, resp['error'] if resp['error'] result = resp['result'] result.symbolize_keys! if result.is_a? Hash result end def http_post_request(post_body) http = Net::HTTP.new(#uri.host, #uri.port) request = Net::HTTP::Post.new(#uri.request_uri) request.basic_auth #uri.user, #uri.password request.content_type = 'application/json' request.body = post_body http.request(request).body rescue Errno::ECONNREFUSED => e raise ConnectionRefusedError end def safe_getbalance begin getbalance rescue 'N/A' end end some info was obfuscated for security reasons. (username/password) The expected result is null, indicating no error. But instead I get the error: Error on PaymentTransaction::Normal: undefined local variable or method `c' for #<Deposits::Mobitglobal:0x0055995b000b78> /home/deploy/peatio/vendor/bundle/ruby/2.2.0/gems/activemodel-4.0.12/lib/active_model/attribute_methods.rb:439:in `method_missing' /home/deploy/peatio/vendor/bundle/ruby/2.2.0/gems/activerecord-4.0.12/lib/active_record/attribute_methods.rb:168:in `method_missing' Any help or insight into where I could be going wrong would be greatly appreciated
undefined method trying to match string
I'm getting an 'undefined method' error on the get_nums method below, and I can't figure out why. list_hostnames returns an array, but get_nums can't do anything with it. Could someone please point me in the right direction? class Hostname attr_accessor :hostname, :domain_controller_ip, :username, :password, :hosts def initialize(hostname, domain_controller_ip, ad_username, ad_password) #domain_controller_ip = domain_controller_ip #ad_username = ad_username #ad_password = ad_password #hostname = hostname #hosts = [] def list_hostnames a = Ldap.new(#domain_controller_ip, #ad_username, #ad_password) hostname = #hostname + "*" a.ldap_con.search(:base => a.treebase, :filter => a.filter('cn', hostname)) do |entry| self.hosts.push(entry.cn[0]) end self.hosts.each do |x| p x end end def get_nums self.hosts.each do |x| i = x.match(/\d+$/) p i end end end a = Hostname.new('prod-srv-1', '192.168.1.1', 'administrator', 'password') b = a.list_hostnames b.get_nums end
It seems, that you've been confused by indentation and didn't correctly close the methods by end. I think that the following code is the correct version of the code you're trying to implement: class Hostname attr_accessor :hostname, :domain_controller_ip, :username, :password, :hosts def initialize(hostname, domain_controller_ip, ad_username, ad_password) #domain_controller_ip = domain_controller_ip #ad_username = ad_username #ad_password = ad_password #hostname = hostname #hosts = [] end def list_hostnames a = Ldap.new(#domain_controller_ip, #ad_username, #ad_password) hostname = #hostname + "*" a.ldap_con.search(:base => a.treebase, :filter => a.filter('cn', hostname)) do |entry| self.hosts.push(entry.cn[0]) end self.hosts.each do |x| p x end self end def get_nums self.hosts.each do |x| i = x.match(/\d+$/) p i end end end a = Hostname.new('prod-srv-1', '192.168.1.1', 'administrator', 'password') b = a.list_hostnames b.get_nums
Since you have an attr_accessor defined for hosts, you don't need the self.hosts. You could just do: hosts.each do |h| # code here end
NoMethodError: undefined method `[]=' for nil:NilClass
Error in title. What's going wrong? Attempting to initialize Temperature object with a hash. If I just do puts Temperature.from_celsius(50).in_fahrenheit then it works fine and returns 122.0 But Temperature.new(:f => 50) returns an error. class Temperature attr_accessor :f, :c #temp = {:f => 32, :c => 0} def initialize(params) if params[:f] != nil self.class.from_fahrenheit(params[:f]) else self.class.from_celsius(params[:c]) end end def self.from_fahrenheit(temp) #temp[:f] = temp #temp[:c] = ((temp - 32.0)/1.8).round(1) return #temp end def self.from_celsius(temp) #temp[:c] = temp #temp[:f] = (temp * 1.8 + 32).round(1) return #temp end def in_fahrenheit #temp[:f] end def in_celsius #temp[:c] end end class Hash def in_fahrenheit self[:f] end def in_celsius self[:c] end end puts Temperature.from_celsius(50).in_celsius tempo = Temperature.new(:f => 50) tempo.in_fahrenheit
Just as the error message says. You are calling []= on #temp in a Temperature instance, which is nil by default because you have not assigned anything to it anywhere.
You can't initialize instance variable in a class body, as you did. You should do it in a constructor, and because you have three constructors, your code should look like this: class Temperature def initialize(params) #temp = {:f => 32, :c => 0} if params[:f] != nil self.class.from_fahrenheit(params[:f]) else self.class.from_celsius(params[:c]) end end def self.from_fahrenheit(temp) #temp = {} #temp[:f] = temp #temp[:c] = ((temp - 32.0)/1.8).round(1) return #temp end def self.from_celsius(temp) #temp = {} #temp[:c] = temp #temp[:f] = (temp * 1.8 + 32).round(1) return #temp end def in_fahrenheit #temp[:f] end def in_celsius #temp[:c] end end
Why do i never get to on_connect in ShadyHttpClient
So witness and observe the following code, my questions is why do i never make it to the on_connect after starting the cool.io loop in send_to_server, the l.run should fire off the request as per the documented example on the github, and how the code handles incoming connections in module Server #socket.attach(l) l.run which does work and accepts the incoming data and sends it to my parser, which does work and fires off all the way up until the aforementioned send_to_server. So what is going on here? require 'cool.io' require 'http/parser' require 'uri' class Hash def downcase_key keys.each do |k| store(k.downcase, Array === (v = delete(k)) ? v.map(&:downcase_key) : v) end self end end module ShadyProxy extend self module ClientParserCallbacks extend self def on_message_complete(conn) lambda do puts "on_message_complete" PluginHooks.before_request_to_server(conn) end end def on_headers_complete(conn) lambda do |headers| conn.headers = headers end end def on_body(conn) lambda do |chunk| conn.body << chunk end end end module PluginHooks extend self def before_request_to_server(conn) # modify request here conn.parser.headers.delete "Proxy-Connection" conn.parser.headers.downcase_key send_to_server(conn) end def send_to_server(conn) parser = conn.parser uri = URI::parse(parser.request_url) l = Coolio::Loop.default puts uri.scheme + "://" + uri.host c = ShadyHttpClient.connect(uri.scheme + "://" + uri.host,uri.port).attach(l) c.connection_reference = conn c.request(parser.http_method,uri.request_uri) l.run end def before_reply_to_client(conn) end end class ShadyHttpClient < Coolio::HttpClient def connection_reference=(conn) puts "haz conneciton ref" #connection_reference = conn end def connection_reference #connection_reference end def on_connect super #never gets here #headers = nil #body = '' #buffer = '' end def on_connect_failed super # never gets here either end def on_response_header(header) #headers = header end def on_body_data(data) puts "on data?" #body << data STDOUT.write data end def on_request_complete puts "Headers" puts #headers puts "Body" puts #body end def on_error(reason) STDERR.puts "Error: #{reason}" end end class ShadyProxyConnection < Cool.io::TCPSocket attr_accessor :headers, :body, :buffer, :parser def on_connect #headers = nil #body = '' #buffer = '' #parser = Http::Parser.new #parser.on_message_complete = ClientParserCallbacks.on_message_complete(self) #parser.on_headers_complete = ClientParserCallbacks.on_headers_complete(self) #parser.on_body = ClientParserCallbacks.on_body(self) end def on_close puts "huh?" end def on_read(data) #buffer << data #parser << data end end module Server def run(opts) begin # Start our server to handle connections (will raise things on errors) l = Coolio::Loop.new #socket = Cool.io::TCPServer.new(opts[:host],opts[:port], ShadyProxy::ShadyProxyConnection) #socket.attach(l) l.run # Handle every request in another thread loop do Thread.new s = #socket.accept end # CTRL-C rescue Interrupt puts 'Got Interrupt..' # Ensure that we release the socket on errors ensure if #socket #socket.close puts 'Socked closed..' end puts 'Quitting.' end end module_function :run end end ShadyProxy::Server.run(:host => '0.0.0.0',:port => 1234)
How do I HTTP post stream data from memory in Ruby?
I would like to upload data I generated at runtime in Ruby, something like feeding the upload from a block. All examples I found only show how to stream a file that must be on disk prior to the request but I do not want to buffer the file. What is the best solution besides rolling my own socket connection? This a pseudocode example: post_stream('127.0.0.1', '/stream/') do |body| generate_xml do |segment| body << segment end end
Code that works. require 'thread' require 'net/http' require 'base64' require 'openssl' class Producer def initialize #mutex = Mutex.new #body = '' #eof = false end def eof!() #eof = true end def eof?() #eof end def read(size) #mutex.synchronize { #body.slice!(0,size) } end def produce(str) if #body.empty? && #eof nil else #mutex.synchronize { #body.slice!(0,size) } end end end data = "--60079\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test.file\"\r\nContent-Type: application/x-ruby\r\n\r\nthis is just a test\r\n--60079--\r\n" req = Net::HTTP::Post.new('/') producer = Producer.new req.body_stream = producer req.content_length = data.length req.content_type = "multipart/form-data; boundary=60079" t1 = Thread.new do producer.produce(data) producer.eof! end res = Net::HTTP.new('127.0.0.1', 9000).start {|http| http.request(req) } puts res
There's a Net::HTTPGenericRequest#body_stream=( obj.should respond_to?(:read) ) You use it more or less like this: class Producer def initialize #mutex = Mutex.new #body = '' end def read(size) #mutex.synchronize { #body.slice!(0,size) } end def produce(str) #mutex.synchronize { #body << str } end end # Create a producer thread req = Net::HTTP::Post.new(url.path) req.body_stream = producer res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }