Integrate Docker support into Archipelago and Neode UI
- Added StateManager and data_model modules to manage application state. - Updated ApiHandler to utilize StateManager for WebSocket connections. - Enhanced Server initialization to include StateManager. - Implemented Docker container querying in Neode UI to populate app data dynamically. - Removed temporary dummy app configurations in favor of real Docker-based applications. - Improved WebSocket reconnection logic and error handling in the UI. - Updated package.json and package-lock.json to include dockerode dependency.
This commit is contained in:
@@ -139,8 +139,8 @@ export class WebSocketClient {
|
||||
// Always try to reconnect unless we've exceeded max attempts
|
||||
// Code 1001 (Going Away) happens on HMR reloads - reconnect IMMEDIATELY
|
||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
// Immediate reconnection for HMR (code 1001) - no delay
|
||||
const isHMR = event.code === 1001 || event.code === 1006
|
||||
// Only code 1001 is HMR, NOT 1006 (1006 is abnormal closure)
|
||||
const isHMR = event.code === 1001
|
||||
const delay = isHMR ? 0 : (this.reconnectAttempts === 0 ? 100 : Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts), 5000))
|
||||
console.log(`[WebSocket] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts + 1}/${this.maxReconnectAttempts}, code: ${event.code}, HMR: ${isHMR})`)
|
||||
|
||||
|
||||
@@ -144,35 +144,19 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter, RouterLink } from 'vue-router'
|
||||
import { useAppStore } from '../stores/app'
|
||||
import { PackageState } from '../types/api'
|
||||
import { dummyApps } from '../utils/dummyApps'
|
||||
import { fetchMultipleAppInfo } from '../utils/githubAppInfo'
|
||||
|
||||
const router = useRouter()
|
||||
const store = useAppStore()
|
||||
|
||||
// TEMPORARY: Always show dummy apps for now (until real apps are ready)
|
||||
// TODO: Remove this and use real packages when they're available
|
||||
// Use real packages from store - no more dummy apps
|
||||
const packages = computed(() => {
|
||||
const realPackages = store.packages
|
||||
const packageKeys = realPackages ? Object.keys(realPackages) : []
|
||||
|
||||
console.log('[Apps] Real packages from store:', packageKeys.length, 'apps:', packageKeys)
|
||||
console.log('[Apps] Dummy apps available:', Object.keys(dummyApps).length, 'apps:', Object.keys(dummyApps))
|
||||
|
||||
// FOR NOW: Always return dummy apps regardless of what's in store
|
||||
// This ensures all dummy apps show up for development
|
||||
console.log('[Apps] Returning dummy apps')
|
||||
return dummyApps
|
||||
|
||||
// TODO: Uncomment this when ready to use real packages
|
||||
// if (packageKeys.length === 0) {
|
||||
// return dummyApps
|
||||
// }
|
||||
// return realPackages
|
||||
console.log('[Apps] Real packages from store:', Object.keys(realPackages || {}).length, 'apps')
|
||||
return realPackages || {}
|
||||
})
|
||||
|
||||
// Sorted by manifest title, case-insensitive; order stable regardless of running/stopped
|
||||
@@ -319,96 +303,6 @@ function handleImageError(e: Event) {
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch GitHub app info for dummy apps on mount
|
||||
const appInfoCache = ref<Record<string, any>>({})
|
||||
|
||||
// In development, skip external API calls to avoid rate limiting and noise
|
||||
// App icons and descriptions are already defined in dummyApps.ts
|
||||
const isDev = import.meta.env.DEV
|
||||
|
||||
// Watch for packages and fetch app info when showing dummy apps (DISABLED IN DEV)
|
||||
watch(() => Object.keys(store.packages).length, async (packageCount) => {
|
||||
// Skip external API calls in development to avoid 403/404 errors
|
||||
if (isDev) {
|
||||
console.log('[Apps] Using local app data (dev mode, external API calls disabled)')
|
||||
return
|
||||
}
|
||||
|
||||
// Only fetch if we're showing dummy apps (no real packages)
|
||||
if (packageCount === 0) {
|
||||
try {
|
||||
// First try Start9 registry for icons
|
||||
console.log('[Apps] Fetching app info from Start9 registry...')
|
||||
try {
|
||||
const registryResponse = await fetch('https://registry.start9.com/api/v1/packages')
|
||||
if (registryResponse.ok) {
|
||||
const registryData = await registryResponse.json()
|
||||
|
||||
// Update dummy apps with registry data
|
||||
Object.entries(registryData).forEach(([id, pkg]: [string, any]) => {
|
||||
if (dummyApps[id]) {
|
||||
const latestVersion = pkg.versions ? Object.keys(pkg.versions).sort().reverse()[0] : null
|
||||
const versionData = latestVersion ? pkg.versions[latestVersion] : {}
|
||||
|
||||
// Update icon from registry
|
||||
if (versionData.icon) {
|
||||
dummyApps[id]['static-files'].icon = versionData.icon
|
||||
} else if (pkg.icon) {
|
||||
dummyApps[id]['static-files'].icon = pkg.icon
|
||||
}
|
||||
|
||||
// Update description
|
||||
if (versionData.description) {
|
||||
const desc = typeof versionData.description === 'string'
|
||||
? versionData.description
|
||||
: versionData.description.short || versionData.description.long || ''
|
||||
if (desc) {
|
||||
dummyApps[id].manifest.description.short = desc.substring(0, 100)
|
||||
if (!dummyApps[id].manifest.description.long) {
|
||||
dummyApps[id].manifest.description.long = desc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log('[Apps] Updated apps from Start9 registry')
|
||||
return
|
||||
}
|
||||
} catch (registryErr) {
|
||||
// Silently fail in production
|
||||
console.debug('[Apps] Registry unavailable')
|
||||
}
|
||||
|
||||
// Fallback to GitHub fetching
|
||||
const appsToFetch = Object.entries(dummyApps).map(([id, pkg]) => ({
|
||||
id,
|
||||
'wrapper-repo': pkg.manifest['wrapper-repo']
|
||||
}))
|
||||
|
||||
console.log('[Apps] Fetching GitHub info for dummy apps...')
|
||||
const githubInfo = await fetchMultipleAppInfo(appsToFetch)
|
||||
appInfoCache.value = githubInfo
|
||||
|
||||
// Update dummy apps with fetched info
|
||||
Object.entries(githubInfo).forEach(([id, info]) => {
|
||||
if (dummyApps[id] && info.icon) {
|
||||
dummyApps[id]['static-files'].icon = info.icon
|
||||
}
|
||||
if (dummyApps[id] && info.description) {
|
||||
dummyApps[id].manifest.description.short = info.description.substring(0, 100)
|
||||
if (!dummyApps[id].manifest.description.long) {
|
||||
dummyApps[id].manifest.description.long = info.description
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log('[Apps] GitHub info fetched:', Object.keys(githubInfo).length, 'apps')
|
||||
} catch (err) {
|
||||
console.debug('[Apps] External API fetch skipped or failed')
|
||||
}
|
||||
}
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -788,174 +788,6 @@ function getCuratedAppList() {
|
||||
]
|
||||
}
|
||||
|
||||
// Helper function at end of script
|
||||
function getCuratedAppList() {
|
||||
return [
|
||||
title: 'Nextcloud',
|
||||
version: '29.0.0',
|
||||
description: 'Self-hosted file sync and sharing platform. Your own private cloud storage with calendar, contacts, and office suite.',
|
||||
icon: '/assets/img/nextcloud.png',
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/nextcloud-startos/releases/latest/download/nextcloud.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/nextcloud-startos'
|
||||
},
|
||||
{
|
||||
id: 'synapse',
|
||||
title: 'Synapse (Matrix)',
|
||||
version: '1.96.0',
|
||||
description: 'Matrix homeserver for decentralized, encrypted communication. Host your own private messaging server.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/synapse-startos/releases/latest/download/synapse.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/synapse-startos'
|
||||
},
|
||||
{
|
||||
id: 'nostr-rs-relay',
|
||||
title: 'Nostr Relay',
|
||||
version: '0.8.0',
|
||||
description: 'High-performance Nostr relay written in Rust. Host your own decentralized social media relay.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/nostr-rs-relay-startos/releases/latest/download/nostr-rs-relay.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/nostr-rs-relay-startos'
|
||||
},
|
||||
{
|
||||
id: 'bitcoinknots',
|
||||
title: 'Bitcoin Knots',
|
||||
version: '27.0',
|
||||
description: 'Bitcoin Knots full node - a derivative of Bitcoin Core with additional features and enhancements.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/bitcoinknots-startos/releases/latest/download/bitcoinknots.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/bitcoinknots-startos'
|
||||
},
|
||||
{
|
||||
id: 'electrs',
|
||||
title: 'Electrs',
|
||||
version: '0.10.0',
|
||||
description: 'Efficient Electrum Server implementation in Rust. Index Bitcoin blockchain for lightweight wallets.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/electrs-startos/releases/latest/download/electrs.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/electrs-startos'
|
||||
},
|
||||
{
|
||||
id: 'cups-messenger',
|
||||
title: 'CUPS Messenger',
|
||||
version: '2.0.0',
|
||||
description: 'Private messaging over the Bitcoin Lightning Network. Censorship-resistant, encrypted communication.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/cups-messenger-startos/releases/latest/download/cups.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/cups-messenger-startos'
|
||||
},
|
||||
{
|
||||
id: 'ride-the-lightning',
|
||||
title: 'Ride The Lightning',
|
||||
version: '0.14.0',
|
||||
description: 'Web UI for managing Lightning Network nodes (LND and CLN). Beautiful interface for node management.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/ride-the-lightning-startos/releases/latest/download/ride-the-lightning.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/ride-the-lightning-startos'
|
||||
},
|
||||
{
|
||||
id: 'thunderhub',
|
||||
title: 'ThunderHub',
|
||||
version: '0.13.0',
|
||||
description: 'Lightning Network node management interface. Monitor channels, make payments, and manage your LND node.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/thunderhub-startos/releases/latest/download/thunderhub.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/thunderhub-startos'
|
||||
},
|
||||
{
|
||||
id: 'specter-desktop',
|
||||
title: 'Specter Desktop',
|
||||
version: '2.0.0',
|
||||
description: 'Multi-signature Bitcoin wallet interface. Advanced wallet management with hardware wallet support.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/specter-desktop-startos/releases/latest/download/specter-desktop.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/specter-desktop-startos'
|
||||
},
|
||||
{
|
||||
id: 'mempool',
|
||||
title: 'Mempool Explorer',
|
||||
version: '2.5.0',
|
||||
description: 'Self-hosted Bitcoin blockchain and mempool visualizer. Beautiful explorer for your node.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/mempool-startos/releases/latest/download/mempool.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/mempool-startos'
|
||||
},
|
||||
{
|
||||
id: 'vaultwarden',
|
||||
title: 'Vaultwarden',
|
||||
version: '1.30.0',
|
||||
description: 'Self-hosted password manager (Bitwarden-compatible). Secure vault for all your passwords and secrets.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/vaultwarden-startos/releases/latest/download/vaultwarden.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/vaultwarden-startos'
|
||||
},
|
||||
{
|
||||
id: 'jellyfin',
|
||||
title: 'Jellyfin',
|
||||
version: '10.8.0',
|
||||
description: 'Free media server system. Stream your movies, music, and photos to any device.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/jellyfin-startos/releases/latest/download/jellyfin.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/jellyfin-startos'
|
||||
},
|
||||
{
|
||||
id: 'photoprism',
|
||||
title: 'PhotoPrism',
|
||||
version: '231128',
|
||||
description: 'AI-powered photo management. Organize and browse your photo collection with facial recognition.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/photoprism-startos/releases/latest/download/photoprism.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/photoprism-startos'
|
||||
},
|
||||
{
|
||||
id: 'immich',
|
||||
title: 'Immich',
|
||||
version: '1.90.0',
|
||||
description: 'High-performance self-hosted photo and video backup solution. Mobile-first with ML features.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/immich-startos/releases/latest/download/immich.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/immich-startos'
|
||||
},
|
||||
{
|
||||
id: 'filebrowser',
|
||||
title: 'File Browser',
|
||||
version: '2.27.0',
|
||||
description: 'Web-based file manager. Browse, upload, and manage files on your server through a web interface.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/filebrowser-startos/releases/latest/download/filebrowser.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/filebrowser-startos'
|
||||
},
|
||||
{
|
||||
id: 'home-assistant',
|
||||
title: 'Home Assistant',
|
||||
version: '2023.12.0',
|
||||
description: 'Open-source home automation platform. Control and automate your smart home devices privately.',
|
||||
icon: null,
|
||||
author: 'Start9',
|
||||
manifestUrl: 'https://github.com/Start9Labs/home-assistant-startos/releases/latest/download/home-assistant.s9pk',
|
||||
repoUrl: 'https://github.com/Start9Labs/home-assistant-startos'
|
||||
}
|
||||
]
|
||||
console.log(`📦 Loaded ${communityApps.value.length} Docker-based apps`)
|
||||
} finally {
|
||||
loadingCommunity.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function viewAppDetails(app: any) {
|
||||
console.log('[Marketplace] Navigating to app detail:', app)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user