This repository has been archived by the owner on May 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b118280
Showing
24 changed files
with
2,434 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
dist | ||
.env | ||
.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
name: production-build | ||
concurrency: | ||
group: api | ||
cancel-in-progress: true | ||
|
||
on: | ||
push: | ||
branches: | ||
- "main" | ||
|
||
jobs: | ||
build-push: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
|
||
- name: Login to GitHub Container Registry | ||
uses: docker/login-action@v1 | ||
with: | ||
registry: ghcr.io | ||
username: ${{ github.actor }} | ||
password: ${{ github.token }} | ||
|
||
- name: Build and push | ||
uses: docker/build-push-action@v2 | ||
with: | ||
context: . | ||
push: true | ||
tags: ghcr.io/${{ github.repository }}:latest,ghcr.io/${{ github.repository }}:${{ github.sha }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
dist | ||
|
||
node_modules | ||
|
||
.env | ||
.env.* | ||
!.env.example | ||
|
||
volumes | ||
|
||
yarn-error.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"semi": true, | ||
"trailingComma": "none", | ||
"singleQuote": true, | ||
"printWidth": 180, | ||
"tabWidth": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
FROM node:alpine AS builder | ||
|
||
RUN apk update | ||
RUN apk add python3 build-base | ||
|
||
WORKDIR /app | ||
COPY . . | ||
|
||
RUN yarn | ||
RUN yarn build | ||
|
||
FROM node:alpine | ||
|
||
WORKDIR /app | ||
|
||
COPY --from=builder /app/node_modules node_modules | ||
COPY --from=builder /app/dist dist | ||
COPY --from=builder /app/templates templates | ||
COPY --from=builder /app/package.json ./ | ||
|
||
ENTRYPOINT yarn start |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
services: | ||
postgres: | ||
container_name: hosting-psql | ||
image: postgres | ||
ports: | ||
- 5432:5432 | ||
environment: | ||
- POSTGRES_PASSWORD=postgres | ||
volumes: | ||
- ./volumes/postgres:/var/lib/postgresql/data | ||
keydb: | ||
container_name: hosting-keydb | ||
hostname: keydb | ||
image: eqalpha/keydb | ||
ports: | ||
- 6379:6379 | ||
volumes: | ||
- ./volumes/keydb:/data | ||
rabbit: | ||
container_name: hosting-rabbit | ||
image: rabbitmq:3-management | ||
environment: | ||
- "RABBITMQ_DEFAULT_USER=rabbit" | ||
- "RABBITMQ_DEFAULT_PASS=docker" | ||
ports: | ||
- 5672:5672 | ||
- 15672:15672 | ||
volumes: | ||
- ./volumes/rabbitmq:/var/lib/rabbitmq/mnesia |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"name": "api", | ||
"version": "1.0.0", | ||
"description": "API", | ||
"main": "dist/server.js", | ||
"repository": "[email protected]:dustinrouillard/api", | ||
"author": "Dustin Rouillard <[email protected]>", | ||
"license": "MIT", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "NODE_ENV=development ts-node-esm --files -r dotenv/config src/server.ts", | ||
"prepare": "prisma generate", | ||
"start": "node dist/server.js", | ||
"build": "tsc" | ||
}, | ||
"dependencies": { | ||
"@aws-sdk/client-s3": "^3.198.0", | ||
"@fastify/multipart": "^7.3.0", | ||
"@prisma/client": "4.3.1", | ||
"amqplib": "^0.10.3", | ||
"deep-object-diff": "^1.1.7", | ||
"envsafe": "^2.0.3", | ||
"erlpack": "^0.1.4", | ||
"fastify": "^4.6.0", | ||
"fastify-plugin": "^4.2.1", | ||
"file-type": "^18.0.0", | ||
"otplib": "^12.0.1", | ||
"pika-id": "^1.0.4", | ||
"redis": "^4.3.1" | ||
}, | ||
"devDependencies": { | ||
"@types/amqplib": "^0.8.2", | ||
"@types/node": "^18.7.18", | ||
"dotenv": "^16.0.2", | ||
"prisma": "^4.3.1", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.8.3" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
generator client { | ||
provider = "prisma-client-js" | ||
} | ||
|
||
datasource db { | ||
provider = "postgresql" | ||
url = env("DATABASE_URL") | ||
} | ||
|
||
model spotify_devices { | ||
id Int @id @default(autoincrement()) | ||
name String? | ||
type String? | ||
spotify_history spotify_history[] | ||
} | ||
|
||
model spotify_history { | ||
id String @id | ||
type String @default("track") | ||
name String | ||
artists Json[] | ||
length Int | ||
image String | ||
device Int @default(autoincrement()) | ||
listened_at DateTime @default(now()) @db.Timestamptz(6) | ||
spotify_devices spotify_devices @relation(fields: [device], references: [id], onDelete: NoAction, onUpdate: NoAction) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { createClient } from 'redis'; | ||
import { env } from '../env.js'; | ||
|
||
export const keydb = createClient({ url: env.KEYDB_URI }); | ||
keydb.connect(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { S3Client } from '@aws-sdk/client-s3'; | ||
import { env } from '../env.js'; | ||
|
||
export const minio = new S3Client({ | ||
endpoint: env.MINIO_ENDPOINT, | ||
forcePathStyle: true, | ||
region: 'none', | ||
credentials: { | ||
accessKeyId: env.MINIO_CLIENT_ID, | ||
secretAccessKey: env.MINIO_CLIENT_SECRET | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import { PrismaClient } from '@prisma/client'; | ||
export const prisma = new PrismaClient(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Channel, connect, Connection } from 'amqplib'; | ||
import { env } from '../env.js'; | ||
|
||
export enum RabbitOp { | ||
SpotifyUpdate | ||
} | ||
|
||
export let rabbitClient: Connection; | ||
export let rabbitChannel: Channel; | ||
(async () => { | ||
rabbitClient = await connect(env.RABBIT_URI); | ||
rabbitChannel = await rabbitClient.createChannel(); | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { str, envsafe, port } from 'envsafe'; | ||
|
||
export const env = envsafe({ | ||
HOST: str({ | ||
default: '0.0.0.0' | ||
}), | ||
PORT: port({ | ||
default: 8080 | ||
}), | ||
KEYDB_URI: str({ | ||
default: 'redis://10.7.20.3:6379' | ||
}), | ||
RABBIT_URI: str({ | ||
default: 'amqp://rabbit:[email protected]:5672' | ||
}), | ||
SPOTIFY_REDIRECT: str({ | ||
default: 'http://rest.dstn.to/v1/spotify/setup', | ||
devDefault: 'http://127.0.0.1:8080/v1/spotify/setup' | ||
}), | ||
SPOTIFY_CLIENT_ID: str({ | ||
desc: 'Spotify Client ID' | ||
}), | ||
SPOTIFY_CLIENT_SECRET: str({ | ||
desc: 'Spotify Client Secret' | ||
}), | ||
FILES_DOMAIN: str({ | ||
default: 'https://files.dstn.to' | ||
}), | ||
IMAGES_DOMAIN: str({ | ||
default: 'https://dustin.pics' | ||
}), | ||
MINIO_ENDPOINT: str({ | ||
default: 'https://dcs.rouillard.cloud' | ||
}), | ||
MINIO_BUCKET: str({ | ||
default: 'cdn' | ||
}), | ||
MINIO_CLIENT_ID: str({ | ||
desc: 'Minio Client ID' | ||
}), | ||
MINIO_CLIENT_SECRET: str({ | ||
desc: 'Minio Client Secret' | ||
}) | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { createHash } from 'crypto'; | ||
import { fileTypeFromBuffer } from 'file-type'; | ||
import { PutObjectCommand } from '@aws-sdk/client-s3'; | ||
import { Multipart } from '@fastify/multipart'; | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
|
||
import { env } from '../../env.js'; | ||
import { minio } from '../../connectivity/minio.js'; | ||
|
||
const mimeConversations: { [key: string]: string } = { | ||
'text/plain': 'txt' | ||
}; | ||
|
||
interface FileType { | ||
mime: string; | ||
extension: string; | ||
} | ||
|
||
const AlllowedTypes = ['image/gif', 'image/png', 'image/svg', 'image/webp', 'image/jpeg']; | ||
const AlllowedFileTypes = [ | ||
...AlllowedTypes, | ||
'application/octet-stream', | ||
'application/ogg', | ||
'application/pdf', | ||
'application/rtf', | ||
'application/x-sh', | ||
'application/x-tar', | ||
'application/zip', | ||
'audio/mpeg', | ||
'audio/ogg', | ||
'audio/opus', | ||
'audio/wav', | ||
'audio/webm', | ||
'font/otf', | ||
'font/ttf', | ||
'font/woff', | ||
'font/woff2', | ||
'image/webp', | ||
'text/css', | ||
'text/csv', | ||
'text/javascript', | ||
'text/plain', | ||
'video/mov', | ||
'video/mp4', | ||
'video/mpeg', | ||
'video/ogg', | ||
'video/webm' | ||
]; | ||
|
||
async function GetType(file: Multipart, buffer: Buffer): Promise<FileType> { | ||
const preType = file.mimetype; | ||
|
||
let bufferType; | ||
if (Object.keys(mimeConversations).includes(preType)) { | ||
bufferType = { mime: preType, ext: mimeConversations[preType] }; | ||
} else bufferType = await fileTypeFromBuffer(buffer); | ||
|
||
return { | ||
mime: bufferType?.mime || preType, | ||
extension: bufferType?.ext || mimeConversations[preType] | ||
}; | ||
} | ||
|
||
export async function uploadFile(req: FastifyRequest<{ Params: { type: string } }>, res: FastifyReply) { | ||
const file = await req.file(); | ||
|
||
const { type } = req.params; | ||
|
||
if (!['images', 'files'].includes(type)) return res.status(400).send({ code: 'invalid_upload_type', message: 'Invalid upload type' }); | ||
|
||
if (!file) return res.status(400).send({ code: 'file_required', message: 'File to upload is required in the multipart formdata' }); | ||
|
||
const buffer = await file?.toBuffer(); | ||
const file_type = await GetType(file, buffer); | ||
|
||
if (!file.mimetype || !(type == 'images' ? AlllowedTypes : AlllowedFileTypes).includes(file.mimetype)) throw { code: 'invalid_file_type', data: file.mimetype }; | ||
|
||
const hash = createHash('sha1').update(buffer).digest('hex').substring(0, 16); | ||
|
||
const folder = type == 'images' ? 'i' : 'u'; | ||
const file_path = `${hash}${file_type.extension ? `.${file_type.extension}` : ''}`; | ||
|
||
try { | ||
await minio.send( | ||
new PutObjectCommand({ | ||
Bucket: env.MINIO_BUCKET, | ||
Key: `${folder}/${file_path}`, | ||
Body: buffer, | ||
ContentType: file_type.mime | ||
}) | ||
); | ||
} catch (error) { | ||
return res.status(400).send({ code: 'failed_to_put_object', message: 'Failed to put object to s3 bucket' }); | ||
} | ||
|
||
return res.status(200).send({ success: true, data: { url: type == 'images' ? `${env.IMAGES_DOMAIN}/${file_path}` : `${env.FILES_DOMAIN}/${file_path}` } }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { stringify } from 'querystring'; | ||
import { keydb } from '../../connectivity/keydb.js'; | ||
import { env } from '../../env.js'; | ||
|
||
export async function authorizeSpotify(req: FastifyRequest, res: FastifyReply) { | ||
if (await keydb.exists('spotify/refresh_token')) return res.status(400).send({ code: 'already_authorized', message: 'Spotify is already authorized.' }); | ||
|
||
const query = stringify({ | ||
response_type: 'code', | ||
client_id: env.SPOTIFY_CLIENT_ID, | ||
scope: encodeURIComponent('user-read-playback-state user-read-currently-playing'), | ||
redirect_uri: `${env.SPOTIFY_REDIRECT}` | ||
}); | ||
|
||
return res.status(200).send({ url: `https://accounts.spotify.com/authorize?${query}` }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { keydb } from '../../connectivity/keydb.js'; | ||
|
||
export async function getCurrentPlaying(req: FastifyRequest, res: FastifyReply) { | ||
const current = await keydb.get('spotify/current'); | ||
if (!current) return res.status(200).send({ success: true, data: { playing: false } }); | ||
return res.status(200).send({ success: true, data: { playing: true, ...JSON.parse(current) } }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { FastifyReply, FastifyRequest } from 'fastify'; | ||
import { prisma } from '../../connectivity/postgres.js'; | ||
|
||
export async function getRecentPlays(req: FastifyRequest<{ Querystring: { limit: number } }>, res: FastifyReply) { | ||
const entries = await prisma.spotify_history.findMany({ orderBy: { listened_at: 'desc' }, take: req.query.limit || 10 }); | ||
|
||
return res.status(200).send({ success: true, data: { recents: entries, count: entries.length, limit: req.query.limit } }); | ||
} |
Oops, something went wrong.