138 lines
3.8 KiB
JavaScript
138 lines
3.8 KiB
JavaScript
import axios from "axios";
|
|
import { Buffer } from "buffer";
|
|
import { BaseService } from "../base/BaseService.js";
|
|
import { AircallDataManager } from "./AircallDataManager.js";
|
|
|
|
export class AircallService extends BaseService {
|
|
constructor(config) {
|
|
super(config);
|
|
this.baseUrl = "https://api.aircall.io/v1";
|
|
console.log('Initializing Aircall service with credentials:', {
|
|
apiId: config.apiId ? 'present' : 'missing',
|
|
apiToken: config.apiToken ? 'present' : 'missing'
|
|
});
|
|
this.auth = Buffer.from(`${config.apiId}:${config.apiToken}`).toString(
|
|
"base64"
|
|
);
|
|
this.dataManager = new AircallDataManager(
|
|
this.mongodb,
|
|
this.redis,
|
|
this.timeManager
|
|
);
|
|
|
|
if (!config.apiId || !config.apiToken) {
|
|
throw new Error("Aircall API credentials are required");
|
|
}
|
|
}
|
|
|
|
async getMetrics(timeRange) {
|
|
const dateRange = await this.timeManager.getDateRange(timeRange);
|
|
console.log('Fetching metrics for date range:', {
|
|
start: dateRange.start.toISOString(),
|
|
end: dateRange.end.toISOString()
|
|
});
|
|
|
|
return this.dataManager.getData(dateRange, async (range) => {
|
|
const calls = await this.fetchAllCalls(range.start, range.end);
|
|
console.log('Fetched calls:', {
|
|
count: calls.length,
|
|
sample: calls.length > 0 ? calls[0] : null
|
|
});
|
|
return calls;
|
|
});
|
|
}
|
|
|
|
async fetchAllCalls(start, end) {
|
|
try {
|
|
let allCalls = [];
|
|
let currentPage = 1;
|
|
let hasMore = true;
|
|
let totalPages = null;
|
|
|
|
while (hasMore) {
|
|
const response = await this.makeRequest("/calls", {
|
|
from: Math.floor(start.getTime() / 1000),
|
|
to: Math.floor(end.getTime() / 1000),
|
|
order: "asc",
|
|
page: currentPage,
|
|
per_page: 50,
|
|
});
|
|
|
|
console.log('API Response:', {
|
|
page: currentPage,
|
|
totalPages: response.meta.total_pages,
|
|
callsCount: response.calls?.length,
|
|
params: {
|
|
from: Math.floor(start.getTime() / 1000),
|
|
to: Math.floor(end.getTime() / 1000)
|
|
}
|
|
});
|
|
|
|
if (!response.calls) {
|
|
throw new Error("Invalid API response format");
|
|
}
|
|
|
|
allCalls = [...allCalls, ...response.calls];
|
|
hasMore = response.meta.next_page_link !== null;
|
|
totalPages = response.meta.total_pages;
|
|
currentPage++;
|
|
|
|
if (hasMore) {
|
|
// Rate limiting pause
|
|
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
}
|
|
}
|
|
|
|
return allCalls;
|
|
} catch (error) {
|
|
console.error("Error fetching all calls:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async makeRequest(endpoint, params = {}) {
|
|
try {
|
|
console.log('Making API request:', {
|
|
endpoint,
|
|
params
|
|
});
|
|
const response = await axios.get(`${this.baseUrl}${endpoint}`, {
|
|
headers: {
|
|
Authorization: `Basic ${this.auth}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
params,
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
if (error.response?.status === 429) {
|
|
console.log("Rate limit reached, waiting before retry...");
|
|
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
return this.makeRequest(endpoint, params);
|
|
}
|
|
|
|
this.handleApiError(error, `Error making request to ${endpoint}`);
|
|
}
|
|
}
|
|
|
|
validateApiResponse(response, context = "") {
|
|
if (!response || typeof response !== "object") {
|
|
throw new Error(`${context}: Invalid API response format`);
|
|
}
|
|
|
|
if (response.error) {
|
|
throw new Error(`${context}: ${response.error}`);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
getPaginationInfo(meta) {
|
|
return {
|
|
currentPage: meta.current_page,
|
|
totalPages: meta.total_pages,
|
|
hasNextPage: meta.next_page_link !== null,
|
|
totalRecords: meta.total,
|
|
};
|
|
}
|
|
}
|