cloudloyaldb
Version:
Centralized NoSQL Database - MongoDB benzeri API ile cloud server'a veri saklama, real-time sync
430 lines (378 loc) • 13 kB
JavaScript
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;