wip
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@ node_modules/
|
|||||||
dist/
|
dist/
|
||||||
.idea/
|
.idea/
|
||||||
.env
|
.env
|
||||||
|
secrets.json
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const EXPIRE = 30 * 60 // 30min
|
const EXPIRE = 300 * 60 // 300min
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
accessSecret: process.env.JWT_SECRET ?? 'JWTAccessSecret',
|
accessSecret: process.env.JWT_SECRET ?? 'JWTAccessSecret',
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import type { LoginDto, WebSocketCtx, WebSocketData } from './types/types.ts'
|
|||||||
import { createAccessToken, verifyAccessToken } from './utils/jwt.ts'
|
import { createAccessToken, verifyAccessToken } from './utils/jwt.ts'
|
||||||
import { config } from './config.ts'
|
import { config } from './config.ts'
|
||||||
import { messageService } from './grpc/message.ts'
|
import { messageService } from './grpc/message.ts'
|
||||||
|
import { storage } from './storage'
|
||||||
|
import { randomUUIDv7 } from 'bun'
|
||||||
|
|
||||||
export const handlers = {
|
export const handlers = {
|
||||||
async getVersion(req: Request) {
|
async getVersion(req: Request) {
|
||||||
@@ -44,6 +46,20 @@ export const handlers = {
|
|||||||
return Response.json({ message: 'Login failed' }, { status: HttpStatusCodes.BAD_REQUEST })
|
return Response.json({ message: 'Login failed' }, { status: HttpStatusCodes.BAD_REQUEST })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async setAvatar(req: Request) {
|
||||||
|
const formdata = await req.formData()
|
||||||
|
const file = formdata.get('file') as File
|
||||||
|
if (!file) {
|
||||||
|
return Response.json({ message: 'Invalid image' }, { status: HttpStatusCodes.BAD_REQUEST })
|
||||||
|
}
|
||||||
|
const uuid = randomUUIDv7()
|
||||||
|
await storage.upload(file,`${uuid}.${file.type.split('/')[1]}`)
|
||||||
|
},
|
||||||
|
async getAvatar(req: Request) {
|
||||||
|
const url = storage.presign('avatar.jpg')
|
||||||
|
|
||||||
|
return Response.json({ url })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function upgrade(req: Request, server: Bun.Server<WebSocketCtx>) {
|
export async function upgrade(req: Request, server: Bun.Server<WebSocketCtx>) {
|
||||||
|
|||||||
22
src/index.ts
22
src/index.ts
@@ -15,6 +15,8 @@ const server = Bun.serve({
|
|||||||
const method = req.method
|
const method = req.method
|
||||||
|
|
||||||
if (pathname === '/api/version' && method === 'GET') return handlers.getVersion(req)
|
if (pathname === '/api/version' && method === 'GET') return handlers.getVersion(req)
|
||||||
|
if (pathname === '/api/avatar' && method === 'POST') return handlers.setAvatar(req)
|
||||||
|
if (pathname === '/api/avatar' && method === 'GET') return handlers.getAvatar(req)
|
||||||
if (pathname === '/api/login' && method === 'POST') return handlers.login(req)
|
if (pathname === '/api/login' && method === 'POST') return handlers.login(req)
|
||||||
if (pathname === '/ws') return upgrade(req, server)
|
if (pathname === '/ws') return upgrade(req, server)
|
||||||
|
|
||||||
@@ -55,16 +57,30 @@ const server = Bun.serve({
|
|||||||
const webSocketData = JSON.parse(message) as WebSocketData
|
const webSocketData = JSON.parse(message) as WebSocketData
|
||||||
if (!webSocketData) return
|
if (!webSocketData) return
|
||||||
|
|
||||||
|
if(webSocketData.type === 'GET_CHATS') {
|
||||||
|
const chatResponse = await messageService.listChat({ page: 0, userId: ws.data.userId })
|
||||||
|
chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
||||||
|
ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
||||||
|
}
|
||||||
|
|
||||||
if (webSocketData.type === 'CREATE_CHAT') {
|
if (webSocketData.type === 'CREATE_CHAT') {
|
||||||
const chat = await messageService.createChat({ users: [{ userId: webSocketData.data.userId }, { userId: ws.data.userId }] })
|
const chat = await messageService.createChat({
|
||||||
ws.send(JSON.stringify({ type: 'CHATS', ...chat }))
|
users: [
|
||||||
|
{ userId: webSocketData.data.userId },
|
||||||
|
{ userId: ws.data.userId }
|
||||||
|
] })
|
||||||
|
if (chat?.data) {
|
||||||
|
ws.subscribe(chat.data.id)
|
||||||
|
ws.send(JSON.stringify({ type: 'CHATS', ...chat }))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (webSocketData.type === 'CREATE_MESSAGE') {
|
if (webSocketData.type === 'CREATE_MESSAGE') {
|
||||||
const messageResponse = await messageService.createMessage({
|
const messageResponse = await messageService.createMessage({
|
||||||
chatId: webSocketData.data.chatId,
|
chatId: webSocketData.data.chatId,
|
||||||
userId: ws.data.userId,
|
|
||||||
message: webSocketData.data.message,
|
message: webSocketData.data.message,
|
||||||
|
userId: ws.data.userId,
|
||||||
})
|
})
|
||||||
server.publish(webSocketData.data.chatId, JSON.stringify({ type: 'MESSAGE', ...messageResponse }))
|
server.publish(webSocketData.data.chatId, JSON.stringify({ type: 'MESSAGE', ...messageResponse }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { S3Client } from "@aws-sdk/client-s3";
|
|
||||||
|
|
||||||
|
|
||||||
const rustfs_client = new S3Client({
|
|
||||||
region: "cn-east-1",
|
|
||||||
credentials: {
|
|
||||||
accessKeyId: process.env.RUSTFS_ACCESS_KEY_ID!,
|
|
||||||
secretAccessKey: process.env.RUSTFS_SECRET_ACCESS_KEY!,
|
|
||||||
},
|
|
||||||
endpoint: process.env.RUSTFS_ENDPOINT_URL!,
|
|
||||||
});
|
|
||||||
30
src/storage/index.ts
Normal file
30
src/storage/index.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// import { ListBucketsCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
|
||||||
|
import { S3Client, type S3File } from 'bun'
|
||||||
|
|
||||||
|
class Storage {
|
||||||
|
client: S3Client
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.client = new S3Client({
|
||||||
|
region: 'cn-east-1',
|
||||||
|
accessKeyId: process.env.RUSTFS_ACCESS_KEY_ID!,
|
||||||
|
secretAccessKey: process.env.RUSTFS_SECRET_ACCESS_KEY!,
|
||||||
|
bucket: 'stor1',
|
||||||
|
endpoint: process.env.RUSTFS_ENDPOINT_URL!,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async upload(file: Blob, name: string): Promise<void> {
|
||||||
|
const s3File: S3File = this.client.file(name)
|
||||||
|
const result = await s3File.write(file)
|
||||||
|
console.log({result})
|
||||||
|
}
|
||||||
|
|
||||||
|
presign(name: string) {
|
||||||
|
const s3File = this.client.file(name)
|
||||||
|
|
||||||
|
return s3File.presign({method: 'GET'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const storage = new Storage()
|
||||||
@@ -25,6 +25,10 @@ interface ListMessages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ListChats {
|
||||||
|
type: 'GET_CHATS'
|
||||||
|
}
|
||||||
|
|
||||||
interface CreateMessage {
|
interface CreateMessage {
|
||||||
type: 'CREATE_MESSAGE'
|
type: 'CREATE_MESSAGE'
|
||||||
data: {
|
data: {
|
||||||
@@ -48,4 +52,4 @@ interface CreateChat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WebSocketData = ListMessages | CreateMessage | ListUsers | CreateChat
|
export type WebSocketData = ListMessages | CreateMessage | ListUsers | CreateChat | ListChats
|
||||||
|
|||||||
Reference in New Issue
Block a user