BaaS_Driver_Android_App/services/paymentSocket.ts

136 lines
3.6 KiB
TypeScript

// services/socketService.ts
import {
PAYMENT_SOCKET_BASE_URL,
payments,
STORAGE_KEYS,
} from "@/constants/config";
import AsyncStorage from "@react-native-async-storage/async-storage";
import io, { Socket } from "socket.io-client";
class SocketService {
private socket: Socket | null = null;
private static instance: SocketService;
private constructor() {}
public static getInstance(): SocketService {
if (!SocketService.instance) {
SocketService.instance = new SocketService();
}
return SocketService.instance;
}
public async connect(): Promise<Socket> {
try {
const token = await AsyncStorage.getItem(STORAGE_KEYS.AUTH_TOKEN);
if (!token) {
throw new Error("No auth token found");
}
this.socket = io(PAYMENT_SOCKET_BASE_URL, {
transports: ["websocket"],
autoConnect: true,
reconnection: true,
reconnectionDelay: 1000,
reconnectionAttempts: 5,
timeout: 20000,
extraHeaders: {
Authorization: `Bearer ${token}`,
},
});
return new Promise((resolve, reject) => {
this.socket!.on("connect", () => {
console.log("Socket connected:", this.socket?.id);
resolve(this.socket!);
});
this.socket!.on("connect_error", (error) => {
console.error("Socket connection error:", error);
reject(error);
});
this.socket!.on("disconnect", (reason) => {
console.log("Socket disconnected:", reason);
});
});
} catch (error) {
console.error("Failed to connect socket:", error);
return Promise.reject(error);
}
}
public registerTransaction(transactionId: string): Promise<void> {
return new Promise((resolve, reject) => {
const socket = this.socket; // Save reference to socket here
if (!socket || !socket.connected) {
reject(new Error("Socket not connected"));
return;
}
const timeoutSecs = payments.SOCKET_CONNECTION_TIMEOUT_IN_SECS * 1000;
const timeoutId = setTimeout(() => {
socket.off("registration-ack", onRegistrationAck);
reject(new Error("Timeout: No registration-ack received"));
}, timeoutSecs);
const onRegistrationAck = (data: any) => {
if (data.transactionId === transactionId) {
clearTimeout(timeoutId);
socket.off("registration-ack", onRegistrationAck);
if (data.success) {
resolve();
} else {
reject(new Error("Registration failed"));
}
}
};
//register the transaction with the specific 'transactionId'
socket.emit(payments.REGISTER_TRANSACTION_EMIT_EVENT_NAME, {
transactionId,
});
socket.on(
payments.REGISTER_TRANSACTION_LISTEN_EVENT_NAME,
onRegistrationAck
);
});
}
//payment confirmation is received on 'register-transaction' eventName
public onPaymentConfirmation(callback: (data: any) => void): void {
if (!this.socket) {
console.error("Socket not connected");
return;
}
this.socket.on(payments.PAYMENT_CONFIRMATION_EVENT_NAME, callback);
}
public offPaymentConfirmation(): void {
if (this.socket) {
this.socket.off(payments.PAYMENT_CONFIRMATION_EVENT_NAME);
}
}
public disconnect(): void {
if (this.socket) {
this.socket.disconnect();
this.socket = null;
}
}
public isConnected(): boolean {
return this.socket?.connected || false;
}
public getSocket(): Socket | null {
return this.socket;
}
}
export default SocketService.getInstance();