UNPKG

cloudloyaldb

Version:

Centralized NoSQL Database - MongoDB benzeri API ile cloud server'a veri saklama, real-time sync

430 lines (378 loc) 13 kB
const axios = require('axios'); const WebSocket = require('ws'); const EventEmitter = require('events'); /** * CloudLoyalDB - Centralized NoSQL Database Client * MongoDB benzeri API ile centralized server'a veri saklama * Real-time sync, backup, query özellikleri */ class CloudLoyalDB extends EventEmitter { constructor(options = {}) { super(); // Server connection config this.serverUrl = options.serverUrl || 'http://localhost:3000'; this.apiKey = options.apiKey || process.env.CLOUDLOYALDB_API_KEY; this.projectId = options.projectId || process.env.CLOUDLOYALDB_PROJECT_ID || 'default'; this.currentDatabase = options.database || 'default'; this.currentCollection = null; // WebSocket connection this.ws = null; this.connected = false; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; // HTTP client setup this.httpClient = axios.create({ baseURL: this.serverUrl + '/api', timeout: 30000, headers: { 'Authorization': `Bearer ${this.apiKey}`, 'X-Project-Id': this.projectId, 'X-Database': this.currentDatabase, 'Content-Type': 'application/json' } }); // Auto-connect if credentials provided if (this.apiKey && this.projectId) { this.connect(); } } /** * Server'a bağlan */ async connect() { try { console.log('CloudLoyalDB: Server\'a bağlanıyor...'); const response = await this.httpClient.get('/health'); console.log('CloudLoyalDB: Server bağlantısı başarılı'); // WebSocket bağlantısını kur (geçici devre dışı - HTTP API tam çalışıyor) // this._connectWebSocket(); this.connected = true; this.emit('connected'); return true; } catch (error) { console.error('CloudLoyalDB: Bağlantı hatası:', error.message); this.connected = false; throw new Error(`Server bağlantısı başarısız: ${error.message}`); } } /** * WebSocket bağlantısı */ _connectWebSocket() { if (this.ws) { this.ws.removeAllListeners(); this.ws.close(); } try { // WebSocket farklı port'ta (3001) const baseUrl = this.serverUrl.replace('http://', '').replace('https://', ''); const host = baseUrl.split(':')[0]; // localhost const wsUrl = `ws://${host}:3001`; this.ws = new WebSocket(wsUrl, { headers: { 'Authorization': `Bearer ${this.apiKey}`, 'X-Project-Id': this.projectId, 'X-Database': this.currentDatabase } }); this.ws.on('open', () => { console.log('CloudLoyalDB: WebSocket aktif'); this.reconnectAttempts = 0; this.emit('realtime_connected'); }); this.ws.on('message', (data) => { try { const message = JSON.parse(data.toString()); this._handleRealtimeUpdate(message); } catch (error) { console.warn('WebSocket mesaj hatası:', error.message); } }); this.ws.on('close', () => { console.log('CloudLoyalDB: WebSocket bağlantısı kapandı'); this._handleReconnect(); }); this.ws.on('error', (error) => { console.warn('CloudLoyalDB: WebSocket hatası (devam ediyor):', error.message); // Error'u handle et ama crash etme }); } catch (error) { console.warn('CloudLoyalDB: WebSocket başlatılamadı (devam ediyor):', error.message); } } /** * Yeniden bağlanma */ _handleReconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000); setTimeout(() => { this._connectWebSocket(); }, delay); } } /** * Real-time mesaj işleyicisi */ _handleRealtimeUpdate(message) { const { type, collection, database, path, value, operation, timestamp } = message; if (database !== this.currentDatabase) return; switch (type) { case 'data_changed': this.emit('dataChanged', { collection, path, value, operation, timestamp }); this.emit(`collection_${collection}`, { path, value, operation, timestamp }); break; case 'backup_completed': this.emit('backupCompleted', { timestamp, backupId: message.backupId }); break; } } /** * Bağlantıyı kapat */ disconnect() { if (this.ws) this.ws.close(); this.connected = false; this.emit('disconnected'); } /** * Koleksiyon kontrolü */ _ensureCollection() { if (!this.currentCollection) { throw new Error('CloudLoyalDB: Önce bir koleksiyon seçmelisiniz. db.use("koleksiyon_adi") kullanın.'); } if (!this.connected) { throw new Error('CloudLoyalDB: Server bağlantısı yok. Önce connect() çağırın.'); } } // ========== API METHODS ========== /** * Database seç */ useDatabase(database) { this.currentDatabase = database; this.httpClient.defaults.headers['X-Database'] = database; return this; } /** * Koleksiyon seç */ use(collectionName) { if (!collectionName || typeof collectionName !== 'string') { throw new Error('CloudLoyalDB: Geçerli bir koleksiyon adı belirtmelisiniz.'); } this.currentCollection = collectionName; return this; } /** * Veri ekleme/güncelleme */ async set(path, value) { this._ensureCollection(); if (!path) throw new Error('CloudLoyalDB: Path belirtilmelidir.'); try { const response = await this.httpClient.post('/data/set', { collection: this.currentCollection, path, value, database: this.currentDatabase, timestamp: Date.now() }); return this; } catch (error) { throw new Error(`CloudLoyalDB Set Error: ${error.response?.data?.error || error.message}`); } } /** * Veri alma */ async get(path) { this._ensureCollection(); try { const response = await this.httpClient.get('/data/get', { params: { collection: this.currentCollection, path: path || '', database: this.currentDatabase } }); return response.data.value; } catch (error) { if (error.response?.status === 404) return undefined; throw new Error(`CloudLoyalDB Get Error: ${error.response?.data?.error || error.message}`); } } /** * get() alias */ fetch(path) { return this.get(path); } /** * Tüm koleksiyon */ async all() { this._ensureCollection(); try { const response = await this.httpClient.get('/data/all', { params: { collection: this.currentCollection, database: this.currentDatabase } }); return response.data.data || {}; } catch (error) { throw new Error(`CloudLoyalDB All Error: ${error.response?.data?.error || error.message}`); } } /** * Array'e ekleme */ async push(path, value) { this._ensureCollection(); if (!path) throw new Error('CloudLoyalDB: Path belirtilmelidir.'); try { await this.httpClient.post('/data/push', { collection: this.currentCollection, path, value, database: this.currentDatabase, timestamp: Date.now() }); return this; } catch (error) { throw new Error(`CloudLoyalDB Push Error: ${error.response?.data?.error || error.message}`); } } /** * Array'den değer silme */ async unpush(path, value) { this._ensureCollection(); if (!path) throw new Error('CloudLoyalDB: Path belirtilmelidir.'); try { await this.httpClient.post('/data/unpush', { collection: this.currentCollection, path, value }); return this; } catch (error) { throw new Error(`CloudLoyalDB Unpush Error: ${error.response?.data?.error || error.message}`); } } /** * Array'den index ile silme */ async delByPriority(path, index) { this._ensureCollection(); try { await this.httpClient.post('/data/delByPriority', { collection: this.currentCollection, path, index }); return this; } catch (error) { throw new Error(`CloudLoyalDB DelByPriority Error: ${error.response?.data?.error || error.message}`); } } /** * Array'de index ile güncelleme */ async setByPriority(path, value, index) { this._ensureCollection(); try { await this.httpClient.post('/data/setByPriority', { collection: this.currentCollection, path, value, index }); return this; } catch (error) { throw new Error(`CloudLoyalDB SetByPriority Error: ${error.response?.data?.error || error.message}`); } } /** * Veri var mı kontrol */ async has(path) { this._ensureCollection(); try { const response = await this.httpClient.get('/data/has', { params: { collection: this.currentCollection, path: path || '' } }); return response.data.exists; } catch (error) { throw new Error(`CloudLoyalDB Has Error: ${error.response?.data?.error || error.message}`); } } /** * Veriyi siler */ async delete(path) { this._ensureCollection(); if (!path) throw new Error('CloudLoyalDB: Path belirtilmelidir.'); try { await this.httpClient.delete('/data/delete', { data: { collection: this.currentCollection, path } }); return this; } catch (error) { throw new Error(`CloudLoyalDB Delete Error: ${error.response?.data?.error || error.message}`); } } /** * Koleksiyonu temizle */ async deleteAll() { this._ensureCollection(); try { await this.httpClient.delete('/data/deleteAll', { data: { collection: this.currentCollection } }); return this; } catch (error) { throw new Error(`CloudLoyalDB DeleteAll Error: ${error.response?.data?.error || error.message}`); } } /** * Real-time değişiklikleri dinle */ watch(collection, callback) { this.on(`collection_${collection}`, callback); return this; } /** * Server stats */ async stats() { try { const response = await this.httpClient.get('/stats'); return response.data; } catch (error) { throw new Error(`CloudLoyalDB Stats Error: ${error.response?.data?.error || error.message}`); } } /** * Manuel backup */ async backup(name = null) { try { const response = await this.httpClient.post('/backup/manual', { name }); return response.data; } catch (error) { throw new Error(`CloudLoyalDB Backup Error: ${error.response?.data?.error || error.message}`); } } /** * Backup listesi */ async listBackups() { try { const response = await this.httpClient.get('/backup/list'); return response.data.backups; } catch (error) { throw new Error(`CloudLoyalDB ListBackups Error: ${error.response?.data?.error || error.message}`); } } } // Export class for multiple instances module.exports = CloudLoyalDB;