github.com/abolfazlbeh/zhycan@v0.0.0-20230819144214-24cf38237387/internal/watcher/manager.go (about)

     1  package watcher
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/abolfazlbeh/zhycan/internal/config"
     6  	"github.com/radovskyb/watcher"
     7  	"log"
     8  	"regexp"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  // Mark: manager
    14  
    15  // Manager object
    16  type manager struct {
    17  	name              string
    18  	watcher           *watcher.Watcher
    19  	lock              sync.Mutex
    20  	isInitialized     bool
    21  	printWatchedFiles bool
    22  	watchInterval     int
    23  }
    24  
    25  type watchDirStruct struct {
    26  	Path      string
    27  	Recursive bool
    28  }
    29  
    30  // MARK: Module variables
    31  var managerInstance *manager = nil
    32  var once sync.Once
    33  
    34  // MARK: Module Initializer
    35  func init() {
    36  	log.Println("Initializing Watcher Manager ...")
    37  }
    38  
    39  // MARK: Private Methods
    40  
    41  // init - Constructor -> It initializes the config configuration params
    42  func (m *manager) init() {
    43  	log.Println("Constructing Watcher Manager ...")
    44  
    45  	m.name = "watcher"
    46  	m.isInitialized = false
    47  	m.printWatchedFiles = false
    48  	m.watchInterval = 100
    49  
    50  	m.lock.Lock()
    51  	defer m.lock.Unlock()
    52  
    53  	// read filter options
    54  	filterOptions, err := config.GetManager().Get(m.name, "filter_operations")
    55  	if err != nil {
    56  		return
    57  	}
    58  
    59  	var filterOptionsArray []string
    60  	for _, v := range filterOptions.([]interface{}) {
    61  		filterOptionsArray = append(filterOptionsArray, v.(string))
    62  	}
    63  
    64  	filterHooks, err := config.GetManager().Get(m.name, "filter_hooks")
    65  	if err != nil {
    66  		return
    67  	}
    68  
    69  	var filterHooksArray []string
    70  	for _, v := range filterHooks.([]interface{}) {
    71  		filterHooksArray = append(filterHooksArray, v.(string))
    72  	}
    73  
    74  	maxEvent, err := config.GetManager().Get(m.name, "max_event")
    75  	if err != nil {
    76  		return
    77  	}
    78  
    79  	printWatchedFiles, err := config.GetManager().Get(m.name, "print_watched_files")
    80  	if err != nil {
    81  		return
    82  	}
    83  	m.printWatchedFiles = printWatchedFiles.(bool)
    84  
    85  	watchInterval, err := config.GetManager().Get(m.name, "watch_interval")
    86  	if err != nil {
    87  		return
    88  	}
    89  	m.watchInterval = watchInterval.(int)
    90  
    91  	var watchDirs []watchDirStruct
    92  	watchDirsObj, err := config.GetManager().Get(m.name, "watch_dirs")
    93  	if err != nil {
    94  		return
    95  	}
    96  
    97  	for _, v := range watchDirsObj.([]interface{}) {
    98  		item := v.(map[string]interface{})
    99  		watchDirs = append(watchDirs, watchDirStruct{
   100  			Path:      item["path"].(string),
   101  			Recursive: item["recursive"].(bool),
   102  		})
   103  	}
   104  
   105  	// Let's config a watcher
   106  	m.watcher = watcher.New()
   107  
   108  	var filterOps []watcher.Op
   109  	for _, item := range filterOptionsArray {
   110  		switch item {
   111  		case "create":
   112  			filterOps = append(filterOps, watcher.Create)
   113  			break
   114  		case "move":
   115  			filterOps = append(filterOps, watcher.Move)
   116  			break
   117  		case "rename":
   118  			filterOps = append(filterOps, watcher.Rename)
   119  			break
   120  		case "remove":
   121  			filterOps = append(filterOps, watcher.Remove)
   122  			break
   123  		case "write":
   124  			filterOps = append(filterOps, watcher.Write)
   125  			break
   126  		}
   127  	}
   128  
   129  	m.watcher.FilterOps(filterOps...)
   130  
   131  	for _, item := range filterHooksArray {
   132  		m.watcher.AddFilterHook(watcher.RegexFilterHook(
   133  			regexp.MustCompile(item), false))
   134  	}
   135  
   136  	m.watcher.SetMaxEvents(maxEvent.(int))
   137  
   138  	for _, item := range watchDirs {
   139  		if item.Recursive {
   140  			if err := m.watcher.AddRecursive(item.Path); err != nil {
   141  				continue
   142  			}
   143  		} else {
   144  			if err := m.watcher.Add(item.Path); err != nil {
   145  				continue
   146  			}
   147  		}
   148  	}
   149  
   150  	m.isInitialized = true
   151  }
   152  
   153  // restartOnChangeConfig - subscribe a function for when the config is changed
   154  func (m *manager) restartOnChangeConfig() {
   155  	m.lock.Lock()
   156  	defer m.lock.Unlock()
   157  
   158  	// Config config server to reload
   159  	wrapper, err := config.GetManager().GetConfigWrapper(m.name)
   160  	if err == nil {
   161  		wrapper.RegisterChangeCallback(func() interface{} {
   162  			m.Stop()
   163  			m.init()
   164  			m.Start()
   165  			return nil
   166  		})
   167  	} else {
   168  		// TODO: make some logs
   169  	}
   170  }
   171  
   172  // MARK: Public Functions
   173  
   174  // GetManager - This function returns singleton instance of Logger Manager
   175  func GetManager() *manager {
   176  	// once used for prevent race condition and manage critical section.
   177  	once.Do(func() {
   178  		managerInstance = &manager{}
   179  		managerInstance.init()
   180  		managerInstance.restartOnChangeConfig()
   181  	})
   182  	return managerInstance
   183  }
   184  
   185  // Start - start the watcher and listen for changes
   186  func (m *manager) Start() (bool, error) {
   187  	m.lock.Lock()
   188  	defer m.lock.Unlock()
   189  
   190  	if m.printWatchedFiles {
   191  		for path, f := range m.watcher.WatchedFiles() {
   192  			fmt.Printf("%s: %s\n", path, f.Name())
   193  		}
   194  	}
   195  
   196  	if err := m.watcher.Start(time.Millisecond * time.Duration(m.watchInterval)); err != nil {
   197  		return false, NewStartWatcherErr(err)
   198  	}
   199  
   200  	return true, nil
   201  }
   202  
   203  // Stop - stop the watcher and listen for changes
   204  func (m *manager) Stop() {
   205  	m.lock.Lock()
   206  	defer m.lock.Unlock()
   207  
   208  	m.watcher.Close()
   209  	<-m.watcher.Closed
   210  }