wip
This commit is contained in:
@@ -1,6 +1,9 @@
|
|||||||
name: Gitea Actions Demo
|
name: Gitea Actions Demo
|
||||||
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
|
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
|
||||||
on: [push]
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Explore-Gitea-Actions:
|
Explore-Gitea-Actions:
|
||||||
@@ -13,6 +16,10 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner!"
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner!"
|
||||||
|
# - name: List files in the repository
|
||||||
|
# run: |
|
||||||
|
# ls ${{ gitea.workspace }}
|
||||||
|
# docker run -d --name tracker -p 3300:3000 git.madsky.ru/vadim/tracker:latest
|
||||||
- name: List files in the repository
|
- name: List files in the repository
|
||||||
run: |
|
run: |
|
||||||
ls ${{ gitea.workspace }}
|
ls ${{ gitea.workspace }}
|
||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#FROM node:lts-alpine
|
||||||
|
FROM oven/bun:canary-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV TZ=Europe/Moscow
|
||||||
|
|
||||||
|
CMD ["node", "dist/main"]
|
||||||
|
EXPOSE 3000/tcp
|
||||||
|
ENTRYPOINT [ "bun", "run", "index.ts" ]
|
||||||
73
src/grpc/message.ts
Normal file
73
src/grpc/message.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import grpc, { type ServiceError } from '@grpc/grpc-js'
|
||||||
|
import type { Empty } from '../generated/google/protobuf/empty.ts'
|
||||||
|
import {
|
||||||
|
type CreateChatRequest,
|
||||||
|
type CreateChatResponse,
|
||||||
|
type CreateMessageRequest,
|
||||||
|
type CreateMessageResponse,
|
||||||
|
type GetUserByEmailRequest,
|
||||||
|
type GetUserRequest,
|
||||||
|
GetUserResponse,
|
||||||
|
type GetVersionResponse,
|
||||||
|
type ListChatRequest,
|
||||||
|
type ListChatResponse,
|
||||||
|
type ListMessageRequest,
|
||||||
|
type ListMessageResponse,
|
||||||
|
type ListUserRequest,
|
||||||
|
type ListUserResponse,
|
||||||
|
MessageServiceClient,
|
||||||
|
} from '../generated/message.ts'
|
||||||
|
|
||||||
|
class MessageService {
|
||||||
|
private client: MessageServiceClient
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.client = new MessageServiceClient('192.168.1.11:8070', grpc.credentials.createInsecure())
|
||||||
|
}
|
||||||
|
|
||||||
|
private toPromise<T, R>(
|
||||||
|
request: T,
|
||||||
|
service: (request: T, callback: (error: ServiceError | null, response: R) => void) => void,
|
||||||
|
): Promise<R> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
service(request, (error, data) => {
|
||||||
|
if (error) reject(error?.message)
|
||||||
|
else resolve(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser(req: GetUserRequest) {
|
||||||
|
return this.toPromise<GetUserRequest, GetUserResponse>(req, this.client.getUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
listChat(req: ListChatRequest) {
|
||||||
|
return this.toPromise<ListChatRequest, ListChatResponse>(req, this.client.listChat)
|
||||||
|
}
|
||||||
|
|
||||||
|
createChat(req: CreateChatRequest) {
|
||||||
|
return this.toPromise<CreateChatRequest, CreateChatResponse>(req, this.client.createChat)
|
||||||
|
}
|
||||||
|
|
||||||
|
createMessage(req: CreateMessageRequest) {
|
||||||
|
return this.toPromise<CreateMessageRequest, CreateMessageResponse>(req, this.client.createMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
listMessage(req: ListMessageRequest) {
|
||||||
|
return this.toPromise<ListMessageRequest, ListMessageResponse>(req, this.client.listMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
listUser(req: ListUserRequest) {
|
||||||
|
return this.toPromise<ListUserRequest, ListUserResponse>(req, this.client.listUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserByEmail(req: GetUserByEmailRequest) {
|
||||||
|
return this.toPromise<GetUserByEmailRequest, GetUserResponse>(req, this.client.getUserByEmail)
|
||||||
|
}
|
||||||
|
|
||||||
|
getVersion() {
|
||||||
|
return this.toPromise<Empty, GetVersionResponse>({}, this.client.getVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const messageService = new MessageService()
|
||||||
@@ -1,48 +1,55 @@
|
|||||||
import { HttpStatusCodes } from './constants.ts'
|
import { HttpStatusCodes } from './constants.ts'
|
||||||
import { errors } from 'jose'
|
import { errors } from 'jose'
|
||||||
import type { LoginDto, WebSocketData } from './types/types.ts'
|
import type { LoginDto, WebSocketCtx, WebSocketData } from './types/types.ts'
|
||||||
import { createAccessToken, verifyAccessToken } from './utils/jwt.ts'
|
import { createAccessToken, verifyAccessToken } from './utils/jwt.ts'
|
||||||
import { grpcClient as client } from './grpc/client.ts'
|
|
||||||
import { config } from './config.ts'
|
import { config } from './config.ts'
|
||||||
|
import { messageService } from './grpc/message.ts'
|
||||||
|
|
||||||
export async function login(req: Request) {
|
export const handlers = {
|
||||||
try {
|
async getVersion() {
|
||||||
const body: LoginDto = await req.json()
|
try {
|
||||||
|
const res = await messageService.getVersion()
|
||||||
|
return Response.json(res)
|
||||||
|
} catch (error) {
|
||||||
|
return Response.json({ message: 'Error' }, { status: HttpStatusCodes.BAD_REQUEST })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async login(req: Request) {
|
||||||
|
try {
|
||||||
|
const body: LoginDto = await req.json()
|
||||||
|
|
||||||
const versionResponse = await client.getVersion({})
|
const { email } = body
|
||||||
console.log(versionResponse?.data)
|
if (!email) return Response.json({ message: 'email required' }, { status: HttpStatusCodes.BAD_REQUEST })
|
||||||
|
|
||||||
const { email } = body
|
const userResponse = await messageService.getUserByEmail({ email: body.email })
|
||||||
if (!email) return Response.json({ message: 'email required' }, { status: HttpStatusCodes.BAD_REQUEST })
|
const user = userResponse.data
|
||||||
|
if (!user) return Response.json({ message: 'Invalid email or password' }, { status: HttpStatusCodes.NOT_FOUND })
|
||||||
|
|
||||||
const userResponse = await client.getUserByEmail({ email: body.email })
|
const accessToken = await createAccessToken(user.id, user.email)
|
||||||
const user = userResponse.data
|
const expires = new Date(Date.now() + config.cookieExpiry * 1000)
|
||||||
|
|
||||||
if (!user) return Response.json({ message: 'Invalid email or password' }, { status: HttpStatusCodes.NOT_FOUND })
|
return Response.json(
|
||||||
|
{
|
||||||
const accessToken = await createAccessToken(user.id, user.email)
|
accessToken: accessToken.token,
|
||||||
|
tokenType: 'Bearer',
|
||||||
const expires = new Date(Date.now() + config.cookieExpiry * 1000)
|
expires: expires,
|
||||||
return Response.json(
|
},
|
||||||
{
|
{ status: HttpStatusCodes.CREATED },
|
||||||
accessToken: accessToken.token,
|
)
|
||||||
tokenType: 'Bearer',
|
} catch (error) {
|
||||||
expires: expires,
|
console.log({ error })
|
||||||
},
|
return Response.json({ message: 'Login failed' }, { status: HttpStatusCodes.BAD_REQUEST })
|
||||||
{ status: HttpStatusCodes.CREATED },
|
}
|
||||||
)
|
},
|
||||||
} catch (error) {
|
|
||||||
console.log({ error })
|
|
||||||
return Response.json({ message: 'Login failed' }, { status: HttpStatusCodes.BAD_REQUEST })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function upgrade(req: Request, server: Bun.Server<WebSocketData>) {
|
export async function upgrade(req: Request, server: Bun.Server<WebSocketCtx>) {
|
||||||
const payload = await checkRequest(req)
|
const payload = await checkRequest(req)
|
||||||
if (!payload) return new Response('Invalid token', { status: HttpStatusCodes.NOT_FOUND })
|
if (!payload) return new Response('Invalid token', { status: HttpStatusCodes.NOT_FOUND })
|
||||||
|
|
||||||
const success = server.upgrade(req, { data: { userId: +payload.sub, email: payload.email } })
|
const success = server.upgrade(req, { data: { userId: +payload.sub, email: payload.email } })
|
||||||
if (success) return undefined
|
if (success) return undefined
|
||||||
|
|
||||||
return new Response('Upgrade failed', { status: HttpStatusCodes.BAD_REQUEST })
|
return new Response('Upgrade failed', { status: HttpStatusCodes.BAD_REQUEST })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
src/index.ts
51
src/index.ts
@@ -1,7 +1,8 @@
|
|||||||
import { HttpStatusCodes } from './constants.ts'
|
import { HttpStatusCodes } from './constants.ts'
|
||||||
import type { WebSocketData, WsData } from './types/types.ts'
|
import type { WebSocketCtx, WebSocketData } from './types/types.ts'
|
||||||
import { grpcClient as client } from './grpc/client.ts'
|
|
||||||
import { login, upgrade } from './handles.ts'
|
import { handlers, upgrade } from './handles.ts'
|
||||||
|
import { messageService } from './grpc/message.ts'
|
||||||
|
|
||||||
const PORT = 3000
|
const PORT = 3000
|
||||||
|
|
||||||
@@ -13,13 +14,14 @@ const server = Bun.serve({
|
|||||||
const pathname = url.pathname
|
const pathname = url.pathname
|
||||||
const method = req.method
|
const method = req.method
|
||||||
|
|
||||||
if (pathname === '/login' && method === 'POST') return login(req)
|
if (pathname === '/version' && method === 'GET') return handlers.getVersion()
|
||||||
|
if (pathname === '/login' && method === 'POST') return handlers.login(req)
|
||||||
if (pathname === '/ws') return upgrade(req, server)
|
if (pathname === '/ws') return upgrade(req, server)
|
||||||
|
|
||||||
return new Response('Not found', { status: HttpStatusCodes.NOT_FOUND })
|
return new Response('Not found', { status: HttpStatusCodes.NOT_FOUND })
|
||||||
},
|
},
|
||||||
websocket: {
|
websocket: {
|
||||||
data: {} as WebSocketData,
|
data: {} as WebSocketCtx,
|
||||||
async open(ws) {
|
async open(ws) {
|
||||||
try {
|
try {
|
||||||
const ipAddr = ws.remoteAddress
|
const ipAddr = ws.remoteAddress
|
||||||
@@ -27,10 +29,10 @@ const server = Bun.serve({
|
|||||||
|
|
||||||
const user = ws.data
|
const user = ws.data
|
||||||
|
|
||||||
const userResponse = await client.getUser({ id: user.userId })
|
const userResponse = await messageService.getUser({ id: user.userId })
|
||||||
ws.send(JSON.stringify({ type: 'USER', ...userResponse }))
|
ws.send(JSON.stringify({ type: 'USER', ...userResponse }))
|
||||||
|
|
||||||
const chatResponse = await client.listChat({ page: 0, user_id: user.userId })
|
const chatResponse = await messageService.listChat({ page: 0, userId: user.userId })
|
||||||
chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
chatResponse.data.forEach((el) => ws.subscribe(el.id))
|
||||||
ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
ws.send(JSON.stringify({ type: 'CHATS', ...chatResponse }))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -47,34 +49,37 @@ const server = Bun.serve({
|
|||||||
},
|
},
|
||||||
async message(ws, message) {
|
async message(ws, message) {
|
||||||
console.log('Websocket message', message)
|
console.log('Websocket message', message)
|
||||||
// const result = ws.send(message);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof message === 'string') {
|
if (typeof message === 'string') {
|
||||||
const o = JSON.parse(message) as WsData
|
const webSocketData = JSON.parse(message) as WebSocketData
|
||||||
if (!o) return
|
if (!webSocketData) return
|
||||||
|
|
||||||
if (o.type === 'CREATE_CHAT') {
|
if (webSocketData.type === 'CREATE_CHAT') {
|
||||||
const chat = await client.createChat({ users: [{ user_id: o.data.userId }, { user_id: ws.data.userId }] })
|
const chat = await messageService.createChat({ users: [{ userId: webSocketData.data.userId }, { userId: ws.data.userId }] })
|
||||||
ws.send(JSON.stringify({ type: 'CHATS', ...chat }))
|
ws.send(JSON.stringify({ type: 'CHATS', ...chat }))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o.type === 'CREATE_MESSAGE') {
|
if (webSocketData.type === 'CREATE_MESSAGE') {
|
||||||
const messageResponse = await client.createMessage({
|
const messageResponse = await messageService.createMessage({
|
||||||
chat_id: o.data.chat_id,
|
chatId: webSocketData.data.chatId,
|
||||||
user_id: ws.data.userId,
|
userId: ws.data.userId,
|
||||||
text: o.data.text,
|
message: webSocketData.data.message,
|
||||||
})
|
})
|
||||||
server.publish(o.data.chat_id, JSON.stringify({ type: 'MESSAGE', ...messageResponse }))
|
server.publish(webSocketData.data.chatId, JSON.stringify({ type: 'MESSAGE', ...messageResponse }))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o.type === 'GET_MESSAGES') {
|
if (webSocketData.type === 'GET_MESSAGES') {
|
||||||
const messages = await client.listMessage({ user_id: ws.data.userId, chat_id: o.data.chatId, page: 1 })
|
const messages = await messageService.listMessage({
|
||||||
server.publish(o.data.chatId, JSON.stringify({ type: 'MESSAGES', ...messages }))
|
userId: ws.data.userId,
|
||||||
|
chatId: webSocketData.data.chatId,
|
||||||
|
page: 1,
|
||||||
|
})
|
||||||
|
server.publish(webSocketData.data.chatId, JSON.stringify({ type: 'MESSAGES', ...messages }))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o.type === 'GET_USERS') {
|
if (webSocketData.type === 'GET_USERS') {
|
||||||
const users = await client.listUser({})
|
const users = await messageService.listUser({ page: 1, userIds: [] })
|
||||||
ws.send(JSON.stringify({ type: 'USERS', ...users }))
|
ws.send(JSON.stringify({ type: 'USERS', ...users }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export interface WebSocketData {
|
export interface WebSocketCtx {
|
||||||
chatId?: string
|
chatId?: string
|
||||||
token?: string
|
token?: string
|
||||||
userId: number
|
userId: number
|
||||||
@@ -28,8 +28,8 @@ interface ListMessages {
|
|||||||
interface CreateMessage {
|
interface CreateMessage {
|
||||||
type: 'CREATE_MESSAGE'
|
type: 'CREATE_MESSAGE'
|
||||||
data: {
|
data: {
|
||||||
chat_id: string
|
chatId: string
|
||||||
text: string
|
message: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ interface ListUsers {
|
|||||||
type: 'GET_USERS'
|
type: 'GET_USERS'
|
||||||
data: {
|
data: {
|
||||||
page?: number
|
page?: number
|
||||||
user_ids?: number[]
|
userIds?: number[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,4 +48,4 @@ interface CreateChat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WsData = ListMessages | CreateMessage | ListUsers | CreateChat
|
export type WebSocketData = ListMessages | CreateMessage | ListUsers | CreateChat
|
||||||
|
|||||||
Reference in New Issue
Block a user