205 lines
4.8 KiB
TypeScript
205 lines
4.8 KiB
TypeScript
|
|
import Store from 'electron-store'
|
||
|
|
import { app } from 'electron'
|
||
|
|
import * as path from 'path'
|
||
|
|
import * as fs from 'fs'
|
||
|
|
import type { AppSettings, Channel, ErrorLogEntry } from '../shared/types'
|
||
|
|
|
||
|
|
// Default settings
|
||
|
|
export const defaultSettings: AppSettings = {
|
||
|
|
general: {
|
||
|
|
startMinimized: false,
|
||
|
|
minimizeToTray: true,
|
||
|
|
autoStart: false,
|
||
|
|
language: 'tr',
|
||
|
|
},
|
||
|
|
monitoring: {
|
||
|
|
pingInterval: 30,
|
||
|
|
streamCheckInterval: 60,
|
||
|
|
timeout: 5000,
|
||
|
|
retryCount: 2,
|
||
|
|
},
|
||
|
|
notifications: {
|
||
|
|
enabled: true,
|
||
|
|
windows: { enabled: true },
|
||
|
|
telegram: {
|
||
|
|
enabled: false,
|
||
|
|
botToken: '',
|
||
|
|
chatId: '',
|
||
|
|
},
|
||
|
|
email: {
|
||
|
|
enabled: false,
|
||
|
|
smtpHost: '',
|
||
|
|
smtpPort: 587,
|
||
|
|
smtpUser: '',
|
||
|
|
smtpPass: '',
|
||
|
|
fromEmail: '',
|
||
|
|
toEmail: '',
|
||
|
|
},
|
||
|
|
autoNotify: true,
|
||
|
|
notifyOnPingFail: true,
|
||
|
|
notifyOnStreamError: true,
|
||
|
|
notifyOn404: true,
|
||
|
|
notifyOnConnReset: true,
|
||
|
|
},
|
||
|
|
panel: {
|
||
|
|
apiUrl: '',
|
||
|
|
authToken: '',
|
||
|
|
monitorId: '',
|
||
|
|
enabled: false,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if running in portable mode
|
||
|
|
function isPortableMode(): boolean {
|
||
|
|
// Check for portable marker file next to exe
|
||
|
|
const exePath = app.getPath('exe')
|
||
|
|
const exeDir = path.dirname(exePath)
|
||
|
|
const portableMarker = path.join(exeDir, 'portable.txt')
|
||
|
|
const portableDataDir = path.join(exeDir, 'data')
|
||
|
|
|
||
|
|
// Portable mode if:
|
||
|
|
// 1. portable.txt exists next to exe
|
||
|
|
// 2. OR data folder exists next to exe
|
||
|
|
// 3. OR running from a removable drive (simplified check)
|
||
|
|
if (fs.existsSync(portableMarker) || fs.existsSync(portableDataDir)) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if exe name contains "Portable"
|
||
|
|
if (exePath.toLowerCase().includes('portable')) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get the data directory for storing config
|
||
|
|
function getDataDirectory(): string {
|
||
|
|
if (isPortableMode()) {
|
||
|
|
const exeDir = path.dirname(app.getPath('exe'))
|
||
|
|
const dataDir = path.join(exeDir, 'data')
|
||
|
|
|
||
|
|
// Create data directory if it doesn't exist
|
||
|
|
if (!fs.existsSync(dataDir)) {
|
||
|
|
fs.mkdirSync(dataDir, { recursive: true })
|
||
|
|
}
|
||
|
|
|
||
|
|
return dataDir
|
||
|
|
}
|
||
|
|
|
||
|
|
// Use default app data location
|
||
|
|
return app.getPath('userData')
|
||
|
|
}
|
||
|
|
|
||
|
|
// Store schema
|
||
|
|
interface StoreSchema {
|
||
|
|
settings: AppSettings
|
||
|
|
channels: Channel[]
|
||
|
|
errorLog: ErrorLogEntry[]
|
||
|
|
windowBounds: {
|
||
|
|
x?: number
|
||
|
|
y?: number
|
||
|
|
width: number
|
||
|
|
height: number
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create store instance
|
||
|
|
let storeInstance: Store<StoreSchema> | null = null
|
||
|
|
|
||
|
|
export function getStore(): Store<StoreSchema> {
|
||
|
|
if (!storeInstance) {
|
||
|
|
const dataDir = getDataDirectory()
|
||
|
|
|
||
|
|
storeInstance = new Store<StoreSchema>({
|
||
|
|
name: 'ip-monitor-config',
|
||
|
|
cwd: dataDir,
|
||
|
|
defaults: {
|
||
|
|
settings: defaultSettings,
|
||
|
|
channels: [],
|
||
|
|
errorLog: [],
|
||
|
|
windowBounds: {
|
||
|
|
width: 1400,
|
||
|
|
height: 900,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
// Enable encryption for sensitive data
|
||
|
|
encryptionKey: 'ip-monitor-v1-key',
|
||
|
|
// Clear invalid config
|
||
|
|
clearInvalidConfig: true,
|
||
|
|
})
|
||
|
|
|
||
|
|
console.log(`[Store] Config location: ${dataDir}`)
|
||
|
|
console.log(`[Store] Portable mode: ${isPortableMode()}`)
|
||
|
|
}
|
||
|
|
|
||
|
|
return storeInstance
|
||
|
|
}
|
||
|
|
|
||
|
|
// Helper functions for common operations
|
||
|
|
export function getSettings(): AppSettings {
|
||
|
|
return getStore().get('settings', defaultSettings)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function saveSettings(settings: AppSettings): void {
|
||
|
|
getStore().set('settings', settings)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getChannels(): Channel[] {
|
||
|
|
return getStore().get('channels', [])
|
||
|
|
}
|
||
|
|
|
||
|
|
export function saveChannels(channels: Channel[]): void {
|
||
|
|
getStore().set('channels', channels)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function addChannel(channel: Channel): void {
|
||
|
|
const channels = getChannels()
|
||
|
|
channels.push(channel)
|
||
|
|
saveChannels(channels)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function updateChannel(channelId: string, updates: Partial<Channel>): void {
|
||
|
|
const channels = getChannels()
|
||
|
|
const index = channels.findIndex(c => c.id === channelId)
|
||
|
|
if (index !== -1) {
|
||
|
|
channels[index] = { ...channels[index], ...updates }
|
||
|
|
saveChannels(channels)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function removeChannel(channelId: string): void {
|
||
|
|
const channels = getChannels().filter(c => c.id !== channelId)
|
||
|
|
saveChannels(channels)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getErrorLog(): ErrorLogEntry[] {
|
||
|
|
return getStore().get('errorLog', [])
|
||
|
|
}
|
||
|
|
|
||
|
|
export function addErrorLog(entry: ErrorLogEntry): void {
|
||
|
|
const log = getErrorLog()
|
||
|
|
log.unshift(entry) // Add to beginning
|
||
|
|
// Keep only last 100 entries
|
||
|
|
if (log.length > 100) {
|
||
|
|
log.length = 100
|
||
|
|
}
|
||
|
|
getStore().set('errorLog', log)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function clearErrorLog(): void {
|
||
|
|
getStore().set('errorLog', [])
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getWindowBounds() {
|
||
|
|
return getStore().get('windowBounds')
|
||
|
|
}
|
||
|
|
|
||
|
|
export function saveWindowBounds(bounds: { x?: number; y?: number; width: number; height: number }): void {
|
||
|
|
getStore().set('windowBounds', bounds)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Export portable mode check
|
||
|
|
export { isPortableMode }
|
||
|
|
|