無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

SSL対応版HTTPアクセスユーティリティ

Adobe Shareのクライアントライブラリを作ろうと思っていろいろやっていたのですが、ログインさえできず・・。何をやっても"BadAuthQuery"がかえってくるのみ。とりあえず今日はあきらめました。

それはさておき、↑の課程で以前作成したHTTPアクセスユーティリティSSL通信に対応させたので公開してみます。

接続先の設定ファイルで、ssl,ca_fileを指定してやれば、SSLでアクセスするはず。

---
# コンフィグレーション
conf:
  #proxy_host: <プロキシホスト>
  #proxy_port: <プロキシポート>

# デフォルトの接続先設定
default:
  host: api.share.adobe.com
  path: /webservices/api/v1/
  port: 443
  ssl: true               # ★sslを使うかどうか
  ca_file: "./server.cer" # ★サーバーの公開鍵証明書
  headers:

# メソッド名に対応する接続先の設定
requests:
  auth:
      path: /webservices/api/v1/auth/
      method: POST

ちゃんと動作確認してないので、バグってたらゴメンナサイ。実装は以下です。

require "net/http"
require "net/https"
require 'yaml'
require 'cgi'

class HttpRequestor

  # 初期化する。
  def initialize( request_file="./request.yaml" )
    File.open( request_file ) {|f|
      @request = YAML.load( f )
    }
  end

  # メソッドが定義されていない場合に呼ばれる。
  def method_missing( name, *args, &block )
    return do_request( name.to_s, &block )
  end

  # リクエストを実行する。
  # ブロックが与えられた場合は、ブロックにリクエスト情報を渡し編集する。
  def do_request ( method, &block )
    fail "unknown method " << method unless @request["requests"].key?( method )
    request = merge( {"params"=>{}, "headers"=>{}}, @request["requests"][method] )
    request = merge( request, @request["default"] )
    block.call( request ) if block_given?

    response = nil
    Net::HTTP.version_1_2

    requestor = nil
    if ( @request["conf"] != nil &&  @request["conf"]["proxy_host"] != nil && @request["conf"]["proxy_port"] != nil )
      requestor = Net::HTTP::Proxy(
        @request["conf"]["proxy_host"],
        @request["conf"]["proxy_port"]
      ).new( request["host"], request["port"] )
    else
      requestor = Net::HTTP.new( request["host"], request["port"] )
    end

    # for ssl
    if ( request["ssl"] )
        requestor.use_ssl = true
        requestor.ca_file = request["ca_file"]
        requestor.verify_mode = OpenSSL::SSL::VERIFY_PEER
        requestor.verify_depth = 5
    end

    requestor.start { |http|

      param = map_to_param( request["params"] )
      param += "&" + list_to_param(request["param-list"])
      if request["method"] == "get"
        response = http.get( request["path"] + "?" + param, request["headers"] )
      elsif request["method"] == "POST"
        # POSTの場合、bodyの指定があればそちらを優先する。
        param = request["body"] != nil ?  request["body"] : param
        response = http.post( request["path"], param, request["headers"] )
      end
    }
    return response
  end

private
  def map_to_param( map )
   return "" if map == nil
    str = ""
    map.each { | key, value |
      str << key << '=' << CGI.escape(value.to_s) << '&' if value != nil
    }
    return str
  end

  def list_to_param( list )
   return "" if list == nil
    str = ""
    list.each { | item |
      if item["key"] != nil && item["value"] != nil
        str << item["key"] << '=' << CGI.escape(item["value"].to_s) << '&'
      end
    }
    return str
  end

  # リクエストの設定をマージする。
  def merge (request, parent)
    return request if ( parent == nil )
    request.merge!(parent) { |key, self_val, other_val|
      if ( key == "headers" || key == "params" )
        merge(self_val != nil ? self_val : {}, other_val)
      else
        self_val != nil ? self_val : other_val
      end
    }
    return request
  end

end