feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
This commit is contained in:
477
setup-production.php
Normal file
477
setup-production.php
Normal file
@@ -0,0 +1,477 @@
|
||||
<?php
|
||||
/*******************************************************************************************************************
|
||||
| EasyStream Production Setup Script
|
||||
| Sets up the platform for production deployment
|
||||
|*******************************************************************************************************************/
|
||||
|
||||
define('_ISVALID', true);
|
||||
|
||||
// Include core configuration
|
||||
include_once 'f_core/config.core.php';
|
||||
|
||||
/**
|
||||
* Production Setup Manager
|
||||
*/
|
||||
class ProductionSetup
|
||||
{
|
||||
private $logger;
|
||||
private $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logger = VLogger::getInstance();
|
||||
$this->db = VDatabase::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run complete production setup
|
||||
*/
|
||||
public function setup()
|
||||
{
|
||||
echo "EasyStream Production Setup\n";
|
||||
echo str_repeat("=", 40) . "\n\n";
|
||||
|
||||
$steps = [
|
||||
'checkRequirements' => 'Checking system requirements',
|
||||
'createDirectories' => 'Creating required directories',
|
||||
'setupDatabase' => 'Setting up database tables',
|
||||
'configurePermissions' => 'Configuring file permissions',
|
||||
'setupCronJobs' => 'Setting up cron jobs',
|
||||
'testComponents' => 'Testing core components',
|
||||
'generateConfig' => 'Generating production config'
|
||||
];
|
||||
|
||||
$totalSteps = count($steps);
|
||||
$currentStep = 0;
|
||||
|
||||
foreach ($steps as $method => $description) {
|
||||
$currentStep++;
|
||||
echo "[{$currentStep}/{$totalSteps}] {$description}...\n";
|
||||
|
||||
try {
|
||||
$result = $this->$method();
|
||||
|
||||
if ($result['success']) {
|
||||
echo " ✓ " . $result['message'] . "\n";
|
||||
} else {
|
||||
echo " ✗ " . $result['message'] . "\n";
|
||||
if (isset($result['details'])) {
|
||||
foreach ($result['details'] as $detail) {
|
||||
echo " - {$detail}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo " ✗ Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo "Production setup completed!\n\n";
|
||||
echo "Next steps:\n";
|
||||
echo "1. Start queue workers: php start-workers.php\n";
|
||||
echo "2. Monitor system: php f_core/f_workers/queue-monitor.php monitor\n";
|
||||
echo "3. Check logs in: logs/\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check system requirements
|
||||
*/
|
||||
private function checkRequirements()
|
||||
{
|
||||
$requirements = [
|
||||
'PHP version >= 8.0' => version_compare(PHP_VERSION, '8.0.0', '>='),
|
||||
'FFmpeg installed' => $this->checkFFmpeg(),
|
||||
'Redis available' => $this->checkRedis(),
|
||||
'Database connection' => $this->checkDatabase(),
|
||||
'GD extension' => extension_loaded('gd'),
|
||||
'JSON extension' => extension_loaded('json'),
|
||||
'cURL extension' => extension_loaded('curl'),
|
||||
'OpenSSL extension' => extension_loaded('openssl')
|
||||
];
|
||||
|
||||
$passed = 0;
|
||||
$failed = [];
|
||||
|
||||
foreach ($requirements as $requirement => $status) {
|
||||
if ($status) {
|
||||
$passed++;
|
||||
} else {
|
||||
$failed[] = $requirement;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($failed)) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "All {$passed} requirements met"
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => count($failed) . ' requirements failed',
|
||||
'details' => $failed
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create required directories
|
||||
*/
|
||||
private function createDirectories()
|
||||
{
|
||||
$directories = [
|
||||
'f_data/temp',
|
||||
'f_data/processed',
|
||||
'f_data/media',
|
||||
'f_data/thumbnails',
|
||||
'f_data/logs',
|
||||
'logs'
|
||||
];
|
||||
|
||||
$created = 0;
|
||||
$errors = [];
|
||||
|
||||
foreach ($directories as $dir) {
|
||||
$fullPath = _FPATH . $dir;
|
||||
|
||||
if (!is_dir($fullPath)) {
|
||||
if (mkdir($fullPath, 0755, true)) {
|
||||
$created++;
|
||||
} else {
|
||||
$errors[] = "Failed to create: {$dir}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Created {$created} directories"
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Directory creation failed',
|
||||
'details' => $errors
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup database tables
|
||||
*/
|
||||
private function setupDatabase()
|
||||
{
|
||||
try {
|
||||
// Check if new tables exist
|
||||
$newTables = [
|
||||
'db_votes',
|
||||
'db_comments',
|
||||
'db_social_shares',
|
||||
'db_video_views',
|
||||
'db_video_analytics',
|
||||
'db_watch_progress',
|
||||
'db_notifications',
|
||||
'db_queue_jobs',
|
||||
'db_live_streams',
|
||||
'db_stream_chat',
|
||||
'db_admin_logs',
|
||||
'db_user_follows',
|
||||
'db_content_categories',
|
||||
'db_content_tags',
|
||||
'db_content_category_relations'
|
||||
];
|
||||
|
||||
$existingTables = [];
|
||||
$missingTables = [];
|
||||
|
||||
foreach ($newTables as $table) {
|
||||
$query = "SHOW TABLES LIKE '{$table}'";
|
||||
$result = $this->db->doQuery($query);
|
||||
|
||||
if ($this->db->doFetch($result)) {
|
||||
$existingTables[] = $table;
|
||||
} else {
|
||||
$missingTables[] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($missingTables)) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'All database tables exist'
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => count($missingTables) . ' tables missing',
|
||||
'details' => array_merge(
|
||||
['Run: mysql -u username -p database < __install/easystream.sql'],
|
||||
['Missing tables: ' . implode(', ', $missingTables)]
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Database check failed: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure file permissions
|
||||
*/
|
||||
private function configurePermissions()
|
||||
{
|
||||
$paths = [
|
||||
'f_data' => 0755,
|
||||
'logs' => 0755,
|
||||
'f_templates' => 0644
|
||||
];
|
||||
|
||||
$configured = 0;
|
||||
$errors = [];
|
||||
|
||||
foreach ($paths as $path => $permission) {
|
||||
$fullPath = _FPATH . $path;
|
||||
|
||||
if (file_exists($fullPath)) {
|
||||
if (chmod($fullPath, $permission)) {
|
||||
$configured++;
|
||||
} else {
|
||||
$errors[] = "Failed to set permissions on: {$path}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => empty($errors),
|
||||
'message' => empty($errors) ?
|
||||
"Configured permissions for {$configured} paths" :
|
||||
'Permission configuration failed',
|
||||
'details' => $errors
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup cron jobs
|
||||
*/
|
||||
private function setupCronJobs()
|
||||
{
|
||||
$cronJobs = [
|
||||
'0 2 * * * cd ' . _FPATH . ' && php -f start-workers.php >/dev/null 2>&1',
|
||||
'*/5 * * * * cd ' . _FPATH . ' && php -f f_core/f_workers/queue-monitor.php >/dev/null 2>&1'
|
||||
];
|
||||
|
||||
$cronFile = _FPATH . 'easystream-cron.txt';
|
||||
|
||||
$cronContent = "# EasyStream Cron Jobs\n";
|
||||
$cronContent .= "# Add these to your crontab with: crontab easystream-cron.txt\n\n";
|
||||
|
||||
foreach ($cronJobs as $job) {
|
||||
$cronContent .= $job . "\n";
|
||||
}
|
||||
|
||||
if (file_put_contents($cronFile, $cronContent)) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'Cron jobs file created: easystream-cron.txt',
|
||||
'details' => ['Run: crontab easystream-cron.txt']
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Failed to create cron jobs file'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test core components
|
||||
*/
|
||||
private function testComponents()
|
||||
{
|
||||
$tests = [
|
||||
'Video Processor' => $this->testVideoProcessor(),
|
||||
'Queue System' => $this->testQueueSystem(),
|
||||
'Social Features' => $this->testSocialFeatures(),
|
||||
'Streaming System' => $this->testStreamingSystem(),
|
||||
'Live Streaming' => $this->testLiveStreaming(),
|
||||
'Admin System' => $this->testAdminSystem(),
|
||||
'Content Manager' => $this->testContentManager()
|
||||
];
|
||||
|
||||
$passed = 0;
|
||||
$failed = [];
|
||||
|
||||
foreach ($tests as $component => $result) {
|
||||
if ($result) {
|
||||
$passed++;
|
||||
} else {
|
||||
$failed[] = $component;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => empty($failed),
|
||||
'message' => empty($failed) ?
|
||||
"All {$passed} components working" :
|
||||
count($failed) . ' components failed',
|
||||
'details' => $failed
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate production configuration
|
||||
*/
|
||||
private function generateConfig()
|
||||
{
|
||||
$config = [
|
||||
'production' => true,
|
||||
'debug' => false,
|
||||
'log_level' => 'info',
|
||||
'queue_workers' => [
|
||||
'video_processing' => 2,
|
||||
'general' => 1
|
||||
],
|
||||
'cleanup_schedule' => [
|
||||
'logs_retention_days' => 30,
|
||||
'temp_files_max_age_hours' => 24,
|
||||
'analytics_retention_days' => 90
|
||||
],
|
||||
'video_processing' => [
|
||||
'default_formats' => ['1080p', '720p', '480p', '360p'],
|
||||
'generate_hls' => true,
|
||||
'generate_thumbnails' => true
|
||||
]
|
||||
];
|
||||
|
||||
$configFile = _FPATH . 'production-config.json';
|
||||
|
||||
if (file_put_contents($configFile, json_encode($config, JSON_PRETTY_PRINT))) {
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'Production config created: production-config.json'
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Failed to create production config'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper methods for testing
|
||||
*/
|
||||
private function checkFFmpeg()
|
||||
{
|
||||
$output = shell_exec('ffmpeg -version 2>&1');
|
||||
return strpos($output, 'ffmpeg version') !== false;
|
||||
}
|
||||
|
||||
private function checkRedis()
|
||||
{
|
||||
try {
|
||||
$redis = VRedis::getInstance();
|
||||
return $redis->isConnected();
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function checkDatabase()
|
||||
{
|
||||
try {
|
||||
$query = "SELECT 1";
|
||||
$result = $this->db->doQuery($query);
|
||||
return $result !== false;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function testVideoProcessor()
|
||||
{
|
||||
try {
|
||||
$processor = new VVideoProcessor();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function testQueueSystem()
|
||||
{
|
||||
try {
|
||||
$queueManager = new VQueueManager();
|
||||
$health = $queueManager->healthCheck();
|
||||
return $health['status'] !== 'unhealthy';
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function testSocialFeatures()
|
||||
{
|
||||
try {
|
||||
$social = VSocial::getInstance();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function testStreamingSystem()
|
||||
{
|
||||
try {
|
||||
$streaming = new VStreaming();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function testLiveStreaming()
|
||||
{
|
||||
try {
|
||||
$liveStreaming = new VLiveStreaming();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function testAdminSystem()
|
||||
{
|
||||
try {
|
||||
$admin = VAdmin::getInstance();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function testContentManager()
|
||||
{
|
||||
try {
|
||||
$contentManager = VContentManager::getInstance();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CLI execution
|
||||
if (php_sapi_name() === 'cli') {
|
||||
$setup = new ProductionSetup();
|
||||
$setup->setup();
|
||||
} else {
|
||||
echo "This script must be run from command line\n";
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user