pyodideKernel.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import PyodideWorker from '$lib/pyodide/pyodideKernel.worker?worker';
  2. export type CellState = {
  3. id: string;
  4. status: 'idle' | 'running' | 'completed' | 'error';
  5. result: any;
  6. stdout: string;
  7. stderr: string;
  8. };
  9. export class PyodideKernel {
  10. private worker: Worker;
  11. private listeners: Map<string, (data: any) => void>;
  12. constructor() {
  13. this.worker = new PyodideWorker();
  14. this.listeners = new Map();
  15. // Listen to messages from the worker
  16. this.worker.onmessage = (event) => {
  17. const { type, id, ...data } = event.data;
  18. if ((type === 'stdout' || type === 'stderr') && this.listeners.has(id)) {
  19. this.listeners.get(id)?.({ type, id, ...data });
  20. } else if (type === 'result' && this.listeners.has(id)) {
  21. this.listeners.get(id)?.({ type, id, ...data });
  22. // Remove the listener once the result is delivered
  23. this.listeners.delete(id);
  24. } else if (type === 'kernelState') {
  25. this.listeners.forEach((listener) => listener({ type, ...data }));
  26. }
  27. };
  28. // Initialize the worker
  29. this.worker.postMessage({ type: 'initialize' });
  30. }
  31. async execute(id: string, code: string): Promise<CellState> {
  32. return new Promise((resolve, reject) => {
  33. // Set up the listener for streaming and execution result
  34. const state: CellState = {
  35. id,
  36. status: 'running',
  37. result: null,
  38. stdout: '',
  39. stderr: ''
  40. };
  41. this.listeners.set(id, (data) => {
  42. if (data.type === 'stdout') {
  43. state.stdout += data.message;
  44. } else if (data.type === 'stderr') {
  45. state.stderr += data.message;
  46. } else if (data.type === 'result') {
  47. // Final result
  48. const { state: finalState } = data;
  49. resolve(finalState);
  50. }
  51. });
  52. // Send execute request to the worker
  53. this.worker.postMessage({ type: 'execute', id, code });
  54. });
  55. }
  56. async getState() {
  57. return new Promise<Record<string, CellState>>((resolve) => {
  58. this.worker.postMessage({ type: 'getState' });
  59. this.listeners.set('kernelState', (data) => {
  60. if (data.type === 'kernelState') {
  61. resolve(data.state);
  62. }
  63. });
  64. });
  65. }
  66. terminate() {
  67. this.worker.postMessage({ type: 'terminate' });
  68. this.worker.terminate();
  69. }
  70. }