Diff of /web/server/server.js [000000] .. [8c4ad8]

Switch to unified view

a b/web/server/server.js
1
/*
2
 * DNAnalyzer Server Page JavaScript
3
 * Copyright © 2025 Piyush Acharya
4
 */
5
6
document.addEventListener('DOMContentLoaded', function() {
7
    // Mobile navigation toggle
8
    const mobileToggle = document.getElementById('mobileToggle');
9
    const navLinks = document.getElementById('navLinks');
10
11
    if (mobileToggle && navLinks) {
12
        mobileToggle.addEventListener('click', function() {
13
            navLinks.classList.toggle('active');
14
            mobileToggle.querySelector('i').classList.toggle('fa-bars');
15
            mobileToggle.querySelector('i').classList.toggle('fa-times');
16
        });
17
    }
18
19
    // Navbar scroll behavior
20
    const navbar = document.getElementById('navbar');
21
    
22
    window.addEventListener('scroll', function() {
23
        if (window.scrollY > 100) {
24
            navbar.classList.add('scrolled');
25
        } else {
26
            navbar.classList.remove('scrolled');
27
        }
28
    });
29
30
    // Server status check
31
    const serverStatusElement = document.getElementById('server-status');
32
    let statusCheckInterval;
33
    let retryCount = 0;
34
    const MAX_RETRIES = 3;
35
    const SERVER_PORT = 8080;
36
    
37
    // Copy commands functionality
38
    window.copyCloneCommand = function() {
39
        copyToClipboard('git clone https://github.com/VerisimilitudeX/DNAnalyzer.git && cd DNAnalyzer', 0);
40
    };
41
    
42
    window.copyChmodCommand = function() {
43
        copyToClipboard('chmod +x ./gradlew', 1);
44
    };
45
    
46
    window.copyBuildCommand = function() {
47
        copyToClipboard('./gradlew clean bootJar', 2);
48
    };
49
    
50
    window.copyRunCommand = function() {
51
        copyToClipboard('java -jar build/libs/DNAnalyzer.jar', 3);
52
    };
53
    
54
    function copyToClipboard(text, buttonIndex) {
55
        navigator.clipboard.writeText(text).then(() => {
56
            const buttons = document.querySelectorAll('.copy-button');
57
            const button = buttons[buttonIndex];
58
            button.textContent = 'Copied!';
59
            button.classList.add('success');
60
            setTimeout(() => {
61
                button.textContent = 'Copy';
62
                button.classList.remove('success');
63
            }, 2000);
64
        }).catch(() => {
65
            const buttons = document.querySelectorAll('.copy-button');
66
            const button = buttons[buttonIndex];
67
            button.textContent = 'Failed';
68
            button.classList.add('error');
69
            setTimeout(() => {
70
                button.textContent = 'Copy';
71
                button.classList.remove('error');
72
            }, 2000);
73
        });
74
    }
75
76
    // Server status check with retry logic
77
    async function checkServerStatus(isInitialCheck = false) {
78
        try {
79
            const controller = new AbortController();
80
            const timeoutId = setTimeout(() => controller.abort(), 5000);
81
82
            // Try the API status endpoint first
83
            const response = await fetch(`http://localhost:${SERVER_PORT}/api/v1/status`, {
84
                method: 'GET',
85
                signal: controller.signal,
86
                headers: {
87
                    'Accept': 'application/json',
88
                }
89
            });
90
91
            clearTimeout(timeoutId);
92
            retryCount = 0; // Reset retry count on success
93
            
94
            serverStatusElement.innerHTML = `
95
                <div class="status-indicator online">
96
                    <div class="status-dot"></div>
97
                    <div class="status-details">
98
                        <div class="status-main">Server Online</div>
99
                        <div class="status-info">
100
                            <span>Status: Running</span>
101
                            <span>Last checked: ${new Date().toLocaleTimeString()}</span>
102
                            <span>Ready to process DNA sequences</span>
103
                        </div>
104
                    </div>
105
                </div>
106
            `;
107
            return true;
108
        } catch (error) {
109
            // Try root URL as fallback
110
            try {
111
                const controller = new AbortController();
112
                const timeoutId = setTimeout(() => controller.abort(), 5000);
113
114
                const response = await fetch(`http://localhost:${SERVER_PORT}/`, {
115
                    method: 'GET',
116
                    signal: controller.signal
117
                });
118
119
                clearTimeout(timeoutId);
120
121
                if (response.ok || response.status === 404) {
122
                    // Even a 404 means the server is running
123
                    retryCount = 0;
124
                    
125
                    serverStatusElement.innerHTML = `
126
                        <div class="status-indicator online">
127
                            <div class="status-dot"></div>
128
                            <div class="status-details">
129
                                <div class="status-main">Server Online</div>
130
                                <div class="status-info">
131
                                    <span>Status: Running</span>
132
                                    <span>Last checked: ${new Date().toLocaleTimeString()}</span>
133
                                    <span>Ready to process DNA sequences</span>
134
                                </div>
135
                            </div>
136
                        </div>
137
                    `;
138
                    return true;
139
                }
140
                throw new Error('Server not responding correctly');
141
            } catch (fallbackError) {
142
                retryCount++;
143
                const isMaxRetries = retryCount >= MAX_RETRIES;
144
                
145
                serverStatusElement.innerHTML = `
146
                    <div class="status-indicator offline">
147
                        <div class="status-dot"></div>
148
                        <div class="status-details">
149
                            <div class="status-main">Server Offline</div>
150
                            <div class="status-info">
151
                                <span>Last checked: ${new Date().toLocaleTimeString()}</span>
152
                                ${isInitialCheck ? '<span>Follow the setup steps above to start the server</span>' : ''}
153
                                ${!isInitialCheck && !isMaxRetries ? `<span>Retrying... (${retryCount}/${MAX_RETRIES})</span>` : ''}
154
                                ${isMaxRetries ? '<span>Max retries reached. Check server setup instructions above.</span>' : ''}
155
                            </div>
156
                        </div>
157
                    </div>
158
                `;
159
                if (isMaxRetries) {
160
                    clearInterval(statusCheckInterval);
161
                    showTroubleshooting();
162
                }
163
                return false;
164
            }
165
        }
166
    }
167
168
    function showTroubleshooting() {
169
        const troubleshootingSection = document.getElementById('troubleshooting');
170
        if (troubleshootingSection) {
171
            troubleshootingSection.classList.add('active');
172
            troubleshootingSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
173
        }
174
    }
175
176
    // Initialize status checking
177
    async function initializeStatusCheck() {
178
        const isOnline = await checkServerStatus(true);
179
        
180
        if (!isOnline) {
181
            // If offline on first check, start checking more frequently initially
182
            statusCheckInterval = setInterval(() => checkServerStatus(), 5000);
183
            
184
            // After 30 seconds, switch to normal interval if server is still offline
185
            setTimeout(() => {
186
                clearInterval(statusCheckInterval);
187
                statusCheckInterval = setInterval(() => checkServerStatus(), 30000);
188
            }, 30000);
189
        } else {
190
            // If online, check every 30 seconds
191
            statusCheckInterval = setInterval(() => checkServerStatus(), 30000);
192
        }
193
    }
194
195
    // Start status checking
196
    initializeStatusCheck();
197
198
    // Cleanup on page unload
199
    window.addEventListener('unload', () => {
200
        if (statusCheckInterval) {
201
            clearInterval(statusCheckInterval);
202
        }
203
    });
204
205
    // Add animated appearance for steps
206
    const animateSteps = () => {
207
        const stepCards = document.querySelectorAll('.step-card');
208
        const observer = new IntersectionObserver((entries) => {
209
            entries.forEach((entry) => {
210
                if (entry.isIntersecting) {
211
                    entry.target.style.opacity = 1;
212
                    entry.target.style.transform = 'translateY(0)';
213
                    observer.unobserve(entry.target);
214
                }
215
            });
216
        }, {
217
            threshold: 0.1
218
        });
219
220
        stepCards.forEach((card, index) => {
221
            card.style.opacity = 0;
222
            card.style.transform = 'translateY(20px)';
223
            card.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
224
            card.style.transitionDelay = `${index * 0.1}s`;
225
            observer.observe(card);
226
        });
227
    };
228
229
    // Initialize animations
230
    setTimeout(animateSteps, 500);
231
});