0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NIJIBOXAdvent Calendar 2017

Day 19

ErrbotのStorageプラグインを作ってみる

Last updated at Posted at 2017-12-18

興味本位で、ErrbotのStorageプラグインを1個作ってみた話です。
以降、このページのコードはPython3.6系のみで動きます。1

Storageプラグインの役割

Errbotのプラグインが、「永続化したいデータを管理するためのプラグイン」です。
何も指定しなければ、ビルトインのShelfが使われます。
サードパーティ製のプラグインでは、SQLAlchemyを経由してRDBMSで管理するerr-storage-sql、Firebaseを使うerr-storage-firebaseなどなどがあります。詳しくはErrbotのGithubプロジェクトページにあるWikiを見てみましょう。2

作る前に

Storageプラグインの使われ方

読み込みまで

プラグインが探索されるタイミングは起動時のみです。
また、設定上のBOT_EXTRA_PLUGIN_DIRではなくBOT_EXTRA_STORAGE_PLUGINS_DIRを追加の探索対象とします。
そこからプラグインマネージャーが認識するまでは、他のプラグインと同じです。

初期化するまで

Storageプラグイン自体の仕事は、コアプラグイン・Botプラグインが起動するタイミングで、ストレージを生成することです。
それ以降は(多分)何もしません。

Errbot稼働中

以前に書いた記事でざっくり説明した通り、Botプラグインが永続化させたいデータに対するやり取りは、オーバライドされている辞書アクセス用メソッドを介して行われます。3
この際の最終アクセス先がストレージとなります。

some_plugin.py
from errbot import BotPlugin, botcmd

class SomePlugin(BotPlugin):
   @botcmd
   def like(self, msg, args):
       self['like'] = args  # <- ここで使われる
       return f"OK! You like {args}. I remembered"

Errbot終了

ストレージが持っている終了時に呼ばれるメソッドが呼ばれて役目を終えます。4

ファイル構造について

普通のプラグインと同様に、****.plugファイルとplugファイルが参照している***.pyが必要になります。
この辺は、yapsyを使っているからか、BotプラグインもBackendプラグインもStorageプラグインも同じです。

file_list.rst
* 必須
  * json.plg
  * jsonpg.py
* 任意
  * README.md
  * requirements.txt
  * LICENSE

requirements.txtには依存ライブラリが書かれていることが多いのですが、起動時にこのファイルがあったら自動でpip installをすることが無いです。
ので、面倒だったらなくてもいいかもしれません。

作ってみる

プラグインの中身

errbot.storage.base内にあるStorageBase,StoragePluginBaseを継承して@abstractmethodでデコレートされているメソッドを全部実装すればいいです。

Pluginクラス

この3条件を満たしていればいいです。

  • XXXPluginという形式のクラス名であること(XXXにはplugファイルで定義したNAMEが入ります)
  • __init__が引数を1個受け取ること
  • open()が引数を1個受け取り、ストレージ本体のインスタンスを返すこと(以降、このインスタンスはStorageクラスとします)

Storageクラス

  • 次のメソッドが実装されていること
    • set: キーと値を受け取る
    • get: キーを受け取り、値を返す
    • remove: 指定したキーの値を削除する
    • len: キーの数を返す
    • keys: キーのリストを返す
    • close: 保存する

出来上がったものがこちら

「きちんと動くと思うけど、端折れるところは端折ってる」感じで記載します。

なお、個人的にはYAMLのほうが手っ取り早く見やすくできたので、YAMLストレージも作ってます。

json.plug
[Core]
Name = JSON
Module = jsonpg

[Documentation]
Description = JSON save/load storage for Errbot
jsonpg.py
import os, json
from errbot.storage.base import StorageBase, StoragePluginBase


class JSONStorage(StorageBase):
    def __init__(self, save_path):
        self.save_path = save_path
        try:
            with open(self.save_path) as fp:
                self.data = json.load(fp)
        except FileNotFoundError:
            self.data = {}

    def set(self, key, value):
        self.data[key] = value

    def get(self, key):
        return self.data[key]

    def remove(self, key):
        del self.data[key]

    def len(self):
        return len(self.keys())

    def keys(self):
        return self.data.keys()

    def close(self):
        with open(self.save_path, 'w') as fp:
            json.dump(self.data, fp)


class JSONPlugin(StoragePluginBase):
    def __init__(self, bot_config):
        super().__init__(bot_config)
        # 保存先はShelfプラグイン等と同じ場所
        self.data_dir = bot_config.BOT_DATA_DIR

    def open(self, namespace):
        # 各プラグインごとに呼ばれるので、namespaceをファイル名に使う
        save_path = os.path.join(self.data_dir, f"{namespace}.json")
        return JSONStorage(save_path)

最後に

昨年にBackendプラグインの記事を書いてる方がいましたが、Storageプラグインは考慮したほうがいい点がやや少ないので作りやすいですね。
とはいえ、保存先の仕様をちゃんと把握しないといけないので、楽とまでは言えないですが。

参考

  1. f-stringを直せば、Python3系ならだいたい動くはずです

  2. 定期的に更新されています

  3. https://github.com/errbotio/errbot/blob/master/errbot/storage/__init__.py

  4. もちろん、実装によっては即時保存されることもあります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?