watcher.js 2.5 KB

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