Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"Bash(grep:*)",
"Bash(pnpm type-check:*)",
"Bash(pnpm lint:*)",
"Bash(pnpm --filter ./api lint)"
"Bash(pnpm --filter ./api lint)",
"Bash(mv:*)"
]
},
"enableAllProjectMcpServers": false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { writeFile } from 'fs/promises';

import { ConnectionMetadata, ConfigType } from './connect.config.js';

@Injectable()
export class ConnectStatusWriterService implements OnModuleInit {
constructor(private readonly configService: ConfigService<ConfigType, true>) {}

private logger = new Logger(ConnectStatusWriterService.name);

get statusFilePath() {
// Write to /var/local/emhttp/connectStatus.json so PHP can read it
return '/var/local/emhttp/connectStatus.json';
}

async onModuleInit() {
this.logger.verbose(`Status file path: ${this.statusFilePath}`);

// Write initial status
await this.writeStatus();

// Listen for changes to connection status
this.configService.changes$.subscribe({
next: async (change) => {
const connectionChanged = change.path && change.path.startsWith('connect.mothership');
if (connectionChanged) {
await this.writeStatus();
}
},
error: (err) => {
this.logger.error('Error receiving config changes:', err);
},
});
}

private async writeStatus() {
try {
const connectionMetadata = this.configService.get<ConnectionMetadata>('connect.mothership');

// Try to get allowed origins from the store
let allowedOrigins = '';
try {
// We can't import from @app here, so we'll skip allowed origins for now
// This can be added later if needed
allowedOrigins = '';
} catch (error) {
this.logger.debug('Could not get allowed origins:', error);
}

const statusData = {
connectionStatus: connectionMetadata?.status || 'PRE_INIT',
error: connectionMetadata?.error || null,
lastPing: connectionMetadata?.lastPing || null,
allowedOrigins: allowedOrigins,
timestamp: Date.now()
};

const data = JSON.stringify(statusData, null, 2);
this.logger.verbose(`Writing connection status: ${data}`);

await writeFile(this.statusFilePath, data);
this.logger.verbose(`Status written to ${this.statusFilePath}`);
} catch (error) {
this.logger.error(error, `Error writing status to '${this.statusFilePath}'`);
}
}
}
3 changes: 2 additions & 1 deletion packages/unraid-api-plugin-connect/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { ConfigModule, ConfigService } from '@nestjs/config';

import { ConnectConfigPersister } from './config/config.persistence.js';
import { configFeature } from './config/connect.config.js';
import { ConnectStatusWriterService } from './config/connect-status-writer.service.js';
import { MothershipModule } from './mothership-proxy/mothership.module.js';
import { ConnectModule } from './unraid-connect/connect.module.js';

export const adapter = 'nestjs';

@Module({
imports: [ConfigModule.forFeature(configFeature), ConnectModule, MothershipModule],
providers: [ConnectConfigPersister],
providers: [ConnectConfigPersister, ConnectStatusWriterService],
exports: [],
})
class ConnectPluginModule {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,16 @@
$myservers = file_exists($myservers_flash_cfg_path) ? @parse_ini_file($myservers_flash_cfg_path,true) : [];
$isRegistered = !empty($myservers['remote']['username']);

$myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
$mystatus = (file_exists($myservers_memory_cfg_path)) ? @parse_ini_file($myservers_memory_cfg_path) : [];
$isConnected = (($mystatus['minigraph']??'')==='CONNECTED') ? true : false;
// Read connection status from the new API status file
$statusFilePath = '/var/local/emhttp/connectStatus.json';
$connectionStatus = '';

if (file_exists($statusFilePath)) {
$statusData = @json_decode(file_get_contents($statusFilePath), true);
$connectionStatus = $statusData['connectionStatus'] ?? '';
}

$isConnected = ($connectionStatus === 'CONNECTED') ? true : false;

$flashbackup_ini = '/var/local/emhttp/flashbackup.ini';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,8 @@ private function getFlashBackupStatus()
private function getMyServersCfgValues()
{
/**
* @todo can we read this from somewhere other than the flash? Connect page uses this path and /boot/config/plugins/dynamix.my.servers/myservers.cfg…
* - $myservers_memory_cfg_path ='/var/local/emhttp/myservers.cfg';
* - $mystatus = (file_exists($myservers_memory_cfg_path)) ? @parse_ini_file($myservers_memory_cfg_path) : [];
* Memory config is now written by the new API to /usr/local/emhttp/state/myservers.cfg
* This contains runtime state including connection status.
*/
$flashCfgPath = '/boot/config/plugins/dynamix.my.servers/myservers.cfg';
$this->myServersFlashCfg = file_exists($flashCfgPath) ? @parse_ini_file($flashCfgPath, true) : [];
Expand Down Expand Up @@ -212,11 +211,19 @@ private function getConnectKnownOrigins()
* Include localhost in the test, but only display HTTP(S) URLs that do not include localhost.
*/
$this->host = $_SERVER['HTTP_HOST'] ?? "unknown";
$memoryCfgPath = '/var/local/emhttp/myservers.cfg';
$this->myServersMemoryCfg = (file_exists($memoryCfgPath)) ? @parse_ini_file($memoryCfgPath) : [];
$this->myServersMiniGraphConnected = (($this->myServersMemoryCfg['minigraph'] ?? '') === 'CONNECTED');
// Read connection status and allowed origins from the new API status file
$statusFilePath = '/var/local/emhttp/connectStatus.json';
$connectionStatus = '';
$allowedOrigins = '';

if (file_exists($statusFilePath)) {
$statusData = @json_decode(file_get_contents($statusFilePath), true);
$connectionStatus = $statusData['connectionStatus'] ?? '';
$allowedOrigins = $statusData['allowedOrigins'] ?? '';
}

$this->myServersMiniGraphConnected = ($connectionStatus === 'CONNECTED');

$allowedOrigins = $this->myServersMemoryCfg['allowedOrigins'] ?? "";
$extraOrigins = $this->myServersFlashCfg['api']['extraOrigins'] ?? "";
$combinedOrigins = $allowedOrigins . "," . $extraOrigins; // combine the two strings for easier searching
$combinedOrigins = str_replace(" ", "", $combinedOrigins); // replace any spaces with nothing
Expand Down