PageSourceSearch

https://stringart.ro/workers/algo2-worker-manager.js

js stringart.ro collected 2026-10-02 14:28:58 UTC 7,663 bytes, 255 lines download raw bytes

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.