mirror of
https://github.com/OpenFactorioServerManager/factorio-server-manager.git
synced 2025-01-24 05:17:24 +02:00
finally got rid of the race-conditions (Usability will be fixed later)
This commit is contained in:
parent
5703a22544
commit
8179e2c917
@ -5,6 +5,8 @@ import (
|
||||
"path"
|
||||
"os"
|
||||
"log"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FileLock struct {
|
||||
@ -17,8 +19,13 @@ type Lock struct {
|
||||
Write int
|
||||
}
|
||||
|
||||
func newLock() FileLock {
|
||||
lock := FileLock{}
|
||||
var ErrorLocking error = errors.New("error locking file")
|
||||
var ErrorAlreadyLocked error = errors.New("file already locke by another routine")
|
||||
|
||||
func NewLock() FileLock {
|
||||
lock := FileLock{
|
||||
Locks: make(map[string]Lock),
|
||||
}
|
||||
return lock
|
||||
}
|
||||
|
||||
@ -36,70 +43,103 @@ func makeAbsolutePath(target string) string {
|
||||
return path.Join(wd, target)
|
||||
}
|
||||
|
||||
func (fl *FileLock) Lock(path string) {
|
||||
func (fl *FileLock) Lock(filePath string) error {
|
||||
fl.m.Lock()
|
||||
defer fl.m.Unlock()
|
||||
|
||||
path = makeAbsolutePath(path)
|
||||
filePath = makeAbsolutePath(filePath)
|
||||
|
||||
if fl.Locks[path].Read == 0 && fl.Locks[path].Write == 0 {
|
||||
lock := fl.Locks[path]
|
||||
if fl.Locks[filePath].Read == 0 && fl.Locks[filePath].Write == 0 {
|
||||
lock := fl.Locks[filePath]
|
||||
lock.Write = 1
|
||||
fl.Locks[path] = lock
|
||||
fl.Locks[filePath] = lock
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("write locked")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fl *FileLock) Unlock(path string) {
|
||||
func (fl *FileLock) Unlock(filePath string) error {
|
||||
fl.m.Lock()
|
||||
defer fl.m.Unlock()
|
||||
|
||||
path = makeAbsolutePath(path)
|
||||
filePath = makeAbsolutePath(filePath)
|
||||
|
||||
lock := fl.Locks[path]
|
||||
lock := fl.Locks[filePath]
|
||||
if lock.Read == 0 && lock.Write == 1 {
|
||||
lock.Write = 0
|
||||
fl.Locks[path] = lock
|
||||
fl.Locks[filePath] = lock
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("write unlocked")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fl *FileLock) RLock(path string) {
|
||||
func (fl *FileLock) RLock(filePath string) error {
|
||||
fl.m.Lock()
|
||||
defer fl.m.Unlock()
|
||||
|
||||
path = makeAbsolutePath(path)
|
||||
filePath = makeAbsolutePath(filePath)
|
||||
|
||||
lock := fl.Locks[path]
|
||||
lock := fl.Locks[filePath]
|
||||
if lock.Write == 0 {
|
||||
lock.Read++
|
||||
fl.Locks[path] = lock
|
||||
fl.Locks[filePath] = lock
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("read locked")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fl *FileLock) RUnlock(path string) {
|
||||
func (fl *FileLock) RUnlock(filePath string) error {
|
||||
fl.m.Lock()
|
||||
defer fl.m.Unlock()
|
||||
|
||||
path = makeAbsolutePath(path)
|
||||
filePath = makeAbsolutePath(filePath)
|
||||
|
||||
lock := fl.Locks[path]
|
||||
lock := fl.Locks[filePath]
|
||||
if lock.Read > 0 && lock.Write == 0 {
|
||||
lock.Read--
|
||||
fl.Locks[path] = lock
|
||||
fl.Locks[filePath] = lock
|
||||
} else {
|
||||
return ErrorAlreadyLocked
|
||||
}
|
||||
log.Println("read unlocked")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fl *FileLock) LockW(path string) {
|
||||
func (fl *FileLock) LockW(filePath string) {
|
||||
log.Println("LockW called")
|
||||
for {
|
||||
err := fl.Lock(filePath)
|
||||
log.Println(err)
|
||||
if err == ErrorAlreadyLocked {
|
||||
time.Sleep(time.Second * 2)
|
||||
log.Println("file locked wait two seconds to access write-lock")
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (fl *FileLock) UnlockW(path string) {
|
||||
return
|
||||
}
|
||||
func (fl *FileLock) RLockW(filePath string) {
|
||||
for {
|
||||
err := fl.RLock(filePath)
|
||||
|
||||
func (fl *FileLock) RLockW(path string) {
|
||||
return
|
||||
}
|
||||
if err == ErrorAlreadyLocked {
|
||||
time.Sleep(time.Second * 2)
|
||||
log.Println("file locked wait two seconds to access read-lock")
|
||||
}
|
||||
|
||||
func (fl *FileLock) RUnlockW(path string) {
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ type ModsResultList struct {
|
||||
ModsResult []ModsResult `json:"mods"`
|
||||
}
|
||||
|
||||
var fileLock lockfile.FileLock = lockfile.newLock()
|
||||
var fileLock lockfile.FileLock = lockfile.NewLock()
|
||||
|
||||
func newMods(destination string) (Mods, error) {
|
||||
var err error
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"io"
|
||||
"lockfile"
|
||||
)
|
||||
|
||||
type ModInfoList struct {
|
||||
@ -44,6 +45,16 @@ func (mod_info_list *ModInfoList) listInstalledMods() (error) {
|
||||
|
||||
err = filepath.Walk(mod_info_list.Destination, func(path string, info os.FileInfo, err error) error {
|
||||
if !info.IsDir() && filepath.Ext(path) == ".zip" {
|
||||
err = fileLock.RLock(path)
|
||||
if err != nil && err == lockfile.ErrorAlreadyLocked {
|
||||
log.Println(err)
|
||||
return nil
|
||||
} else if err != nil {
|
||||
log.Printf("error locking file: %s", err)
|
||||
return err
|
||||
}
|
||||
defer fileLock.RUnlock(path)
|
||||
|
||||
zip_file, err := zip.OpenReader(path)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
@ -77,8 +88,12 @@ func (mod_info_list *ModInfoList) deleteMod(mod_name string) (error) {
|
||||
//search for mod, that should be deleted
|
||||
for _, mod := range mod_info_list.Mods {
|
||||
if mod.Name == mod_name {
|
||||
filePath := mod_info_list.Destination + "/" + mod.FileName
|
||||
|
||||
fileLock.LockW(filePath)
|
||||
//delete mod
|
||||
err = os.Remove(mod_info_list.Destination + "/" + mod.FileName)
|
||||
err = os.Remove(filePath)
|
||||
fileLock.Unlock(filePath)
|
||||
if err != nil {
|
||||
log.Printf("ModInfoList ... error when deleting mod: %s", err)
|
||||
return err
|
||||
@ -134,26 +149,31 @@ func (mod_info_list *ModInfoList) createMod(mod_name string, file_name string, m
|
||||
var err error
|
||||
|
||||
//save uploaded file
|
||||
new_file, err := os.Create(mod_info_list.Destination + "/" + file_name)
|
||||
filePath := mod_info_list.Destination + "/" + file_name
|
||||
new_file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
log.Printf("error on creating new file - %s: %s", file_name, err)
|
||||
return err
|
||||
}
|
||||
defer new_file.Close()
|
||||
|
||||
fileLock.LockW(filePath)
|
||||
|
||||
_, err = io.Copy(new_file, mod_file)
|
||||
if err != nil {
|
||||
log.Printf("error on copying file to disk: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
//reload the list
|
||||
err = new_file.Close()
|
||||
if err != nil {
|
||||
log.Printf("error on closing new created zip-file: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
fileLock.Unlock(filePath)
|
||||
|
||||
//reload the list
|
||||
err = mod_info_list.listInstalledMods()
|
||||
if err != nil {
|
||||
log.Printf("error on listing mod-infos: %s", err)
|
||||
|
Loading…
x
Reference in New Issue
Block a user