Electronメインプロセス中にレンダラーのasarファイルをダウンロードして開く方法

# コード

- 成功すれば`true`、失敗すれば`false`が返ってくる 
- `fs`ではなく`original-fs`を使用
- バージョンアップで既存のモジュールが使えなくなるなど、保守性を考えて、デフォルトの`http`または`https`でダウンロード
- 今回は`GoogleDrive`に保存したasarファイルを`DriveToWeb`でホスティングしていたため、asarファイルのように容量が大きいと`303`が返ってくるので再帰でもう一度リクエストを送っている

https://teratail.com/questions/cy6vyydt1hnbn7

```asarDownLoad.js
const https = require('https')
const originalfs = require('original-fs')

/**
 * http.get
 * asarのダウンロード・置き換え
 * @param {*} url ダウンロードするファイルのURL
 * @param {*} outURL 出力するファイルのURL
 */
const asarDownLoadTest = async (url, outURL) => {

    try {
        return await new Promise((resolve, reject) => {

            const req = https.get(url, async (res) => {

                console.log(res.statusCode) // 303が返ってくる
                console.log(res.statusMessage)

                // 303だった場合locationを見てそこから取得
                if (res.statusCode === 303) {
                    await asarDownLoadTest(res.headers.location, outURL) // 再帰
                    resolve(true) //trueを返す
                    return
                }
                // ダウンロードした内容をそのまま、ファイル書き出し。
                let total = 0 // 合計byte数
                let percent = 0 // %
                // データを取得する度に実行される
                res.on("data", (chunk) => {
                    total += chunk.length // これまで読み取ったbyte数
                    const length = res.headers['content-length']
                    if (percent !== parseInt(total / length * 100)) {
                        percent = parseInt(total / length * 100)
                        console.log(`${percent} %`)
                    }
                });
                // ダウンロードした内容をそのまま、ファイル書き出し。
                const outFile = originalfs.createWriteStream(outURL)
                res.pipe(outFile)

                // 終わったらファイルストリームをクローズ。
                res.on('end', () => {
                    console.log('end')
                    outFile.close()
                    resolve(true) // trueを返す
                })
            })

            // エラーがあれば扱う。
            req.on('error', (err) => {
                console.log('Error: ', err)
                reject(false) // falseを返す
            })
        })
    } catch (err) { // rejectのfalseをキャッチ
        console.log(err)
        return err // falseを返す
    }

}

exports.asarDownLoadTest = asarDownLoadTest
```

- `main.js`で実行
- asarファイルの保存場所は`app.getPath('userData') + '/render.asar'`にする

```main.js
// モジュールロード
const { app, Menu, BrowserWindow, dialog } = require('electron')
const { asarDownLoad } = require('./asarDownLoad.js')

//一部抜粋

// asyncの中
// URLを指定 
const url = ''
// 出力ファイル名を指定
const outURL = app.getPath('userData') + '/render.asar'

const download =  await asarDownLoad(url, outURL) // ダウンロード開始
if (!download) { // 失敗時
   dialog.showErrorBox('Connection Failed','インターネットへの接続が失敗しました。インターネットに接続して、もう一度アプリを起動してください');
}

// メインウィンドウ起動 const win = new BrowserWindow({}) // 適宜設定してください
win.loadURL('file://' + app.getPath('userData') + '/render.asar/index.html') // asarの中のアプリを開く

```

# なぜこのコードを書く必要があるのか？

- 署名なしでフロント部分のアップデート機能を実装するため
- メインプロセスが実行されて、レンダラープロセスに入り前にasarファイルを置き換える
- 詳しくは以下の記事を参照してください

https://qiita.com/syumai/items/967ec9cd967e7dbe09d0

バージョン確認してからアップデートするかしないかを判断するのはまた今度