フィルタストリームを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インターフェイスで定義されているのは、以下のとおり
- Boolean IsInput { get; set; }
- 実装内容が InputStream なのか OutputStream なのか
- InOutStream CreateStream(Stream baseStream)
- フィルタストリームを返す(マルチスレッドを考慮した実装をしてほしい)
- String ArgorithmName()
- フィルタ内容(圧縮アルゴリズム名とか)を返す
jp.dip.rocketeer.Plugins.IPluginFilterStream インターフェイスで定義しているメソッド/プロパティ
実装する必要があるのは以下
jp.dip.rocketeer.Plugins.IPluginFilterStreamインターフェイスで定義されているのは、以下のとおり
- Dictionary ListDescription()
- 引数文字列などを返す
- IPluginFilterStreamEntity CreateFilterStreamEntity(String name, String value, PluginManagePublicObj iObj, ref String errMsg)
- 名称から FilterStream オブジェクトの実体を作成する。不適切な名称(他のプラグイン呼び出しとかなので)ならnullを返す
jp.dip.rocketeer.Plugins.IPluginBaseインターフェイスで定義されている分については、インターフェイス IPluginBase についてを参照
jp.dip.rocketeer.Plugins.InOutStream クラス
jp.dip.rocketeer.Plugins.InOutStream クラスは、既存の圧縮ストリームとか、暗号ストリームが双方向ストリームではないので、双方向化するためにラップされたストリーム。
例えば、インプットとして設定された圧縮ストリームに、アウトプット(Write)しようとするとエラーとなるので、そういうのをスルーして上位ストリームへ渡したりしてくれるストリーム。
(StreamRelay.NET.exeは、双方向ストリームを前提としているので)
なんとなくのなんちゃってコードだとこんな感じ
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を生成して、返してほしい。