Complete CoreState v2.0 Android-managed backup system

Created by Wiktor/overspend1 - Revolutionary enterprise backup solution:

 Features:
- Complete Android-only management (no web dashboards)
- AI-powered backup optimization and anomaly detection
- Real-time WebSocket communication and CRDT sync
- Hardware-accelerated encryption with KernelSU integration
- Comprehensive microservices architecture
- System-level file monitoring and COW snapshots

🏗️ Implementation:
- Android app with complete system administration
- Rust daemon with Android bridge and gRPC services
- ML-powered backup prediction and scheduling optimization
- KernelSU module with native kernel integration
- Enterprise microservices (Kotlin, Python, Node.js, Rust)
- Production-ready CI/CD with proper release packaging

📱 Management via Android:
- Real-time backup monitoring and control
- Service management and configuration
- Device registration and security management
- Performance monitoring and troubleshooting
- ML analytics dashboard and insights

🔒 Enterprise Security:
- End-to-end encryption with hardware acceleration
- Multi-device key management and rotation
- Zero-trust architecture with device authentication
- Audit logging and security event monitoring

Author: Wiktor (overspend1)
Version: 2.0.0
License: MIT
This commit is contained in:
Wiktor
2025-07-23 23:10:41 +02:00
parent 3beb3768ff
commit 0f0cfdb075
25 changed files with 6045 additions and 307 deletions

View File

@@ -0,0 +1,503 @@
package com.corestate.androidApp.data.repository
import com.corestate.androidApp.data.model.*
import com.corestate.androidApp.network.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class BackupRepository @Inject constructor(
private val apiService: CoreStateApiService,
private val deviceManager: DeviceManager
) {
suspend fun startBackup(
paths: List<String>,
backupType: BackupType = BackupType.INCREMENTAL,
options: BackupOptions = BackupOptions()
): ApiResult<BackupJobResponse> {
return try {
val deviceId = deviceManager.getDeviceId()
val request = BackupRequest(
deviceId = deviceId,
paths = paths,
backupType = backupType,
options = options
)
apiService.startBackup(request)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to start backup")
}
}
suspend fun getBackupStatus(jobId: String): ApiResult<BackupJobStatus> {
return apiService.getBackupStatus(jobId)
}
fun streamBackupProgress(jobId: String): Flow<BackupProgress> {
return apiService.getBackupProgress(jobId)
}
suspend fun pauseBackup(jobId: String): ApiResult<Unit> {
return apiService.pauseBackup(jobId)
}
suspend fun resumeBackup(jobId: String): ApiResult<Unit> {
return apiService.resumeBackup(jobId)
}
suspend fun cancelBackup(jobId: String): ApiResult<Unit> {
return apiService.cancelBackup(jobId)
}
suspend fun getBackupHistory(
page: Int = 0,
size: Int = 20
): ApiResult<BackupJobListResponse> {
return apiService.listBackups(page, size)
}
suspend fun getActiveBackups(): ApiResult<List<BackupJobSummary>> {
return when (val result = apiService.listBackups(0, 50)) {
is ApiResult.Success -> {
val activeJobs = result.data.jobs.filter {
it.status in listOf(JobStatus.RUNNING, JobStatus.QUEUED, JobStatus.PAUSED)
}
ApiResult.Success(activeJobs)
}
is ApiResult.Error -> result
ApiResult.Loading -> ApiResult.Loading
}
}
suspend fun startRestore(
snapshotId: String,
files: List<String>,
targetPath: String,
overwriteExisting: Boolean = false
): ApiResult<RestoreJobResponse> {
return try {
val deviceId = deviceManager.getDeviceId()
val request = RestoreRequest(
deviceId = deviceId,
snapshotId = snapshotId,
files = files,
targetPath = targetPath,
overwriteExisting = overwriteExisting
)
apiService.startRestore(request)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to start restore")
}
}
suspend fun getRestoreStatus(jobId: String): ApiResult<RestoreJobStatus> {
return apiService.getRestoreStatus(jobId)
}
suspend fun getSnapshots(
page: Int = 0,
size: Int = 20
): ApiResult<SnapshotListResponse> {
val deviceId = deviceManager.getDeviceId()
return apiService.listSnapshots(deviceId, page, size)
}
suspend fun browseSnapshotFiles(
snapshotId: String,
path: String = "/"
): ApiResult<FileListResponse> {
return apiService.browseSnapshot(snapshotId, path)
}
suspend fun getBackupPrediction(
paths: List<String>,
estimatedSize: Long
): ApiResult<BackupPrediction> {
return try {
val deviceId = deviceManager.getDeviceId()
val request = BackupPredictionRequest(
deviceId = deviceId,
filePaths = paths,
estimatedSize = estimatedSize,
metadata = deviceManager.getDeviceMetadata()
)
apiService.predictBackupPerformance(request)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to get backup prediction")
}
}
suspend fun optimizeBackupSchedule(
backupJobs: List<BackupJobRequest>
): ApiResult<OptimizationResult> {
return try {
val request = ScheduleOptimizationRequest(
backupJobs = backupJobs,
resourceConstraints = mapOf(
"maxConcurrentJobs" to 3,
"maxCpuUsage" to 80,
"maxMemoryUsage" to 90
),
optimizationGoals = listOf("minimize_time", "maximize_throughput")
)
apiService.optimizeBackupSchedule(request)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to optimize backup schedule")
}
}
}
@Singleton
class FileRepository @Inject constructor(
private val apiService: CoreStateApiService,
private val deviceManager: DeviceManager
) {
suspend fun listFiles(path: String): ApiResult<FileListResponse> {
return apiService.listFiles(path)
}
suspend fun getFileInfo(path: String): ApiResult<BackupFileInfo> {
return when (val result = listFiles(path)) {
is ApiResult.Success -> {
val file = result.data.files.find { it.path == path }
if (file != null) {
ApiResult.Success(file)
} else {
ApiResult.Error(Exception("File not found"), "File not found: $path")
}
}
is ApiResult.Error -> result
ApiResult.Loading -> ApiResult.Loading
}
}
suspend fun searchFiles(
query: String,
path: String = "/",
fileTypes: List<String> = emptyList()
): ApiResult<List<BackupFileInfo>> {
return when (val result = listFiles(path)) {
is ApiResult.Success -> {
val filteredFiles = result.data.files.filter { file ->
val matchesQuery = file.name.contains(query, ignoreCase = true) ||
file.path.contains(query, ignoreCase = true)
val matchesType = fileTypes.isEmpty() ||
fileTypes.any { type -> file.name.endsWith(".$type", ignoreCase = true) }
matchesQuery && matchesType
}
ApiResult.Success(filteredFiles)
}
is ApiResult.Error -> result
ApiResult.Loading -> ApiResult.Loading
}
}
suspend fun getDirectoryTree(rootPath: String, maxDepth: Int = 3): ApiResult<DirectoryNode> {
return buildDirectoryTree(rootPath, maxDepth, 0)
}
private suspend fun buildDirectoryTree(
path: String,
maxDepth: Int,
currentDepth: Int
): ApiResult<DirectoryNode> {
if (currentDepth >= maxDepth) {
return ApiResult.Success(DirectoryNode(path, emptyList(), emptyList()))
}
return when (val result = listFiles(path)) {
is ApiResult.Success -> {
val files = result.data.files.filter { !it.isDirectory }
val directories = result.data.files.filter { it.isDirectory }
val childNodes = mutableListOf<DirectoryNode>()
for (dir in directories) {
when (val childResult = buildDirectoryTree(dir.path, maxDepth, currentDepth + 1)) {
is ApiResult.Success -> childNodes.add(childResult.data)
is ApiResult.Error -> continue // Skip failed directories
ApiResult.Loading -> continue
}
}
ApiResult.Success(DirectoryNode(path, files, childNodes))
}
is ApiResult.Error -> result
ApiResult.Loading -> ApiResult.Loading
}
}
}
@Singleton
class StatisticsRepository @Inject constructor(
private val apiService: CoreStateApiService,
private val deviceManager: DeviceManager
) {
suspend fun getSystemMetrics(): ApiResult<SystemMetricsResponse> {
return apiService.getSystemMetrics()
}
suspend fun getBackupMetrics(): ApiResult<BackupMetrics> {
return apiService.getSystemMetrics().let { result ->
when (result) {
is ApiResult.Success -> ApiResult.Success(result.data.backupMetrics)
is ApiResult.Error -> result
ApiResult.Loading -> ApiResult.Loading
}
}
}
suspend fun getStorageUsage(): ApiResult<StorageUsageResponse> {
val deviceId = deviceManager.getDeviceId()
return apiService.getStorageUsage(deviceId)
}
suspend fun getSystemHealth(): ApiResult<ServicesHealthResponse> {
return apiService.getAllServicesHealth()
}
suspend fun getAnomalyReport(
timeRange: TimeRange = TimeRange.LAST_24_HOURS
): ApiResult<AnomalyReport> {
return try {
val deviceId = deviceManager.getDeviceId()
val metrics = deviceManager.getCurrentMetrics()
val request = AnomalyDetectionRequest(
deviceId = deviceId,
metrics = metrics,
timestamp = System.currentTimeMillis()
)
when (val result = apiService.detectAnomalies(request)) {
is ApiResult.Success -> {
val report = AnomalyReport(
deviceId = deviceId,
timeRange = timeRange,
anomalies = listOf(result.data),
totalAnomalies = if (result.data.isAnomaly) 1 else 0,
timestamp = System.currentTimeMillis()
)
ApiResult.Success(report)
}
is ApiResult.Error -> result
ApiResult.Loading -> ApiResult.Loading
}
} catch (e: Exception) {
ApiResult.Error(e, "Failed to get anomaly report")
}
}
suspend fun getPerformanceReport(
timeRange: TimeRange = TimeRange.LAST_7_DAYS
): ApiResult<PerformanceReport> {
return try {
val backupMetrics = getBackupMetrics()
val systemMetrics = getSystemMetrics()
when {
backupMetrics is ApiResult.Success && systemMetrics is ApiResult.Success -> {
val report = PerformanceReport(
timeRange = timeRange,
averageBackupDuration = backupMetrics.data.averageBackupDuration,
compressionRatio = backupMetrics.data.compressionRatio,
deduplicationRatio = backupMetrics.data.deduplicationRatio,
successRate = calculateSuccessRate(backupMetrics.data),
systemUtilization = systemMetrics.data.systemUtilization,
timestamp = System.currentTimeMillis()
)
ApiResult.Success(report)
}
backupMetrics is ApiResult.Error -> backupMetrics
systemMetrics is ApiResult.Error -> systemMetrics
else -> ApiResult.Loading
}
} catch (e: Exception) {
ApiResult.Error(e, "Failed to get performance report")
}
}
private fun calculateSuccessRate(metrics: BackupMetrics): Double {
val total = metrics.totalBackupsCompleted + metrics.totalBackupsFailed
return if (total > 0) {
metrics.totalBackupsCompleted.toDouble() / total * 100
} else {
0.0
}
}
}
@Singleton
class SettingsRepository @Inject constructor(
private val apiService: CoreStateApiService,
private val deviceManager: DeviceManager,
private val localPreferences: LocalPreferences
) {
suspend fun getConfiguration(): ApiResult<DaemonConfigResponse> {
return apiService.getConfiguration()
}
suspend fun updateConfiguration(config: DaemonConfigRequest): ApiResult<ConfigUpdateResponse> {
return apiService.updateConfiguration(config)
}
suspend fun getLocalSettings(): LocalSettings {
return localPreferences.getSettings()
}
suspend fun updateLocalSettings(settings: LocalSettings) {
localPreferences.saveSettings(settings)
}
suspend fun getNotificationSettings(): NotificationSettings {
return localPreferences.getNotificationSettings()
}
suspend fun updateNotificationSettings(settings: NotificationSettings) {
localPreferences.saveNotificationSettings(settings)
}
suspend fun getSecuritySettings(): SecuritySettings {
return localPreferences.getSecuritySettings()
}
suspend fun updateSecuritySettings(settings: SecuritySettings) {
localPreferences.saveSecuritySettings(settings)
}
suspend fun exportConfiguration(): ApiResult<String> {
return when (val result = getConfiguration()) {
is ApiResult.Success -> {
try {
val json = kotlinx.serialization.json.Json.encodeToString(result.data)
ApiResult.Success(json)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to export configuration")
}
}
is ApiResult.Error -> result
ApiResult.Loading -> ApiResult.Loading
}
}
suspend fun importConfiguration(configJson: String): ApiResult<ConfigUpdateResponse> {
return try {
val config = kotlinx.serialization.json.Json.decodeFromString<DaemonConfigRequest>(configJson)
updateConfiguration(config)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to import configuration")
}
}
}
// Device management repository
@Singleton
class DeviceRepository @Inject constructor(
private val apiService: CoreStateApiService,
private val deviceManager: DeviceManager
) {
suspend fun registerDevice(): ApiResult<DeviceRegistrationResponse> {
return try {
val request = DeviceRegistrationRequest(
deviceId = deviceManager.getDeviceId(),
deviceInfo = deviceManager.getDeviceInfo(),
capabilities = deviceManager.getDeviceCapabilities()
)
apiService.registerDevice(request)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to register device")
}
}
suspend fun getRegisteredDevices(): ApiResult<RegisteredDevicesResponse> {
return apiService.getRegisteredDevices()
}
suspend fun getConnectedDevices(): ApiResult<ConnectedDevicesResponse> {
return apiService.getConnectedDevices()
}
suspend fun getCurrentDevice(): ApiResult<DeviceInfo> {
return try {
val deviceInfo = deviceManager.getDeviceInfo()
ApiResult.Success(deviceInfo)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to get current device info")
}
}
suspend fun updateDeviceStatus(status: DeviceStatus): ApiResult<Unit> {
return try {
deviceManager.updateStatus(status)
ApiResult.Success(Unit)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to update device status")
}
}
suspend fun getKernelModuleStatus(): ApiResult<KernelStatusResponse> {
return apiService.getKernelStatus()
}
suspend fun loadKernelModule(): ApiResult<KernelOperationResponse> {
return apiService.loadKernelModule()
}
suspend fun unloadKernelModule(): ApiResult<KernelOperationResponse> {
return apiService.unloadKernelModule()
}
}
// Security repository for encryption and key management
@Singleton
class SecurityRepository @Inject constructor(
private val apiService: CoreStateApiService,
private val deviceManager: DeviceManager
) {
suspend fun generateDeviceKey(): ApiResult<DeviceKeyInfo> {
val deviceId = deviceManager.getDeviceId()
return apiService.generateDeviceKey(deviceId)
}
suspend fun rotateDeviceKey(): ApiResult<DeviceKeyInfo> {
val deviceId = deviceManager.getDeviceId()
return apiService.rotateDeviceKey(deviceId)
}
suspend fun getDeviceKeys(): ApiResult<DeviceKeysResponse> {
val deviceId = deviceManager.getDeviceId()
return apiService.getDeviceKeys(deviceId)
}
suspend fun encryptData(data: String): ApiResult<EncryptionResult> {
return try {
val request = EncryptionRequest(
data = data,
deviceId = deviceManager.getDeviceId()
)
apiService.encryptData(request)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to encrypt data")
}
}
suspend fun decryptData(encryptedData: String, keyId: String? = null): ApiResult<DecryptionResult> {
return try {
val request = DecryptionRequest(
encryptedData = encryptedData,
deviceId = deviceManager.getDeviceId(),
keyId = keyId
)
apiService.decryptData(request)
} catch (e: Exception) {
ApiResult.Error(e, "Failed to decrypt data")
}
}
}

View File

@@ -0,0 +1,299 @@
package com.corestate.androidApp.network
import com.corestate.androidApp.data.model.*
import retrofit2.Response
import retrofit2.http.*
import kotlinx.coroutines.flow.Flow
import okhttp3.MultipartBody
import okhttp3.RequestBody
interface BackupEngineApi {
@POST("api/v1/backup/start")
suspend fun startBackup(@Body request: BackupRequest): Response<BackupJobResponse>
@GET("api/v1/backup/job/{jobId}")
suspend fun getJobStatus(@Path("jobId") jobId: String): Response<BackupJobStatus>
@GET("api/v1/backup/job/{jobId}/progress")
suspend fun getProgress(@Path("jobId") jobId: String): Flow<BackupProgress>
@POST("api/v1/backup/job/{jobId}/pause")
suspend fun pauseJob(@Path("jobId") jobId: String): Response<Unit>
@POST("api/v1/backup/job/{jobId}/resume")
suspend fun resumeJob(@Path("jobId") jobId: String): Response<Unit>
@DELETE("api/v1/backup/job/{jobId}")
suspend fun cancelJob(@Path("jobId") jobId: String): Response<Unit>
@GET("api/v1/backup/jobs")
suspend fun listJobs(
@Query("page") page: Int = 0,
@Query("size") size: Int = 20,
@Query("deviceId") deviceId: String? = null,
@Query("status") status: String? = null
): Response<BackupJobListResponse>
@POST("api/v1/backup/restore")
suspend fun startRestore(@Body request: RestoreRequest): Response<RestoreJobResponse>
@GET("api/v1/backup/restore/{jobId}")
suspend fun getRestoreStatus(@Path("jobId") jobId: String): Response<RestoreJobStatus>
@GET("api/v1/backup/snapshots")
suspend fun listSnapshots(
@Query("deviceId") deviceId: String,
@Query("page") page: Int = 0,
@Query("size") size: Int = 20
): Response<SnapshotListResponse>
@GET("api/v1/backup/snapshot/{snapshotId}/files")
suspend fun browseSnapshotFiles(
@Path("snapshotId") snapshotId: String,
@Query("path") path: String = "/"
): Response<FileListResponse>
@GET("api/v1/backup/health")
suspend fun getHealthStatus(): Response<HealthStatus>
@GET("api/v1/backup/metrics")
suspend fun getMetrics(): Response<BackupMetrics>
}
interface EncryptionApi {
@POST("api/v1/encrypt")
suspend fun encryptData(@Body request: EncryptionRequest): Response<EncryptionResult>
@POST("api/v1/decrypt")
suspend fun decryptData(@Body request: DecryptionRequest): Response<DecryptionResult>
@POST("api/v1/keys/generate")
suspend fun generateKey(@Body request: KeyGenerationRequest): Response<DeviceKeyInfo>
@POST("api/v1/keys/rotate")
suspend fun rotateKey(@Body request: KeyRotationRequest): Response<DeviceKeyInfo>
@GET("api/v1/keys/{deviceId}")
suspend fun getKeyInfo(@Path("deviceId") deviceId: String): Response<DeviceKeysResponse>
@GET("api/v1/health")
suspend fun getHealthStatus(): Response<ServiceHealthStatus>
@GET("api/v1/metrics")
suspend fun getMetrics(): Response<EncryptionMetrics>
}
interface MLOptimizerApi {
@POST("predict/backup")
suspend fun predictBackup(@Body request: BackupPredictionRequest): Response<BackupPrediction>
@POST("detect/anomaly")
suspend fun detectAnomaly(@Body request: AnomalyDetectionRequest): Response<AnomalyResult>
@POST("optimize/schedule")
suspend fun optimizeSchedule(@Body request: ScheduleOptimizationRequest): Response<OptimizationResult>
@GET("models/status")
suspend fun getModelStatus(): Response<ModelStatusResponse>
@GET("health")
suspend fun getHealthStatus(): Response<ServiceHealthStatus>
@GET("metrics")
suspend fun getMetrics(): Response<MLMetrics>
}
interface SyncCoordinatorApi {
@GET("health")
suspend fun getHealthStatus(): Response<ServiceHealthStatus>
@GET("metrics")
suspend fun getMetrics(): Response<SyncMetrics>
@GET("devices")
suspend fun getConnectedDevices(): Response<ConnectedDevicesResponse>
@POST("sync/manual")
suspend fun triggerManualSync(@Body request: ManualSyncRequest): Response<SyncResult>
@GET("sync/status")
suspend fun getSyncStatus(): Response<SyncStatusResponse>
}
interface StorageHalApi {
@POST("storage/store")
suspend fun storeChunk(@Body request: StoreChunkRequest): Response<StorageResult>
@GET("storage/retrieve/{chunkId}")
suspend fun retrieveChunk(@Path("chunkId") chunkId: String): Response<ChunkData>
@DELETE("storage/delete/{chunkId}")
suspend fun deleteChunk(@Path("chunkId") chunkId: String): Response<Unit>
@GET("storage/health")
suspend fun getHealthStatus(): Response<StorageHealthStatus>
@GET("storage/metrics")
suspend fun getMetrics(): Response<StorageMetrics>
@GET("storage/usage")
suspend fun getStorageUsage(@Query("deviceId") deviceId: String): Response<StorageUsageResponse>
}
interface CompressionEngineApi {
@POST("compress")
suspend fun compressData(@Body request: CompressionRequest): Response<CompressionResult>
@POST("decompress")
suspend fun decompressData(@Body request: DecompressionRequest): Response<DecompressionResult>
@GET("algorithms")
suspend fun getSupportedAlgorithms(): Response<CompressionAlgorithmsResponse>
@GET("health")
suspend fun getHealthStatus(): Response<ServiceHealthStatus>
@GET("metrics")
suspend fun getMetrics(): Response<CompressionMetrics>
}
interface DeduplicationApi {
@POST("deduplicate")
suspend fun deduplicateChunks(@Body request: DeduplicationRequest): Response<DeduplicationResult>
@GET("stats")
suspend fun getDeduplicationStats(@Query("deviceId") deviceId: String): Response<DeduplicationStats>
@GET("health")
suspend fun getHealthStatus(): Response<ServiceHealthStatus>
@GET("metrics")
suspend fun getMetrics(): Response<DeduplicationMetrics>
}
interface DaemonApi {
@GET("status")
suspend fun getSystemStatus(): Response<SystemStatusInfo>
@GET("logs")
suspend fun getLogs(
@Query("level") level: String = "info",
@Query("lines") lines: Int = 100
): Response<LogDataResponse>
@GET("config")
suspend fun getConfiguration(): Response<DaemonConfigResponse>
@PUT("config")
suspend fun updateConfiguration(@Body config: DaemonConfigRequest): Response<ConfigUpdateResponse>
@GET("kernel/status")
suspend fun getKernelStatus(): Response<KernelStatusResponse>
@POST("kernel/load")
suspend fun loadKernelModule(): Response<KernelOperationResponse>
@POST("kernel/unload")
suspend fun unloadKernelModule(): Response<KernelOperationResponse>
@GET("files")
suspend fun listFiles(@Query("path") path: String): Response<FileListResponse>
@POST("backup/start")
suspend fun startBackupViaDaemon(@Body request: DaemonBackupRequest): Response<DaemonBackupResponse>
@GET("devices")
suspend fun getRegisteredDevices(): Response<RegisteredDevicesResponse>
@POST("devices/register")
suspend fun registerDevice(@Body request: DeviceRegistrationRequest): Response<DeviceRegistrationResponse>
}
// Aggregated API service that combines all microservices
interface CoreStateApiService {
// Backup operations
suspend fun startBackup(request: BackupRequest): ApiResult<BackupJobResponse>
suspend fun getBackupStatus(jobId: String): ApiResult<BackupJobStatus>
suspend fun getBackupProgress(jobId: String): Flow<BackupProgress>
suspend fun pauseBackup(jobId: String): ApiResult<Unit>
suspend fun resumeBackup(jobId: String): ApiResult<Unit>
suspend fun cancelBackup(jobId: String): ApiResult<Unit>
suspend fun listBackups(page: Int = 0, size: Int = 20): ApiResult<BackupJobListResponse>
// Restore operations
suspend fun startRestore(request: RestoreRequest): ApiResult<RestoreJobResponse>
suspend fun getRestoreStatus(jobId: String): ApiResult<RestoreJobStatus>
// File management
suspend fun listFiles(path: String): ApiResult<FileListResponse>
suspend fun browseSnapshot(snapshotId: String, path: String = "/"): ApiResult<FileListResponse>
suspend fun listSnapshots(deviceId: String, page: Int = 0, size: Int = 20): ApiResult<SnapshotListResponse>
// System management
suspend fun getSystemStatus(): ApiResult<SystemStatusInfo>
suspend fun getSystemLogs(level: String = "info", lines: Int = 100): ApiResult<LogDataResponse>
suspend fun getConfiguration(): ApiResult<DaemonConfigResponse>
suspend fun updateConfiguration(config: DaemonConfigRequest): ApiResult<ConfigUpdateResponse>
// Kernel module management
suspend fun getKernelStatus(): ApiResult<KernelStatusResponse>
suspend fun loadKernelModule(): ApiResult<KernelOperationResponse>
suspend fun unloadKernelModule(): ApiResult<KernelOperationResponse>
// Device management
suspend fun getRegisteredDevices(): ApiResult<RegisteredDevicesResponse>
suspend fun registerDevice(request: DeviceRegistrationRequest): ApiResult<DeviceRegistrationResponse>
suspend fun getConnectedDevices(): ApiResult<ConnectedDevicesResponse>
// Security operations
suspend fun encryptData(request: EncryptionRequest): ApiResult<EncryptionResult>
suspend fun decryptData(request: DecryptionRequest): ApiResult<DecryptionResult>
suspend fun generateDeviceKey(deviceId: String): ApiResult<DeviceKeyInfo>
suspend fun rotateDeviceKey(deviceId: String): ApiResult<DeviceKeyInfo>
suspend fun getDeviceKeys(deviceId: String): ApiResult<DeviceKeysResponse>
// ML and Analytics
suspend fun predictBackupPerformance(request: BackupPredictionRequest): ApiResult<BackupPrediction>
suspend fun detectAnomalies(request: AnomalyDetectionRequest): ApiResult<AnomalyResult>
suspend fun optimizeBackupSchedule(request: ScheduleOptimizationRequest): ApiResult<OptimizationResult>
suspend fun getMLModelStatus(): ApiResult<ModelStatusResponse>
// Storage operations
suspend fun getStorageUsage(deviceId: String): ApiResult<StorageUsageResponse>
suspend fun getStorageMetrics(): ApiResult<StorageMetrics>
// Sync operations
suspend fun getSyncStatus(): ApiResult<SyncStatusResponse>
suspend fun triggerManualSync(deviceId: String): ApiResult<SyncResult>
// Health and metrics
suspend fun getAllServicesHealth(): ApiResult<ServicesHealthResponse>
suspend fun getSystemMetrics(): ApiResult<SystemMetricsResponse>
// Real-time updates
fun subscribeToBackupProgress(jobId: String): Flow<BackupProgress>
fun subscribeToSystemEvents(): Flow<SystemEvent>
fun subscribeToSyncEvents(): Flow<SyncEvent>
}
sealed class ApiResult<out T> {
data class Success<T>(val data: T) : ApiResult<T>()
data class Error(val exception: Throwable, val message: String? = null) : ApiResult<Nothing>()
object Loading : ApiResult<Nothing>()
}
// Extension functions for easier result handling
inline fun <T> ApiResult<T>.onSuccess(action: (T) -> Unit): ApiResult<T> {
if (this is ApiResult.Success) action(data)
return this
}
inline fun <T> ApiResult<T>.onError(action: (Throwable, String?) -> Unit): ApiResult<T> {
if (this is ApiResult.Error) action(exception, message)
return this
}
inline fun <T> ApiResult<T>.onLoading(action: () -> Unit): ApiResult<T> {
if (this is ApiResult.Loading) action()
return this
}

View File

@@ -0,0 +1,507 @@
package com.corestate.androidApp.ui.screens.admin
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.corestate.androidApp.data.model.*
import com.corestate.androidApp.ui.components.*
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SystemAdminScreen(
viewModel: SystemAdminViewModel = hiltViewModel()
) {
val uiState by viewModel.uiState.collectAsState()
LaunchedEffect(Unit) {
viewModel.loadSystemStatus()
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
Text(
text = "System Administration",
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(16.dp))
LazyColumn(
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
// System Status Overview
item {
SystemStatusCard(
systemStatus = uiState.systemStatus,
isLoading = uiState.isLoading
)
}
// Service Management
item {
ServiceManagementCard(
services = uiState.services,
onServiceAction = viewModel::performServiceAction
)
}
// Kernel Module Management
item {
KernelModuleCard(
kernelStatus = uiState.kernelStatus,
onLoadModule = viewModel::loadKernelModule,
onUnloadModule = viewModel::unloadKernelModule,
isLoading = uiState.kernelOperationInProgress
)
}
// Device Management
item {
DeviceManagementCard(
devices = uiState.connectedDevices,
onRefresh = viewModel::refreshDevices
)
}
// Configuration Management
item {
ConfigurationCard(
configuration = uiState.configuration,
onUpdateConfig = viewModel::updateConfiguration,
onExportConfig = viewModel::exportConfiguration,
onImportConfig = viewModel::importConfiguration
)
}
// System Logs
item {
SystemLogsCard(
logs = uiState.systemLogs,
onRefreshLogs = viewModel::refreshLogs,
onClearLogs = viewModel::clearLogs
)
}
// Performance Monitoring
item {
PerformanceMonitoringCard(
metrics = uiState.performanceMetrics,
onRefresh = viewModel::refreshMetrics
)
}
}
}
}
@Composable
fun SystemStatusCard(
systemStatus: SystemStatusInfo?,
isLoading: Boolean
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "System Status",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold
)
if (isLoading) {
CircularProgressIndicator(modifier = Modifier.size(20.dp))
} else {
systemStatus?.let { status ->
StatusIndicator(
isHealthy = status.daemonUptime > 0 && status.servicesStatus.values.all { it },
text = if (status.daemonUptime > 0) "Online" else "Offline"
)
}
}
}
Spacer(modifier = Modifier.height(12.dp))
systemStatus?.let { status ->
StatusMetricRow("Daemon Uptime", formatUptime(status.daemonUptime))
StatusMetricRow("Active Backups", status.activeBackups.toString())
StatusMetricRow("Total Files Backed Up", formatNumber(status.totalFilesBackedUp))
StatusMetricRow("Total Backup Size", formatBytes(status.totalBackupSize))
StatusMetricRow("Memory Usage", formatBytes(status.memoryUsage))
StatusMetricRow("CPU Usage", "${status.cpuUsage}%")
StatusMetricRow("Kernel Module", if (status.kernelModuleLoaded) "Loaded" else "Not Loaded")
}
}
}
}
@Composable
fun ServiceManagementCard(
services: Map<String, ServiceStatus>,
onServiceAction: (String, ServiceAction) -> Unit
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = "Microservices",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(12.dp))
services.forEach { (serviceName, status) ->
ServiceRow(
serviceName = serviceName,
status = status,
onAction = { action -> onServiceAction(serviceName, action) }
)
if (serviceName != services.keys.last()) {
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))
}
}
}
}
}
@Composable
fun ServiceRow(
serviceName: String,
status: ServiceStatus,
onAction: (ServiceAction) -> Unit
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = formatServiceName(serviceName),
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Medium
)
Text(
text = "Response: ${status.responseTime}ms",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
StatusIndicator(
isHealthy = status.isHealthy,
text = if (status.isHealthy) "Healthy" else "Error"
)
IconButton(
onClick = { onAction(ServiceAction.RESTART) }
) {
Icon(Icons.Default.Refresh, contentDescription = "Restart Service")
}
IconButton(
onClick = { onAction(ServiceAction.VIEW_LOGS) }
) {
Icon(Icons.Default.Description, contentDescription = "View Logs")
}
}
}
}
@Composable
fun KernelModuleCard(
kernelStatus: KernelStatusResponse?,
onLoadModule: () -> Unit,
onUnloadModule: () -> Unit,
isLoading: Boolean
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
text = "Kernel Module",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(12.dp))
kernelStatus?.let { status ->
StatusMetricRow("Status", if (status.loaded) "Loaded" else "Not Loaded")
StatusMetricRow("Version", status.version)
if (status.features.isNotEmpty()) {
Text(
text = "Features:",
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium,
modifier = Modifier.padding(vertical = 8.dp)
)
status.features.forEach { feature ->
Text(
text = "$feature",
style = MaterialTheme.typography.bodySmall,
modifier = Modifier.padding(start = 16.dp)
)
}
}
Spacer(modifier = Modifier.height(16.dp))
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
if (status.loaded) {
Button(
onClick = onUnloadModule,
enabled = !isLoading,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.error
)
) {
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.size(16.dp),
color = MaterialTheme.colorScheme.onError
)
} else {
Text("Unload Module")
}
}
} else {
Button(
onClick = onLoadModule,
enabled = !isLoading
) {
if (isLoading) {
CircularProgressIndicator(
modifier = Modifier.size(16.dp),
color = MaterialTheme.colorScheme.onPrimary
)
} else {
Text("Load Module")
}
}
}
}
}
}
}
}
@Composable
fun DeviceManagementCard(
devices: List<ConnectedDevice>,
onRefresh: () -> Unit
) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Connected Devices",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold
)
IconButton(onClick = onRefresh) {
Icon(Icons.Default.Refresh, contentDescription = "Refresh Devices")
}
}
Spacer(modifier = Modifier.height(12.dp))
if (devices.isEmpty()) {
Text(
text = "No devices connected",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
} else {
devices.forEach { device ->
DeviceRow(device)
if (device != devices.last()) {
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))
}
}
}
}
}
}
@Composable
fun DeviceRow(device: ConnectedDevice) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = device.deviceName,
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Medium
)
Text(
text = device.deviceId,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = "Last seen: ${formatTimestamp(device.lastSeen)}",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
StatusIndicator(
isHealthy = device.isOnline,
text = if (device.isOnline) "Online" else "Offline"
)
}
}
@Composable
fun StatusIndicator(
isHealthy: Boolean,
text: String
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
Box(
modifier = Modifier
.size(8.dp)
.background(
color = if (isHealthy) Color.Green else Color.Red,
shape = androidx.compose.foundation.shape.CircleShape
)
)
Text(
text = text,
style = MaterialTheme.typography.bodySmall,
color = if (isHealthy) Color.Green else Color.Red
)
}
}
@Composable
fun StatusMetricRow(label: String, value: String) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 2.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = label,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = value,
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium
)
}
}
// Helper functions
private fun formatUptime(uptimeSeconds: Long): String {
val days = uptimeSeconds / 86400
val hours = (uptimeSeconds % 86400) / 3600
val minutes = (uptimeSeconds % 3600) / 60
return when {
days > 0 -> "${days}d ${hours}h ${minutes}m"
hours > 0 -> "${hours}h ${minutes}m"
else -> "${minutes}m"
}
}
private fun formatBytes(bytes: Long): String {
val units = arrayOf("B", "KB", "MB", "GB", "TB")
var size = bytes.toDouble()
var unitIndex = 0
while (size >= 1024 && unitIndex < units.size - 1) {
size /= 1024
unitIndex++
}
return "%.1f %s".format(size, units[unitIndex])
}
private fun formatNumber(number: Long): String {
return when {
number >= 1_000_000 -> "%.1fM".format(number / 1_000_000.0)
number >= 1_000 -> "%.1fK".format(number / 1_000.0)
else -> number.toString()
}
}
private fun formatServiceName(serviceName: String): String {
return serviceName.split("-", "_")
.joinToString(" ") { it.replaceFirstChar { char -> char.uppercase() } }
}
private fun formatTimestamp(timestamp: Long): String {
val now = System.currentTimeMillis()
val diff = now - timestamp
return when {
diff < 60_000 -> "Just now"
diff < 3_600_000 -> "${diff / 60_000}m ago"
diff < 86_400_000 -> "${diff / 3_600_000}h ago"
else -> "${diff / 86_400_000}d ago"
}
}
enum class ServiceAction {
RESTART,
VIEW_LOGS,
CONFIGURE
}