フィルタストリームをプラグインとして実装する方法

---
### フィルタストリームをStreamRelay.NET.exe のプラグインとして実装する方法について説明する

StreamRelay.NET.exe/StreamRelay.NET.x86.exeには、いくつかの機能をプラグインとして実装できるようにインターフェイスを公開している。

今回は、フィルタストリーム(ストリームを受け取ってストリームを返すストリーム)をStreamRelay.NET.exeから呼び出させるインターフェイスを使って、プラグインを作成する方法を記述する。

---
### 既存のプラグイン

圧縮ストリームとか、BASExx系の変換ストリームとか、そういうものを既存として作った。

プラグイン的には、このあたり。

- Plugins\Plugin.7zip.dll
- Plugins\Plugin.BaseFilterStream.dll
- Plugins\Plugin.BouncyCastle.Crypto.dll
- Plugins\Plugin.Brotli.dll
- Plugins\Plugin.CSharpCode.SharpZipLib.dll
- Plugins\Plugin.LZ4.dll
- Plugins\Plugin.sEncoding.dll
- Plugins\Plugin.Snappy.dll
- Plugins\Plugin.xz.dll
- Plugins\Plugin.zlib.NET.dll
- Plugins\Win32\Plugin.Zopfli.x86.dll
- Plugins\Win64\Plugin.Zopfli.x64.dll
- Plugins\Plugin.ZstdNet.dll

---
### 実装したプラグインの呼び出され方

-[Local/Remote]Proxy オプションのnetstreamスキームの引数として渡された引数に応じて、ストリームを包んだりする

という感じ。

---
### 実装するインターフェイス

以下のインターフェイスを継承したクラスを実装すればよい

- IPlugin.dll 中の jp.dip.rocketeer.Plugins.IPluginFilterStreamEntity インターフェイス
- IPlugin.dll 中の jp.dip.rocketeer.Plugins.IPluginFilterStream インターフェイス

このクラス一つだけ実装すればよい。

---
### jp.dip.rocketeer.Plugins.IPluginFilterStreamEntity インターフェイス

StreamRelay.NET.exeから、引数/オプションの解析処理中に呼び出して、引数の指定内容によって、IPluginFilterStreamEntityを返す。
すると、IPluginFilterStreamEntityから、Streamを包んでStreamを返すものを呼び出したりする。

という感じ。

例えば

`-RemoteProxy netstream:///?GzipCompress=lv1&GzipDeCompress`

という引数の「**GzipCompress**」とか「**GzipDeCompress**」というのが、**IPluginFilterStreamEntity CreateFilterStreamEntity(String name, String value, PluginManagePublicObj iObj, ref String errMsg)** の「**name**」に渡されるので、自分の引数であれば、IPluginFilterStreamEntityオブジェクトを返してほしい。

ちなみに「**value**」には「**name=GzipCompress**」時には「**lv1**」が、「**name=GzipDeCompress**」時には「**null**」が渡される感じ。

そしてストリームの生成時に、IPluginFilterStreamEntity#**CreateStream(Stream)** 
が呼ばれるので、ストリームを包んでくれればよい。

---
#### jp.dip.rocketeer.Plugins.IPluginFilterStreamEntity インターフェイスで定義しているメソッド/プロパティ

実装する必要があるのは以下

jp.dip.rocketeer.Plugins.IPluginFilterStreamEntityインターフェイスで定義されているのは、以下のとおり

<dl>
 <dt><b>Boolean IsInput { get; set; }</b>
  <dd>実装内容が InputStream なのか OutputStream なのか
 <dt><b>InOutStream CreateStream(Stream baseStream)</b>
  <dd>フィルタストリームを返す(マルチスレッドを考慮した実装をしてほしい)
 <dt><b>String ArgorithmName()</b>
  <dd>フィルタ内容(圧縮アルゴリズム名とか)を返す
</dl>

---
#### jp.dip.rocketeer.Plugins.IPluginFilterStream インターフェイスで定義しているメソッド/プロパティ

実装する必要があるのは以下

jp.dip.rocketeer.Plugins.IPluginFilterStreamインターフェイスで定義されているのは、以下のとおり

<dl>
 <dt><b>Dictionary<String, String> ListDescription()</b>
  <dd>引数文字列などを返す
 <dt><b>IPluginFilterStreamEntity CreateFilterStreamEntity(String name, String value, PluginManagePublicObj iObj, ref String errMsg)</b>
  <dd>名称から FilterStream オブジェクトの実体を作成する。不適切な名称(他のプラグイン呼び出しとかなので)ならnullを返す
</dl>

jp.dip.rocketeer.Plugins.IPluginBaseインターフェイスで定義されている分については、[インターフェイス IPluginBase について](https://qiita.com/tomoki0sanaki/items/60613c29f0d627353e67)を参照

---
### jp.dip.rocketeer.Plugins.InOutStream クラス

jp.dip.rocketeer.Plugins.<b>InOutStream</b> クラスは、既存の圧縮ストリームとか、暗号ストリームが双方向ストリームではないので、双方向化するためにラップされたストリーム。

例えば、インプットとして設定された圧縮ストリームに、アウトプット(Write)しようとするとエラーとなるので、そういうのをスルーして上位ストリームへ渡したりしてくれるストリーム。
(StreamRelay.NET.exeは、双方向ストリームを前提としているので)

なんとなくのなんちゃってコードだとこんな感じ

```c#:
public class exampleFilter : IPluginFilterStreamEntity{
// 例えば、何か圧縮するストリームだとする。
CompressStream compressStream;

InOutStream CreateStream(Stream baseStream){
	// baseStreamストリームを包む
	// 例えば、何かを圧縮するストリームを生成する
        compressStream = new CompressStream(baseStream);

	// 何かを圧縮するストリームを包んだInOutStream(System.IO.Stream)を返す
	// 入力側は圧縮するのでcompressStreamだけど、
	// 出力側は圧縮しないのでbaseStreamそのままを引数に与える
	return new InOutStream(compressStream, baseStream);
}}
```

みたいな感じで InOutStreamを生成して、返してほしい。

---
### 目次へ戻る

[目次というか最初の一歩](http://qiita.com/tomoki0sanaki/items/85f20cbe18378e33cd6f)