Chinachu / Mirakurun

A Modern DVR Tuner Server for Japanese TV.
https://chinachu.moe
Apache License 2.0
626 stars 101 forks source link

Windows 環境で Mirakurun 3.9.0-rc.0 以降のバージョンをインストールすると起動に失敗する [BUG] #132

Closed KakologArchivesBot closed 1 year ago

KakologArchivesBot commented 1 year ago

Issue (不具合の内容)

管理者権限で起動した PowerShell で、npm install mirakurun@latest -g --foreground-scripts --production を実行して Mirakurun をインストール/アップデートした際に問題が発生しています。

Windows サービスは正常に起動するものの、Mirakurun 本体は起動に失敗し、Web UI や API に接続できなくなります。

エラーメッセージ:

SyntaxError: Invalid regular expression: /^\/api\/tuners\(?:([^\/]+?))\process\/?$/: Unmatched ')'
    at new RegExp (<anonymous>)
    at pathtoRegexp (C:\Applications\Node.js\node_modules\mirakurun\node_modules\path-to-regexp\index.js:128:10)
    at new Layer (C:\Applications\Node.js\node_modules\mirakurun\node_modules\express\lib\router\layer.js:45:17)
    at Function.route (C:\Applications\Node.js\node_modules\mirakurun\node_modules\express\lib\router\index.js:500:15)
    at app.<computed> [as get] (C:\Applications\Node.js\node_modules\mirakurun\node_modules\express\lib\application.js:481:30)
    at Object.visitOperation (C:\Applications\Node.js\node_modules\mirakurun\node_modules\express-openapi\dist\index.js:143:33)
    at C:\Applications\Node.js\node_modules\mirakurun\node_modules\openapi-framework\dist\index.js:359:29
    at Set.forEach (<anonymous>)
    at C:\Applications\Node.js\node_modules\mirakurun\node_modules\openapi-framework\dist\index.js:227:100
    at Array.forEach (<anonymous>)

この問題は、Mirakurun 3.9.0-beta.26 以前のバージョンでは発生しません。 また、Node.js のバージョンはこの問題の発生条件とは無関係です (14, 16, 18 の全ての Node.js バージョンでこの問題が発生することを確認済み) 。

問題の原因は、Mirakurun が間接的に依存している glob パッケージの破壊的変更により、Mirakurun の API パスが正規表現に変換される際のエラーです。 具体的には、glob v8.x 系以降、Windows のパス区切り文字 \ が glob() においてエスケープ文字として認識され、パス区切り文字としては認識されなくなりました。 これにより、API パス中の一部のパス区切り文字が、正規表現におけるエスケープ文字として認識される状態になってしまいました。

Expected (期待される動作)

Mirakurun の HTTP サーバーが正常に起動し、http://(ip):40772/ で Mirakurun の Web UI が表示されることが期待されます。

不具合の解決方法

Mirakurun の package.json 内の dependencies に、"glob": "^7.2.3", を再度追記することで問題が解決します。

  1. npm 経由で Mirakurun 3.9.0-rc.3 をグローバルインストールする
  2. Mirakurun の Windows サービスを停止する
  3. Mirakurun がインストールされているディレクトリ (node_modules/mirakurun/ 以下) に移動する
  4. node_modules/mirakurun/package.json の dependencies"glob": "^7.2.3", を追記する
  5. package.json と同じディレクトリで npm install --production を実行する
  6. Mirakurun の Windows サービスを起動する

手元の Windows 環境にて、上記の手順で正常に Mirakurun を起動できることを確認しています。

お手数をおかけしますが、何卒 package.json の修正と npm への修正版のリリースのほど、よろしくお願いいたします。

KakologArchivesBot commented 1 year ago

補足:不具合の原因

スタックトレースから、Mirakurun 側の問題ではないことが予想されましたが、間接的に依存するライブラリの破壊的変更が他のライブラリの処理中に顕在化する非常に複雑な問題であり、原因特定に時間がかかりました。

不具合の発生ロジックは下記の通りです (一部推測を含む) 。

  1. Mirakurun の API 実装では、src/Mirakurun/api/tuners/{index}/process.ts のような {} を含むディレクトリ名が、Express が HTTP サーバーを起動する際に、src/Mirakurun/api/tuners/:index/process.ts のような表現に内部的に置き換えられる。
  2. Mirakurun が間接的に依存している glob パッケージ(mirakurun -> express-openapi -> openapi-framework -> glob)が、v8.x 系以降で Windows のパス区切り文字 \ をエスケープ文字としてのみ認識し、パス区切り文字として認識しなくなった
  3. この破壊的変更により、glob v8.x 系では戻り値のパス中の一部のパス区切りが \ として返されるようになった(一部未検証)。
  4. これにより、ルーティング用に構築された API パスの区切り文字の一部が、正規表現におけるエスケープ文字として認識される状態になってしまった
  5. Mirakurun 3.9.0-rc.3 でインストールされる openapi-framework 8.0.0 は、glob パッケージのバージョンを指定していない (現在も指定していない)
  6. Mirakurun は https://github.com/Chinachu/Mirakurun/commit/f7349be8de71b6dfcf2e10206351d5dcae33c325 のコミットで、dependencies 内にあった "glob": "^7.1.7", の明示的な指定を外してしまっている
  7. Express は、内部的に path-to-regexp パッケージを利用して :index のような表現を実際の値に置換している (未検証)
  8. この際に path-to-regexp の内部で生成された正規表現 (/^\/api\/tuners\(?:([^\/]+?))\process\/?$/) のうち、本来 :index のような値をグループ化するための (?:([^\/]+?)) の最初の ( のみ、その直前に配置されているパス区切り文字である \ によってエスケープされてしまい、グループ化子として機能しなくなる
  9. その結果、本来 ( に対応するはずの ) が正規表現中で余ってしまう
  10. これにより、path-to-regexp 内の RegExp オブジェクトを初期化する処理で上記の例外が発生するため、Express の初期化に失敗する
  11. Express の起動に失敗するため、Mirakurun の HTTP サーバーも起動せず、結果として Mirakurun が利用できない状態になる

私の環境ではアップデート前にインストールしていた Mirakurun 3.9.0-rc.2 にロールバックしても引き続きこの問題が発生していたのですが、

  1. openapi-frameworkglob の依存バージョンを指定していないため、Mirakurun 3.9.0-rc.0 で dependencies における glob パッケージのバージョン指定が削除されたことで、常に最新版の glob パッケージがインストールされるようになってしまった
  2. Mirakurun 3.9.0-rc.2 が npm にリリースされた 2022/03/09 には、glob v8.x 系 (v8.x 系が npm にリリースされた最初のバージョンは v8.0.1) はリリースされていなかった
  3. 2022/04/11 に上記の破壊的変更を含む glob v8.x 系 (v8.0.1) が npm にリリースされたことで、その日以降新規に Mirakurun を npm でインストール/アップデートする場合、Mirakurun の依存関係として glob パッケージの v8 系(2023/02/27 以降は v9 系)がインストールされるようになってしまった。

これらの点を考慮すると、すべての状況が説明できます。

Last-Order commented 1 year ago

I'm getting this issue too.

It seems that the version of glob is described in the package-lock.json of openapi-framework but unfortunately the package-lock.json will be ignored if the package is published.

So maybe we should send a PR for openapi-framework to list glob = 7.1.6 in the package.json. (They did do that in the root project.)

KakologArchivesBot commented 1 year ago

Mirakurun 3.9.0-rc.4Platforms.md の手順に従って npm 経由でインストールし、Windows 環境にて正常に起動および動作することを確認できました。 忙しい中での迅速な対応に心から感謝いたします。どうもありがとうございました。