UNPKG

@plotinus/matrix-package-observable-coordinator

Version:

Observable coordinator pattern components using IntrospectableBaseCommunicationComponent and proper presentation architecture

198 lines (174 loc) 6.41 kB
// Component source templates for the coordinator package export const componentSources = { // App component sources appCommunication: `class AppComponent extends window.Matrix.BaseCommunicationComponent { static dslTag = 'app'; static isMatrixComponent = true; startExecution() { console.log(\`App \${this.id} started\`); this.setState({ status: 'ready' }); } handleStartProcessing() { console.log('App: Starting processing'); this.sendCommand('myCoordinator', 'StartProcessing', { jobCount: 5 }); } handleCoordinatorReady() { console.log('App: Coordinator is ready, sending StartProcessing command'); this.sendCommand('myCoordinator', 'StartProcessing', { jobCount: 5 }); } handleCoordinatorDone(data) { console.log('App: All done!', data); this.setState({ completedJobs: data.completedJobIds }); } }`, appPresentation: `class AppPresentationElement extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } bindTo(commComponent) { this.commComponent = commComponent; this.render(); } render() { this.shadowRoot.innerHTML = \` <style> :host { display: block; } .app { border: 2px solid #8b5cf6; padding: 16px; border-radius: 8px; } button { background: #8b5cf6; color: white; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; } </style> <div class="app"> <h3>App: \${this.commComponent?.id}</h3> <button onclick="this.getRootNode().host.startProcessing()">Start Processing</button> <slot></slot> </div> \`; } startProcessing() { this.commComponent?.handleStartProcessing(); } }`, // Coordinator component sources coordinatorCommunication: `class CoordinatorComponent extends window.Matrix.BaseCommunicationComponent { static dslTag = 'coordinator'; static isMatrixComponent = true; constructor(id, eventBus) { super(id, eventBus); this.workers = new Set(); this.completedJobs = new Set(); this.jobQueue = []; } startExecution() { this.setState({ status: 'ready' }); this.emitEvent('CoordinatorReady'); } startProcessingHandler(data) { console.log('Coordinator: Starting processing'); console.log('Coordinator: Creating jobs'); for (let i = 0; i < (data.jobCount || 5); i++) { this.jobQueue.push({ id: \`job-\${i + 1}\` }); } this.distributeJobs(); } distributeJobs() { this.workers.forEach(workerId => { if (this.jobQueue.length > 0) { const job = this.jobQueue.shift(); this.sendCommand(workerId, 'ProcessJob', job); } }); } handleWorkerRegistered(data) { this.workers.add(data.workerId); this.setState({ workerCount: this.workers.size }); } handleWorkerJobCompleted(data) { this.completedJobs.add(data.jobId); if (this.jobQueue.length > 0) { const job = this.jobQueue.shift(); this.sendCommand(data.workerId, 'ProcessJob', job); } else if (this.completedJobs.size >= 5) { this.emitEvent('CoordinatorDone', { completedJobIds: Array.from(this.completedJobs) }); } } }`, coordinatorPresentation: `class CoordinatorPresentationElement extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } bindTo(commComponent) { this.commComponent = commComponent; // Subscribe to state changes if (commComponent.eventBus) { const stateKey = \`cmp:\${commComponent.id}:_stateChanged\`; commComponent.eventBus.on(stateKey, () => this.render()); } this.render(); } render() { const state = this.commComponent?.state || {}; this.shadowRoot.innerHTML = \` <style> :host { display: block; } .coordinator { border: 2px solid #58a6ff; padding: 16px; margin: 8px; border-radius: 8px; } </style> <div class="coordinator"> <h3>Coordinator: \${this.commComponent?.id}</h3> <div>Workers: \${state.workerCount || 0}</div> <slot></slot> </div> \`; } }`, // Worker component sources workerCommunication: `class WorkerComponent extends window.Matrix.BaseCommunicationComponent { static dslTag = 'worker'; static isMatrixComponent = true; startExecution() { this.setState({ jobsProcessed: 0 }); this.emitEvent('Registered', { workerId: this.id }); } processJobHandler(job) { console.log(\`Worker \${this.id}: Processing \${job.id}\`); setTimeout(() => { this.setState({ jobsProcessed: (this.state.jobsProcessed || 0) + 1 }); this.emitEvent('JobCompleted', { workerId: this.id, jobId: job.id }); }, 1000); } }`, workerPresentation: `class WorkerPresentationElement extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } bindTo(commComponent) { this.commComponent = commComponent; // Subscribe to state changes if (commComponent.eventBus) { const stateKey = \`cmp:\${commComponent.id}:_stateChanged\`; commComponent.eventBus.on(stateKey, () => this.render()); } this.render(); } render() { const state = this.commComponent?.state || {}; this.shadowRoot.innerHTML = \` <style> :host { display: block; } .worker { border: 2px solid #3fb950; padding: 12px; margin: 8px; border-radius: 6px; } </style> <div class="worker"> <h4>Worker: \${this.commComponent?.id}</h4> <div>Jobs: \${state.jobsProcessed || 0}</div> </div> \`; } }` };