Office 365 Teamsにoutgoing webhookが来たのでbotっぽいものを作ってみた
Twitterを眺めていたらMS TeamsにOutgoing Webhookが導入されたという情報が流れてきたので早速これを利用してbotを作成してみた。
システム構成
WebHookの通知を受けるAPIはServerlessFrameworkを利用して作成する。
ServerlessFrameworkのセットアップ等手順は以下のページを参照。
bot作成
Outgoing WebHookの登録
Teams上でOutgoing WebHookの登録を行う。
チームを選択して右クリック→「チームを管理」をクリック
「アプリ」タブをクリック
画面右下の「送信WebHook」をクリックする(少し場所が分かりづらい)
送信WebHookのダイアログが表示されるので各項目を埋めていく。
「作成」をクリックするとセキュリティトークンが表示されるのでコピーしてLambdaの環境変数に設定する。
発信者の認証をする
リクエストに含まれるHMAC証明書の検証を行う必要がある。
検証OKの場合、後続の処理に進めるようにする。
const crypto = require('crypto'); // ①セキュリティトークン取得(セキュリティトークンは環境変数から取得する) const sharedSecret = process.env.SHARED_SECRET; const bufSecret = Buffer(sharedSecret, "base64"); // ②HTTPヘッダに含まれるAuthorizationの値を取得 const auth = event.headers['Authorization']; // ③リクエストボディ + セキュリティトークンを用いてハッシュ値を生成しHMACを作成する const msgBuf = Buffer.from(body, 'utf8'); const msgHash = "HMAC " + crypto.createHmac('sha256', bufSecret).update(msgBuf).digest("base64"); // ④HMACとヘッダのAuthorizationが一致すればOK msgHash === auth
レスポンスを返却(テキストのみ)
以下の形式でレスポンスを返却するとテキストのみのメッセージが返せる。
{ "type": "message", "text": "Hello World" }
レスポンスを返却(画像のみ)
以下の形式でレスポンスを返却するとテキスト + 画像サムネイルのメッセージが返せる。
{ "type": "message", "text": "任意の文字列", "attachments": [{ "contentType": "image/jpg", "contentUrl": "画像のURL", }] }
その他の形式については以下を参照
botに実装した機能
動作テスト用にテキトウに作ったけどもうちょっとちゃんとしたやつを作りたい。
UUIDv4生成
たまに任意のUUIDv4文字列が欲しくなるときがあるのでbotで生成できるようにした。
為替情報取得
内部でAPI叩いて取得してきた為替情報を取得するだけ。外部API呼び出しの動作確認用に作った。
botのコード
日帰りダム&温泉ツーリング(スパー美輝)
本日は行ったことのない温泉を開拓するべくツーリングをしてきた。 まずは下呂方面へ向かう。休日だったが大通りから外れた道を選んだのでそこまで混雑はしていなかった。
金山湖 岩屋ダム
金山湖沿いの道は程よいワインディングになっておりバイクで走っていてとても楽しい道だった。また、両車線ともにほとんど他の車がおらず快適に走行できた。
岩屋ダムはロックフィル式のダムで、頂上部分が道になっているので乗り入れることができる。頂上からは広大なダム湖を望むことができる。結構高さがあり柵も簡単に乗り越えられそうなものなのでちょっと怖かった。
放水側、高低差がありちょっと怖い
貯水側
スパー美輝
本日の目的地。未開拓の温泉。事前調査から食事も美味しそうだったので、食事と入浴券のセットメニューを購入した。
温泉は内湯、サウナの種類が豊富で飽きずに入ることができる。また、露天風呂からは山々を眺めながらゆっくりと入ることができた。この温泉の一つ山を超えたところには下呂温泉があり、普通の人は下呂の方へ行くのでこの温泉は施設が充実しているにも関わらず人が少なくゆったりと入ることができた。
美輝の里定食
Apache IgniteでバックエンドにH2 Databaseを利用して永続化する
概要
Apache Igniteはインメモリデータグリッドを実現するミドルウェアであるがデータを永続化したいことがある。
永続化の方法としてディスク領域に保存するNative Parsistenceと外部のデータベース等に保存する3rd Party Persistence機能があり、
この記事では後者の3rd Party Persistence機能試してみる。
環境
構成
手順
H2 Database
All Platformsのzipファイルをダウンロードして、解凍する。
binディレクトリのh2.batを起動するとWeb管理画面が開く
Apache Igniteからも接続したいので設定済みファイルをServerにして接続する
build.sbt
ignite関連のlibraryを追加
libraryDependencies ++= { val igniteVersion = "2.4.0" Seq( "org.apache.ignite" % "ignite-core" % igniteVersion, "org.apache.ignite" % "ignite-spring" % igniteVersion, "org.apache.ignite" % "ignite-indexing" % igniteVersion ) }
config(xml)
Apache Igniteは設定をxmlファイルで保持する。
xmlファイルはsrc/main/resources/META-INF
ディレクトリに配置した。
H2 Databaseへの接続設定
先程のH2 DatabaseのWeb管理画面に指定した接続先設定と同じものを指定する。
<bean id= "simpleDataSource" class="org.h2.jdbcx.JdbcDataSource"> <property name="user" value = "sa" /> <property name="url" value="jdbc:h2:tcp://localhost/~/test" /> </bean>
キャッシュの設定
- CacheJdbcBlobStoreFactoryを利用してBLOB形式でデータベースに保存
- write, readスルー機能を有効化
<property name="cacheConfiguration"> <list> <bean class="org.apache.ignite.configuration.CacheConfiguration"> <constructor-arg name="name" value="testCache"></constructor-arg> <property name="cacheStoreFactory"> <bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory"> <property name="user" value = "sa" /> <property name="dataSourceBean" value = "simpleDataSource" /> </bean> </property> <property name="writeThrough" value="true"/> <property name="readThrough" value="true"/> </bean> </list> </property>
Scalaプログラム
データをputしてgetするだけの単純なプログラムを書いた。
import org.apache.ignite.Ignition object Main extends App { using(Ignition.start("example-ignite.xml")) { ignite => using (ignite.getOrCreateCache[String, String]("testCache")) { cache => cache.put("test1", "test1Value") cache.put("test2", "test2Value") println(s"test1 = ${cache.get("test1")}") println(s"test2 = ${cache.get("test2")}") } } def using[T <: AutoCloseable, A](resource: T)(proc: T => A): Unit = { try { proc(resource) } catch { case e: Throwable => e.printStackTrace() } finally { resource.close() } } }
実行した
上記のScalaプログラムを実行した。igniteのログが表示され、getしたデータが取得できた
[22:58:03] __________ ________________ [22:58:03] / _/ ___/ |/ / _/_ __/ __/ [22:58:03] _/ // (7 7 // / / / / _/ [22:58:03] /___/\___/_/|_/___/ /_/ /___/ [22:58:03] [22:58:03] ver. 2.4.0#20180305-sha1:aa342270 [22:58:03] 2018 Copyright(C) Apache Software Foundation [22:58:03] [22:58:03] Ignite documentation: http://ignite.apache.org ・・・・
永続化されたか確認する
H2 DatabaseのWeb管理画面から確認したところ、ENTRIES
テーブルが新たに追加されていた。
内容を確認したところ先程putしたデータが保存されているようだ。
SELECT UTF8TOSTRING(akey), UTF8TOSTRING(val) FROM ENTRIES;
Akka Remoteを利用したServer, Clientの簡単なActor通信するサンプルで動作確認した
概要
akka remoteを使ったリモート間のActorプログラムに慣れるために、client -> server構成の単純なプログラムを作成して動作を確認した。
作成したプログラムは以下
動作環境
構成
- メッセージを待ち受けるserverと、メッセージを送信するclientの2プロジェクト構成
- serverとclientは別プロセスとする
動作シーケンス
- client
- serverのActorに対して一定時間間隔でメッセージを送信する
- 最後にserverを停止するメッセージを送信する
- server
- メッセージ待受するActorを起動する
- 受け付けたメッセージを標準出力に表示する
パケットキャプチャ
remote actorに対する通信を理解するためにパケットキャプチャを用いて通信の内容を確認する。
このサンプルプロジェクトはlocalhost環境で動かしている。WireSharkでは自マシン間での通信はキャプチャできない為、RawCapを利用した。
server起動
sbt project server run
client起動
serverとは別のsbtで以下を実行する
sbt project client run
キャプチャ結果確認
RawCapは標準でpcap形式のファイルを出力するので、キャプチャ内容を確認するときはWireSharkを利用することができる。
- 一度コネクションを張るとshutdownするまでずっとコネクションを維持し続ける
- デフォルトでは4秒?毎にheart beatが投げられている
- 小さいメッセージ(今回はString9文字程度)だとペイロードの大半がactor pathの情報が占めるように見える
ServerlessFrameworkでS3の静的サイトのホスティングをする
概要
S3に静的サイトのホスティング機能がある。静的ファイル(HTML, js, css等)をS3に配置すると、それらのファイルをウェブ公開してくれる機能だ。
ウェブホスティング用のS3バケットを作成したり、静的ファイルをS3にアップロードしたりするのをServerlessFramework経由で行う。
プロジェクトを作成
とりあえず以下のコマンドを実行してプロジェクトを作成する。プロジェクト名はs3-sync-test
にした。
sls create --template aws-nodejs --path s3-sync-test
プラグイン導入
ファイルをS3にアップロードする機能はServerlessFramework標準には無いようなので以下のプラグインを利用する。
以下のコマンドでプラグインをインストールする。
sls plugin install -n serverless-s3-sync
serverless.ymlの末尾にpluginsの項目が追加されたはずだ。
plugins: - serverless-s3-sync
S3バケットの設定
resourcesの項目にS3バケット設定とS3バケットポリシーを記載する。
resources: Resources: StaticSite: Type: AWS::S3::Bucket Properties: BucketName: ${self:custom.webSiteName} AccessControl: PublicRead WebsiteConfiguration: IndexDocument: index.html ErrorDocument: error.html StaticSiteS3BucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: Ref: StaticSite PolicyDocument: Statement: - Sid: PublicReadGetObject Effect: Allow Principal: "*" Action: - s3:GetObject Resource: Fn::Join: ["", ["arn:aws:s3:::",{"Ref": "StaticSite"},"/*"]]
customにウェブサイト名とS3にアップロードするファイルを配置しているディレクトリ名を記載する。
custom: webSiteName: s3-sync-test.com s3Sync: - bucketName: ${self:custom.webSiteName} localDir: static
HTML用意
<project>/static
ディレクトリにindex.html
とerror.html
を配置した。
デプロイ
以下のコマンドでデプロイする。
sls deploy -v
動作確認
AWSのマネジメントコンソールからS3のページへ遷移して、上記で作成したバケットがあるか確認する。
バケット内を確認し、HTMLファイルがアップロードされているか確認する。
ブラウザから確認
プロパティからStatic website hostingを選択してエンドポイントを開く。
ブラウザから表示することができた。
水辺の温泉 日帰りツーリングしてきた
GW, せっかく天気が良いのにずっと家に引き篭もっているのもアレなので、久しぶりに日本海側の温泉へ行くことにした。日本海側は天気が良い日が少ないので今日みたいな「全国的に晴れ」みたいな日を狙って行かないと満足度が低いのだ。
道程が長くなりそうなので、朝早めに出発した。
まずは滋賀県方面へ向かう。途中、木曽川河川敷で休憩した。
走ること2時間程度、琵琶湖の辺りに到着した。朝早めだったので他の車もおらず、快適に運転することができた(通常だと名古屋抜けるのに相当苦労する)
敦賀湾のあたり。
敦賀湾を抜けると、道がどんどん低くなり殆ど海面と変わらないぐらいになってきた。波間の静かな湾と違い、ここまで来ると日本海の荒波を感じる。波消しブロックに波があたり鈍い低温が響いている。路面の位置も海と比べてそこまで高くないので、ちょっと波が強いと波しぶきが道路まではみ出していて、運転しているとちょっと怖かった。あと波しぶきでヘルメットが汚れた。
越前温泉露天風呂漁火
ここの温泉は道の駅に併設されており、食事施設と併せて利用できて便利。また、日本海側に面しているので大海原を見ながら露天風呂に浸かることができる。
以前、能登&金沢ツーリングへ行った時に見つけたスポットだ。
hkou.hatenablog.com
残念ながら、撮影禁止のため湯船の写真は無い。日本海の大海原を眺めながら露天風呂に浸かるとついつい長居してしまった。
朝ごはんを食べずに来たので、ここで朝ごはんを食べることにする。道の駅内のお食事処かねいちというお店でお刺身定食を食べた。
南砺市平ふれあい温泉センター ゆ~楽
予定よりも早く到着したので時間に余裕があった。このまま自宅へ帰るというのも味気ない感じがしたのでまた別の温泉へ行くことにした。
それがここである。少し距離は遠いが日本海側に来ることはあまりないのでせっかく来たのだしということで、足を伸ばそうという気分になった。
庄川の祖山ダム湖の辺りに併設された温泉で、高い位置にある露天風呂からダム湖全体を見渡せる景観の良い温泉です。
まとめ
- 総走行距離508km(GoogleMapタイムラインから)
- GWだからか結構ツーリングしている人達を見かけた
- 日本海側のルートはヤエー返答率が高いような気がする
- 一日中快晴だったが、早朝夜のあたりはバイクで走っているとまだまだ寒い
第6世代iPad(シルバーグレー)を購入した
概要
最近手書きでメモすることが多くなり、いつも紙に描いていたが、いつの間にかどこかへ行ってしまったり、整理がしづらかったのでデジタル化したいなぁと常々感じていた。
Apple PencilはiPad Proでしか利用できなかったが、この前新しく出た第6世代iPadでも利用できるようになったとのことで、
iPad or iPad Proのどちらにするかで迷っていた。
家電量販店に展示されていた実機を触ってみたところ、確かにiPad Proの方が書き味が良くレスポンスも早いが、自分にとっては無印iPadでも充分レスポンス早いし、いろいろ触っててもうこれで良いやと思えてきたので購入に踏み切った。
外箱
Apple製品らしいスッキリしたデザイン
開封
Apple Pencil
Apple Pencilももちろん同時購入した。
電源ON
最近のiPadはiPhoneと同期させることで初期設定をスキップすることができるようになったらしい。
画面中央のモヤモヤしたところをiPhoneのカメラで撮影すると同期される。
手書きノートアプリ
手書きノートアプリで一番有名どころのGoodNotes4をとりあえず購入してみた。
SplitView
iPadにはSplit Viewという画面分割してそれぞれ別のアプリを同時に動かす機能がある。
早速KindleとGoodNotes4で利用してみた。読書しながらメモが書けるようになった。
まとめ
良いところ
- Apple Pencilの書き味、レスポンスは素晴らしい
- GoodNotes4との組み合わせは最高だった
- カメラの出っ張りがなくて良い
- 低価格なので傷とかあまり気にせず使用することができる
悪いところ
- Apple Pencilの持ち手がツルツルしてるので汗で滑る