mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 21:16:26 +01:00 
			
		
		
		
	To keep blame info accurate and to avoid [changes like this](https://github.com/go-gitea/gitea/pull/29977/files#diff-c3422631a14edbe1e508c4b22f0c718db318be08a6e889427802f9b6165d88d6R359), it's good to always have a trailing comma, so let's enforce it in JS. This rule is completely automatically fixable with `make lint-js-fix` and that's what I did here.
		
			
				
	
	
		
			142 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
const sourcesByUrl = {};
 | 
						|
const sourcesByPort = {};
 | 
						|
 | 
						|
class Source {
 | 
						|
  constructor(url) {
 | 
						|
    this.url = url;
 | 
						|
    this.eventSource = new EventSource(url);
 | 
						|
    this.listening = {};
 | 
						|
    this.clients = [];
 | 
						|
    this.listen('open');
 | 
						|
    this.listen('close');
 | 
						|
    this.listen('logout');
 | 
						|
    this.listen('notification-count');
 | 
						|
    this.listen('stopwatches');
 | 
						|
    this.listen('error');
 | 
						|
  }
 | 
						|
 | 
						|
  register(port) {
 | 
						|
    if (this.clients.includes(port)) return;
 | 
						|
 | 
						|
    this.clients.push(port);
 | 
						|
 | 
						|
    port.postMessage({
 | 
						|
      type: 'status',
 | 
						|
      message: `registered to ${this.url}`,
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  deregister(port) {
 | 
						|
    const portIdx = this.clients.indexOf(port);
 | 
						|
    if (portIdx < 0) {
 | 
						|
      return this.clients.length;
 | 
						|
    }
 | 
						|
    this.clients.splice(portIdx, 1);
 | 
						|
    return this.clients.length;
 | 
						|
  }
 | 
						|
 | 
						|
  close() {
 | 
						|
    if (!this.eventSource) return;
 | 
						|
 | 
						|
    this.eventSource.close();
 | 
						|
    this.eventSource = null;
 | 
						|
  }
 | 
						|
 | 
						|
  listen(eventType) {
 | 
						|
    if (this.listening[eventType]) return;
 | 
						|
    this.listening[eventType] = true;
 | 
						|
    this.eventSource.addEventListener(eventType, (event) => {
 | 
						|
      this.notifyClients({
 | 
						|
        type: eventType,
 | 
						|
        data: event.data,
 | 
						|
      });
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  notifyClients(event) {
 | 
						|
    for (const client of this.clients) {
 | 
						|
      client.postMessage(event);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  status(port) {
 | 
						|
    port.postMessage({
 | 
						|
      type: 'status',
 | 
						|
      message: `url: ${this.url} readyState: ${this.eventSource.readyState}`,
 | 
						|
    });
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
self.addEventListener('connect', (e) => {
 | 
						|
  for (const port of e.ports) {
 | 
						|
    port.addEventListener('message', (event) => {
 | 
						|
      if (!self.EventSource) {
 | 
						|
        // some browsers (like PaleMoon, Firefox<53) don't support EventSource in SharedWorkerGlobalScope.
 | 
						|
        // this event handler needs EventSource when doing "new Source(url)", so just post a message back to the caller,
 | 
						|
        // in case the caller would like to use a fallback method to do its work.
 | 
						|
        port.postMessage({type: 'no-event-source'});
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      if (event.data.type === 'start') {
 | 
						|
        const url = event.data.url;
 | 
						|
        if (sourcesByUrl[url]) {
 | 
						|
          // we have a Source registered to this url
 | 
						|
          const source = sourcesByUrl[url];
 | 
						|
          source.register(port);
 | 
						|
          sourcesByPort[port] = source;
 | 
						|
          return;
 | 
						|
        }
 | 
						|
        let source = sourcesByPort[port];
 | 
						|
        if (source) {
 | 
						|
          if (source.eventSource && source.url === url) return;
 | 
						|
 | 
						|
          // How this has happened I don't understand...
 | 
						|
          // deregister from that source
 | 
						|
          const count = source.deregister(port);
 | 
						|
          // Clean-up
 | 
						|
          if (count === 0) {
 | 
						|
            source.close();
 | 
						|
            sourcesByUrl[source.url] = null;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        // Create a new Source
 | 
						|
        source = new Source(url);
 | 
						|
        source.register(port);
 | 
						|
        sourcesByUrl[url] = source;
 | 
						|
        sourcesByPort[port] = source;
 | 
						|
      } else if (event.data.type === 'listen') {
 | 
						|
        const source = sourcesByPort[port];
 | 
						|
        source.listen(event.data.eventType);
 | 
						|
      } else if (event.data.type === 'close') {
 | 
						|
        const source = sourcesByPort[port];
 | 
						|
 | 
						|
        if (!source) return;
 | 
						|
 | 
						|
        const count = source.deregister(port);
 | 
						|
        if (count === 0) {
 | 
						|
          source.close();
 | 
						|
          sourcesByUrl[source.url] = null;
 | 
						|
          sourcesByPort[port] = null;
 | 
						|
        }
 | 
						|
      } else if (event.data.type === 'status') {
 | 
						|
        const source = sourcesByPort[port];
 | 
						|
        if (!source) {
 | 
						|
          port.postMessage({
 | 
						|
            type: 'status',
 | 
						|
            message: 'not connected',
 | 
						|
          });
 | 
						|
          return;
 | 
						|
        }
 | 
						|
        source.status(port);
 | 
						|
      } else {
 | 
						|
        // just send it back
 | 
						|
        port.postMessage({
 | 
						|
          type: 'error',
 | 
						|
          message: `received but don't know how to handle: ${event.data}`,
 | 
						|
        });
 | 
						|
      }
 | 
						|
    });
 | 
						|
    port.start();
 | 
						|
  }
 | 
						|
});
 |