HEX
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.4.30
System: Linux iZj6c1151k3ad370bosnmsZ 3.10.0-1160.76.1.el7.x86_64 #1 SMP Wed Aug 10 16:21:17 UTC 2022 x86_64
User: root (0)
PHP: 7.4.30
Disabled: NONE
Upload Files
File: /var/www/html/www.winghung.com/wp-content/plugins/mxchat-basic/js/mxchat-test-streaming.js
jQuery(document).ready(function($) {
    $('#mxchat-test-streaming-btn').on('click', function() {
        const $button = $(this);
        const $result = $('#mxchat-test-streaming-result');
        
        $button.prop('disabled', true).text('Testing...');
        $result.text('Testing streaming environment...');
        
        // Test both backend capability AND frontend environment
        testCompleteStreamingEnvironment()
            .then(result => {
                if (result.success) {
                    $result.css('color', 'green').html(result.message);
                } else {
                    $result.css('color', 'red').html(result.message);
                }
            })
            .catch(error => {
                $result.css('color', 'red').html('❌ Test failed: ' + error.message);
            })
            .finally(() => {
                $button.prop('disabled', false).text('Test Streaming Compatibility');
            });
    });
    
    function testCompleteStreamingEnvironment() {
        return new Promise((resolve, reject) => {
            let results = {
                backendSupported: false,
                frontendWorking: false,
                chunks: 0,
                timing: null,
                issues: []
            };
            
            let startTime = Date.now();
            let firstChunkTime = null;
            let lastChunkTime = null;
            let timeout;
            
            // Set overall timeout
            timeout = setTimeout(() => {
                resolve({
                    success: false,
                    message: getFailureMessage(results)
                });
            }, 15000);
            
            // Test the actual chat streaming endpoint (not the test endpoint)
            const formData = new FormData();
            formData.append('action', 'mxchat_stream_chat');
            formData.append('message', 'Say "test 1", then "test 2", then "test 3" - each on a separate line.');
            formData.append('session_id', 'streaming_test_' + Date.now());
            formData.append('nonce', mxchatTestStreamingAjax.nonce);
            
            fetch(mxchatTestStreamingAjax.ajax_url, {
                method: 'POST',
                body: formData,
                credentials: 'same-origin'
            })
            .then(response => {
                const contentType = response.headers.get('content-type');
                console.log('Content-Type:', contentType);
                
                // Check if we got JSON (streaming failed)
                if (contentType && contentType.includes('application/json')) {
                    response.json().then(data => {
                        clearTimeout(timeout);
                        results.backendSupported = true;
                        results.frontendWorking = false;
                        results.issues.push('Server fell back to JSON response');
                        resolve({
                            success: false,
                            message: getFailureMessage(results)
                        });
                    });
                    return;
                }
                
                // Check for proper SSE content type
                if (!contentType || !contentType.includes('text/event-stream')) {
                    clearTimeout(timeout);
                    results.issues.push(`Wrong content-type: ${contentType || 'none'}`);
                    resolve({
                        success: false,
                        message: getFailureMessage(results)
                    });
                    return;
                }
                
                results.backendSupported = true;
                
                // Process streaming response
                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let buffer = '';
                
                function processStream() {
                    reader.read().then(({ done, value }) => {
                        if (done) {
                            clearTimeout(timeout);
                            results.timing = {
                                total: Date.now() - startTime,
                                firstChunk: firstChunkTime ? firstChunkTime - startTime : null,
                                lastChunk: lastChunkTime ? lastChunkTime - startTime : null
                            };
                            
                            if (results.chunks > 0) {
                                resolve({
                                    success: true,
                                    message: getSuccessMessage(results)
                                });
                            } else {
                                results.issues.push('No chunks received');
                                resolve({
                                    success: false,
                                    message: getFailureMessage(results)
                                });
                            }
                            return;
                        }
                        
                        buffer += decoder.decode(value, { stream: true });
                        const lines = buffer.split('\n');
                        buffer = lines.pop() || '';
                        
                        for (const line of lines) {
                            if (line.startsWith('data: ')) {
                                const data = line.substring(6);
                                
                                if (data === '[DONE]') {
                                    // Stream complete - will be handled in done section
                                    continue;
                                }
                                
                                try {
                                    const json = JSON.parse(data);
                                    if (json.content && json.content.trim().length > 0) {
                                        results.chunks++;
                                        results.frontendWorking = true;
                                        
                                        if (!firstChunkTime) {
                                            firstChunkTime = Date.now();
                                        }
                                        lastChunkTime = Date.now();
                                        
                                        $result.text(`✅ Streaming working... (${results.chunks} chunks received)`);
                                    }
                                } catch (e) {
                                    // Non-JSON data is fine for some SSE implementations
                                }
                            }
                        }
                        
                        processStream();
                    }).catch(error => {
                        clearTimeout(timeout);
                        results.issues.push('Stream read error: ' + error.message);
                        resolve({
                            success: false,
                            message: getFailureMessage(results)
                        });
                    });
                }
                
                processStream();
            })
            .catch(error => {
                clearTimeout(timeout);
                results.issues.push('Fetch error: ' + error.message);
                resolve({
                    success: false,
                    message: getFailureMessage(results)
                });
            });
        });
    }
    
    function getSuccessMessage(results) {
        return `✅ <strong>Streaming is working!</strong><br>
                📊 Received ${results.chunks} chunks in ${results.timing.total}ms<br>
                ⚡ First chunk: ${results.timing.firstChunk}ms<br>
                🎯 Your users will see real-time streaming responses.`;
    }
    
    function getFailureMessage(results) {
        let message = '❌ <strong>Streaming is not working in your environment. Please disable and use regular response.</strong><br><br>';
        
        if (results.backendSupported) {
            message += '<strong>Likely causes:</strong><br>';
            message += '• Caching plugin (WP Rocket, W3 Total Cache, etc.)<br>';
            message += '• CDN buffering (Cloudflare, etc.)<br>';
            message += '• Server-level buffering (nginx, Apache)<br>';
            message += '• Hosting provider optimizations<br><br>';
            
            message += '<strong>Solutions:</strong><br>';
            message += '• Disable caching for chat endpoints<br>';
            message += '• Add streaming exceptions in your CDN<br>';
            message += '• Contact your hosting provider<br>';
        } else {
            message += '❌ Backend streaming not supported<br>';
            if (results.issues.length > 0) {
                message += '<br><strong>Issues detected:</strong><br>';
                results.issues.forEach(issue => {
                    message += `• ${issue}<br>`;
                });
            }
        }
        
        return message;
    }
});