Code quality improvements and cleanup + Implemented ChatService
Some checks failed
Setup testing environment and test the code / build (push) Has been cancelled

This commit is contained in:
2026-04-05 15:19:55 +02:00
parent ec418ca7c9
commit 4a34d73c2f
20 changed files with 380 additions and 39 deletions

View File

@@ -0,0 +1,24 @@
import {describe, expect, it} from "vitest";
import {ChatService} from "./chatService";
import {DatabaseMock} from "../mocks/storage/database";
import {faker} from "@faker-js/faker/locale/en";
describe("ChatService", () => {
const service = new ChatService("", "", new DatabaseMock(), (action, data) => {})
it('should get chats', async () => {
const chats = await service.get()
expect(chats[0].userid).toBe("chatPartnerId")
})
it('should get availability', async () => {
const available = await service.getUserAvailability("")
expect(available).toBeTruthy()
});
it('should create a new chat', async () => {
const chatPartnerName = faker.internet.displayName()
const newChat = await service.startNew(chatPartnerName)
expect(newChat.username).toBe(chatPartnerName)
});
})

116
src/services/chatService.ts Normal file
View File

@@ -0,0 +1,116 @@
import {DatabaseAPI} from "../storage/database";
import {MessageListener} from "../domain/websocket.schema";
import {getClient} from "../core/http";
import {WebSocketHandler} from "../core/webSocketHandler";
import {AxiosInstance, isAxiosError} from "axios";
import {NetworkInvite} from "../domain/networkService.schema";
import {GenericErrorBody} from "../domain/http.schema";
import {
Chat,
GetAvailabilityReq,
GetAvailabilityResp,
StartNewReq,
ToggleChatMuteReq
} from "../domain/chatService.schema";
/**
* ChatService is an exception because it's one instance for all chats because it's unnecessary to create a new instance for each chat
*/
export class ChatService {
userid: string;
database: DatabaseAPI;
client: AxiosInstance;
constructor(userid: string, token: string, database: DatabaseAPI, wsMessageListener: MessageListener) {
this.userid = userid;
this.database = database;
this.client = getClient(false).create({
headers: {
"Authorization": token,
}
})
WebSocketHandler.getInstance().registerService({
identifier: userid,
onNewConnId: this.onNewConnId,
onNewMessage: wsMessageListener,
})
}
private onNewConnId(newConnId: string) {
console.log("ChatService: New connection id")
this.client.defaults.headers["X-WS-ID"] = newConnId;
}
/**
* Fetches all chat partners
*/
async get(): Promise<Chat[]> {
try {
const resp = await this.client.get<Chat[]>(`chat/get?userid=${this.userid}`);
return resp.data
} catch (e) {
console.log(e)
if (isAxiosError<GenericErrorBody>(e)) {
throw e;
}
throw new Error("Unexpected error")
}
}
/**
* Gets the availability of the specified user
* @param userid
*/
async getUserAvailability(userid: string): Promise<boolean> {
try {
const resp = await this.client.get<GetAvailabilityResp>(`chat/availability?target=${this.userid}&connId=${WebSocketHandler.getInstance().connId}`);
return resp.data.available
} catch (e) {
console.log(e)
if (isAxiosError<GenericErrorBody>(e)) {
throw e;
}
throw new Error("Unexpected error")
}
}
/**
* (un)mutes the specified chat
* @param chatid
*/
async toggleMute(chatid: string): Promise<void> {
try {
const resp = await this.client.post("v2/chat/toggleMute", <ToggleChatMuteReq>{
userid: this.userid,
chatid: chatid,
});
return
} catch (e) {
console.log(e)
if (isAxiosError<GenericErrorBody>(e)) {
throw e;
}
throw new Error("Unexpected error")
}
}
/**
* Starts a new chat with the specified user
* @param peerUsername
*/
async startNew(peerUsername: string): Promise<Chat> {
try {
const resp = await this.client.post("chat/startNew", <StartNewReq>{
userid: this.userid,
peerUsername: peerUsername,
});
return resp.data
} catch (e) {
console.log(e)
if (isAxiosError<GenericErrorBody>(e)) {
throw e;
}
throw new Error("Unexpected error")
}
}
}

View File

@@ -3,7 +3,7 @@ import {FileUploadService} from "./fileUploadService";
describe("fileUploadService", () => {
it('should upload files', async () => {
const service = new FileUploadService("", null, null);
const service = new FileUploadService("");
const uploadId = await service.uploadFiles("", "", [])
expect(uploadId).toBe("MockUploadId")
});

View File

@@ -15,13 +15,13 @@ export class FileUploadService {
client: AxiosInstance;
cdnClient: AxiosInstance;
constructor(token: string, private httpClientOverwrite: AxiosInstance | null, private cdnHttpClientOverwrite: AxiosInstance | null) {
this.client = (httpClientOverwrite ?? getClient(false)).create({
constructor(token: string) {
this.client = getClient(false).create({
headers: {
"Authorization": token
}
})
this.cdnClient = (cdnHttpClientOverwrite ?? getClient(true)).create({
this.cdnClient = getClient(true).create({
headers: {
"Authorization": token
}

View File

@@ -6,7 +6,7 @@ import {getClient} from "../core/http";
import {environment, SDKConfig} from "../core/environment";
describe("NetworkService", () => {
const service = new NetworkService("", "", "", new DatabaseMock(), getClient(false))
const service = new NetworkService("", "", "", new DatabaseMock(), (action, data) => {})
it('should get invites', async () => {
const invites = await service.getInvites();

View File

@@ -1,5 +1,4 @@
import {DatabaseAPI} from "../storage/database";
import {AuthMethods} from "../domain/authService.schema";
import {getClient} from "../core/http";
import {AxiosInstance, isAxiosError} from "axios";
import {GenericErrorBody} from "../domain/http.schema";
@@ -18,7 +17,8 @@ import {
UnbanMemberReq, UploadNewPictureReq
} from "../domain/networkService.schema";
import {PublicUserData, RGB} from "../domain/common.schema";
import {http} from "msw";
import {WebSocketHandler} from "../core/webSocketHandler";
import {MessageListener} from "../domain/websocket.schema";
export class NetworkService {
userid: string;
@@ -26,15 +26,26 @@ export class NetworkService {
database: DatabaseAPI;
client: AxiosInstance
constructor(userid: string, token: string, networkId: string, database: DatabaseAPI, httpClientOverwrite: AxiosInstance | null) {
constructor(userid: string, token: string, networkId: string, database: DatabaseAPI, wsMessageListener: MessageListener) {
this.userid = userid;
this.networkId = networkId;
this.database = database;
this.client = (httpClientOverwrite ?? getClient(false)).create({
this.client = getClient(false).create({
headers: {
"Authorization": token
"Authorization": token,
"X-WS-ID": WebSocketHandler.getInstance().connId
}
})
WebSocketHandler.getInstance().registerService({
identifier: networkId,
onNewConnId: this.onNewConnId,
onNewMessage: wsMessageListener,
})
}
private onNewConnId(newConnId: string) {
console.log("NetworkService: New connection id")
this.client.defaults.headers["X-WS-ID"] = newConnId;
}
/**
@@ -101,7 +112,7 @@ export class NetworkService {
*/
async acceptInvite(inviteId: string): Promise<void> {
try {
const resp = await this.client.post("network/acceptInvite", <AcceptInviteReq>{
await this.client.post("network/acceptInvite", <AcceptInviteReq>{
userid: this.userid,
inviteId: inviteId,
});

View File

@@ -4,7 +4,7 @@ import {DatabaseMock} from "../mocks/storage/database";
import {faker} from "@faker-js/faker/locale/en";
describe("PictureService", () => {
const service = new PictureService("", "", "", new DatabaseMock(), null, null)
const service = new PictureService("", "", "", new DatabaseMock())
it('should get pictures', async () => {
const uploads = await service.get()

View File

@@ -20,16 +20,16 @@ export class PictureService {
client: AxiosInstance
cdnClient: AxiosInstance
constructor(token: string, uploaderId: string, userid: string, database: DatabaseAPI, httpClientOverwrite: AxiosInstance | null, cdnClientOverwrite: AxiosInstance | null) {
constructor(token: string, uploaderId: string, userid: string, database: DatabaseAPI) {
this.userid = userid;
this.uploaderId = uploaderId;
this.database = database;
this.client = (httpClientOverwrite ?? getClient(false)).create({
this.client = getClient(false).create({
headers: {
"Authorization": token
}
})
this.cdnClient = (cdnClientOverwrite ?? getClient(true)).create({
this.cdnClient = getClient(true).create({
headers: {
"Authorization": token
}