333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
'use strict';
 
const Base = require('sdk-base');
const utils = require('./utils');
const camelcase = require('camelcase');
 
module.exports = class Watcher extends Base {
  constructor(config) {
    super();
 
    const options = config.watcher;
 
    let EventSource = options.eventSources[options.type];
    if (typeof EventSource === 'string') {
      EventSource = require(EventSource);
    }
 
    // chokidar => watcherChokidar
    // custom => watcherCustom
    const key = camelcase([ 'watcher', options.type ]);
    const eventSourceOpts = config[key];
    this._eventSource = new EventSource(eventSourceOpts)
      .on('change', this._onChange.bind(this))
      .on('fuzzy-change', this._onFuzzyChange.bind(this))
      .on('info', (...args) => this.emit('info', ...args))
      .on('warn', (...args) => this.emit('warn', ...args))
      .on('error', (...args) => this.emit('error', ...args));
 
    this._eventSource.ready(() => this.ready(true));
  }
 
  watch(path, callback) {
    this.emit('info', '[egg-watcher] Start watching: %j', path);
    if (!path) return;
 
    // support array
    if (Array.isArray(path)) {
      path.forEach(p => this.watch(p, callback));
      return;
    }
 
    // one file only watch once
    if (!this.listenerCount(path)) this._eventSource.watch(path);
    this.on(path, callback);
  }
 
  /*
  // TODO wait unsubscribe implementation of cluster-client
  unwatch(path, callback) {
    if (!path) return;
 
    // support array
    if (Array.isArray(path)) {
      path.forEach(p => this.unwatch(p, callback));
      return;
    }
 
    if (callback) {
      this.removeListener(path, callback);
      // stop watching when no listener bound to the path
      if (this.listenerCount(path) === 0) {
        this._eventSource.unwatch(path);
      }
      return;
    }
 
    this.removeAllListeners(path);
    this._eventSource.unwatch(path);
  }
  */
 
  _onChange(info) {
    this.emit('info', '[egg-watcher] Recieved a change event from eventSource: %j', info);
    const path = info.path;
 
    for (const p in this._events) {
      // if it is a sub path, emit a `change` event
      if (utils.isEqualOrParentPath(p, path)) {
        this.emit(p, info);
      }
    }
  }
 
  _onFuzzyChange(info) {
    this.emit('info', '[egg-watcher] Recieved a fuzzy-change event from eventSource: %j', info);
    const path = info.path;
 
    for (const p in this._events) {
      // if it is a parent path, emit a `change` event
      // just the oppsite to `_onChange`
      if (utils.isEqualOrParentPath(path, p)) {
        this.emit(p, info);
      }
    }
  }
 
};