外部サービスから通知を受信するか、Hookslerが作成された理由

最近、 Slackチームのコミュニケーションサービスが非常に人気を集めています。 すぐに使用できるように、 さまざまなサービスとかなり便利な外部APIが統合されています。 しかし、これらすべてにより、無料アカウントでは5つの統合の制限があります。 github、newrelic +数枚のボードをtrelloにフックしましたが、それで終わりです。 汎用のIncoming WebHookを使用できますが、独自の形式があり、他のサービスとの互換性はありません。 しかし、この問題を解決していなければ、プログラマーはプログラマーではありません。



解決策はハンマーのように簡単です。 サービスからのフックを受け入れ、必要な形式でSlackを処理およびスローします。

リスト内の統合とともに、 ハンモックが発見されました。これはPHPで記述され、特定のプラグインのセットを備えていますが、このソリューションは特に好まれませんでした。 既成の統合はありますが、残念ながら、それらは必要ありません。また、コードを読み取り、「ディレクトリ内の何かを修正する」レベルでPHPに精通しているため、独自のコードを作成する必要はありません。



したがって、私は自分のサービスを書くことにしました。 コアと、「入力」と「出力」用の個別のモジュールという、モジュールベースで完全に構築することにしました。 Rubyを言語として使用しましたが、その動的な性質はこの計画の実装に大いに役立ちました。



会いましょう



フックラー!



通知を受信して​​さらに送信するための最小限のコードでサービスを収集できます。 設定するには、独自のDSLを使用します。



require 'hooksler/slack' require 'hooksler/newrelic' require 'hooksler/trello' require 'dotenv' Dotenv.load Hooksler::Router.config do secret_code 'very_secret_code' host_name 'http://example.com' endpoints do input 'simple', type: :simple input 'newrelic', type: :newrelic input 'trello', type: :trello, create: false, public_key: ENV['TRELLO_KEY'], member_token: ENV['TRELLO_TOKEN'], board_id: ENV['TRELLO_ID1'] output 'black_hole', type: :dummy output 'slack_out', type: :slack, url: ENV['SLACK_WEBHOOK_URL'], channel: '#test' end route 'simple' => 'slack_out' route 'trello' => ['black_hole', 'slack_out'] route 'newrelic' => ['black_hole', 'slack_out'] end
      
      





初めに、入力入力ポイントが宣言され、それぞれが独自の名前とタイプを持ち、初期化のための追加のパラメーターを含むこともあります。 ルートは次のとおりです。 別の形式で指定できます。1対1、1対多、またはその逆です。

また、各ルートにフィルターを配置できます。フィルターは、メッセージの変更とフィルターの両方を行うことができます。 したがって、ポイントAからポイントBにメッセージをルーティングするための十分に柔軟なカーネルを取得します。

内部のメッセージは内部表現で送信されますが、受信されたサービス(タイプ)+元のメッセージは既知です。 受信すると、一般的なフィールドが入力されます:ユーザー、テキスト、タイトル、リンク、レベル。 将来的には、それらを使用して通知を生成できます。

現時点では、カーネルは完全に実装、テストされ、テストでカバーされています。 いくつかの統合も実装されています:trello、newrelic、slack。 統合の作成は非常に簡単です。



ちょっとした練習



メッセージを受信する



たとえば、POSTリクエストの本文をメッセージフィールドに配置できるモジュールを作成します。



 class DummyInput extend Hooksler::Channel::Input register :dummy def initialize(params) @params = params end def load(request) build_message({}) do |msg| msg.message = request.body.read end end end
      
      





クラスを宣言し、適切なモジュールで拡張します。 次に、彼の名前を登録します。 すべて、その後、着信データを受信して​​処理する準備が整いました。 要求処理は、 Rack :: Requestクラスのオブジェクトという1つのパラメーターのみをとるloadメソッドで実行されます。 複雑な処理は必要ありませんので、すぐにメッセージを作成してフィールドに入力してください。 その後、構成で説明されているルートに沿ってさらに進みます。 送信のために、複数のメッセージを一度に作成できます。 loadメソッドは配列を返します。 将来、各オブジェクトは個別に処理されます。



メッセージを送信する



送信用のモジュールを作成するのも簡単です。これにより、受信したメッセージをコンソールで確認できます。



 class DummyOutput extend Hooksler::Channel::Output register :dummy def initialize(params) @params = params end def dump(message) puts "-- #{message.title} : #{message.level} --" puts message.user puts message.message puts message.url end end
      
      





着信アクションと同じアクションを実行し、適切な拡張モジュールのみを選択します。 この場合、コンソールへの出力の送信は、 dumpメソッドで実行されます。 メソッド名は議論の余地がありますが、sendはすでに使用されているため、再定義したくありませんでした。



それでは、すべてを収集してルートを説明しましょう。



 Hooksler::Router.config do secret_code 'very_secret_code' host_name 'http://example.com' endpoints do input 'in', type: :dummy output 'out', type: :dummy end route 'in' => 'out' end
      
      





パスを生成するために使用されるコードと、サービスがハングするホストを示します。 開始し、準備ができました。 最終パスはアドレスhttp://example.com/_endpoints_で確認できます。応答はJSONです。 より詳細な例は、DEMOアプリケーションで見ることができます: github.com/hooksler/hooksler-demo



したがって、多くの労力をかけずに、異なるポイントに同時にメッセージを送信するように設定できます。Trelloからの変更の受信、Slackへの変更の送信、または電話へのプッシュを介した重要な変更(キーワードやタグなど)の送信。 たくさんのスキームを思いつくことができ、その利点は柔軟です。



より実用的な例。



先日、ユーザーをSlackに招待するプロセスを自動化するタスクがありました。 それぞれを手動で追加するのは長くて面倒ですが、すぐにオープン登録を行うことはできません。 インターネット上のnodejsには既製のフォームがあります。 しかし、以来 私はすでにそれでやろうと決めた作業フックラーを持っています。 まず、なんらかの方法で正しいメールを取得する必要があります。これは、Webhookで受信メッセージをラップするMandrillの機能を利用しました(医師が注文したものだけです)。 次に、受信トレイを作成し、Webhookを構成して、レシーバーを記述します。



 require 'hashie' module Hooksler module Mandrill class Input extend Hooksler::Channel::Input register :mandrill def initialize(params) @params = Hashie::Mash.new(params) end def load(request) return unless request.content_type == 'application/x-www-form-urlencoded' action, payload = request.POST.first return unless action == 'mandrill_events' payload = MultiJson.load(payload) payload.map do |event| build_message(event) do |msg| begin method_name = "for_#{event['event']}" self.send method_name, msg, event if respond_to? method_name rescue end end end end def for_inbound(msg, event) msg.message = event['msg']['text'] || event['msg']['html'] msg.title = event['msg']['subject'] msg.user = event['msg']['headers']['From'] end end end end
      
      







イベントを受け入れ、メッセージとヘルメットをさらに包み込みます。 次に、ユーザーの招待を実行するコードが必要です。



 class SlackInviteOutbound extend Hooksler::Channel::Output register :slack_invite def initialize(params) @params = params end def dump(message) return unless message.source == :mandrill email = message.raw['msg']['from_email'] url = "https://#{@params[:team]}.slack.com/api/users.admin.invite" HTTParty.post url, body: { email: email, token: @params[:token], set_active: true } end end
      
      







メッセージを受け入れ、マンドリルからのものであることを確認し、メール、リクエストを受け取り、ユーザーを招待します。 同時に、ボックスが有効であると確信しています。



最後の仕上げとして、ルーティングのセットアップ:



 endpoints do input 'slack_invite', type: :mandrill output 'slack_invite', type: :slack_invite, team: 'myteam', token: 'mysupersecrettoken' end route 'slack_invite' => 'slack_invite'
      
      





プロセスを開始し、楽しんでいます。



結論として



問題が発生するまで、すべてを安定して実行するまで、私はこのソリューションをしばらく使用しています。 唯一のことは、trelloの場合、すべてのケースが処理されているわけではなく、すでに多くの異なるタイプの通知があることです。 また、Slackの場合、独自のフォーマットモジュールが作成されました 。興味のある方はこちらの例をご覧ください



将来的には、メッセージの受信と送信の両方でアダプターの数を増やす計画です。 このソリューションが他の誰かに役立つことを願っています。



批判と提案は歓迎です。PMのテキストにエラーメッセージがあります。



Hooksler自体とアダプターはGithubで入手できます: github.com/hooksler



All Articles