Beispiel #1
0
// StreamListings takes a path and generates a assets.DirListing struct when it receives any signal, it will go through all the files within each listings.
func StreamListings(config ListingConfig) (flux.Reactor, error) {
	dir, err := assets.DirListings(config.Path, config.Validator, config.Mux)

	if err != nil {
		return nil, err
	}

	return flux.FlatSimple(func(root flux.Reactor, data interface{}) {
		if err := dir.Reload(); err != nil {
			root.ReplyError(err)
			return
		}

		// no error occured reloading, so we stream out the directory, list
		dir.Listings.Wo.RLock()
		for _, files := range dir.Listings.Tree {
			if config.DirAlso {
				if !config.UseRelative {
					root.Reply(files.AbsDir)
				} else {
					root.Reply(filepath.ToSlash(files.Dir))
				}
			}
			files.Tree.Each(func(mod, real string) {
				if !config.UseRelative {
					rel, err := filepath.Abs(real)
					if err != nil {
						rel = real
					}
					// log.Printf("Sending %s -> %s -> %s", files.AbsDir, real, rel)
					root.Reply(rel)
				} else {
					root.Reply(filepath.Join(files.Dir, real))
				}
			})
		}
		dir.Listings.Wo.RUnlock()

	}), nil
}
Beispiel #2
0
// Watch returns a task handler that watches a path for changes and passes down the file which changed
func Watch(m WatchConfig) flux.Reactor {
	var running bool
	mo := flux.Reactive(func(root flux.Reactor, err error, _ interface{}) {
		if err != nil {
			root.ReplyError(err)
			return
		}

		if running {
			return
		}

		stat, err := os.Stat(m.Path)

		if err != nil {
			root.ReplyError(err)
			go root.Close()
			return
		}

		running = true

		if !stat.IsDir() {
			flux.GoDefer("Watch", func() {
				defer root.Close()

				for {

					wo, err := fsnotify.NewWatcher()

					if err != nil {
						root.ReplyError(err)
						break
					}

					if err := wo.Add(m.Path); err != nil {
						wo.Close()
						break
					}

					select {
					case ev, ok := <-wo.Events:
						if ok {
							root.Reply(ev)
						}
					case erx, ok := <-wo.Errors:
						if ok {
							root.ReplyError(erx)
						}
					case <-root.CloseNotify():
						wo.Close()
						break
					}

					wo.Close()
				}
			})

			return
		}

		dir, err := assets.DirListings(m.Path, m.Validator, m.Mux)

		if err != nil {
			root.ReplyError(err)
			go root.Close()
			return
		}

		flux.GoDefer("Watch", func() {
			defer root.Close()

			for {

				wo, err := fsnotify.NewWatcher()

				if err != nil {
					root.ReplyError(err)
					break
				}

				dir.Listings.Wo.RLock()
				for _, files := range dir.Listings.Tree {
					wo.Add(files.AbsDir)
					files.Tree.Each(func(mod, real string) {
						rel, _ := filepath.Abs(real)
						wo.Add(rel)
						// wo.Add(filepath.Join(files.AbsDir, real))
					})
				}
				dir.Listings.Wo.RUnlock()

				select {
				case <-root.CloseNotify():
					wo.Close()
					break
				case ev, ok := <-wo.Events:
					if ok {
						file := filepath.Clean(ev.Name)
						// stat, _ := os.Stat(file)
						if (&m).Validator != nil {
							if (&m).Validator(file, nil) {
								root.Reply(ev)
							}
						} else {
							root.Reply(ev)
						}
					}
				case erx, ok := <-wo.Errors:
					if ok {
						root.ReplyError(erx)
					}
				}

				wo.Close()

				if err = dir.Reload(); err != nil {
					root.ReplyError(err)
				}

			}
		})

	})

	mo.Send(true)
	return mo
}
Beispiel #3
0
// WatchSet unlike Watch is not set for only working with one directory, by providing a WatchSetConfig you can supply multiple directories and files which will be sorted and watch if all paths were found to be invalid then the watcher will be closed and so will the task, an invalid file error will be forwarded down the reactor chain
func WatchSet(m WatchSetConfig) flux.Reactor {
	var running bool
	mo := flux.Reactive(func(root flux.Reactor, err error, _ interface{}) {
		if err != nil {
			root.ReplyError(err)
			return
		}

		if running {
			return
		}

		running = true

		var dirlistings []*assets.DirListing
		var files []string
		var dirsAdded = make(map[string]bool)

		for _, path := range m.Path {
			if dirsAdded[path] {
				continue
			}

			stat, err := os.Stat(path)
			if err != nil {
				// log.Printf("stat error: %s", err)
				root.ReplyError(err)
				continue
			}

			if stat.IsDir() {
				if dir, err := assets.DirListings(path, m.Validator, m.Mux); err == nil {
					dirsAdded[path] = true
					dirlistings = append(dirlistings, dir)
				} else {
					root.ReplyError(err)
				}
			} else {
				if !dirsAdded[filepath.Dir(path)] {
					files = append(files, path)
				}
			}
		}

		if len(dirlistings) <= 0 && len(files) <= 0 {
			log.Printf("no dirlistings, will close")
			go root.Close()
			log.Printf("no dirlistings, will close")
			return
		}

		flux.GoDefer("Watch", func() {
			defer root.Close()

			for {

				wo, err := fsnotify.NewWatcher()

				if err != nil {
					root.ReplyError(err)
					break
				}

				// var watched = make(map[string]bool)
				//reload all concerned directories into watcher
				for _, dir := range dirlistings {
					dir.Listings.Wo.RLock()
					for _, files := range dir.Listings.Tree {
						// log.Printf("Checking folder: %s", files.Dir)
						// if !watched[files.AbsDir] {
						// watched[files.AbsDir] = true
						wo.Add(files.AbsDir)
						// }

						files.Tree.Each(func(mod, real string) {
							// if watched[real] {
							// log.Printf("duplicate found %s -> %s -> %s", mod, real, files.AbsDir)
							// return
							// }

							// watched[real] = true
							rel, _ := filepath.Abs(real)
							wo.Add(rel)
							// if err != nil {
							// 	rel = real
							// }
							// wo.Add(filepath.Join(files.Dir, real))
							// wo.Add(filepath.Join(files.AbsDir, real))
						})
					}
					dir.Listings.Wo.RUnlock()
				}

				//reload all concerned files found in the path
				for _, file := range files {
					wo.Add(file)
				}

				select {
				case <-root.CloseNotify():
					break
				case ev, ok := <-wo.Events:
					if ok {
						if (&m).Validator != nil {
							file := filepath.Clean(ev.Name)
							// log.Printf("checking file: %s", file)
							if (&m).Validator(file, nil) {
								// log.Printf("passed file: %s", file)
								root.Reply(ev)
							}
						} else {
							// log.Printf("backdrop file: %s", ev)
							root.Reply(ev)
						}
					}
				case erx, ok := <-wo.Errors:
					if ok {
						root.ReplyError(erx)
					}
				}

				wo.Close()

				//reload all concerned directories
				for _, dir := range dirlistings {
					dir.Reload()
				}
			}
		})

	})

	mo.Send(true)
	return mo
}