Skip to content

Shutdown Receiver

Initiates a controlled shutdown of the IPCom service. The shutdown process begins a few seconds after the request is received, allowing the API to respond before the service terminates.

Request

http
POST /api/shutdown-receiver

Authentication Required: Must include JWT token in Authorization header.

Required Scope: turnoff_receiver

Content-Type: application/json

Request Body: No request body required.

Request Examples

Basic Shutdown Request

bash
curl -X POST "http://your-server-ip:port/api/shutdown-receiver" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json"

Using JavaScript

javascript
const response = await fetch('/api/shutdown-receiver', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

Response

Success (200 OK)

json
{
  "success": true
}

Error Responses

Standard HTTP error responses may be returned:

401 Unauthorized

json
{
  "error": "NOT_LOGGED_IN"
}

403 Forbidden

json
{
  "error": "FORBIDDEN"
}

405 Method Not Allowed

json
{
  "error": "Method Not Allowed"
}

Shutdown Process

Shutdown Sequence

  1. Request Received: API validates authentication and scope permissions
  2. Response Sent: Success response is immediately returned to client
  3. Delayed Shutdown: After a few seconds, the shutdown process begins
  4. Service Termination: IPCom service gracefully terminates

Usage Examples

Basic Shutdown

javascript
async function shutdownReceiver(token) {
  try {
    console.log('Initiating IPCom shutdown...');
    
    const response = await fetch('/api/shutdown-receiver', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    });
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(`HTTP ${response.status}: ${error.error}`);
    }
    
    const result = await response.json();
    console.log('Shutdown initiated successfully');
    console.log('IPCom service will terminate in a few seconds...');
    
    return result;
  } catch (error) {
    console.error('Failed to initiate shutdown:', error);
    throw error;
  }
}

Shutdown Manager Class

javascript
class ShutdownManager {
  constructor(token) {
    this.token = token;
  }
  
  async initiateShutdown(reason = 'Manual shutdown request') {
    console.log(`Initiating shutdown: ${reason}`);
    
    try {
      // Log shutdown initiation
      await this.logShutdownEvent('shutdown_initiated', reason);
      
      const response = await fetch('/api/shutdown-receiver', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.token}`,
          'Content-Type': 'application/json'
        }
      });
      
      if (!response.ok) {
        const error = await response.json();
        throw new Error(`Shutdown failed: ${error.error}`);
      }
      
      const result = await response.json();
      
      // Log successful shutdown request
      await this.logShutdownEvent('shutdown_accepted', reason);
      
      console.log('✓ Shutdown request accepted');
      console.log('⚠ IPCom service will terminate shortly...');
      
      return result;
      
    } catch (error) {
      // Log failed shutdown request
      await this.logShutdownEvent('shutdown_failed', reason, error.message);
      
      console.error('✗ Shutdown request failed:', error.message);
      throw error;
    }
  }
  
  async confirmAndShutdown(reason, confirmCallback = null) {
    // Optional confirmation before shutdown
    if (confirmCallback && !await confirmCallback(reason)) {
      console.log('Shutdown cancelled by user');
      return false;
    }
    
    return await this.initiateShutdown(reason);
  }
  
  async logShutdownEvent(event, reason, error = null) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      event: event,
      reason: reason,
      error: error,
      user: this.getCurrentUser()
    };
    
    console.log('SHUTDOWN_EVENT:', JSON.stringify(logEntry));
    
    // Log to local storage or external logging system
    try {
      const logs = JSON.parse(localStorage.getItem('shutdownLogs') || '[]');
      logs.push(logEntry);
      localStorage.setItem('shutdownLogs', JSON.stringify(logs));
    } catch (storageError) {
      console.warn('Could not save shutdown log locally:', storageError.message);
    }
  }
  
  getCurrentUser() {
    try {
      const token = localStorage.getItem('authToken');
      const payload = JSON.parse(atob(token.split('.')[1]));
      return payload.username || payload.sub;
    } catch {
      return 'unknown';
    }
  }
}

// Usage
const shutdownManager = new ShutdownManager(authToken);

// Simple shutdown
await shutdownManager.initiateShutdown('Planned maintenance shutdown');

// Shutdown with confirmation
const confirmShutdown = async (reason) => {
  return confirm(`Are you sure you want to shutdown IPCom?\nReason: ${reason}`);
};

await shutdownManager.confirmAndShutdown('Emergency shutdown', confirmShutdown);

Maintenance Shutdown Workflow

javascript
class MaintenanceShutdown {
  constructor(token) {
    this.token = token;
    this.shutdownManager = new ShutdownManager(token);
  }
  
  async performMaintenanceShutdown(maintenanceDetails) {
    const shutdownPlan = {
      reason: maintenanceDetails.reason || 'Scheduled maintenance',
      scheduledTime: maintenanceDetails.scheduledTime || new Date(),
      estimatedDowntime: maintenanceDetails.estimatedDowntime || 'Unknown',
      contact: maintenanceDetails.contact || 'System Administrator'
    };
    
    console.log('=== MAINTENANCE SHUTDOWN INITIATED ===');
    console.log(`Reason: ${shutdownPlan.reason}`);
    console.log(`Scheduled: ${shutdownPlan.scheduledTime}`);
    console.log(`Estimated Downtime: ${shutdownPlan.estimatedDowntime}`);
    console.log(`Contact: ${shutdownPlan.contact}`);
    console.log('==========================================');
    
    try {
      // Step 1: Notify about impending shutdown
      await this.notifyActiveUsers(shutdownPlan);
      
      // Step 2: Save current system state
      await this.saveSystemState();
      
      // Step 3: Log maintenance shutdown
      await this.logMaintenanceShutdown(shutdownPlan, 'initiated');
      
      // Step 4: Initiate shutdown
      const result = await this.shutdownManager.initiateShutdown(shutdownPlan.reason);
      
      // Step 5: Log successful shutdown request
      await this.logMaintenanceShutdown(shutdownPlan, 'accepted');
      
      console.log('✓ Maintenance shutdown initiated successfully');
      console.log('⚠ System will be offline shortly');
      
      return result;
      
    } catch (error) {
      await this.logMaintenanceShutdown(shutdownPlan, 'failed', error.message);
      console.error('✗ Maintenance shutdown failed:', error.message);
      throw error;
    }
  }
  
  async notifyActiveUsers(shutdownPlan) {
    console.log('Notifying active users about shutdown...');
    
    // This would typically send notifications through WebSocket or other means
    const notification = {
      type: 'system_shutdown',
      message: `System shutdown scheduled: ${shutdownPlan.reason}`,
      estimatedDowntime: shutdownPlan.estimatedDowntime,
      contact: shutdownPlan.contact,
      timestamp: new Date().toISOString()
    };
    
    console.log('USER_NOTIFICATION:', JSON.stringify(notification));
    
    // Simulate notification sending
    try {
      await fetch('/api/notifications/broadcast', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(notification)
      });
    } catch (error) {
      console.warn('Could not send user notifications:', error.message);
    }
  }
  
  async saveSystemState() {
    console.log('Saving current system state...');
    
    try {
      // Get current system status
      const statusResponse = await fetch('/api/status', {
        headers: { 'Authorization': `Bearer ${this.token}` }
      });
      
      if (statusResponse.ok) {
        const systemStatus = await statusResponse.json();
        
        // Save to local storage or send to backup service
        const stateSnapshot = {
          timestamp: new Date().toISOString(),
          systemStatus: systemStatus,
          shutdownReason: 'Maintenance shutdown'
        };
        
        localStorage.setItem('lastSystemState', JSON.stringify(stateSnapshot));
        console.log('✓ System state saved');
      }
    } catch (error) {
      console.warn('Could not save system state:', error.message);
    }
  }
  
  async logMaintenanceShutdown(shutdownPlan, status, error = null) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      action: 'maintenance_shutdown',
      status: status,
      plan: shutdownPlan,
      error: error,
      user: this.shutdownManager.getCurrentUser()
    };
    
    console.log('MAINTENANCE_LOG:', JSON.stringify(logEntry));
    
    // Save to local storage or send to external logging system
    try {
      const logs = JSON.parse(localStorage.getItem('maintenanceLogs') || '[]');
      logs.push(logEntry);
      localStorage.setItem('maintenanceLogs', JSON.stringify(logs));
    } catch (storageError) {
      console.warn('Could not save maintenance log locally:', storageError.message);
    }
  }
}

// Usage
const maintenanceShutdown = new MaintenanceShutdown(authToken);

const maintenanceDetails = {
  reason: 'Monthly system maintenance',
  scheduledTime: new Date(),
  estimatedDowntime: '2-4 hours',
  contact: 'IT Support: +1-555-0123'
};

await maintenanceShutdown.performMaintenanceShutdown(maintenanceDetails);

Emergency Shutdown

javascript
class EmergencyShutdown {
  constructor(token) {
    this.token = token;
    this.shutdownManager = new ShutdownManager(token);
  }
  
  async performEmergencyShutdown(emergencyDetails) {
    const emergency = {
      reason: emergencyDetails.reason || 'Emergency shutdown',
      severity: emergencyDetails.severity || 'HIGH',
      reportedBy: emergencyDetails.reportedBy || 'System Monitor',
      immediateAction: true
    };
    
    console.log('🚨 EMERGENCY SHUTDOWN INITIATED 🚨');
    console.log(`Reason: ${emergency.reason}`);
    console.log(`Severity: ${emergency.severity}`);
    console.log(`Reported By: ${emergency.reportedBy}`);
    console.log('=====================================');
    
    try {
      // Log emergency immediately
      await this.logEmergencyEvent(emergency, 'initiated');
      
      // Send emergency alert
      await this.sendEmergencyAlert(emergency);
      
      // Initiate immediate shutdown
      const result = await this.shutdownManager.initiateShutdown(
        `EMERGENCY: ${emergency.reason}`
      );
      
      // Log successful emergency shutdown
      await this.logEmergencyEvent(emergency, 'shutdown_accepted');
      
      console.log('🚨 Emergency shutdown initiated');
      console.log('⚠ System terminating immediately');
      
      return result;
      
    } catch (error) {
      await this.logEmergencyEvent(emergency, 'shutdown_failed', error.message);
      console.error('🚨 Emergency shutdown failed:', error.message);
      throw error;
    }
  }
  
  async sendEmergencyAlert(emergency) {
    const alert = {
      type: 'EMERGENCY_SHUTDOWN',
      severity: emergency.severity,
      message: emergency.reason,
      reportedBy: emergency.reportedBy,
      timestamp: new Date().toISOString(),
      requiresImmediate: true
    };
    
    console.log('EMERGENCY_ALERT:', JSON.stringify(alert));
    
    // Send to emergency notification system
    try {
      await fetch('/api/emergency/alert', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(alert)
      });
    } catch (error) {
      console.error('Could not send emergency alert:', error.message);
    }
  }
  
  async logEmergencyEvent(emergency, status, error = null) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      action: 'emergency_shutdown',
      status: status,
      emergency: emergency,
      error: error,
      user: this.shutdownManager.getCurrentUser()
    };
    
    console.log('EMERGENCY_LOG:', JSON.stringify(logEntry));
    
    // Save to local storage or send to external logging system
    try {
      const logs = JSON.parse(localStorage.getItem('emergencyLogs') || '[]');
      logs.push(logEntry);
      localStorage.setItem('emergencyLogs', JSON.stringify(logs));
    } catch (storageError) {
      console.warn('Could not save emergency log locally:', storageError.message);
    }
  }
}

// Usage
const emergencyShutdown = new EmergencyShutdown(authToken);

const emergencyDetails = {
  reason: 'Critical system error detected',
  severity: 'CRITICAL',
  reportedBy: 'Automated Monitor'
};

await emergencyShutdown.performEmergencyShutdown(emergencyDetails);

Error Handling and Validation

javascript
class ShutdownValidator {
  static validateShutdownPermissions(token) {
    try {
      const payload = JSON.parse(atob(token.split('.')[1]));
      const scopes = payload.scopes || [];
      
      if (!scopes.includes('turnoff_receiver')) {
        throw new Error('Insufficient permissions: turnoff_receiver scope required');
      }
      
      // Check token expiration
      const now = Math.floor(Date.now() / 1000);
      if (payload.exp && payload.exp < now) {
        throw new Error('Token expired: Please log in again');
      }
      
      return true;
    } catch (error) {
      throw new Error(`Token validation failed: ${error.message}`);
    }
  }
  
  static validateShutdownRequest(reason, userContext) {
    // Validate reason
    if (!reason || reason.trim().length === 0) {
      throw new Error('Shutdown reason is required');
    }
    
    if (reason.length > 200) {
      throw new Error('Shutdown reason too long (max 200 characters)');
    }
    
    // Validate user context
    if (!userContext || !userContext.username) {
      throw new Error('User context required for shutdown');
    }
    
    return true;
  }
}

// Usage with validation
async function safeShutdown(token, reason, userContext) {
  try {
    // Validate permissions and request
    ShutdownValidator.validateShutdownPermissions(token);
    ShutdownValidator.validateShutdownRequest(reason, userContext);
    
    // Proceed with shutdown
    const shutdownManager = new ShutdownManager(token);
    return await shutdownManager.initiateShutdown(reason);
  } catch (error) {
    console.error('Shutdown validation failed:', error.message);
    throw error;
  }
}

Shutdown Status Monitor

javascript
class ShutdownStatusMonitor {
  constructor(token) {
    this.token = token;
    this.shutdownHistory = [];
  }
  
  async monitoredShutdown(reason) {
    const shutdownEvent = {
      id: Date.now(),
      reason: reason,
      startTime: new Date(),
      status: 'initiated'
    };
    
    this.shutdownHistory.push(shutdownEvent);
    
    try {
      // Capture pre-shutdown system state
      const preShutdownStatus = await this.getSystemStatus();
      shutdownEvent.preShutdownStatus = preShutdownStatus;
      
      console.log(`Monitored shutdown initiated: ${reason}`);
      
      // Perform shutdown
      const shutdownManager = new ShutdownManager(this.token);
      const result = await shutdownManager.initiateShutdown(reason);
      
      // Update shutdown event
      shutdownEvent.responseTime = new Date();
      shutdownEvent.status = 'accepted';
      shutdownEvent.success = true;
      shutdownEvent.response = result;
      
      console.log('✓ Shutdown request accepted and logged');
      
      // Note: We cannot monitor actual shutdown completion since the service will terminate
      console.log('⚠ Service will terminate - no further monitoring possible');
      
      return shutdownEvent;
      
    } catch (error) {
      shutdownEvent.responseTime = new Date();
      shutdownEvent.status = 'failed';
      shutdownEvent.error = error.message;
      shutdownEvent.success = false;
      
      console.error('✗ Monitored shutdown failed:', error.message);
      throw error;
    }
  }
  
  async getSystemStatus() {
    try {
      const response = await fetch('/api/status', {
        headers: { 'Authorization': `Bearer ${this.token}` }
      });
      
      if (response.ok) {
        return await response.json();
      }
    } catch (error) {
      console.warn('Could not fetch system status:', error.message);
    }
    
    return null;
  }
  
  getShutdownHistory() {
    return this.shutdownHistory;
  }
  
  getLastShutdown() {
    return this.shutdownHistory[this.shutdownHistory.length - 1];
  }
}

// Usage
const shutdownMonitor = new ShutdownStatusMonitor(authToken);

// Perform monitored shutdown
const shutdownEvent = await shutdownMonitor.monitoredShutdown('Planned maintenance');

// Check shutdown history
const history = shutdownMonitor.getShutdownHistory();
console.log('Shutdown history:', history);

Security Considerations

Access Control

  • Critical Scope: turnoff_receiver scope should be highly restricted
  • Admin Only: Typically only system administrators should have shutdown access
  • Audit Requirements: All shutdown attempts must be logged for security audit

Shutdown Safety

  • Confirmation Required: Always implement confirmation dialogs for shutdown
  • Reason Logging: Require and log reasons for all shutdown requests
  • Emergency Procedures: Have clear procedures for emergency vs planned shutdowns

Monitoring and Recovery

javascript
async function secureShutdown(token, reason, userContext, requireConfirmation = true) {
  // Validate user and permissions
  if (!userContext.isAdmin) {
    throw new Error('Only administrators can initiate system shutdown');
  }
  
  // Require confirmation for non-emergency shutdowns
  if (requireConfirmation && !reason.toLowerCase().includes('emergency')) {
    const confirmed = confirm(
      `CRITICAL ACTION: This will shutdown the entire IPCom system.\n\n` +
      `Reason: ${reason}\n\n` +
      `Are you absolutely sure you want to proceed?`
    );
    
    if (!confirmed) {
      console.log('Shutdown cancelled by user');
      return false;
    }
  }
  
  // Log shutdown attempt locally
  const shutdownLog = {
    action: 'system_shutdown_initiated',
    user: userContext.username,
    reason: reason,
    timestamp: new Date().toISOString(),
    userAgent: navigator.userAgent,
    ipAddress: userContext.ipAddress
  };
  
  console.log('SHUTDOWN_AUDIT:', JSON.stringify(shutdownLog));
  
  try {
    const shutdownManager = new ShutdownManager(token);
    const result = await shutdownManager.initiateShutdown(reason);
    
    // Log successful shutdown request
    const successLog = {
      action: 'system_shutdown_accepted',
      user: userContext.username,
      reason: reason,
      success: true,
      timestamp: new Date().toISOString()
    };
    
    console.log('SHUTDOWN_SUCCESS:', JSON.stringify(successLog));
    
    return result;
  } catch (error) {
    // Log failed shutdown request
    const errorLog = {
      action: 'system_shutdown_failed',
      user: userContext.username,
      reason: reason,
      success: false,
      error: error.message,
      timestamp: new Date().toISOString()
    };
    
    console.log('SHUTDOWN_ERROR:', JSON.stringify(errorLog));
    
    throw error;
  }
}

Important Notes

  • Critical Operation: This endpoint terminates the entire IPCom service
  • Scope Required: Users must have the turnoff_receiver scope (highly restricted)
  • Delayed Execution: Shutdown begins a few seconds after API response
  • No Rollback: Once initiated, shutdown cannot be cancelled
  • Service Unavailable: All API endpoints become unavailable after shutdown
  • Manual Restart: IPCom service must be manually restarted after shutdown
  • Data Safety: Ensure all critical data is saved before shutdown
  • User Notification: Consider notifying active users before shutdown
  • Emergency Use: Should be used only for planned maintenance or emergencies
  • Audit Trail: All shutdown attempts should be logged for security and compliance
  • Recovery Planning: Have clear procedures for restarting services after shutdown

Released under the MIT License.