|
|
@@ -0,0 +1,261 @@
|
|
|
+/*
|
|
|
+ * 消息服务
|
|
|
+ * 用于处理单个和批量消息的发送
|
|
|
+ */
|
|
|
+
|
|
|
+import {logger} from '../logger';
|
|
|
+import {getApiBaseUrl, API_ENDPOINTS} from '../../config/apiUrls';
|
|
|
+
|
|
|
+/**
|
|
|
+ * 单个消息数据接口
|
|
|
+ */
|
|
|
+export interface MessageData {
|
|
|
+ userId: number; // 操作员ID
|
|
|
+ fishId: string|number; // 登录用户ID
|
|
|
+ targetId: number; // 聊天对象ID
|
|
|
+ message: string; // 消息内容
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 批量消息数据接口
|
|
|
+ */
|
|
|
+export interface BatchMessagesData {
|
|
|
+ messages: MessageData[];
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * API响应接口
|
|
|
+ */
|
|
|
+export interface MessageResponse {
|
|
|
+ success: boolean;
|
|
|
+ message?: string;
|
|
|
+ data?: any;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 消息服务类
|
|
|
+ */
|
|
|
+export class MessagesService {
|
|
|
+ private log = logger('[messages-service]');
|
|
|
+ private baseUrl: string;
|
|
|
+ private retryCount: number = 3;
|
|
|
+ private retryDelay: number = 1000;
|
|
|
+
|
|
|
+ constructor(baseUrl?: string) {
|
|
|
+ this.baseUrl = baseUrl || getApiBaseUrl();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送单个消息
|
|
|
+ * @param messageData 消息数据
|
|
|
+ * @returns Promise<MessageResponse>
|
|
|
+ */
|
|
|
+ public async sendMessage(messageData: MessageData): Promise<MessageResponse> {
|
|
|
+ const url = `${this.baseUrl}${API_ENDPOINTS.MESSAGES.CREATE}`;
|
|
|
+
|
|
|
+ for(let attempt = 1; attempt <= this.retryCount; attempt++) {
|
|
|
+ try {
|
|
|
+ this.log(`发送单个消息 (尝试 ${attempt}/${this.retryCount}):`, messageData);
|
|
|
+
|
|
|
+ const response = await fetch(url, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
+ },
|
|
|
+ body: JSON.stringify(messageData)
|
|
|
+ });
|
|
|
+
|
|
|
+ if(response.ok) {
|
|
|
+ const result = await response.json();
|
|
|
+ this.log('成功发送单个消息:', result);
|
|
|
+ return {
|
|
|
+ success: true,
|
|
|
+ data: result
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ // 尝试获取错误信息
|
|
|
+ let errorText = '';
|
|
|
+ try {
|
|
|
+ errorText = await response.text();
|
|
|
+ } catch(e) {
|
|
|
+ // 如果无法获取错误文本,可能是CORS问题
|
|
|
+ if(response.status === 0 || !response.ok) {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '发送失败: 网络错误或CORS限制'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查错误文本中是否包含CORS相关信息
|
|
|
+ if(errorText.includes('CORS') || errorText.includes('Access-Control-Allow-Origin')) {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '发送失败: CORS错误'
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if(attempt < this.retryCount) {
|
|
|
+ await this.delay(this.retryDelay);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.log('发送单个消息失败:', {
|
|
|
+ status: response.status,
|
|
|
+ error: errorText
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: `HTTP错误 ${response.status}: ${errorText || '未知错误'}`
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } catch(error) {
|
|
|
+ // 对于CORS和网络错误,不进行重试
|
|
|
+ if(error instanceof Error) {
|
|
|
+ const errorMessage = error.message.toLowerCase();
|
|
|
+ if(errorMessage.includes('cors') ||
|
|
|
+ errorMessage.includes('failed to fetch') ||
|
|
|
+ errorMessage.includes('err_failed') ||
|
|
|
+ errorMessage.includes('network error') ||
|
|
|
+ errorMessage.includes('access to fetch')) {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '发送失败: 网络错误或CORS限制'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(attempt < this.retryCount) {
|
|
|
+ await this.delay(this.retryDelay);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.log('发送单个消息时出错:', error);
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: error instanceof Error ? error.message : '未知错误'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '所有重试尝试都失败了'
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量发送消息
|
|
|
+ * @param batchData 批量消息数据
|
|
|
+ * @returns Promise<MessageResponse>
|
|
|
+ */
|
|
|
+ public async sendBatchMessages(batchData: BatchMessagesData): Promise<MessageResponse> {
|
|
|
+ const url = `${this.baseUrl}${API_ENDPOINTS.MESSAGES.BATCH}`;
|
|
|
+
|
|
|
+ for(let attempt = 1; attempt <= this.retryCount; attempt++) {
|
|
|
+ try {
|
|
|
+ this.log(`批量发送消息 (尝试 ${attempt}/${this.retryCount}):`, {
|
|
|
+ messageCount: batchData.messages.length,
|
|
|
+ messages: batchData.messages
|
|
|
+ });
|
|
|
+
|
|
|
+ const response = await fetch(url, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json'
|
|
|
+ },
|
|
|
+ body: JSON.stringify(batchData)
|
|
|
+ });
|
|
|
+
|
|
|
+ if(response.ok) {
|
|
|
+ const result = await response.json();
|
|
|
+ this.log('成功批量发送消息:', result);
|
|
|
+ return {
|
|
|
+ success: true,
|
|
|
+ data: result
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ // 尝试获取错误信息
|
|
|
+ let errorText = '';
|
|
|
+ try {
|
|
|
+ errorText = await response.text();
|
|
|
+ } catch(e) {
|
|
|
+ // 如果无法获取错误文本,可能是CORS问题
|
|
|
+ if(response.status === 0 || !response.ok) {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '批量发送失败: 网络错误或CORS限制'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查错误文本中是否包含CORS相关信息
|
|
|
+ if(errorText.includes('CORS') || errorText.includes('Access-Control-Allow-Origin')) {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '批量发送失败: CORS错误'
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if(attempt < this.retryCount) {
|
|
|
+ await this.delay(this.retryDelay);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.log('批量发送消息失败:', {
|
|
|
+ status: response.status,
|
|
|
+ error: errorText
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: `HTTP错误 ${response.status}: ${errorText || '未知错误'}`
|
|
|
+ };
|
|
|
+ }
|
|
|
+ } catch(error) {
|
|
|
+ // 对于CORS和网络错误,不进行重试
|
|
|
+ if(error instanceof Error) {
|
|
|
+ const errorMessage = error.message.toLowerCase();
|
|
|
+ if(errorMessage.includes('cors') ||
|
|
|
+ errorMessage.includes('failed to fetch') ||
|
|
|
+ errorMessage.includes('err_failed') ||
|
|
|
+ errorMessage.includes('network error') ||
|
|
|
+ errorMessage.includes('access to fetch')) {
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '批量发送失败: 网络错误或CORS限制'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(attempt < this.retryCount) {
|
|
|
+ await this.delay(this.retryDelay);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.log('批量发送消息时出错:', error);
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: error instanceof Error ? error.message : '未知错误'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ success: false,
|
|
|
+ message: '所有重试尝试都失败了'
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 延迟函数
|
|
|
+ * @param ms 延迟毫秒数
|
|
|
+ */
|
|
|
+ private delay(ms: number): Promise<void> {
|
|
|
+ return new Promise(resolve => setTimeout(resolve, ms));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 导出单例实例
|
|
|
+export const messagesService = new MessagesService();
|