Skip to content

Instantly share code, notes, and snippets.

@ezekg
Last active April 23, 2021 21:10
Show Gist options
  • Save ezekg/b6ac796bc9770424969d0b3eb5c2694c to your computer and use it in GitHub Desktop.
Save ezekg/b6ac796bc9770424969d0b3eb5c2694c to your computer and use it in GitHub Desktop.
Custom electron-builder publisher for https://keygen.sh distribution service
/**
* NOTE(ezekg) Place this file in `resources/electron-publisher-custom.js`
*/
const { Publisher } = require('electron-publish')
const { log } = require('builder-util')
const { basename } = require('path')
const { stat } = require('fs-extra')
const { URL } = require('url')
const https = require('https')
const mime = require('mime')
const {
KEYGEN_PRODUCT_TOKEN,
KEYGEN_ACCOUNT_ID,
KEYGEN_PRODUCT_ID,
} = process.env
class KeygenPublisher extends Publisher {
providerName = 'Keygen'
async upload(task) {
const { file, packager: { platform } } = task
const { cancellationToken } = this.context
const fileName = basename(file)
const options = {
hostname: 'dist.keygen.sh',
path: `/v1/${KEYGEN_ACCOUNT_ID}/${KEYGEN_PRODUCT_ID}/releases/${platform}/${fileName}`,
port: 443,
method: 'POST',
headers: {
authorization: `Bearer ${KEYGEN_PRODUCT_TOKEN}`,
accept: 'application/json',
},
}
log.info({ provider: this.providerName, platform, fileName }, 'creating release')
return await cancellationToken.createPromise((resolve, reject, onCancel) => {
onCancel(() => process.kill(process.pid, 'SIGINT'))
const req = https.request(options, res => {
if (res.statusCode !== 200) {
log.error({ provider: this.providerName, status: res.statusCode, platform, fileName }, 'http error during release')
return reject()
}
res.setEncoding('utf8')
let body = ''
res.on('data', chunk => body += chunk)
res.on('end', async () => {
const data = JSON.parse(body)
const { name, url } = data
log.info({ provider: this.providerName, platform, name, url }, 'created release')
const fileStat = await stat(file)
const progressBar = this.createProgressBar(fileName, fileStat.size)
const stream = this.createReadStreamAndProgressBar(file, fileStat, progressBar, reject)
const { hostname, pathname, search } = new URL(url)
const opts = {
hostname,
path: pathname + search,
port: 443,
method: 'PUT',
headers: {
'Content-Type': mime.lookup(fileName) || 'application/octet-stream',
'Content-Length': fileStat.size,
},
}
log.info({ provider: this.providerName, platform, name, url }, 'uploading release')
const uploader = https.request(opts, r => {
if (r.statusCode !== 200) {
log.error({ provider: this.providerName, status: r.statusCode, platform, fileName }, 'http error during upload')
return reject()
}
r.setEncoding('utf8')
r.on('end', () => {
log.info({ provider: this.providerName, platform, name, url }, 'uploaded release')
if (progressBar != null) {
progressBar.update(1.0)
}
resolve()
})
})
uploader.on('error', error => {
log.error({ provider: this.providerName, error, name, url }, 'failed to upload release')
reject(error)
})
stream.pipe(uploader, { end: true })
})
})
req.on('error', error => {
log.error({ provider: this.providerName, error, platform, fileName }, 'failed to create release')
reject(error)
})
req.end()
})
}
}
module.exports = KeygenPublisher
{
"build": {
"appId": "com.keygen.example",
"directories": {
"buildResources": "./resources",
"output": "dist"
},
"publish": {
"provider": "custom"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment