Switch to using a different method of database access

This commit is contained in:
2025-11-08 19:13:23 -07:00
parent 01e0c233d7
commit 3fe9788a4f
9 changed files with 304 additions and 240 deletions

View File

@@ -11,7 +11,7 @@
"mysql2": "3.15.3", "mysql2": "3.15.3",
}, },
"devDependencies": { "devDependencies": {
"bun-types": "1.3.1", "bun-types": "1.3.2",
}, },
}, },
}, },
@@ -32,7 +32,7 @@
"aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="],
"bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], "bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],

View File

@@ -13,7 +13,7 @@
"mysql2": "3.15.3" "mysql2": "3.15.3"
}, },
"devDependencies": { "devDependencies": {
"bun-types": "1.3.1" "bun-types": "1.3.2"
}, },
"module": "src/index.js" "module": "src/index.js"
} }

View File

@@ -1,37 +1,35 @@
import { Elysia } from "elysia"; import { Elysia } from 'elysia'
import { cors } from "@elysiajs/cors" import { cors } from '@elysiajs/cors'
import { jsonResponse } from "./lib/util"; import { jsonResponse } from './lib/util'
import { drizzle } from 'drizzle-orm/mysql2';
import mysql from 'mysql2/promise';
import dotenv from 'dotenv' import dotenv from 'dotenv'
import { handler as launcherVersionsHandler } from "./routes/launcher/versions"; import { handler as launcherVersionsHandler } from './routes/launcher/versions'
import { handler as launcherLatestHandler } from "./routes/launcher/latest"; import { handler as launcherLatestHandler } from './routes/launcher/latest'
import { handler as launcherLoaderLatestHandler } from "./routes/launcher/loader/latest"; import { handler as launcherLoaderLatestHandler } from './routes/launcher/loader/latest'
import { handler as launcherLoaderUpdateDataHandler } from "./routes/launcher/loader/update-data"; import { handler as launcherLoaderUpdateDataHandler } from './routes/launcher/loader/update-data'
dotenv.config() dotenv.config()
const connection = await mysql.createConnection({ const app = new Elysia().use(
host: process.env.DB_HOST ?? 'localhost', cors({
port: Number(process.env.DB_PORT) || 3306, origin: '*',
user: process.env.DB_USER ?? '', methods: ['POST', 'GET']
password: process.env.DB_PASS ?? '', })
database: process.env.DB_NAME ?? '' )
});
const db = drizzle(connection); app.get('/launcher/versions', context => launcherVersionsHandler(context))
app.get('/launcher/latest', launcherLatestHandler)
app.get('/launcher/loader/latest', launcherLoaderLatestHandler)
app.get('/launcher/loader/update-data', context =>
launcherLoaderUpdateDataHandler(context)
)
app.all('*', () =>
jsonResponse(
{
message: 'No endpoint found (are you using the correct request method?)'
},
404
)
)
const app = new Elysia() app.listen(3342)
.use(cors({
origin: "*",
methods: ["POST", "GET"]
}))
app.get("/launcher/versions", (context) => launcherVersionsHandler(context, db))
app.get("/launcher/latest", () => launcherLatestHandler(db))
app.get("/launcher/loader/latest", launcherLoaderLatestHandler)
app.get("/launcher/loader/update-data", (context) => launcherLoaderUpdateDataHandler(context, db))
app.all("*", () => jsonResponse({ message: "No endpoint found (are you using the correct request method?)" }, 404))
app.listen(3342)

View File

@@ -1,35 +1,45 @@
import { bigint, boolean, int, mysqlTable, text, varchar } from "drizzle-orm/mysql-core"; import {
bigint,
boolean,
int,
mysqlTable,
text,
varchar
} from 'drizzle-orm/mysql-core'
export const launcherGames = mysqlTable('launchergames', { export const launcherGames = mysqlTable('launchergames', {
id: int('id').primaryKey().autoincrement(), id: int('id').primaryKey().autoincrement(),
name: text('name').notNull(), name: text('name').notNull(),
official: boolean('official').notNull().default(false), official: boolean('official').notNull().default(false),
verified: boolean('verified').notNull().default(false), verified: boolean('verified').notNull().default(false),
developer: varchar('developer', { length: 32 }), developer: varchar('developer', { length: 32 }),
cutOff: int('cutOff').notNull().default(-1) cutOff: int('cutOff').notNull().default(-1)
}) })
export const launcherVersions = mysqlTable('launcherversions', { export const launcherVersions = mysqlTable('launcherversions', {
id: varchar('id', { length: 24 }).primaryKey(), id: varchar('id', { length: 24 }).primaryKey(),
versionName: text('versionName').notNull(), versionName: text('versionName').notNull(),
releaseDate: bigint('releaseDate', { mode: 'number' }).notNull(), releaseDate: bigint('releaseDate', { mode: 'number' }).notNull(),
downloadUrls: text('downloadUrls').notNull(), downloadUrls: text('downloadUrls').notNull(),
platforms: text('platforms').notNull(), platforms: text('platforms').notNull(),
executables: text('executables').notNull(), executables: text('executables').notNull(),
hidden: boolean('hidden').notNull().default(false), hidden: boolean('hidden').notNull().default(false),
game: int('game').notNull().default(0).references(() => launcherGames.id), game: int('game')
place: int('place').notNull().default(0), .notNull()
sha512sums: text('sha512sums').notNull().default("[]"), .default(0)
sizes: text('sizes').notNull().default("[]") .references(() => launcherGames.id),
place: int('place').notNull().default(0),
sha512sums: text('sha512sums').notNull().default('[]'),
sizes: text('sizes').notNull().default('[]')
}) })
export const launcherUpdates = mysqlTable('launcherupdates', { export const launcherUpdates = mysqlTable('launcherupdates', {
id: varchar('id', { length: 24 }).primaryKey(), id: varchar('id', { length: 24 }).primaryKey(),
releaseDate: bigint('releaseDate', { mode: 'number' }).notNull(), releaseDate: bigint('releaseDate', { mode: 'number' }).notNull(),
downloadUrls: text('downloadUrls').notNull(), downloadUrls: text('downloadUrls').notNull(),
platforms: text('platforms').notNull(), platforms: text('platforms').notNull(),
executables: text('executables').notNull(), executables: text('executables').notNull(),
hidden: boolean('hidden').notNull().default(false), hidden: boolean('hidden').notNull().default(false),
place: int('place').notNull().default(0), place: int('place').notNull().default(0),
sha512sums: text('sha512sums').notNull().default("[]") sha512sums: text('sha512sums').notNull().default('[]')
}) })

View File

@@ -1,6 +1,22 @@
export function jsonResponse(data: any, status = 200) { import mysql from 'mysql2'
return new Response(JSON.stringify(data, null, 2), { import { drizzle } from 'drizzle-orm/mysql2'
status, import { Connection } from 'mysql2/typings/mysql/lib/Connection'
headers: { "Content-Type": "application/json" }
}) export function jsonResponse (data: any, status = 200) {
} return new Response(JSON.stringify(data, null, 2), {
status,
headers: { 'Content-Type': 'application/json' }
})
}
export function getDatabaseConnection () {
const connection = mysql.createConnection({
host: process.env.DB_HOST ?? 'localhost',
port: Number(process.env.DB_PORT) || 3306,
user: process.env.DB_USER ?? '',
password: process.env.DB_PASS ?? '',
database: process.env.DB_NAME ?? ''
})
return drizzle(connection)
}

View File

@@ -1,15 +1,18 @@
import { MySql2Database } from "drizzle-orm/mysql2" import { launcherUpdates } from '../../lib/tables'
import { launcherUpdates } from "../../lib/tables" import { desc, eq } from 'drizzle-orm'
import { desc, eq } from "drizzle-orm" import { getDatabaseConnection } from '../../lib/util'
export async function handler(db: MySql2Database) { export async function handler () {
const version = await db.select({ const db = getDatabaseConnection()
id: launcherUpdates.id
const version = await db
.select({
id: launcherUpdates.id
}) })
.from(launcherUpdates) .from(launcherUpdates)
.where(eq(launcherUpdates.hidden, false)) .where(eq(launcherUpdates.hidden, false))
.orderBy(desc(launcherUpdates.place)) .orderBy(desc(launcherUpdates.place))
.limit(1) .limit(1)
return version[0].id return version[0].id
} }

View File

@@ -1,3 +1,3 @@
export async function handler() { export async function handler () {
return "1.0.1" return '1.0.1'
} }

View File

@@ -1,80 +1,92 @@
import { MySql2Database } from "drizzle-orm/mysql2"; import { launcherUpdates } from '../../../lib/tables'
import { launcherUpdates } from "../../../lib/tables"; import { desc, eq } from 'drizzle-orm'
import { desc, eq } from "drizzle-orm"; import { getDatabaseConnection, jsonResponse } from '../../../lib/util'
import { jsonResponse } from "../../../lib/util"; import { Context } from 'elysia'
import { Context } from "elysia";
export async function handler(context: Context, db: MySql2Database) { export async function handler (context: Context) {
const platform = context.query.platform as string | undefined const db = getDatabaseConnection()
const arch = context.query.arch as string | undefined
let showAll = false
if (!platform || !arch) { const platform = context.query.platform as string | undefined
showAll = true const arch = context.query.arch as string | undefined
let showAll = false
if (!platform || !arch) {
showAll = true
}
let platString = null
if (!showAll) {
if (platform == 'windows') {
if (arch == 'x86_64') platString = 'windows'
else if (arch == 'aarch64') platString = 'windows-arm64'
else {
return jsonResponse(
{ error: 'Unsupported architecture for Windows' },
400
)
}
} else if (platform == 'linux') {
if (arch == 'x86_64') platString = 'linux'
else {
return jsonResponse(
{ error: 'Unsupported architecture for Linux' },
400
)
}
} else if (platform == 'macos') {
if (arch == 'x86_64') platString = 'macos-intel'
else if (arch == 'aarch64') platString = 'macos-silicon'
else {
return jsonResponse(
{ error: 'Unsupported architecture for macOS' },
400
)
}
} else {
return jsonResponse({ error: 'Unsupported platform' }, 400)
} }
}
let platString = null const versionsRaw = await db
if (!showAll) { .select({
if (platform == "windows") { id: launcherUpdates.id,
if (arch == "x86_64") platString = "windows" releaseDate: launcherUpdates.releaseDate,
else if (arch == "aarch64") platString = "windows-arm64" downloadUrls: launcherUpdates.downloadUrls,
else { platforms: launcherUpdates.platforms,
return jsonResponse({ error: "Unsupported architecture for Windows" }, 400) sha512sums: launcherUpdates.sha512sums
}
} else if (platform == "linux") {
if (arch == "x86_64") platString = "linux"
else {
return jsonResponse({ error: "Unsupported architecture for Linux" }, 400)
}
} else if (platform == "macos") {
if (arch == "x86_64") platString = "macos-intel"
else if (arch == "aarch64") platString = "macos-silicon"
else {
return jsonResponse({ error: "Unsupported architecture for macOS" }, 400)
}
} else {
return jsonResponse({ error: "Unsupported platform" }, 400)
}
}
const versionsRaw = await db.select({
id: launcherUpdates.id,
releaseDate: launcherUpdates.releaseDate,
downloadUrls: launcherUpdates.downloadUrls,
platforms: launcherUpdates.platforms,
sha512sums: launcherUpdates.sha512sums
}) })
.from(launcherUpdates) .from(launcherUpdates)
.where(eq(launcherUpdates.hidden, false)) .where(eq(launcherUpdates.hidden, false))
.orderBy(desc(launcherUpdates.place)) .orderBy(desc(launcherUpdates.place))
.limit(1) .limit(1)
.execute() .execute()
const versions = versionsRaw.map(v => ({ const versions = versionsRaw
...v, .map(v => ({
downloadUrls: JSON.parse(v.downloadUrls), ...v,
platforms: JSON.parse(v.platforms), downloadUrls: JSON.parse(v.downloadUrls),
sha512sums: JSON.parse(v.sha512sums), platforms: JSON.parse(v.platforms),
downloadUrl: undefined as string | undefined, sha512sums: JSON.parse(v.sha512sums),
sha512sum: undefined as string | undefined downloadUrl: undefined as string | undefined,
sha512sum: undefined as string | undefined
})) }))
.filter(v => { .filter(v => {
if (showAll || !platString) { if (showAll || !platString) {
delete v.downloadUrl delete v.downloadUrl
delete v.sha512sum delete v.sha512sum
return true return true
} }
const i = v.platforms.indexOf(platString) const i = v.platforms.indexOf(platString)
if (i !== -1) { if (i !== -1) {
v.downloadUrl = v.downloadUrls[i] v.downloadUrl = v.downloadUrls[i]
v.sha512sum = v.sha512sums[i] v.sha512sum = v.sha512sums[i]
delete v.downloadUrls delete v.downloadUrls
delete v.platforms delete v.platforms
delete v.sha512sums delete v.sha512sums
return true return true
} }
return false return false
}) })
return jsonResponse(versions[0]) return jsonResponse(versions[0])
} }

View File

@@ -1,98 +1,123 @@
import { MySql2Database } from "drizzle-orm/mysql2"; import { launcherGames, launcherVersions } from '../../lib/tables'
import { launcherGames, launcherVersions } from "../../lib/tables"; import { asc, desc, eq } from 'drizzle-orm'
import { asc, desc, eq } from "drizzle-orm"; import { getDatabaseConnection, jsonResponse } from '../../lib/util'
import { jsonResponse } from "../../lib/util"; import { Context } from 'elysia'
import { Context } from "elysia";
export async function handler(context: Context, db: MySql2Database) { export async function handler (context: Context) {
const platform = context.query.platform as string | undefined const db = getDatabaseConnection()
const arch = context.query.arch as string | undefined
let showAll = false
if (!platform || !arch) { const platform = context.query.platform as string | undefined
showAll = true const arch = context.query.arch as string | undefined
} let showAll = false
let platString = null if (!platform || !arch) {
if (!showAll) { showAll = true
if (platform == "windows") { }
if (arch == "x86_64") platString = "windows"
else if (arch == "aarch64") platString = "windows-arm64"
else {
return jsonResponse({ message: "Unsupported architecture for Windows", versions: null, games: null }, 400)
}
} else if (platform == "linux") {
if (arch == "x86_64") platString = "linux"
else {
return jsonResponse({ message: "Unsupported architecture for Linux", versions: null, games: null }, 400)
}
} else if (platform == "macos") {
if (arch == "x86_64" || arch == "aarch64") platString = "macos"
else {
return jsonResponse({ message: "Unsupported architecture for macOS", versions: null, games: null }, 400)
}
} else if (platform == "android") platString = "android"
else if (platform == "ios") platString = "ios"
else {
return jsonResponse({ message: "Unsupported platform", versions: null, games: null }, 400)
}
}
const versionsRaw = await db.select({ let platString = null
id: launcherVersions.id, if (!showAll) {
versionName: launcherVersions.versionName, if (platform == 'windows') {
releaseDate: launcherVersions.releaseDate, if (arch == 'x86_64') platString = 'windows'
game: launcherVersions.game, else if (arch == 'aarch64') platString = 'windows-arm64'
downloadUrls: launcherVersions.downloadUrls, else {
platforms: launcherVersions.platforms, return jsonResponse(
executables: launcherVersions.executables, {
sha512sums: launcherVersions.sha512sums, message: 'Unsupported architecture for Windows',
sizes: launcherVersions.sizes versions: null,
}).from(launcherVersions) games: null
.where(eq(launcherVersions.hidden, false)) },
.orderBy( 400
asc(launcherVersions.game),
desc(launcherVersions.place)
) )
.execute() }
} else if (platform == 'linux') {
if (arch == 'x86_64') platString = 'linux'
else {
return jsonResponse(
{
message: 'Unsupported architecture for Linux',
versions: null,
games: null
},
400
)
}
} else if (platform == 'macos') {
if (arch == 'x86_64' || arch == 'aarch64') platString = 'macos'
else {
return jsonResponse(
{
message: 'Unsupported architecture for macOS',
versions: null,
games: null
},
400
)
}
} else if (platform == 'android') platString = 'android'
else if (platform == 'ios') platString = 'ios'
else {
return jsonResponse(
{ message: 'Unsupported platform', versions: null, games: null },
400
)
}
}
const versions = versionsRaw.map(v => ({ const versionsRaw = await db
...v, .select({
downloadUrls: JSON.parse(v.downloadUrls), id: launcherVersions.id,
platforms: JSON.parse(v.platforms), versionName: launcherVersions.versionName,
executables: JSON.parse(v.executables), releaseDate: launcherVersions.releaseDate,
sha512sums: JSON.parse(v.sha512sums), game: launcherVersions.game,
sizes: JSON.parse(v.sizes), downloadUrls: launcherVersions.downloadUrls,
downloadUrl: undefined as string | undefined, platforms: launcherVersions.platforms,
executable: undefined as string | undefined, executables: launcherVersions.executables,
sha512sum: undefined as string | undefined, sha512sums: launcherVersions.sha512sums,
size: undefined as number | undefined sizes: launcherVersions.sizes
})
.from(launcherVersions)
.where(eq(launcherVersions.hidden, false))
.orderBy(asc(launcherVersions.game), desc(launcherVersions.place))
.execute()
const versions = versionsRaw
.map(v => ({
...v,
downloadUrls: JSON.parse(v.downloadUrls),
platforms: JSON.parse(v.platforms),
executables: JSON.parse(v.executables),
sha512sums: JSON.parse(v.sha512sums),
sizes: JSON.parse(v.sizes),
downloadUrl: undefined as string | undefined,
executable: undefined as string | undefined,
sha512sum: undefined as string | undefined,
size: undefined as number | undefined
})) }))
.filter(v => { .filter(v => {
if (showAll || !platString) { if (showAll || !platString) {
delete v.downloadUrl delete v.downloadUrl
delete v.executable delete v.executable
delete v.sha512sum delete v.sha512sum
delete v.size delete v.size
return true return true
} }
const i = v.platforms.indexOf(platString) const i = v.platforms.indexOf(platString)
if (i !== -1) { if (i !== -1) {
v.downloadUrl = v.downloadUrls[i] v.downloadUrl = v.downloadUrls[i]
v.executable = v.executables[i] v.executable = v.executables[i]
v.sha512sum = v.sha512sums[i] v.sha512sum = v.sha512sums[i]
v.size = v.sizes[i] v.size = v.sizes[i]
delete v.downloadUrls delete v.downloadUrls
delete v.platforms delete v.platforms
delete v.executables delete v.executables
delete v.sha512sums delete v.sha512sums
delete v.sizes delete v.sizes
return true return true
} }
return false return false
}) })
const games = await db.select().from(launcherGames).execute() const games = await db.select().from(launcherGames).execute()
return jsonResponse({ versions, games }) return jsonResponse({ versions, games })
} }