fsnotify-demo/notify.go

266 lines
5.3 KiB
Go

package main
import (
"context"
"fmt"
"log"
"math/rand"
"os"
"os/signal"
"path/filepath"
"sync"
"syscall"
"time"
"github.com/fsnotify/fsnotify"
)
const (
createFile = iota
writeFile
deleteFile
)
func main() {
var (
watcher *fsnotify.Watcher
err error
dir2Watch string
)
if dir2Watch, err = checkArgs(); err != nil {
log.Fatal("Error:", err)
}
if watcher, err = fsnotify.NewWatcher(); err != nil {
log.Fatal("Error:", err)
}
defer func() {
_ = watcher.Close()
}()
ctx, cancel := context.WithCancel(context.Background())
go watcherFunc(ctx, watcher)
if err = watcher.Add(dir2Watch); err != nil {
log.Fatal("Error:", err)
}
// sm := new(sync.Map)
// go createEmptyAndDelete(ctx, sm, time.Second, time.Second, dir2Watch)
// go createWriteAndDelete(ctx, sm, time.Second+(time.Millisecond*100), time.Millisecond*200, dir2Watch)
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGTERM)
fmt.Println("watching the directory, press ctrl-c to stop...")
<-done
cancel()
fmt.Println()
fmt.Println("ended")
}
func watcherFunc(ctx context.Context, watcher *fsnotify.Watcher) {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("event:", event)
if event.Has(fsnotify.Write) {
log.Println("written to file:", event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("Error:", err)
case <-ctx.Done():
return
}
}
}
func checkArgs() (string, error) {
if len(os.Args) != 2 {
return "", fmt.Errorf("invalid arguments")
}
fi, err := os.Stat(os.Args[1])
if err != nil {
return "", err
}
if !fi.IsDir() {
return "", fmt.Errorf("not a directory")
}
return os.Args[1], nil
}
func genUniqueRandomString(sm *sync.Map, len uint) string {
for {
rs := genRandomString(len)
if _, ok := sm.LoadOrStore(rs, nil); !ok {
return rs
}
}
}
func genRandomString(len uint) string {
if len == 0 {
return ""
}
b := make([]byte, len)
var i uint
for i = 0; i < len; i++ {
b[i] = byte(rand.Intn(52))
if b[i] >= 26 {
b[i] += 97 - 26
} else {
b[i] += 65
}
}
return string(b)
}
func createEmptyAndDelete(ctx context.Context, sm *sync.Map, initialWait time.Duration, iterWait time.Duration, dir string) {
if initialWait < 0 {
log.Println("initialWait cannot be less than 0")
return
}
if iterWait < 0 {
log.Println("iterWait cannot be less than 0")
}
tick := time.NewTicker(initialWait)
defer tick.Stop()
var (
next = createFile
nextFileName string
nextFile string
f *os.File
err error
)
nextFile = genUniqueRandomString(sm, 6)
nextFileName = nextFile + ".txt"
for {
select {
case <-tick.C:
tick.Stop()
switch {
case next == createFile:
nextFileName = filepath.Join(dir, nextFileName)
log.Printf("creating file: %s\n", nextFileName)
if f, err = os.OpenFile(nextFileName, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666); err != nil {
log.Printf("Error creating file %s: %+v\n", nextFileName, err)
return
}
_ = f.Close()
next = deleteFile
case next == deleteFile:
if err = os.Remove(nextFileName); err != nil {
log.Printf("Error deleting file %s: %+v\n", nextFileName, err)
return
}
next = createFile
sm.Delete(nextFile)
nextFile = genUniqueRandomString(sm, 6)
nextFileName = nextFile + ".txt"
}
tick.Reset(iterWait)
case <-ctx.Done():
if next == deleteFile {
_ = os.Remove(nextFileName)
}
return
}
}
}
func createWriteAndDelete(ctx context.Context, sm *sync.Map, initialWait time.Duration, iterWait time.Duration, dir string) {
if initialWait < 0 {
log.Println("initialWait cannot be less than 0")
return
}
if iterWait < 0 {
log.Println("iterWait cannot be less than 0")
}
tick := time.NewTicker(initialWait)
defer tick.Stop()
var (
next = createFile
nextFileName string
nextFile string
f *os.File
err error
currLen int64
wLen int
targetLen int64
)
targetLen = 2 * 102400
nextFile = genUniqueRandomString(sm, 6)
nextFileName = nextFile + ".txt"
for {
select {
case <-tick.C:
tick.Stop()
switch {
case next == createFile:
nextFileName = filepath.Join(dir, nextFileName)
log.Printf("creating file: %s\n", nextFileName)
if f, err = os.OpenFile(nextFileName, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666); err != nil {
log.Printf("Error creating file %s: %+v\n", nextFileName, err)
return
}
next = writeFile
case next == writeFile:
if wLen, err = f.WriteString(genRandomString(1024)); err != nil {
log.Printf("Error writing file %s: %+v\n", nextFileName, err)
_ = f.Close()
_ = os.Remove(nextFileName)
return
}
currLen += int64(wLen)
log.Printf("written %d of %d bytes to %s\n", currLen, targetLen, nextFileName)
if currLen > targetLen {
_ = f.Close()
next = deleteFile
}
case next == deleteFile:
if err = os.Remove(nextFileName); err != nil {
log.Printf("Error deleting file %s: %+v\n", nextFileName, err)
return
}
next = createFile
sm.Delete(nextFile)
nextFile = genUniqueRandomString(sm, 6)
nextFileName = nextFile + ".txt"
}
tick.Reset(iterWait)
case <-ctx.Done():
if next == deleteFile {
_ = os.Remove(nextFileName)
}
return
}
}
}