Server now runs

This commit is contained in:
May 2024-03-03 19:03:18 -08:00
parent 549f7de7ac
commit 25afbf493c
15 changed files with 59 additions and 79 deletions

View file

@ -7,10 +7,12 @@ import Files from "./lib/files.js"
import { getAccount } from "./lib/middleware.js" import { getAccount } from "./lib/middleware.js"
import APIRouter from "./routes/api.js" import APIRouter from "./routes/api.js"
import preview from "./routes/preview.js" import preview from "./routes/preview.js"
import {fileURLToPath} from "url"
import {dirname} from "path"
import pkg from "../../package.json" assert {type:"json"}
import config from "../../config.json" assert {type:"json"}
const pkg = require(`${process.cwd()}/package.json`)
const app = new Hono() const app = new Hono()
let config = require(`${process.cwd()}/config.json`)
app.get( app.get(
"/static/assets/*", "/static/assets/*",
@ -72,6 +74,7 @@ app.get("/server", (ctx) =>
// init data // init data
const __dirname = dirname(fileURLToPath(import.meta.url))
if (!fs.existsSync(__dirname + "/../.data/")) if (!fs.existsSync(__dirname + "/../.data/"))
fs.mkdirSync(__dirname + "/../.data/") fs.mkdirSync(__dirname + "/../.data/")
@ -117,4 +120,4 @@ serve(
} }
) )
export default app export default app

View file

@ -92,7 +92,7 @@ export class Client {
} }
let capture = Math.min( let capture = Math.min(
(this.config.maxDiscordFileSize - (bytes_sent % this.config.maxDiscordFileSize)) + 1, (this.config.maxDiscordFileSize - (bytes_sent % this.config.maxDiscordFileSize)),
chunk.byteLength-position chunk.byteLength-position
) )
console.log(`Capturing ${capture} bytes, ${chunk.subarray(position, position+capture).byteLength}`) console.log(`Capturing ${capture} bytes, ${chunk.subarray(position, position+capture).byteLength}`)

View file

@ -137,7 +137,7 @@ export class UploadStream extends Writable {
while (position < data.byteLength) { while (position < data.byteLength) {
let capture = Math.min( let capture = Math.min(
((this.files.config.maxDiscordFileSize*10) - (this.filled % (this.files.config.maxDiscordFileSize*10))) + 1, ((this.files.config.maxDiscordFileSize*10) - (this.filled % (this.files.config.maxDiscordFileSize*10))),
data.byteLength-position data.byteLength-position
) )
console.log(`Capturing ${capture} bytes for megachunk, ${data.subarray(position, position + capture).byteLength}`) console.log(`Capturing ${capture} bytes for megachunk, ${data.subarray(position, position + capture).byteLength}`)

View file

@ -1,9 +1,8 @@
import { createTransport } from "nodemailer" import { createTransport } from "nodemailer"
import "dotenv/config"
import config from "../../../config.json" assert {type:"json"}
// required i guess let mailConfig = config.mail,
require("dotenv").config()
let mailConfig = require(process.cwd() + "/config.json").mail,
transport = createTransport({ transport = createTransport({
...mailConfig.transport, ...mailConfig.transport,
auth: { auth: {

View file

@ -1,8 +1,10 @@
import { Hono } from "hono" import { Hono } from "hono"
import { readFile, readdir } from "fs/promises" import { readFile, readdir } from "fs/promises"
import Files from "../lib/files.js" import Files from "../lib/files.js"
import {fileURLToPath} from "url"
import {dirname} from "path"
const APIDirectory = __dirname + "/api" const APIDirectory = dirname(fileURLToPath(import.meta.url)) + "/api"
interface APIMount { interface APIMount {
file: string file: string
@ -25,18 +27,21 @@ class APIVersion {
readonly definition: APIDefinition readonly definition: APIDefinition
readonly apiPath: string readonly apiPath: string
readonly root: Hono = new Hono() readonly root: Hono = new Hono()
readonly files: Files
constructor(definition: APIDefinition, files: Files) { constructor(definition: APIDefinition, files: Files) {
this.definition = definition this.definition = definition
this.apiPath = APIDirectory + "/" + definition.name this.apiPath = APIDirectory + "/" + definition.name
this.files = files
}
for (let _mount of definition.mount) { async load() {
let mount = resolveMount(_mount) for (let _mount of this.definition.mount) {
let mount = resolveMount(_mount);
// no idea if there's a better way to do this but this is all i can think of // no idea if there's a better way to do this but this is all i can think of
let route = require(`${this.apiPath}/${mount.file}.js`) as ( let { default: route } = await import(`${this.apiPath}/${mount.file}.js`) as { default: (files: Files) => Hono }
files: Files
) => Hono this.root.route(mount.to, route(this.files))
this.root.route(mount.to, route(files))
} }
} }
} }
@ -54,12 +59,15 @@ export default class APIRouter {
* @param definition Definition to mount. * @param definition Definition to mount.
*/ */
private mount(definition: APIDefinition) { private async mount(definition: APIDefinition) {
console.log(`mounting APIDefinition ${definition.name}`) console.log(`mounting APIDefinition ${definition.name}`)
let def = new APIVersion(definition, this.files)
await def.load()
this.root.route( this.root.route(
definition.baseURL, definition.baseURL,
new APIVersion(definition, this.files).root def.root
) )
} }
@ -74,7 +82,7 @@ export default class APIRouter {
) )
).toString() ).toString()
) as APIDefinition ) as APIDefinition
this.mount(def) await this.mount(def)
} }
} }
} }

View file

@ -22,9 +22,7 @@ adminRoutes
.use(requiresAdmin) .use(requiresAdmin)
.use(requiresPermissions("admin")) .use(requiresPermissions("admin"))
let config = require(`${process.cwd()}/config.json`) export default function (files: Files) {
module.exports = function (files: Files) {
adminRoutes.post("/reset", async (ctx) => { adminRoutes.post("/reset", async (ctx) => {
let acc = ctx.get("account") as Accounts.Account let acc = ctx.get("account") as Accounts.Account
const body = await ctx.req.json() const body = await ctx.req.json()

View file

@ -26,12 +26,11 @@ export let authRoutes = new Hono<{
} }
}>() }>()
let config = require(`${process.cwd()}/config.json`) import config from "../../../../../config.json" assert {type:"json"}
authRoutes.all("*", getAccount) authRoutes.all("*", getAccount)
module.exports = function (files: Files) { export default function (files: Files) {
authRoutes.post("/login", async (ctx) => { authRoutes.post("/login", async (ctx) => {
console.log(ctx)
const body = await ctx.req.json() const body = await ctx.req.json()
if ( if (
typeof body.username != "string" || typeof body.username != "string" ||

View file

@ -14,7 +14,6 @@ export let fileApiRoutes = new Hono<{
} }
}>() }>()
let config = require(`${process.cwd()}/config.json`)
fileApiRoutes.use("*", getAccount) // :warning: /list somehow crashes Hono with an internal error! fileApiRoutes.use("*", getAccount) // :warning: /list somehow crashes Hono with an internal error!
/* /*
@ -27,7 +26,7 @@ TypeError: Cannot read properties of undefined (reading 'get')
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
*/ */
module.exports = function (files: Files) { export default function (files: Files) {
fileApiRoutes.get( fileApiRoutes.get(
"/list", "/list",
requiresAccount, requiresAccount,

View file

@ -3,36 +3,24 @@ import { Hono } from "hono"
import * as Accounts from "../../../lib/accounts.js" import * as Accounts from "../../../lib/accounts.js"
import * as auth from "../../../lib/auth.js" import * as auth from "../../../lib/auth.js"
import axios, { AxiosResponse } from "axios" import RangeParser, { type Range } from "range-parser"
import { type Range } from "range-parser"
import multer, { memoryStorage } from "multer"
import { Readable } from "stream"
import ServeError from "../../../lib/errors.js" import ServeError from "../../../lib/errors.js"
import Files from "../../../lib/files.js" import Files from "../../../lib/files.js"
import { getAccount, requiresPermissions } from "../../../lib/middleware.js" import { getAccount } from "../../../lib/middleware.js"
import {Readable} from "node:stream"
let parser = bodyParser.json({
type: ["text/plain", "application/json"],
})
export let primaryApi = new Hono<{ export let primaryApi = new Hono<{
Variables: { Variables: {
account: Accounts.Account account: Accounts.Account
} }
}>() }>()
const multerSetup = multer({ storage: memoryStorage() })
let config = require(`${process.cwd()}/config.json`)
primaryApi.use(getAccount) primaryApi.use(getAccount)
module.exports = function (files: Files) {/* export default function (files: Files) {
primaryApi.get( primaryApi.get(
["/file/:fileId", "/cpt/:fileId/*", "/:fileId"], "/file/:fileId",
async (ctx) => { async (ctx): Promise<Response> => {
const fileId = (ctx.req.param() as {fileId: string}).fileId const fileId = (ctx.req.param() as {fileId: string}).fileId
const reqRange
let acc = ctx.get("account") as Accounts.Account let acc = ctx.get("account") as Accounts.Account
@ -54,8 +42,7 @@ module.exports = function (files: Files) {/*
.getPermissions(auth.tokenFor(ctx)!) .getPermissions(auth.tokenFor(ctx)!)
?.includes("private") ?.includes("private")
) { ) {
ServeError(ctx, 403, "insufficient permissions") return ServeError(ctx, 403, "insufficient permissions")
return
} }
} }
@ -65,29 +52,18 @@ module.exports = function (files: Files) {/*
if (file.sizeInBytes) { if (file.sizeInBytes) {
ctx.header("Content-Length", file.sizeInBytes.toString()) ctx.header("Content-Length", file.sizeInBytes.toString())
if (file.chunkSize) { if (file.chunkSize && ctx.req.header("Range")) {
let range = ctx.range(file.sizeInBytes) let ranges = RangeParser(file.sizeInBytes, ctx.req.header("Range") || "")
if (range) {
// error handling
if (typeof range == "number") {
return ctx.status(range == -1 ? 416 : 400)
}
if (range.type != "bytes") {
return ctx.status(400)
}
// set ranges var if (ranges) {
let rngs = Array.from(range) if (typeof ranges == "number")
if (rngs.length != 1) { return ServeError(ctx, ranges == -1 ? 416 : 400, ranges == -1 ? "unsatisfiable ranges" : "invalid ranges")
return ctx.status(400) if (ranges.length > 1) return ServeError(ctx, 400, "multiple ranges not supported")
} range = ranges[0]
range = rngs[0]
} }
} }
} }
// supports ranges
return files return files
.readFileStream(fileId, range) .readFileStream(fileId, range)
.then(async (stream) => { .then(async (stream) => {
@ -103,8 +79,8 @@ module.exports = function (files: Files) {/*
) )
} }
return ctx.stream((stre) => { return ctx.req.method == "HEAD" ? ctx.body(null) : ctx.stream(async (webStream) => {
// Somehow return a stream? webStream.pipe(Readable.toWeb(stream) as ReadableStream)
}) })
}) })
.catch((err) => { .catch((err) => {
@ -114,7 +90,7 @@ module.exports = function (files: Files) {/*
return ServeError(ctx, 404, "file not found") return ServeError(ctx, 404, "file not found")
} }
} }
)*/ )
// primaryApi.head( // primaryApi.head(
// ["/file/:fileId", "/cpt/:fileId/*", "/:fileId"], // ["/file/:fileId", "/cpt/:fileId/*", "/:fileId"],

View file

@ -19,7 +19,7 @@ import {
import ServeError from "../../../lib/errors.js" import ServeError from "../../../lib/errors.js"
import { sendMail } from "../../../lib/mail.js" import { sendMail } from "../../../lib/mail.js"
const Configuration = require(`${process.cwd()}/config.json`) import Configuration from "../../../../../config.json" assert {type:"json"}
const router = new Hono<{ const router = new Hono<{
Variables: { Variables: {
@ -29,7 +29,7 @@ const router = new Hono<{
router.use(getAccount) router.use(getAccount)
module.exports = function (files: Files) { export default function (files: Files) {
router.post("/login", async (ctx, res) => { router.post("/login", async (ctx, res) => {
const body = await ctx.req.json() const body = await ctx.req.json()
if ( if (

View file

@ -17,8 +17,6 @@ import {
import ServeError from "../../../lib/errors.js" import ServeError from "../../../lib/errors.js"
import { sendMail } from "../../../lib/mail.js" import { sendMail } from "../../../lib/mail.js"
const Configuration = require(`${process.cwd()}/config.json`)
const router = new Hono<{ const router = new Hono<{
Variables: { Variables: {
account?: Accounts.Account account?: Accounts.Account
@ -27,7 +25,7 @@ const router = new Hono<{
router.use(getAccount, requiresAccount, requiresAdmin) router.use(getAccount, requiresAccount, requiresAdmin)
module.exports = function (files: Files) { export default function (files: Files) {
router.patch("/account/:username/password", async (ctx) => { router.patch("/account/:username/password", async (ctx) => {
const Account = ctx.get("account") as Accounts.Account const Account = ctx.get("account") as Accounts.Account
const body = await ctx.req.json() const body = await ctx.req.json()

View file

@ -7,8 +7,7 @@ import {
requiresPermissions, requiresPermissions,
} from "../../../lib/middleware.js" } from "../../../lib/middleware.js"
import ServeError from "../../../lib/errors.js" import ServeError from "../../../lib/errors.js"
import Configuration from "../../../../../config.json" assert {type:"json"}
const Configuration = require(`${process.cwd()}/config.json`)
const router = new Hono<{ const router = new Hono<{
Variables: { Variables: {
@ -18,7 +17,7 @@ const router = new Hono<{
router.use(getAccount) router.use(getAccount)
module.exports = function (files: Files) { export default function (files: Files) {
router.put( router.put(
"/css", "/css",
requiresAccount, requiresAccount,

View file

@ -3,6 +3,6 @@ import Files from "../../../lib/files.js";
const router = new Hono() const router = new Hono()
module.exports = function(files: Files) { export default function(files: Files) {
return router return router
} }

View file

@ -3,6 +3,6 @@ import Files from "../../../lib/files.js"
const router = new Hono() const router = new Hono()
module.exports = function (files: Files) { export default function (files: Files) {
return router return router
} }

View file

@ -4,7 +4,8 @@ import ServeError from "../lib/errors.js"
import * as Accounts from "../lib/accounts.js" import * as Accounts from "../lib/accounts.js"
import type { Handler } from "hono" import type { Handler } from "hono"
import type Files from "../lib/files.js" import type Files from "../lib/files.js"
const pkg = require(`${process.cwd()}/package.json`) import pkg from "../../../package.json" assert {type:"json"}
export default (files: Files): Handler => export default (files: Files): Handler =>
async (ctx) => { async (ctx) => {
let acc = ctx.get("account") as Accounts.Account let acc = ctx.get("account") as Accounts.Account