http-boot-server/bootserver/filelock/filelock.go

55 lines
1 KiB
Go
Raw Normal View History

2023-07-30 09:20:45 +00:00
package filelock
import (
"errors"
"fmt"
"os"
"path"
"time"
)
var ErrLocked = errors.New("failed to get a lock in a timely manner")
type FileLock struct {
lockPath string
}
func New(filepath string) *FileLock {
dir, filename := path.Split(filepath)
lockPath := path.Join(dir, fmt.Sprintf(".%s.lock", filename))
return &FileLock{
lockPath: lockPath,
}
}
func (fl *FileLock) lockFileExists() bool {
if _, err := os.Stat(fl.lockPath); errors.Is(err, os.ErrNotExist) {
return false
}
return true
}
func (fl *FileLock) Lock(timeout time.Duration) error {
start := time.Now().UTC()
end := start.Add(timeout)
for {
if !fl.lockFileExists() {
if _, err := os.Create(fl.lockPath); err != nil {
return fmt.Errorf("failed to create lock: %w", err)
}
}
if time.Now().After(end) {
return ErrLocked
}
time.Sleep(100 * time.Millisecond)
}
}
func (fl *FileLock) Unlock() error {
if err := os.Remove(fl.lockPath); err != nil {
return fmt.Errorf("failed to remove lock: %w", err)
}
return nil
}