段々複雑になってきたので
xterm.jsの画面からは
- 画面からWebSocketで何か送信する
- {
- ssh : {
- logon : {
- username : xxxx
- etc.
- logon : {
- ssh : {
- }…}
- {
- ホスト側で受信
- JSONデータをアドオンのエイリアス(ssh)で配分する
- { ssh : ・・・
- sshエイリアスなアドオンのjsonRequestを呼び出す
- アドオンは受け取ったJSONデータから機能を実行する
- { logon : ・・・
- 処理名(logon)を読み取ってlogon処理を実行する
- logon処理
- { username : xxxx, …}
- 処理名が何か出力したらWebSocketで返信する
にすると後付けが楽な気がしたので、NodeJsで動く部分をアドオン化してみたら更に複雑になった。
├── package.json
├── package-lock.json
├── index.js
├── lock_file.js
├── tree.txt
├── web_socket_entity.js
└── addon
├── package.json
├── base_addon.js
├── js_yaml
│├── package.json
│└── js_yaml.js
└── ssh_client
├── package.json
├── package-lock.json
└── ssh_client.js
アドオンフォルダ(./addon)にプロジェクトごとコピーする方式。
AddonManagerのsetupで、アドオンフォルダ(./addon)の中のフォルダにある
package.jsonのmainかexportをからモジュールのjsファイルを見つけて
エイリアス付きでtypeListsにリストアップするダケなのにとっても長い。
/**
* アドオンマネジャクラス
*/
export class AddonManager extends BaseAddon {
・・・省略・・・
/**
* リスト
*/
typeLists = {};
・・・省略・・・
/**
* コンストラクタ
*/
constructor() {
super();
};
/**
* ./addonディレクトリィのパッケージを検索
* @param (*) pathAddonsDir
*/
setup = (pathAddonsDir, allAddonInfo) => {
this.allAddonInfo = allAddonInfo;
return new Promise((resolve, reject) => {
fs.readdir(pathAddonsDir, { encoding: 'utf-8', withFileTypes: true, recursive: false },
(err, dirents) => {
/**
* error
*/
if (err) {
console.error(err);
reject(err);
return;
}
/**
* ディレクトリィのみに絞込む
*/
dirents = dirents.filter((d) => d.isDirectory());
/**
* とりあえず配列分ループ
*/
const arP = dirents.map((dirent) => {
return new Promise((resolve, reject) => {
const addonPath = `${pathAddonsDir}/${dirent.name}`;
console.log(addonPath);
// dirent配下のpackage.jsonを読む
const packageJsonPathname = `${addonPath}/package.json`;
const packageJsonText = fs.readFileSync(packageJsonPathname);
const packageJson = JSON.parse(packageJsonText);
const mainFile = packageJson.main || packageJson.exports;
if (mainFile !== undefined) {
const mainFilePathname = `${addonPath}/${mainFile}`;
import(mainFilePathname)
.then((module) => {
// 動的に読み込まれたモジュール
const addonModule = new module.default;
// アドオンリストに追加
this.setAddonList(addonModule.addonAlias, addonModule);
resolve(true);
})
.catch((ex) => {
console.error(ex);
reject(ex);
});
} else {
console.error(`addonSetup : ${packageJsonPathname} not found main or exports`);
}
});
});
Promise.all(arP)
.then((values) => {
resolve(true);
});
}
// end of for (const dirent of dirents)
);
});
};
・・・省略・・・
};
アドオンを呼び出す時は
AddonManager::getAddonObject({アドオンのエイリアス})でオブジェクトを取得
/**
* アドオン・オブジェクトを取得
* @param {*} alias
* @returns addon
*/
getAddonObject = (alias) => {
const addonInfo = this.typeLists['addon'][alias];
if (addonInfo) {
const object = new addonInfo.constructor(this.allAddonInfo[alias]);
return object;
} else {
return undefined;
}
};
画面からの要求を{アドオンのオブジェクト}::jsonRequest(WebSocket, json)から
アドオンオブジェクトを作成し実行させている。
/**
* JSONリクエスト処理
* @param {*} webSocketEntity
* @param {*} json
* @param {*} addonObjectList
*/
jsonRequest = (webSocketEntity, json, addonObjectList) => {
const addonModules = this.typeLists['addon'];
for (const alias in json) {
const addon = addonObjectList[alias] ?? this.getAddonObject(alias);
if (!addonObjectList[alias]) { addonObjectList[alias] = addon; }
if (addon) {
try {
addon.request(webSocketEntity, json[alias]);
} catch (ex) {
console.log(`AddonManager::jsonRequest : unknown addon alias '${alias}'`);
}
} else {
console.log(`AddonManager::jsonRequest : unknown addon alias '${alias}'`);
}
}
};
レスポンスはアドオンオブジェクトにWebSocket宛に送信してもらった。
/**
* クライアントに返信する処理
* @param {string} type
* @param {string} commandName
* @param {any} data
*/
sendClient = (type, commandName, data) => {
//console.log(`${commandName} : ${data}`);
const responce = {};
responce[type] = data;
const blob = new Blob([JSON.stringify(responce)], { type: "application/json" });
this.connect.send(blob);
};
やっと画面側もtype毎に処理を分けないといけない事に気が付く。
めんど