Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RELEASES file can't be downloaded from the server #94

Open
DM164 opened this issue Jun 29, 2020 · 7 comments
Open

RELEASES file can't be downloaded from the server #94

DM164 opened this issue Jun 29, 2020 · 7 comments

Comments

@DM164
Copy link

DM164 commented Jun 29, 2020

I've already tried some of the solutions here on GitHub but just couldn't get it to work.
When I open the url: https://forget-me-not-update-server.vercel.app/update/win32/1.0.0/RELEASES it doesn't do anything at all and my app with electron autoupdater says that the file is corrupted/ doesn't exist because as mentioned before it's not downloadable.
The repository is private, hazel is hosted on Vercel (Now) and all variables are set.

@DM164
Copy link
Author

DM164 commented Jul 18, 2020

Can anyone respond to this? Would be really helpful...

@jes-wd
Copy link

jes-wd commented Dec 22, 2020

I have the same issue. @DM164 did you ever figure it out?

@DM164
Copy link
Author

DM164 commented Dec 22, 2020

I changed the cacheReleaseList function to this:

async cacheReleaseList(url) {
const { token } = this.config;
const headers = { Accept: "application/vnd.github.preview" };

if (token && typeof token === "string" && token.length > 0) {
  headers.Authorization = `token ${token}`;
}

const res = await retry(
  async () => {
    const response = await fetch(url, { headers });
    let buffer = await response.buffer();

    if (response.status !== 200) {
      throw new Error(
        `Tried to cache RELEASES, but failed fetching ${url}, status ${status}`
      );
    }

    return await buffer.toString("utf-8");
  },
  { retries: 3 }
);

const content = res;
const matches = content.match(/[^ ]*\.nupkg/gim);

if (matches.length === 0) {
  throw new Error(
    `Tried to cache RELEASES, but failed. RELEASES content doesn't contain nupkg`
  );
}

const nuPKG = url.replace("RELEASES", matches[0]);
return content.replace(matches[0], nuPKG);
}

and then I coded my electron app so that it downloads the .exe file and executes and installs it without using any package or library.

@jes-wd
Copy link

jes-wd commented Dec 22, 2020

Thanks for the response.

I had already updated the cacheReleaseList function to that but sadly I still don't get a RELEASES file at /update/win32/:version/RELEASES

@DM164
Copy link
Author

DM164 commented Dec 22, 2020

I know, for me it's the same so I gave up trying to fix it and solved it by adding this to my code:

let cachedVersion = ''
function checkForUpdates() {
    document.getElementById('update-status').innerText = 'Checking for updates...'

    const Http = new XMLHttpRequest();
    let platform = remote.process.platform
    if (platform === 'linux'){ platform = 'debian' }
    const url = `https://forget-me-not-update-server.vercel.app/update/${platform}/1.0.0/`;
    Http.open("GET", url);
    Http.send();

    Http.onloadend = (e) => {
        let response = JSON.parse(Http.responseText)
        cachedVersion = response.name
        if (response.name.length > 7) {
            cachedVersion = cachedVersion.slice(0, cachedVersion.length - 5)
        }
        if (cachedVersion > remote.app.getVersion()) {
            console.log('Update required!')
            document.getElementById('update-status').innerText = 'Update available!'
            ipcRenderer.send('download-update')
        } else {
            document.getElementById('update-status').innerText = 'No update available.'
            console.log('No update required')
        }
    }
}
function installUpdate() {
    const child = require('child_process').execFile;
    let executablePath = null

    if (remote.process.platform === 'win32'){
        executablePath = path.join(__dirname, `../updates/files/forget_me_not-${cachedVersion}-setup.exe`)
    }else if (remote.process.platform === 'linux'){
        executablePath = path.join(__dirname, `../updates/files/forget-me-not_${cachedVersion}_amd64.deb`)
    }

    child(executablePath, function (err, data) {
        if (err) {
            console.error(err);
            return;
        }
        console.log(data.toString());
    });
}
ipcRenderer.on('download-successfull', () => {
    setTimeout(() => {
        installUpdate()
    }, 4000);
})

It doesn't really fix the issue, it's a work around but at least I can update my app now and it works reliably.

@jes-wd
Copy link

jes-wd commented Dec 24, 2020

Thanks. I ended up doing similar. I copied your code and modified it. I thought I'd leave it here in case anyone else needs it in the future. It's a bit rough right now but it works on Windows. Haven't developed for Mac at this stage.

In renderer process:

const https = require("https");
const { execFile } = require("child_process");

// check for updates and install if there is one
function checkForUpdates() {
  // document.getElementById('update-status').innerText = 'Checking for updates...'
  console.log("Checking for updates...");

  const platform = remote.process.platform;

  https.get(
    `https://my-app-name.jes-wd.vercel.app/update/${platform}/${remote.app.getVersion()}/`,
    (response) => {
      let data = "";

      //another chunk of data has been received, so append it to `str`
      response.on("data", function (chunk) {
        data += chunk;
      });

      response.on("error", function (err) {
        console.log(err);
      });

      //the whole response has been received
      response.on("end", function () {
        data = JSON.parse(data);
        console.log(data);
        const cachedVersion = data.name.substring(1);

        console.log("current app version: ", remote.app.getVersion());
        console.log("latest app version: ", cachedVersion);

        if (cachedVersion > remote.app.getVersion()) {
          console.log("Update required!");
          // document.getElementById('update-status').innerText = 'Update available!'
          ipcRenderer.send("download-update", cachedVersion);
        } else {
          // document.getElementById('update-status').innerText = 'No update available.'
          console.log("No update required");
        }
      });
    }
  );

  ipcRenderer.on("download-successful", (event, filePath) => {
    setTimeout(() => {
      installUpdate(filePath);
    }, 4000);
  });
}

function installUpdate(filePath) {

  console.log("install update..");

  const executablePath = filePath;

  execFile(executablePath, ['--version'], {maxBuffer: 1024 * 102400 }, function (err, data) {
    if (err) {
      console.error(err);
      return;
    }
    console.log(data.toString());
  });
}

checkForUpdates();

and in my main process, I added the following:

const ensureDirExists = require("./ensureDirExists");
const request = require("request");
const progress = require('request-progress');
const fs = require("fs");
const path = require('path');

ipcMain.on("download-update", function () {

    console.log("download-update ipcMain event ran");
    console.log("app path", path.dirname(process.execPath));

    const fileName = `my-app-name-Setup-${cachedVersion}.exe`;
    const dir = path.join(path.dirname(process.execPath), "/updates/");

    console.log("update file name: ", fileName);
    console.log('dir: ', dir);
    
    ensureDirExists(dir, 0744, function (err) {
      if (err) {
        console.log(err);
      } else {
        // The options argument is optional so you can omit it
        progress(request("https://my-app-name.jes-wd.vercel.app/download/win32?update=true"), {
          // throttle: 2000,                    // Throttle the progress event to 2000ms, defaults to 1000ms
          // delay: 1000,                       // Only start to emit after 1000ms delay, defaults to 0ms
          // lengthHeader: 'x-transfer-length'  // Length header to use, defaults to content-length
        })
          .on("progress", function (state) {
            console.log("progress", state);
          })
          .on("error", function (err) {
            console.log(err);
          })
          .on("end", function () {
            console.log("download successful");
            mainWindow.webContents.send("download-successful", dir + fileName);
          })
          .pipe(fs.createWriteStream(dir + fileName));
      } 
    });
  });

The ensureDirExists() function required in the main process looks like this:

const fs = require("fs");

function ensureDirExists(path, mask, cb) {
  if (typeof mask == 'function') { // allow the `mask` parameter to be optional
      cb = mask;
      mask = 0777;
  }
  fs.mkdir(path, mask, function(err) {
      if (err) {
          if (err.code == 'EEXIST') cb(null); // ignore the error if the folder already exists
          else cb(err); // something else went wrong
      } else cb(null); // successfully created folder
  });
}

module.exports = ensureDirExists;

@wobedi
Copy link

wobedi commented Jan 11, 2022

Sharing what worked for me:
#79 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants