1// Web Worker Manager for Algo2 (Image Stylization Threading Algorithm) 2// Provides the same interface as the original algorithm but uses Web Workers for parallel execution 3 4class Algo2WorkerManager { 5 constructor() { 6 this.worker = null; 7 this.progressCallback = null; 8 this.isInitialized = false; 9 this.isCompleted = false; 10 this.lastResult = null; 11 this.lastState = null; 12 this.lastSvg = null; 13 this.pendingStateResolvers = []; 14 this.pendingSvgResolvers = []; 15 } 16 17 // Initialize the worker 18 init(numPins, width = 510, height = 510) { 19 return new Promise((resolve, reject) => { 20 try { 21 // Create new worker 22 this.worker = new Worker('/workers/algo2-worker-complete.js'); 23 24 // Set up message handler 25 this.worker.onmessage = (e) => { 26 const { type, data } = e.data; 27 28 switch (type) { 29 case 'initComplete': 30 this.isInitialized = true; 31 resolve(data); 32 break; 33 34 case 'progress': 35 if (this.progressCallback) { 36 this.progressCallback(data); 37 } 38 break; 39 40 case 'complete': 41 // Debug logging for worker messages (only when DEBUG_ALGO2 is enabled) 42 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 43 console.log('Algo2 Complete message received:', { 44 hasState: !!data.state, 45 hasSvg: !!data.svg, 46 svgLength: data.svg?.length || 0, 47 lineCount: data.lineCount 48 }); 49 console.log('Cached data:', { 50 hasState: !!this.lastState, 51 hasSvg: !!this.lastSvg, 52 svgLength: this.lastSvg?.length || 0 53 }); 54 } 55 this.lastResult = data; 56 this.lastState = data.state; 57 this.lastSvg = data.svg; 58 59 // Mark as completed for immediate access 60 this.isCompleted = true; 61 62 // Resolve all pending getState() calls 63 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 64 console.log('Resolving', this.pendingStateResolvers.length, 'pending state resolvers'); 65 } 66 this.pendingStateResolvers.forEach(resolve => resolve(this.lastState)); 67 this.pendingStateResolvers = []; 68 69 // Resolve all pending getSvg() calls 70 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 71 console.log('Resolving', this.pendingSvgResolvers.length, 'pending SVG resolvers'); 72 } 73 this.pendingSvgResolvers.forEach(resolve => resolve(this.lastSvg)); 74 this.pendingSvgResolvers = []; 75 76 if (this.progressCallback) { 77 this.progressCallback({ 78 progress: 100, 79 lineCount: data.lineCount, 80 lineLimit: data.lineCount 81 }); 82 } 83 break; 84 85 case 'state': 86 this.lastState = data; 87 break; 88 89 case 'svg': 90 this.lastSvg = data; 91 break; 92 93 case 'error': 94 console.error('Algo2 Worker error:', data.error); 95 reject(new Error(data.error)); 96 break; 97 98 case 'stopped': 99 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 100 console.log('Algo2 Worker stopped'); 101 } 102 break; 103 } 104 }; 105 106 this.worker.onerror = (error) => { 107 console.error('Algo2 Worker error:', error); 108 reject(error); 109 }; 110 111 // Initialize the worker 112 this.worker.postMessage({ 113 type: 'init', 114 data: { 115 numPins, 116 width: width, 117 height: height 118 } 119 }); 120 121 } catch (error) { 122 reject(error); 123 } 124 }); 125 } 126 127 // Start the algorithm 128 start(params) { 129 if (!this.worker || !this.isInitialized) { 130 throw new Error('Algo2 Worker not initialized'); 131 } 132 133 return new Promise((resolve, reject) => { 134 // Set up completion handler 135 const originalCallback = this.progressCallback; 136 let completed = false;
137 138 this.progressCallback = (progress) => { 139 if (originalCallback) { 140 originalCallback(progress); 141 } 142 143 // Check for completion 144 if (progress.progress >= 100 && !completed) { 145 completed = true; 146 resolve(); 147 } 148 }; 149 150 try { 151 this.worker.postMessage({ 152 type: 'start', 153 data: params 154 }); 155 } catch (error) { 156 reject(error); 157 } 158 }); 159 } 160 161 // Set progress callback 162 onProgress(callback) { 163 this.progressCallback = callback; 164 } 165 166 // Get current state 167 getState() { 168 return new Promise((resolve) => { 169 // Return cached state from completion if available 170 if (this.isCompleted && this.lastState !== null && this.lastState !== undefined) { 171 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 172 console.log('Returning cached state:', !!this.lastState); 173 } 174 resolve(this.lastState); 175 return; 176 } 177 178 if (!this.worker || !this.isInitialized) { 179 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 180 console.log('Worker not available for getState'); 181 } 182 resolve(null); 183 return; 184 } 185 186 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 187 console.log('Adding state resolver to pending queue'); 188 } 189 190 // Add to pending resolvers - will be resolved when 'complete' message arrives 191 this.pendingStateResolvers.push(resolve); 192 193 // Also try direct request as fallback 194 this.worker.postMessage({ type: 'getState' }); 195 }); 196 } 197 198 // Get SVG output 199 getSvg() { 200 return new Promise((resolve) => { 201 // Return cached SVG from completion if available 202 if (this.isCompleted && this.lastSvg !== null && this.lastSvg !== undefined) { 203 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 204 console.log('Returning cached SVG:', this.lastSvg.length, 'chars'); 205 } 206 resolve(this.lastSvg); 207 return; 208 } 209 210 if (!this.worker || !this.isInitialized) { 211 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 212 console.log('Worker not available for getSvg'); 213 } 214 resolve(''); 215 return; 216 } 217 218 if (typeof self !== 'undefined' && self.DEBUG_ALGO2) { 219 console.log('Adding SVG resolver to pending queue'); 220 } 221 222 // Add to pending resolvers - will be resolved when 'complete' message arrives 223 this.pendingSvgResolvers.push(resolve); 224 225 // Also try direct request as fallback 226 this.worker.postMessage({ type: 'getSvg' }); 227 }); 228 } 229 230 // Stop the algorithm 231 stop() { 232 if (this.worker) { 233 this.worker.postMessage({ type: 'stop' }); 234 } 235 } 236 237 // Terminate the worker 238 terminate() { 239 if (this.worker) { 240 this.worker.terminate(); 241 this.worker = null; 242 this.isInitialized = false; 243 } 244 } 245} 246 247// Export for use in main thread 248if (typeof window !== 'undefined') { 249 window.Algo2WorkerManager = Algo2WorkerManager; 250} 251 252// Export for Node.js if needed 253if (typeof module !== 'undefined' && module.exports) { 254 module.exports = Algo2WorkerManager; 255}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.