5000164 is here
My writing is my life.
No results for undefined
Powered byAlgolia
Rust入門者向けハンズオンに参加した

Rust入門者向けハンズオンに参加した

Rust入門者向けハンズオン #4 - connpass

Rust に興味はあったけど触ったことなかったからよさそうと思って参加した。
触れてよかった。
これからも機会があれば触りたい。

言語に抱いたイメージ

現実的な言語だと思った。
ちゃんと実戦で使えるもの、という現実解としてこの形になったという感じ。
人間は信用できない、安全側に倒している、というのもよい。
メモリー周りの問題を解決することに興味が向いていると思うと納得するところもある。
関数型言語に影響を強く受けているということで触りやすかった。
基本的にイミュータブルとか。
でも参照とかを意識的にたくさん書いてる気配があるあたり、厳密にイミュータブルにするんじゃなくて処理の高速化のためとのバランスを取っている感じ。

結論

現時点でメインで触ることはない。
でも次ツールを書こうと思ったら Go じゃなくて Rust を選択すると思う。

デスクの向きを窓に向けたら気持ちがいい

デスクの向きを窓に向けたら気持ちよかった

今までデスクは壁にしか向けたことがなかった。
何回か部屋の内側に向けるレイアウトを考えたことはあったけど、やっぱりなんかしっくりこない気がしてやめていた。
でも今回やるだけやってみて嫌だったらまた直そうと思ってやってみた。
そしたらとてもよかった。
外の景色とかが見れて気持ちがいい。
おすすめ。

デスクを窓に向けた様子

ケーブルをまとめるために買ったチューブが便利AWS Lambda の Python 3.6 で LINE Bot を動かす

目的

LINE Bot を使って生活を少し便利にしたい。

背景

最近 LINE をよく使ってるから。
なんかちょっとしたメモとか簡単に確認したいなーと思ったから。
たまたま AWS Lambda の料金を調べたら思っていたよりも安かったので使ってみたくなったから。

この記事のスタートとゴール

スタートは、 LINE をすでに使っているが、 API などは使ったことがないところ。
ゴールは、 LINE のグループチャットで特定の発言をしたら特定の内容を返してくれるところ。

LINE Bot を使えるように登録する

Messaging API の登録をする。

Developer Trial を選ぶ。

LINE Bot を使えるように設定する

LINE@ MANAGER から以下の感じに Bot を設定する。

  • API を利用する
  • Webhook を利用する
  • グループトーク参加を利用する
  • 自動応答メッセージを利用しない
  • 友だち追加時あいさつを利用しない
  • 基本設定アカウントページメニュー非表示

LINE Bot と友だちになってグループトークを作成

QR コードから友だち追加する。

友だちになったらグループトークを作成して追加する。

AWS Lambda と Amazon API Gateway を作成する

記事を参考にしながら AWS Lambda と Amazon API Gateway を作成する。

URL に直接アクセスして Hello from Lambda を表示する

そのままではうまく動かなかった。
いろいろ見ていたら「LAMBDA_PROXY」のところが違うということに気付いた。

調べたら新たに追加された機能らしい。
似たような現象を見つけて、レスポンスの返し方が違うと気付く。

公式のサンプルが見つけられなかったけど、この記事のように statusCodebody を入れたら動いた。

この段階でのコードは下記。
これでブラウザでアクセスすることで Hello from Lambda と表示される。

def lambda_handler(event, context):
    return {'statusCode': 200, 'body': 'Hello from Lambda'}

「Lambda プロキシ統合の使用」のオプションを外したら最初のままのコードでも動いたが、このオプションを付けた方が楽な部分があるらしい?ので付けたままにしておく。

LINE からのリクエストを受け取れるようにする

LINE developers の Webhook URL にさきほど作成した Amazon API Gateway の URL を登録する。
この時に amazonaws.com:443 のように HTTPS のポート番号を付けないとうまくいかない、らしい。
Webhook URL を設定したら Bot のいるグループチャットで発言をして CloudWatch にログが出ることを確認する。

LINE に発言する

Python なので Requests とか使えたら楽だけど、サードパーティーのライブラリは zip でアップロードしたりという操作が必要なようだったので、今回は標準の機能だけでやる。

環境変数に LINE developers の Channel Secret と Channel Access Token をセットする。
KMS というやつを使った方がセキュアらしいんですがちょっとよくわかりませんでしたすいません。

ここで event の中身を取ろうとしたら、なんかうまく取れない。
記事によって書いてあることもまちまちでよくわからない。

なのでまずはログを残すことにした。
とても簡単にログが残せて CloudWatch が使えてすごい便利ー、ってなりました。
こういう恩恵が受けられるのがサーバーレスアーキテクチャーなのかなーとかちょっと思ったよくわかってないけど。

ログを残して見てみた結果、 event は dict で event が持ってる body の中身が JSON の文字列だということがわかりました。
なので、他のサイトでやっているように events をループで回したいってなったら以下の方法でいけることがわかった。

for event in json.loads(event['body'])['events']:
    # なにか処理

ここまで来たらあとは LINE に POST を送れば発言できる。

現時点でのコードは下記のような感じ。
発言を受け取ったらただ test と発言するだけ。

import logging

import os
import urllib.request, urllib.parse
import json

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(request, context):
    
    logger.info(request)
    
    for event in json.loads(request['body'])['events']:
        logger.info(json.dumps(event))
        
        url = 'https://api.line.me/v2/bot/message/reply'
        headers = {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + os.environ['LINE_CHANNEL_ACCESS_TOKEN']
        }
        body = {
            'replyToken': event['replyToken'],
            'messages': [
                {
                    "type": "text",
                    "text": "test",
                }
            ]
        }
        
        req = urllib.request.Request(url, data=json.dumps(body).encode('utf-8'), method='POST', headers=headers)
        with urllib.request.urlopen(req) as res:
            logger.info(res.read().decode("utf-8"))
    
    return {'statusCode': 200, 'body': '{}'}

def lambda_handler(request, context): の部分は event っていう変数名が使いたかったので第一引数の変数名を request に変更。
これの "text": "test", の部分を "text": event['message']['text'], と変えるとオウム返しを行うことができる。
logger.info(json.dumps(event)) みたいな感じで JSON 文字列としてログに残しておくと CloudWatch が勝手にログを整形して表示してくれるので便利。

特定の内容の時だけ反応するようにする

ここまできたらあとは作れば動くという感じなので簡単。
event['message']['text'] が発言内容を持っているのでループの最初で下記のように特定の発言以外を弾くようにしてあげればいい。

if event['message']['text'] != 'memo':
    continue

特定の発言者にだけ反応するようにする

こちらも同じような感じ。
発言者のユーザー ID が event['source']['userId'] で取れるので、特定のユーザー ID 以外を弾くようにする。

if event['source']['userId'] != 'userId':
    continue

リクエストの検証を行う

サーバーの公開されている API に送られたリクエストのうち、 LINE からきたリクエストだけを信用するようにする。
この検証を行わないと LINE 以外からのリクエストにも反応してしまう。
個人の認証が LINE からのリクエストの検証と、ユーザー ID の特定だけで、信頼できるものなのかどうかはわからないので別途調査が必要。
リクエストの検証自体はサンプルを元に簡単に実装することができた。
Amazon API Gateway のテスト機能が便利だった。

あらかじめ用意しておいたメモを特定の発言で返してくれる Bot の完成

いろいろ調整して最終的にできあがったコードがこちら。

import logging

import os
import urllib.request, urllib.parse
import json

import base64
import hashlib
import hmac

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(request, context):

    # リクエストの検証を行う
    channel_secret = os.environ['LINE_CHANNEL_SECRET']
    body = request.get('body', '')
    hash = hmac.new(channel_secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256).digest()
    signature = base64.b64encode(hash).decode('utf-8')

    # LINE 以外からのアクセスだった場合は処理を終了させる
    if signature != request.get('headers').get('X-Line-Signature', ''):
        logger.info(f'LINE 以外からのアクセス request={request}')
        return {'statusCode': 200, 'body': '{}'}

    for event in json.loads(body).get('events', []):

        # 発言者を絞り込む
        if event['source']['userId'] != 'userId':
            continue

        # 反応する発言内容を絞り込む
        if event['message']['text'] != 'memo':
            continue

        logger.info(json.dumps(request))
        logger.info(json.dumps(event))

        # LINE に発言する
        url = 'https://api.line.me/v2/bot/message/reply'
        headers = {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + os.environ['LINE_CHANNEL_ACCESS_TOKEN'],
        }
        body = {
            'replyToken': event['replyToken'],
            'messages': [
                {
                    'type': 'text',
                    'text': 'memo\n\n返してもらいたいメモの内容をここに書く',
                }
            ]
        }
        req = urllib.request.Request(url, data=json.dumps(body).encode('utf-8'), method='POST', headers=headers)
        with urllib.request.urlopen(req) as res:
            res_body = res.read().decode('utf-8')
            if res_body != '{}':
                logger.info(res_body)

    return {'statusCode': 200, 'body': '{}'}

感想

最近 Python を触っているのでなにも考えずに Python を選択したが、思ったよりも情報が少なくて大変だった。
bot 作るのって楽しい。
AWS Lambda を触ってみれてよかった。
もうちょい機能とか足して個人用に便利にしていきたい。
こんな感じでコード書いてったらひどいことになりそうだから、 AWS Lambda でうまいこと整理する方法を知りたい。

Hugo でシンタックスハイライトを使う

2018.1.20 追記

バージョン 0.28 から導入された Chroma で何も考えず簡単にシンタックスハイライトが使えるようになった。

結論

  • シンタックスハイライト用の css をテーマで読み込んでおく
  • config.toml に下記の設定を追加
pygmentscodefences = true
pygmentsCodeFencesGuessSyntax = true
pygmentsStyle = "monokai"
pygmentsUseClasses = true
pygmentsoptions = "linenos=inline"

背景

コードを見やすくしたいからシンタックスハイライトを使おうと思った。
やってみたら思ったよりもできなかった。
なんか疲れたのでメモ。

手順

Pygments をインストールする

シンタックスハイライトするのに必要なやつ。
何も考えずに入れる。

sudo easy_install Pygments

シンタックスハイライト用の css を生成する

カラーコードを直接埋め込む方法もあるけど、クラスで指定した方がかっこいいと思ったのでクラスで指定する。
クラスで指定する場合は css を事前に生成しておいて読むこんでおく必要がある。
下記のコマンドで css を生成する。
デフォルトで用意されていないカラースキーマの使い方がわからなかったので今回は monokai を使う。

pygmentize -f html -S monokai -a .highlight > monokai.css

生成した css をテーマで読み込む

テーマの static ディレクトリに css を置いて header で読み込む。

シンタックスハイライトを使うように設定する

config.toml に下記の設定を追加。
pygmentscodefences の設定が公式ドキュメントに見つからなくて罠だった。
これを true にしないとバッククオート 3 つでシンタックスハイライトを有効にする機能が動かない。
pygmentsoptions は Pygments のオプションを指定するところで、ここで見た目を変えたりできる。

pygmentscodefences = true
pygmentsCodeFencesGuessSyntax = true
pygmentsStyle = "monokai"
pygmentsUseClasses = true
pygmentsoptions = "linenos=inline"

感想

スッとできると思ったら意外とひっかかって疲れた。
でも終わってみれば簡単っぽい。

参考

Jekyll の記事と WordPress の記事を Hugo にインポートする

背景

WordPress から Jekyll に移行した時に記事の移行が面倒で放っておいた。
Hugo に移行することにしたから Jekyll の記事と WordPress の記事を Hugo にインポートすることになった。
つらい。

Hugo に合わせた最終的な形式

こんな感じに統一することを目指す。
記事のファイルの見通しをよくするためにディレクトリを分けて管理したかったので URL は各ファイルで指定する。

+++
title = "Jekyll の記事と WordPress の記事を Hugo にインポートする"
date = 2017-08-13T04:26:50+09:00
aliases = ["/2017-08-import/"]
+++

# 記事内容

つらつら

手順

実際に行ったインポート作業の内容はこちら。
Feature import article by 5000164 · Pull Request #2 · 5000164/blog

WordPress の記事を Markdown 形式に変換する

最初は Jekyll に移行しようと思ってたのでこれを使いました。
benbalter/wordpress-to-jekyll-exporter: One-click WordPress plugin that converts all posts, pages, taxonomies, metadata, and settings to Markdown and YAML which can be dropped into Jekyll

ファイル名を調整する

なんか日付がたくさんついてたので年と月でディレクトリを分けてからファイル名をきれいにした。

brew install rename
find . -name "*.md" | xargs rename 's/\d\d\d\d-\d\d-\d\d-\d\d\d\d-\d\d-//'

Jekyll の記事の URL はファイル名に依存してたのでファイルの中に書き込む

ファイル名をファイルの中に書き込んでからあとで url に設定をするようにする。
ついでにファイル名も調整する。

for i in $(find . -name "*.markdown"); do echo ${i} > ${i}.new; cat ${i} >> ${i}.new; done
find . -name "*.markdown.new" | xargs rename 's/.markdown.new/.md/'
find . -name "*.markdown" | xargs rm -f
find . -name "*.md" | xargs rename 's/\d\d\d\d-\d\d-\d\d-//'

ひたすら正規表現で置換する

あとはもう望む形になるようにひたすら正規表現で置換する。
titledate は最初から入っているものをうまく使う。
Jekyll の date の形式が違くてエラーになっていたので書式に気をつける。
WordPress からエクスポートした記事には permalink が入っていたのでそれをうまく利用して url にする。
Jekyll のファイルには先ほどファイルの中に埋め込んだファイル名をうまく使って url にする。
画像のリンクとかもひたすら変換する。

あとはなんかおかしいのを見つけたら手で直す

WordPress からエクスポートしたものが変なふうになってたり、なぜか date が 2 個設定されている記事があったり、おかしいものがあったら見つけ次第手で直す。

見た目おかしかったり壊れてるところがあったりするけどひとまず完了

なんとなく見られるようになればよい、という感じでやりました。

ブログを Hugo に移行しました

管理しやすいブログにしたかった

前は Jekyll で GitHub の機能を使ってブログを公開していたが、パソコンを変えたら環境構築が面倒でブログの環境を作ってなかった。
だからもっとシンプルな構成で管理したくて興味があった Hugo に乗り換えた。

ついでに過去の記事をインポートした

Jekyll に移行した時に、その前の WordPress の記事をインポートしていなかった。
それをサボっていたせいで WordPress と Jekyll の両方の記事をインポートしなきゃいけなくて手間だった。

やっとブログ環境を手に入れた

これで更新し放題や。

調べた PHP のプロファイラーのメモ

プロファイラーを調べた

PHP のパフォーマンスを向上させたくてプロファイリングすればなにかわかるのでは?と思ったので、プロファイリングしてくれるツールを調べた。 New Relic は無料のプランがなくなっていた?ので除外。

結論

テスト流す時に Xdebug でプロファイリングして、開発環境で XHProf でプロファイリングすればいいのかなと思った。
XHProf は fork したプロセスのプロファイリングもできるみたいなことを見かけたため。
実現性についてはこれから調べる。

調べたプロファイラーのメモ

テスト頑張ろう - 技術書「テスト駆動開発入門」の感想

やっと読むことができた

本はだいぶ前に買ったのだけど、買った当時は理解できなくて最後まで読むことができなかった。
テスト駆動開発入門なのであって、テスト入門ではない。
テストを書いたことがないと理解できないと思う。

もっとテストのことを考えられるようになった

どういう考えでテストしていくのかを、なんとなく感じ取ることができた。
正しいテストとは、といったことを考えていたので、この本を読むことでもっとテストのことを考えられるようになった。

テストについてもっと勉強したい

読むことはできたけど、まだわからないことが多かった。
テストについてもっと勉強したい。
次は実戦テスト駆動開発を読む。

2015 年 12 月 20 日のこと

早く寝ようと思ってもうまくいかない

ずっと早く寝ようとは思っているのにな。
なんでうまくいかないんだろ。
対症療法的な方法じゃなくて、もっと根本的な原因を探した方がいいかも。