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 } } }