コンテンツにスキップ

汎用プラグイン開発

このページでは、Sikiの通信や起動時の処理を拡張する「汎用プラグイン」の作り方を説明します。

対応バージョン

内容はSiki 0.43.6の実装を基準にしています。汎用プラグインのAPIは現在正式な互換性保証がないため、配布時は対応するSikiのバージョンを明記してください。

このページの対象

ここで扱うのは request-hook、startup、shutdown のプラグインです。掲示板サイトを追加する gpbc-plugin-*(サイトインタプリタ)は別の仕組みなので、このページの対象外です。

プラグインの仕組み

プラグインは、Sikiのプロファイルにある plugins フォルダの下に、プラグインごとのフォルダを作って配置します。デフォルトのプロファイルは次の場所です。

OS プロファイル
Windows C:\Users\{ユーザー名}\AppData\Roaming\siki\profile
macOS /Users/{ユーザー名}/Library/Application Support/siki/profile
Linux /home/{ユーザー名}/.config/siki/profile

プラグインの場所を変更している場合は、設定の「Plugin Directory」を確認してください。

plugins/
└─ hello-plugin/
   ├─ package.json
   └─ index.js

最小の構成

通常は package.json の main で指定したJavaScriptファイルが読み込まれます。

{
  "name": "hello-plugin",
  "version": "1.0.0",
  "description": "Siki用のサンプルプラグイン",
  "main": "index.js"
}
module.exports.type = 'startup'
module.exports.meta = {
  name: 'hello-plugin',
  description: '起動時に一度だけ実行するサンプル',
  version: '1.0.0',
  needVersion: '0.43.6'
}

module.exports.mainScript = async (settings, tools) => {
  tools.emitter.emit('plugin:hello-plugin:ready')
}

プラグインを配置したら、設定のプラグイン一覧で有効にしてSikiを再起動します。プラグインのコードや package.json を変更した場合も、まず再起動して読み込み直してください。

フォルダ名、package.json の name、meta.name は同じ名前にすることを推奨します。表示名と有効化判定に使われる名前が異なると、設定画面で有効状態を正しく表示できない場合があります。

プラグインの種類

type 実行される処理 主な用途
request-hook beforeRequest、afterRequest 通信のURL・ヘッダー・本文の変更、通信結果の保存や補正
startup mainScript 起動時の初期化、イベント購読、外部サービスの準備
shutdown mainScript Siki終了時の保存や後片付け

meta

モジュールの meta は、設定画面やログに表示する情報です。

プロパティ 内容
name プラグイン名。フォルダ名と一致させることを推奨
description 設定画面に表示する説明
version プラグインのバージョン
needVersion 動作確認したSikiの最低バージョン。互換性チェックを自動で行う値ではありません

type はモジュールのトップレベルに指定します。

module.exports.type = 'request-hook'
module.exports.meta = {
  name: 'example-hook',
  description: '通信を補正する例',
  version: '1.0.0',
  needVersion: '0.43.6'
}

request-hook

beforeRequest

通信を送信する前に呼び出されます。変更したい値を返してください。返さない場合は元の通信内容が使われます。

module.exports.beforeRequest = async (tools, url, method, headers, payload, query) => {
  if (url.includes('example.com')) {
    headers['user-agent'] = 'my-siki-plugin/1.0'
    return { url, method, headers, payload }
  }
}
引数 内容
tools プラグイン用の補助オブジェクト
url リクエストURL
method GET、HEAD、POST、PUT、DELETE
headers リクエストヘッダー。キーは小文字
payload パーセントエンコード済みの本文
query URLクエリ。エンコード前の値

戻り値には url、method、headers、payload のうち変更したものだけを含められます。

afterRequest

通信が完了した後に呼び出されます。レスポンスの本文やステータスを補正できます。

module.exports.afterRequest = async (tools, url, statusCode, response_headers, response_body) => {
  if (url.endsWith('/subject.txt')) {
    response_body = response_body.replaceAll('古い表記', '新しい表記')
  }
  return { statusCode, response_headers, response_body }
}
引数 内容
tools プラグイン用の補助オブジェクト
url リクエストに使ったURL
statusCode HTTPステータスコード
response_headers レスポンスヘッダー。キーは小文字
response_body Unicode文字列に変換済みのレスポンス本文

戻り値には statusCode、response_headers、response_body を指定できます。複数のフックを有効にしている場合は、有効化された順に実行され、前のフックの変更結果が次のフックへ渡されます。

request-hook のツール

beforeRequest と afterRequest の第1引数に渡されます。

プロパティ 内容
conf request_hook_conf に保存する設定。get、set、delete が使えます
simplefetch Sikiの通信処理を使って別のURLを取得する関数
log error、warn、info、verbose、debug のログ関数
siki_values workspaceid、user_dir、log_dir、plugin_dir などの値
get_res URLからSikiのスレッドデータを取得する非同期関数

設定キーにはプラグイン名を含め、他のプラグインと衝突しない名前を使ってください。

const key = 'example-hook.lastValue'
const previous = tools.conf.get(key)
tools.conf.set(key, 'saved value')

通信フックはワークスペース単位で無効化できる場合があります。対象ワークスペースでフックが無効になっていると、関数は呼ばれません。

startup

mainScript(settings, tools) はSiki起動時に一度だけ実行されます。

module.exports.type = 'startup'
module.exports.meta = {
  name: 'startup-example',
  description: '起動時のイベントを監視する例',
  version: '1.0.0'
}

module.exports.mainScript = async (settings, tools) => {
  const { config, userSettings } = settings
  tools.emitter.on('ThreadFetchSuccess', (urlObject) => {
    console.log('thread fetched', urlObject.location)
  })
}

settings

プロパティ 内容
config Sikiのシステム設定。config.js 相当
userSettings ユーザー設定。user.js 相当

startup のツール

プロパティ 内容
emitter Siki内部イベントを購読・発火するイベントエミッター
syncplay Syncplay機能のインスタンス
iconv 文字コード変換ライブラリ

イベント名やイベントデータは内部実装に依存します。利用するイベントは、対応するSikiバージョンで確認してください。

shutdown

shutdown はSikiの終了処理で mainScript(settings) が一度だけ呼ばれます。設定の保存や一時ファイルの後片付けに利用できます。

module.exports.type = 'shutdown'
module.exports.meta = {
  name: 'shutdown-example',
  description: '終了時に処理する例',
  version: '1.0.0'
}

module.exports.mainScript = async (settings) => {
  // 終了前に必要な保存処理を行う
}

終了処理は短時間で完了するようにし、失敗してもSikiの終了を妨げない設計にしてください。

エラーとデバッグ

  • package.json の version または main がないと、通常のプラグインとして読み込まれません。
  • モジュールの読み込みに失敗した場合は、Sikiのログにプラグイン名とエラー内容が記録されます。
  • startup、shutdown、通信フックで発生した例外はSiki側で捕捉され、ログに記録されます。
  • 通信フックで例外が発生した場合は、Siki側で捕捉してログに記録し、処理を継続します。フック内で途中まで値を書き換えていた場合の結果は保証されません。
  • 変更後に反映されない場合は、フォルダ名、有効化状態、package.json の main、構文エラー、Sikiの再起動を順に確認してください。

プラグインはNode.jsの機能を利用できるため、外部から入手したプラグインは内容を確認してから有効にしてください。特に、認証情報、Cookie、通信本文、プロファイル内のファイルを扱うプラグインには注意が必要です。

配布時の確認項目

  • 対応するSikiのバージョンを needVersion とREADMEに記載する
  • package.json の name、version、main を確認する
  • プラグインフォルダをそのままZIPにする
  • 必要な依存パッケージとライセンスを明記する
  • 認証情報や個人のプロファイルファイルをZIPに含めない
  • エラー時にSikiを停止させない

現在の配布プラグイン一覧はプラグインを参照してください。