netanalyzer/services/meraki.js
Joseph McQueen 459301cc4d chore: Phase 0 initial hygiene
- Initialize git repository
- Add comprehensive .gitignore (protects .env and secrets)
- Fix package.json (correct main entry, add metadata)
- Expand .env.example with all required variables and comments
- Add README.md with architecture, setup, and commands
- Clean up empty scaffolding directories (logs removed, agents/models marked)
- Backup previous .env file locally

This establishes a safe foundation before further development.
2026-06-24 13:32:37 -04:00

146 lines
No EOL
3.9 KiB
JavaScript

const axios = require('axios');
const config = require('../config');
const merakiAxios = axios.create({
baseURL: config.meraki.baseUrl,
headers: {
'X-Cisco-Meraki-API-Key': config.meraki.apiKey,
'Content-Type': 'application/json'
}
});
// In-memory cache
let cachedNetworks = [];
let lastCacheTime = 0;
const CACHE_TTL_MS = 4 * 60 * 60 * 1000; // 4 hours
async function refreshMerakiNetworksCache() {
const start = Date.now();
console.log('🔄 Refreshing Meraki networks cache...');
try {
const url = `/organizations/${config.meraki.orgId}/networks?perPage=5000`;
const res = await merakiAxios.get(url);
cachedNetworks = res.data || [];
lastCacheTime = Date.now();
console.log(`✅ Cached ${cachedNetworks.length} Meraki networks (${Date.now() - start}ms)`);
} catch (err) {
console.error('❌ Failed to refresh Meraki networks cache:', err.message);
}
}
async function getMerakiNetworks(forceRefresh = false) {
const now = Date.now();
if (forceRefresh || cachedNetworks.length === 0 || (now - lastCacheTime > CACHE_TTL_MS)) {
await refreshMerakiNetworksCache();
}
return cachedNetworks;
}
async function findMerakiNetwork(storeNum) {
if (!storeNum) return null;
const raw = String(storeNum).trim();
const match = raw.match(/\d+/);
if (!match) return null;
let searchTerm = match[0].padStart(5, '0').slice(-5);
const networks = await getMerakiNetworks();
console.log(`🔍 Searching for store "${raw}" → 5-digit term "${searchTerm}"`);
let bestMatch = null;
let bestScore = -1;
for (const net of networks) {
const name = (net.name || '').toLowerCase();
const term = searchTerm.toLowerCase();
if (name.includes(term)) {
const score = (name.includes(` ${term}`) || name.includes(`-${term}`) || name.includes(term + ' ')) ? 100 : 50;
if (score > bestScore) {
bestScore = score;
bestMatch = net;
}
}
}
if (bestMatch) {
console.log(`✅ Best Meraki match: ${bestMatch.name} (ID: ${bestMatch.id})`);
return bestMatch;
}
console.log(`❌ No Meraki network found for store ${storeNum}`);
return null;
}
async function getNetworkClients(networkId) {
if (!networkId) return [];
try {
const res = await merakiAxios.get(`/networks/${networkId}/clients?timespan=7200`); // last 2 hours
return res.data || [];
} catch (err) {
console.error(`❌ Failed to get clients for network ${networkId}:`, err.message);
return [];
}
}
async function getAllMerakiDevices(networkId) {
if (!networkId) return [];
try {
const res = await merakiAxios.get(`/networks/${networkId}/devices`);
return res.data || [];
} catch (err) {
console.error(`❌ Failed to get devices for network ${networkId}:`, err.message);
return [];
}
}
async function getMerakiDeviceAvailabilities(networkId) {
if (!networkId || !config.meraki.orgId) return [];
try {
const res = await merakiAxios.get(
`/organizations/${config.meraki.orgId}/devices/availabilities`,
{
params: { networkIds: [networkId] }
}
);
return res.data || [];
} catch (err) {
console.error(`❌ Device availabilities failed:`, err.message);
return [];
}
}
async function getMerakiClients(networkId) {
if (!networkId) return [];
try {
// 7 days = much better chance of catching registers & printers
const timespanSeconds = 7 * 24 * 60 * 60; // 604800
const res = await merakiAxios.get(
`/networks/${networkId}/clients?perPage=1000&timespan=${timespanSeconds}`
);
const clients = res.data || [];
console.log(`✅ Fetched ${clients.length} Meraki clients (7-day timespan) [getMerakiClients]`);
return clients;
} catch (err) {
console.error(`❌ Failed to fetch Meraki clients:`, err.message);
return [];
}
}
module.exports = {
findMerakiNetwork,
getNetworkClients,
getMerakiClients,
getAllMerakiDevices,
getMerakiDeviceAvailabilities,
refreshMerakiNetworksCache
};