MyCSS

2010/05/19

Amazon SNSのRubyライブラリを(適当に)つくりました はてなブックマークに追加

Amazon Web ServiceのSimple Notification Serviceですが、Rubyのライブラリが見つからなかったので、適当に作りました。元ネタはRightScale提供のRightAwsで、これをSNS対応させた形です。

ソースを張っておきますので、ご自由にお使いください。動作無保証です。未実装のメソッドもあります。テストも不完全です。無い無い尽くしでアレですが、ご自身の責任範囲でお使いください。

本来であればGitHubからForkさせるべきなんでしょうけど、使い方を把握していないので・・すみません・・

※注:すでに同じ様な事やってらっしゃる方がいました。http://github.com/bemurphy/right_aws/blob/add_sns/lib/sns/right_sns_interface.rb

require "right_aws"

module RightAws

  class SnsInterface < RightAwsBase
    include RightAwsBaseInterface

    DEFAULT_HOST      = 'sns.us-east-1.amazonaws.com'
    DEFAULT_PORT      = 443
    DEFAULT_PROTOCOL  = 'https'
    DEFAULT_PATH      = '/'
    API_VERSION       = '2010-03-31'

    @@bench = AwsBenchmarkingBlock.new
    def self.bench_xml; @@bench.xml;     end
    def self.bench_sns; @@bench.service; end

    # Creates new RightSns instance.
    # 
    # Example:
    #
    #  sns = RightAws::SnsInterface.new(aws_access_key_id, aws_secret_key)
    #
    def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
      params.delete(:nil_representation)
      init({
          :name                => 'SNS',
          :default_host        => ENV['SNS_URL'] ? URI.parse(ENV['SNS_URL']).host    : DEFAULT_HOST,
          :default_port        => ENV['SNS_URL'] ? URI.parse(ENV['SNS_URL']).port    : DEFAULT_PORT,
          :default_service     => DEFAULT_PATH,
          :default_protocol    => ENV['SNS_URL'] ? URI.parse(ENV['SNS_URL']).scheme  : DEFAULT_PROTOCOL,
          :default_api_version => API_VERSION
        },
        aws_access_key_id     || ENV['AWS_ACCESS_KEY_ID'],
        aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
        params)
    end


    #--------------------
    #      APIs
    #--------------------

    def add_permission()
      raise 'Sorry! Not Implemented!'
    end
    
    def confirm_subscription()
      raise 'Sorry! Not Implemented!'
    end
    
    def set_topic_attributes(topic_arn, attribute_name, attribute_value)
      request_params = {'TopicArn' => topic_arn, 'AttributeName' => attribute_name, 'AttributeValue' => attribute_value}
      link   = generate_request("SetTopicAttributes", request_params)
      result = request_info(link, QSnsSetTopicAttributesParser.new(:logger => @logger))
      return result
    rescue Exception
      on_exception
    end
    
    def get_topic_attributes(topic_arn)
      request_params = {'TopicArn' => topic_arn}
      link   = generate_request("GetTopicAttributes", request_params)
      result = request_info(link, QSnsGetTopicAttributesParser.new(:logger => @logger))
      return result
    rescue Exception
      on_exception
    end

    def create_topic(topic_name)
      request_params = {'Name' => topic_name}
      link   = generate_request("CreateTopic", request_params)
      result = request_info(link, QSnsCreateTopicParser.new(:logger => @logger))
      return result
    rescue Exception
      on_exception
    end

    def delete_topic(topic_arn)
      request_params = {'TopicArn' => topic_arn}
      link   = generate_request("DeleteTopic", request_params)
      result = request_info(link, QSnsDeleteTopicParser.new(:logger => @logger))
      return result
    rescue Exception
      on_exception
    end

    def list_topics(next_token = nil )
      request_params = {'NextToken' => next_token}
      link   = generate_request("ListTopics", request_params)
      result = request_info(link, QSnsListTopicsParser.new(:logger => @logger))
      # return result if no block given
      return result unless block_given?
      # loop if block if given
      begin
        # the block must return true if it wanna continue
        break unless yield(result) && result[:next_token]
        # make new request
        request_params['NextToken'] = result[:next_token]
        link   = generate_request("ListTopics", request_params)
        result = request_info(link, QSnsListTopicsParser.new(:logger => @logger))
      end while true
    rescue Exception
      on_exception
    end

    def subscribe(topic_arn, protocol, endpoint)
      request_params = {'TopicArn' => topic_arn, 'Protocol' => protocol, 'Endpoint' => endpoint}
      link   = generate_request("Subscribe", request_params)
      result = request_info(link, QSnsSubscribeParser.new(:logger => @logger))
      return result
    rescue Exception
      on_exception
    end

    def unsubscribe(subscription_arn)
      request_params = {'SubscriptionArn' => subscription_arn}
      link   = generate_request("Unsubscribe", request_params)
      result = request_info(link, QSnsUnubscribeParser.new(:logger => @logger))
      return result
    rescue Exception
      on_exception
    end

    # return {:subscritions => []}
    def list_subscriptions(next_token = nil )
      request_params = {'NextToken' => next_token }
      link   = generate_request("ListSubscriptions", request_params)
      result = request_info(link, QSnsListSubscriptionsParser.new(:logger => @logger))
      # return result if no block given
      return result unless block_given?
      # loop if block if given
      begin
        # the block must return true if it wanna continue
        break unless yield(result) && result[:next_token]
        # make new request
        request_params['NextToken'] = result[:next_token]
        link   = generate_request("ListSubscriptions", request_params)
        result = request_info(link, QSnsListSubscriptionsParser.new(:logger => @logger))
      end while true
    rescue Exception
      on_exception
    end

    # return {:subscritions => []}
    def list_subscriptions_by_topic(topic_arn, next_token = nil )
      request_params = {'TopicArn' => topic_arn, 'NextToken' => next_token}
      link   = generate_request("ListSubscriptionsByTopic", request_params)
      result = request_info(link, QSnsListSubscriptionsParser.new(:logger => @logger))
      # return result if no block given
      return result unless block_given?
      # loop if block if given
      begin
        # the block must return true if it wanna continue
        break unless yield(result) && result[:next_token]
        # make new request
        request_params['NextToken'] = result[:next_token]
        link   = generate_request("ListSubscriptionsByTopic", request_params)
        result = request_info(link, QSnsListSubscriptionsParser.new(:logger => @logger))
      end while true
    rescue Exception
      on_exception
    end

    def publish(topic_arn, subject, message)
      request_params = {'TopicArn' => topic_arn, 'Subject' => subject, 'Message' => message}
      link   = generate_request("Publish", request_params)
      result = request_info(link, QSnsPublishParser.new(:logger => @logger))
      return result
    rescue Exception
      on_exception
    end


    #--------------------
    #      Requests
    #--------------------

    def generate_request(action, params={}) #:nodoc:
      generate_request_impl(:get, action, params )
    end

    # Sends request to Amazon and parses the response
    # Raises AwsError if any banana happened
    def request_info(request, parser)  #:nodoc:
      request_info_impl(:sdb_connection, @@bench, request, parser)
    end

    
    #--------------------
    #      PARSERS:
    #--------------------

    class QSnsCreateTopicParser < RightAWSParser #:nodoc:
      def reset
        @result = {}
      end
      def tagend(name)
        case name
        when 'TopicArn'  then @result[:topic_arn]  =  @text
        when 'RequestId' then @result[:request_id] =  @text
        end
      end
    end

    class QSnsDeleteTopicParser < RightAWSParser #:nodoc:
      def reset
        @result = {}
      end
      def tagend(name)
        case name
        when 'RequestId' then @result[:request_id] =  @text
        end
      end
    end

    class QSnsListTopicsParser < RightAWSParser #:nodoc:
      def reset
        @result = { :topics => [] }
      end
      def tagend(name)
        case name
        when 'NextToken'  then @result[:next_token] =  @text
        when 'TopicArn'   then @result[:topics]     << @text
        end
      end
    end

    class QSnsSubscribeParser < RightAWSParser #:nodoc:
      def reset
        @result = {}
      end
      def tagend(name)
        case name
        when 'SubscriptionArn' then @result[:subscription_arn] =  @text
        when 'RequestId' then @result[:request_id] =  @text
        end
      end
    end

    # same with QSnsDeleteParser...
    class QSnsUnubscribeParser < RightAWSParser #:nodoc:
      def reset
        @result = {}
      end
      def tagend(name)
        case name
        when 'RequestId' then @result[:request_id] =  @text
        end
      end
    end

    class QSnsListSubscriptionsParser < RightAWSParser #:nodoc:
      def reset
        new_member()
        @result = {:subscriptions => [] }
      end
      def tagend(name)
        case name
        when 'NextToken'  then @result[:next_token] =  @text
        when 'TopicArn'   then @member[:topic_arn]  =  @text
        when 'Protocol'   then @member[:protocol]   =  @text
        when 'SubscriptionArn'   then @member[:subscription_arn] =  @text
        when 'Owner'   then @member[:owner]         = @text
        when 'Endpoint'   then @member[:endpoint]   =  @text; @result[:subscriptions] << @member; new_member();
        end
      end
      private
      def new_member
        @member = {:topic_arn => '', :protocol => '', :subscription_arn => '', :owner => '', :endpoint => ''}
      end
    end

    class QSnsPublishParser < RightAWSParser #:nodoc:
      def reset
        @result = {}
      end
      def tagend(name)
        case name
        when 'MessageId' then @result[:message_id] =  @text
        when 'RequestId' then @result[:request_id] =  @text
        end
      end
    end

    # same with QSnsDeleteTopicParser...
    class QSnsSetTopicAttributesParser < RightAWSParser #:nodoc:
      def reset
        @result = {}
      end
      def tagend(name)
        case name
        when 'RequestId' then @result[:request_id] =  @text
        end
      end
    end

    class QSnsGetTopicAttributesParser < RightAWSParser #:nodoc:
      def reset
        @result = {:attributes => []}
      end
      def tagend(name)
        case name
        when 'key' then @key = @text
        when 'value' then @result[:attributes] << {:key => @key, :value => @text}
        when 'RequestId' then @result[:request_id] =  @text
        end
      end
    end
  end

end

2010/05/01

シューゲイザー・ディスク・ガイド はてなブックマークに追加


この本の存在は、ナタリーの記事で知りました。仕事中に「たまたま」見つけまして、おもわず「うそ!」と声を上げてしまった事は内緒です。

なんで2010年にもなって「シューゲイザー」??っていうか、今の若いもん(苦笑)に言っても通じないんじゃ?と、すっかり音楽の世界に疎くなってしまったアラフォーとしては、驚くとともに、嬉しいような、恥ずかしい様な、近年あまり経験した事の無かった感情(?)が渦巻いてしまいました。

Lovelessを彷彿とさせる表紙、帯には明らかにSwervedriver、Adorable、PaleSaints・・おぉ、我が青春の90'sのジャケットが映っているではありませんか。

当時のシューゲイザーは「マッドチェスター」や「ブリッドポップ」「グランジ」の陰に隠れていた様な気がしたのですが、どうもそうではなかったようです。

2008年フジロックでのマイブラ、当然行きました。まだ小さかった息子をおんぶして・・もちろん、耳を保護するイヤーマフ装着で。はじめのうちはおとなしく、キッズゾーンに敷物を敷いて遠巻きに見ておりましたが、あまりにもパフォーマンスがまばゆくて、「すまん、父ちゃん、行ってくる」と母子を残し、前方に駆け寄った記憶が(笑)

フジロックそのものは豊洲で行われた第二回から、初の苗場開催、第三回の伝説の風呂なし斜度20度ゲレンデキャンプ三日間(笑)を経て、もう何回行ったか忘れてしまいましたが、すっかり夏フェスも定着するにつれて人も多くなり、もうハナから行くのはヤメにしておりました。ですが、マイブラは別格ですね。

本の中身ですが、これを編集するのは多大な苦労をされたのではないかと推察します・・。(@otoan69様がすばらしい仕事をされております)本当にこれでもか!という位のディスクレビューの応酬で、編集者の気迫すら感じます。資料としても、非常に貴重なものとなっています。ある意味、万人には勧められないけれども、これから「ワウを半開きにしよう」とか、「トレモロをdepth100%にしよう」とか、「ワーミーペダルを踏もう」としている若人がいたら、「この本に紹介されているアルバムを最低10枚聴いてからにしなさい」と言うでしょう・・って、ほとんど何を言っているのかよくわかりませんが、その位充実している内容です。これが1,900円って安すぎる・・。

貴重なビリンダお姉様のインタビューもありますし、ケヴィンのエフェクターボードの写真も載っています。(楽器屋のエフェクター売り場か!状態です)

さらに、現役シューゲイザー必見のエフェクターガイド。我が家にはなぜかPROCO RAT2
が2つもあり、さらには全然使えないで有名なBOSSのDF-2もあるんですが、やはり両方とも載っていましたね(笑)
ちなみに若かりし頃は、YAMAHAのSPX-900のリバースゲートの代わりに、おなじくYAHAMAのFX-500B(ベース用)のリバースアーリーリフレクションをWet100%で使用しておりました。あぁ、懐かしい。

しかし、来年はLoveless発売から20年ですね。もう、これだけで驚きというか、10代の音楽やっている子たちからすると、それってすでにクラシック?という領域ですもんね。本当にびっくりします(笑)

Chapterhouse、Ulrich Schnaussの来日 + 我らがLuminous Orangeの公演は予想通り仕事で行けませんでしたが、アラフォーの分際で今からシューゲイズするのも悪くないかな?いや、迷惑かな?とか、悶々と考えたりするのでした・・