| 61 | const tick = () => new Promise<void>(r => setTimeout(() => r(), 0)); |
| 62 | |
| 63 | export class ServerExecutor implements IExecutor { |
| 64 | socket?: SocketIOClient.Socket; |
| 65 | connectTimeout: number | null = null; |
| 66 | token: Promise<string | undefined>; |
| 67 | host?: string; |
| 68 | sandboxId?: string; |
| 69 | lastSent?: IFiles; |
| 70 | |
| 71 | constructor() { |
| 72 | this.token = this.retrieveSSEToken(); |
| 73 | } |
| 74 | |
| 75 | private async initializeSocket() { |
| 76 | if (!this.sandboxId) { |
| 77 | throw new Error('initializeSocket: sandboxId is not defined'); |
| 78 | } |
| 79 | const usedHost = this.host || 'https://codesandbox.io'; |
| 80 | const sseLbHost = usedHost.replace('https://', 'https://sse-lb.'); |
| 81 | const res = await axios.get(`${sseLbHost}/api/cluster/${this.sandboxId}`); |
| 82 | const sseHost = res.data.hostname; |
| 83 | |
| 84 | this.socket = io(sseHost, { |
| 85 | autoConnect: false, |
| 86 | transports: ['websocket', 'polling'], |
| 87 | }); |
| 88 | } |
| 89 | |
| 90 | async initialize({ sandboxId, files, host }: ISetupParams) { |
| 91 | if (this.sandboxId === sandboxId && this.socket?.connected) { |
| 92 | return; |
| 93 | } |
| 94 | |
| 95 | this.host = host; |
| 96 | this.sandboxId = sandboxId; |
| 97 | this.lastSent = files; |
| 98 | |
| 99 | await this.dispose(); |
| 100 | await tick(); |
| 101 | |
| 102 | await this.initializeSocket(); |
| 103 | } |
| 104 | |
| 105 | public async setup() { |
| 106 | debug('Setting up server executor...'); |
| 107 | |
| 108 | return this.openSocket(); |
| 109 | } |
| 110 | |
| 111 | public async dispose() { |
| 112 | if (this.socket) { |
| 113 | this.socket.removeAllListeners(); |
| 114 | this.socket.close(); |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | public updateFiles(newFiles: IFiles) { |
| 119 | const changedFiles = this.lastSent |
| 120 | ? getDiff(this.lastSent, newFiles) |
nothing calls this directly
no outgoing calls
no test coverage detected