Skip to content

Commit

Permalink
add electron download proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
kilbot committed Mar 24, 2024
1 parent e6adbfa commit 3db5704
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 65 deletions.
Binary file modified bun.lockb
Binary file not shown.
9 changes: 9 additions & 0 deletions components/hello-world.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function Component(properties: {message: string}) {
return (
<body>
<h1>{properties.message}</h1>
</body>
);
}

export const HelloWorld = <Component message='Hello from server!' />;
112 changes: 78 additions & 34 deletions controllers/electron-controller.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,85 @@
import semver from 'semver';
import {getLatestRelease, getAssetsForPlatform} from '../services/github-service';

export const electronController = {
async getLatest(platform: string, version: string, channel: string) {
const release = await getLatestRelease('electron');

if (!release) {
return {status: 404, error: 'No release found'};
}

/**
* Backwards compatibility for electron versions < 1.4.0
* It expects the response to be in the format:
* {
* version: '1.3.0',
* ...
* }
*/
if (semver.lt(version, '1.4.0')) {
return {
version: release.tag_name.replace(/v/, ''),
name: release.name,
assets: getAssetsForPlatform(release.assets, platform),
releaseDate: release.published_at,
notes: release.body,
};
}
/**
*
* @param platform
* @param version
* @param channel
* @returns
*/
async function getLatest(platform: string, version: string, channel: string) {
const release = await getLatestRelease('electron');

if (!release) {
return {status: 404, error: 'No release found'};
}

/**
* Backwards compatibility for electron versions < 1.4.0
* It expects the response to be in the format:
* {
* version: '1.3.0',
* ...
* }
*/
if (semver.lt(version, '1.4.0')) {
return {
status: 200,
data: {
version: release.tag_name.replace(/v/, ''),
name: release.name,
assets: getAssetsForPlatform(release.assets, platform),
releaseDate: release.published_at,
notes: release.body,
},
version: release.tag_name.replace(/v/, ''),
name: release.name,
assets: getAssetsForPlatform(release.assets, platform),
releaseDate: release.published_at,
notes: release.body,
};
},
}

return {
status: 200,
data: {
version: release.tag_name.replace(/v/, ''),
name: release.name,
assets: getAssetsForPlatform(release.assets, platform),
releaseDate: release.published_at,
notes: release.body,
},
};
}

/**
* Just getting latest at the moment, but could be adjust to get specific version
*
* @param platform
* @param version
* @param channel
*/
async function getDownloadUrl(platform: string, version: string, channel: string) {
const release = await getLatestRelease('electron');

// Define a mapping of platforms to their corresponding file extensions and partial identifiers
const platformMapping = {
'darwin-arm64': {extension: 'dmg', identifier: 'arm64'},
'darwin-x64': {extension: 'dmg', identifier: 'x64'},
'win32-x64': {extension: 'exe', identifier: 'Setup'}, // This is a hack, I need to label the assets properly
};

const {extension, identifier} = platformMapping[platform];

// Filter for assets matching the specified platform by extension and, if applicable, identifier
const filteredAssets = release.assets.filter(asset => {
const matchesExtension = asset.name.endsWith(`.${extension}`);
// If an identifier is specified for the platform, check for its presence
const matchesIdentifier = identifier ? asset.name.includes(identifier) : true;
return matchesExtension && matchesIdentifier;
});

// Assuming we're interested in the first match
return filteredAssets.length > 0 ? filteredAssets[0].browser_download_url : {
status: 404,
error: 'No download found',
};
}

export const electronController = {
getLatest,
getDownloadUrl,
};
7 changes: 4 additions & 3 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {Elysia, t} from 'elysia';
import {electronRoutes} from './routes/electron-routes';
import {proRoutes} from './routes/pro-routes';
import {wpAdminRoutes} from './routes/wp-admin-routes';
import {loggerPlugin} from './services/logging-service';

const models = {
Expand All @@ -19,12 +20,12 @@ const models = {
};

const app = new Elysia().use(loggerPlugin).model(models);
app.use(electronRoutes);
app.use(proRoutes);
app.use(wpAdminRoutes);

app.get('/', () => 'Welcome to the WooCommerce POS Updates Server!');

electronRoutes(app);
proRoutes(app);

app.listen(8080);

export type ElysiaApp = typeof app;
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@
"scripts": {
"init:db": "bun ./db/init.ts",
"start": "bun ./index.ts",
"dev": "watchexec --exts ts,js --restart 'bun ./index.ts'"
"dev": "watchexec --exts ts,js --restart 'bun ./index.ts'",
"update-deps": "bunx npm-check-updates --root --format group -i"
},
"dependencies": {
"@elysiajs/stream": "^0.8.0",
"@elysiajs/stream": "^1.0.2",
"@octokit/rest": "^20.0.2",
"bun": "^1.0.30",
"elysia": "^0.8.17",
"bun": "^1.0.35",
"elysia": "^1.0.7",
"react-dom": "^18.2.0",
"semver": "^7.6.0"
},
"devDependencies": {
"bun-devtools": "^0.0.2",
"bun-types": "^1.0.30",
"typescript": "^5.4.2",
"bun-types": "^1.0.35",
"typescript": "^5.4.3",
"xo": "^0.58.0"
},
"xo": {
Expand All @@ -30,4 +32,4 @@
]
}
}
}
}
52 changes: 47 additions & 5 deletions routes/electron-routes.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,58 @@
import {Elysia, t} from 'elysia';
import {Stream} from '@elysiajs/stream';
import {electronController} from '../controllers/electron-controller';
import type {ElysiaApp} from '../types';

export const electronRoutes = (app: ElysiaApp) => {
app.get('/electron/:platform/:version',
const handleDownload = async ({params, set}) => {
// If 'latest' or no version is provided, you might want to dynamically determine the latest version
const version = params.version || 'latest';
const downloadUrl = await electronController.getDownloadUrl(params.platform, version, '');

if (typeof downloadUrl === 'string') {
// Extract the filename from the downloadUrl
const filename = downloadUrl.split('/').pop();
set.headers['Content-Disposition'] = `attachment; filename="${filename}"`;

return new Stream(
fetch(downloadUrl, {
headers: {
Authorization: `token ${process.env.GITHUB_PAT}`,
Accept: 'application/octet-stream',
},
}),
);
}

set.status = downloadUrl?.status;
return downloadUrl;
};

export const electronRoutes = new Elysia({prefix: '/electron'})
// Route with version
.get('/download/:platform/:version',
handleDownload,
{
params: t.Object({
platform: t.String(),
version: t.String(),
// Channel: t.Union([t.String(), t.Undefined()]),
}),
},
)
// Route without version, treating version as optional
.get('/download/:platform', handleDownload, {
params: t.Object({
platform: t.String(),
// Version is omitted here, making it optional in practice
}),
})
.get('/:platform/:version',
async ({params}) => electronController.getLatest(params.platform, params.version, ''),
{
params: t.Object({
platform: t.String(),
version: t.String(),
// Channel: t.Union([t.String(), t.Undefined()]),
// Channel: t.Union([t.String(), t.Undefined()]),
}),
},
);
};

26 changes: 10 additions & 16 deletions routes/pro-routes.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {Elysia, t} from 'elysia';
import {Stream} from '@elysiajs/stream';
import {proController} from '../controllers/pro-controller';
import type {ElysiaApp} from '../types';

const responseModels = {
200: 'success-response',
Expand All @@ -13,8 +12,8 @@ const responseModels = {
503: 'error-response',
};

export const proRoutes = (app: ElysiaApp) => {
app.get('/pro/update/:version',
export const proRoutes = new Elysia({prefix: '/pro'})
.get('/update/:version',
async ({params, set}) => {
const response = proController.getUpdateDetails(params.version);
set.status = response.status;
Expand All @@ -26,9 +25,8 @@ export const proRoutes = (app: ElysiaApp) => {
}),
response: responseModels,
},
);

app.get('/pro/license/status',
)
.get('/license/status',
async ({query, set}) => {
const response = await proController.getLicenseStatus(query.key, query.instance);
set.status = response.status;
Expand All @@ -41,9 +39,8 @@ export const proRoutes = (app: ElysiaApp) => {
}),
response: responseModels,
},
);

app.post('/pro/license/activate',
)
.post('/license/activate',
async ({body}) => proController.activateLicense(body.key, body.instance),
{
body: t.Object({
Expand All @@ -52,9 +49,8 @@ export const proRoutes = (app: ElysiaApp) => {
}),
response: responseModels,
},
);

app.post('/pro/license/deactivate',
)
.post('/license/deactivate',
async ({body}) => proController.deactivateLicense(body.key, body.instance),
{
body: t.Object({
Expand All @@ -63,9 +59,8 @@ export const proRoutes = (app: ElysiaApp) => {
}),
response: responseModels,
},
);

app.get('/pro/download/:version',
)
.get('/download/:version',
async ({params, query, set}) => {
const downloadUrl = await proController.downloadProPlugin(params.version, query.key, query.instance);
if (typeof downloadUrl === 'string') {
Expand Down Expand Up @@ -95,4 +90,3 @@ export const proRoutes = (app: ElysiaApp) => {
// Response: responseModels,
},
);
};
40 changes: 40 additions & 0 deletions routes/wp-admin-routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {Elysia, t} from 'elysia';
import {renderToReadableStream} from 'react-dom/server';
import {Stream} from '@elysiajs/stream';
import {HelloWorld} from '../components/hello-world.tsx';

export const wpAdminRoutes = new Elysia({prefix: '/wp-admin'})
.get('/landing',
async ({params, query, set}) => {
// Set CORS headers
set.headers['Access-Control-Allow-Origin'] = '*';
set.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS';
set.headers['Access-Control-Allow-Headers'] = 'Content-Type';
set.headers['Access-Control-Allow-Credentials'] = 'true';

const stream = await renderToReadableStream(
HelloWorld,
);

return new Stream(
stream,
// {
// status: 200,
// headers: {
// 'Content-Type': 'text/html',
// },
// },
);
},
{
// Params: t.Object({
// version: t.String(),
// }),
// query: t.Object({
// key: t.String(),
// instance: t.String(),
// }),
// Response: responseModels,
},
);

0 comments on commit 3db5704

Please sign in to comment.