Skip to content

Commit

Permalink
Merge pull request #62 from cirroskais/api-v1
Browse files Browse the repository at this point in the history
unify configuration (use environment variables) and dockerize
  • Loading branch information
nbitzz authored Apr 29, 2024
2 parents 1da5f0e + ef6eb1e commit 2112c75
Show file tree
Hide file tree
Showing 19 changed files with 901 additions and 580 deletions.
11 changes: 11 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.vscode
.gitignore
.prettierrc
LICENSE
README.md
node_modules
.env
.data
out
dist
tsconfig.tsbuildinfo
23 changes: 23 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
PORT=
REQUEST_TIMEOUT=
TRUST_PROXY=
FORCE_SSL=

DISCORD_TOKEN=

MAX__DISCORD_FILES=
MAX__DISCORD_FILE_SIZE=
MAX__UPLOAD_ID_LENGTH=

TARGET__GUILD=
TARGET__CHANNEL=

ACCOUNTS__REGISTRATION_ENABLED=
ACCOUNTS__REQUIRED_FOR_UPLOAD=

MAIL__HOST=
MAIL__PORT=
MAIL__SECURE=
MAIL__SEND_FROM=
MAIL__USER=
MAIL__PASS=
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM node:21-alpine AS base
WORKDIR /usr/src/app

FROM base AS install
RUN mkdir -p /tmp/dev
COPY package.json package-lock.json /tmp/dev/
RUN cd /tmp/dev && npm install

RUN mkdir -p /tmp/prod
COPY package.json package-lock.json /tmp/prod/
RUN cd /tmp/prod && npm install --omit=dev

FROM base AS build
COPY --from=install /tmp/dev/node_modules node_modules
COPY . .

RUN npm run build

FROM base AS app
COPY --from=install /tmp/prod/node_modules node_modules
COPY --from=build /usr/src/app/out out
COPY --from=build /usr/src/app/dist dist
COPY package.json .
COPY assets assets

EXPOSE 3000
ENTRYPOINT [ "node", "./out/server/index.js" ]
10 changes: 10 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:
monofile:
container_name: "monofile"
image: monofile
build: .
env_file: .env
volumes:
- ".data:/usr/src/app/.data"
ports:
- "3000:3000"
64 changes: 29 additions & 35 deletions src/server/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import Files from "./lib/files.js"
import { program } from "commander"
import { basename } from "path"
import { Writable } from "node:stream"
import config from "./lib/config.js"
import pkg from "../../package.json" assert { type: "json" }
import config from "../../config.json" assert { type: "json" }
import { fileURLToPath } from "url"
import { dirname } from "path"

Expand All @@ -23,65 +23,61 @@ program
.description("Quickly run monofile to execute a query or so")
.version(pkg.version)

program.command("list")
program
.command("list")
.alias("ls")
.description("List files in the database")
.action(() => {
Object.keys(files.files).forEach(e => console.log(e))
Object.keys(files.files).forEach((e) => console.log(e))
})


program.command("download")
program
.command("download")
.alias("dl")
.description("Download a file from the database")
.argument("<id>", "ID of the file you'd like to download")
.option("-o, --output <path>", 'Folder or filename to output to')
.option("-o, --output <path>", "Folder or filename to output to")
.action(async (id, options) => {

await (new Promise<void>(resolve => setTimeout(() => resolve(), 1000)))
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1000))

let fp = files.files[id]

if (!fp)
throw `file ${id} not found`

let out = options.output as string || `./`
if (!fp) throw `file ${id} not found`

let out = (options.output as string) || `./`

if (fs.existsSync(out) && (await stat(out)).isDirectory())
out = `${out.replace(/\/+$/, "")}/${fp.filename}`

let filestream = await files.readFileStream(id)

let prog=0
filestream.on("data", dt => {
prog+=dt.byteLength
console.log(`Downloading ${fp.filename}: ${Math.floor(prog/(fp.sizeInBytes??0)*10000)/100}% (${Math.floor(prog/(1024*1024))}MiB/${Math.floor((fp.sizeInBytes??0)/(1024*1024))}MiB)`)
let prog = 0
filestream.on("data", (dt) => {
prog += dt.byteLength
console.log(
`Downloading ${fp.filename}: ${Math.floor((prog / (fp.sizeInBytes ?? 0)) * 10000) / 100}% (${Math.floor(prog / (1024 * 1024))}MiB/${Math.floor((fp.sizeInBytes ?? 0) / (1024 * 1024))}MiB)`
)
})

filestream.pipe(
fs.createWriteStream(out)
)
filestream.pipe(fs.createWriteStream(out))
})


program.command("upload")
program
.command("upload")
.alias("up")
.description("Upload a file to the instance")
.argument("<file>", "Path to the file you'd like to upload")
.option("-id, --fileid <id>", 'Custom file ID to use')
.option("-id, --fileid <id>", "Custom file ID to use")
.action(async (file, options) => {

await (new Promise<void>(resolve => setTimeout(() => resolve(), 1000)))
await new Promise<void>((resolve) => setTimeout(() => resolve(), 1000))

if (!(fs.existsSync(file) && (await stat(file)).isFile()))
throw `${file} is not a file`

let writable = files.createWriteStream()

writable
.setName(basename(file))
?.setType("application/octet-stream")

writable.setName(basename(file))?.setType("application/octet-stream")

if (options.id) writable.setUploadId(options.id)

if (!(writable instanceof Writable))
Expand All @@ -90,7 +86,7 @@ program.command("upload")
console.log(`started: ${file}`)

writable.on("drain", () => {
console.log("Drained");
console.log("Drained")
})

writable.on("finish", async () => {
Expand All @@ -108,11 +104,9 @@ program.command("upload")

writable.on("close", () => {
console.log("Closed.")
});
})

;(await fs.createReadStream(file)).pipe(
writable
)
;(await fs.createReadStream(file)).pipe(writable)
})

program.parse()
program.parse()
42 changes: 22 additions & 20 deletions src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import Files from "./lib/files.js"
import { getAccount } from "./lib/middleware.js"
import APIRouter from "./routes/api.js"
import preview from "./routes/api/web/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"}
import { fileURLToPath } from "url"
import { dirname } from "path"
import pkg from "../../package.json" assert { type: "json" }
import config, { ClientConfiguration } from "./lib/config.js"

const app = new Hono()

Expand All @@ -36,10 +36,8 @@ app.get(
// haha...

app.on(["MOLLER"], "*", async (ctx) => {

ctx.header("Content-Type", "image/webp")
return ctx.body( await readFile("./assets/moller.png") )

return ctx.body(await readFile("./assets/moller.png"))
})

//app.use(bodyParser.text({limit:(config.maxDiscordFileSize*config.maxDiscordFiles)+1048576,type:["application/json","text/plain"]}))
Expand All @@ -64,10 +62,12 @@ if (config.forceSSL) {

app.get("/server", (ctx) =>
ctx.json({
...config,
version: pkg.version,
files: Object.keys(files.files).length,
})
maxDiscordFiles: config.maxDiscordFiles,
maxDiscordFileSize: config.maxDiscordFileSize,
accounts: config.accounts,
} as ClientConfiguration)
)

// funcs
Expand All @@ -87,28 +87,30 @@ apiRouter.loadAPIMethods().then(() => {
console.log("API OK!")

// moved here to ensure it's matched last
app.get("/:fileId", async (ctx) =>
app.get("/:fileId", async (ctx) =>
app.fetch(
new Request(
(new URL(
`/api/v1/file/${ctx.req.param("fileId")}`, ctx.req.raw.url)).href,
ctx.req.raw
),
new URL(
`/api/v1/file/${ctx.req.param("fileId")}`,
ctx.req.raw.url
).href,
ctx.req.raw
),
ctx.env
)
)

// listen on 3000 or MONOFILE_PORT
// listen on 3000 or PORT
// moved here to prevent a crash if someone manages to access monofile before api routes are mounted

serve(
{
fetch: app.fetch,
port: Number(process.env.MONOFILE_PORT || 3000),
port: Number(process.env.PORT || 3000),
serverOptions: {
//@ts-ignore
requestTimeout: config.requestTimeout
}
requestTimeout: config.requestTimeout,
},
},
(info) => {
console.log("Web OK!", info.port, info.address)
Expand All @@ -133,4 +135,4 @@ app.get("/", async (ctx) =>
file serving
*/

export default app
export default app
Loading

0 comments on commit 2112c75

Please sign in to comment.