adding path checks to manager

This commit is contained in:
2020-06-18 23:15:30 -04:00
parent 8c01cdbcf4
commit 7610e3f168
10 changed files with 188 additions and 74 deletions

View File

@@ -1,26 +1,173 @@
package manager
import (
"encoding/base64"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/deranjer/gvc/common/database"
engine "github.com/deranjer/gvc/common/engine"
"github.com/rs/zerolog"
)
// NewManager creates a new manager interface that contains all the needed information to make changes to the repo
func NewManager(version string, informer chan OperatingMessage, log zerolog.Logger) (*Manager, error) {
// rootPath is passed by client or server to let the manager know where to look for the .gvc folder and all the components needed
func NewManager(rootDir string, version string, dbPath string, informer chan OperatingMessage, log *zerolog.Logger) (*Manager, error) {
log.Info().Msg("Creating new Manager...")
patcher, err := engine.NewPatcher(&log, KEYFOLDER, DOWNLOADFOLDER, SYNCFOLDER, THUMBFOLDER, DIFFFOLDER)
dirPaths, err := checkPaths(rootDir)
if err != nil {
return &Manager{}, err
}
patcher, err := engine.NewPatcher(log, dirPaths)
if err != nil {
log.Fatal().Msgf("Error creating a patcher %s", err)
return &Manager{}, err
}
gvcDB, err := database.OpenOrCreateDB(dbPath, log)
if err != nil {
log.Fatal().Msgf("unable to create or open db: %s", err)
}
m := Manager{
version,
//settings,
&log,
log,
patcher,
database,
gvcDB,
informer,
dirPaths,
}
return &m, nil
}
func checkPaths(rootDir string) (filePaths *FilePaths, err error) {
// checking for the .gvc folder (the client (but not the server) already checks for the .gvc folder, but this checks all subdirects to make sure they are there)
rootFolder, err := filepath.Abs(rootDir)
if err != nil {
return &FilePaths{}, err
}
path := rootFolder + string(filepath.Separator) + ".gvc"
//path = filepath.Join(rootFolder, filepath.Separator+".gvc")
var fullFilePaths FilePaths
//where private and public keys are kept
fullFilePaths.KeyFolder = filepath.Join(path, "keys")
//where downloaded files start
fullFilePaths.DownloadFolder = filepath.Join(path, "downloads")
//where file originals live
fullFilePaths.SyncFolder = filepath.Join(path, "sync")
//where patches and last versions live
fullFilePaths.DiffFolder = filepath.Join(path, "diff")
//where the thumbnails are stored
fullFilePaths.ThumbFolder = filepath.Join(path, "thumb")
//where the logs are stored
fullFilePaths.LogFolder = filepath.Join(path, "logs")
//where plugins are stored
fullFilePaths.PluginFolder = filepath.Join(path, "plugins")
engine.InitiateDirectory(fullFilePaths.KeyFolder)
engine.InitiateDirectory(fullFilePaths.DownloadFolder)
engine.InitiateDirectory(fullFilePaths.SyncFolder)
engine.InitiateDirectory(fullFilePaths.DiffFolder)
engine.InitiateDirectory(fullFilePaths.ThumbFolder)
engine.InitiateDirectory(fullFilePaths.LogFolder)
engine.InitiateDirectory(fullFilePaths.PluginFolder)
return &fullFilePaths, nil
}
// This adds a file for the watcher to keep an eye on
// however the file will also need to be backedup
// and added to the database.
// This changes all paths to absolute paths rather than relative
// when adding a file to monitor, this should check if the database
// is already expecting to monitor this file. If it is this function should
// do checks to make sure that it is successfully monitoring it, and that there
// is a historical breadcrumb trail to recreate all the versions that the database
// claims to have a copy of
func (m *Manager) AddFileToRepo(file string, hardCopy bool) (string, error) {
var err error
// the filepath should be absolute, but this should be done dynamically
if file, err = filepath.Abs(file); err != nil {
return "", err
}
//TODO: what needs to happen is a channel for errors/progress is created
//then pass that channel to a routine, and put all of the following in it
// whenever an error returns, fire the string to the channel,
// or send progress on the progress channel
//however need to work out best way of returning the final result to the caller
//- the way to do that is send the result on a third channel, for which is just the result
//see commsManagment.go
// f := NewFileManager()
//DELAYED: this feature affects only large files and user experience. It can wait.
var tmpFile database.File
var filename string //we might aswell only verify the files validity once
var hash [16]byte
//check that the file actually exists
if filename, err = engine.VerifySrcFile(file); err != nil {
//there was no source file or it was not recognisable as a file
return "", err
}
//generate a unique file name from the hash and the moment it was created
//a sampled (and therefore) fast, hash of the file for 'uniqueness'
if hash, err = engine.UniqueFileHash(file); err != nil {
return "", err
}
if tmpFile, err = m.dB.CheckIfFileCurrentlyMonitored(file, hash); err != nil {
if strings.Index(err.Error(), "not found") != -1 {
//the file wasn't found, this is an ok error
m.Info().Msgf("The file was [%s], so continuing to create it in the database", err)
} else {
m.Error().Msgf("Error checking if file [%s] is monitored so will init file. Error: %s", tmpFile.Path, err)
}
tmpFile.CurrentHash = hash
tmpFile.Name = filename
tmpFile.Path = file
tmpFile.CreatedAt = time.Now()
tmpFile.Unique = base64.URLEncoding.EncodeToString([]byte(filename)) + "_" + base64.URLEncoding.EncodeToString((tmpFile.CurrentHash[:])) + "_" + strconv.FormatInt(tmpFile.CreatedAt.Unix(), 10) + "_" + filename
tmpFile.BkpLocation = filepath.Join(SyncFolder, tmpFile.Unique)
tmpFile.CurrentBase = tmpFile.BkpLocation
//tmpFile.Ignore = false //we can have files in the database that are ignored. TODO: This was initially added so that 'All Files' would show up as a file (its a hack as it adds a dummy to the database)
//we should now have a unique name for this file
//if needs be, we can find out the real file name from the string
//the hash will give us a reasononable indication of the similarity of the files
//define filename of backup(s)
if _, err := m.prepareDatabaseForFile(tmpFile); err != nil {
return "", err
} else {
if err := m.copyFileToNewLocation(tmpFile.Path, tmpFile.BkpLocation, hardCopy); err != nil {
m.ErrorF("There was an error copying the file to the backup location %s", err)
return "", err
}
m.Informer <- Op_NewFile.Retrieve()
}
} else {
m.Debug().Msgf("file [%s] is already in the database. Assuming sync file in place", tmpFile.Path)
// we should check if the backup file exists, otherwise there is an issue
if _, err := engine.VerifySrcFile(tmpFile.BkpLocation); err != nil {
//if the backup doesn't exist, something has gone quite wrong....
m.Debug().Msgf("The backup file doesn't seem to exist at the expected location, %s", err)
return "", err
}
}
return tmpFile.Path, m.watcher.Add(tmpFile.Path)
}
// prepareDatabaseForFile is responsible for keeping all references to the version of the file,
// the diff and the metadata of the diffs. Before any file is copied and stored, it should be managed by the database
//
// TODO: This will need to initialise a diff object in the database, currently created by the diff package,
// however going forward a diff maybe defined by the manager.
func (m *Manager) prepareDatabaseForFile(tmpFile engine.File) (int, error) {
fileID, err := m.dB.InitialiseFileInDatabase(tmpFile)
if err != nil {
m.Error().Msgf("Error checking if file [%s] is monitored. Error %s", tmpFile.Path, err)
return 0, err
}
return fileID, nil
}