From 5906ee681abf8c2d6b7de14386e1c1ba42a23d37 Mon Sep 17 00:00:00 2001 From: "Marcel M. Otte" Date: Thu, 13 Apr 2023 11:27:03 +0200 Subject: [PATCH] Add implementations for protocoldb, yet untested. --- protocoldb/protocoldb.go | 99 +++++++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 12 deletions(-) diff --git a/protocoldb/protocoldb.go b/protocoldb/protocoldb.go index c0f2e72..c82e377 100644 --- a/protocoldb/protocoldb.go +++ b/protocoldb/protocoldb.go @@ -4,34 +4,50 @@ import ( "fmt" "io/fs" "os" + "path" "path/filepath" + "strings" "gitea.mmo.to/ProtocolPacketForger/ppf/protocol" "gitea.mmo.to/ProtocolPacketForger/ppf/protocolctl" ) +// PPFDatabases is a list of all databases, with the most simple interface type PPFDatabases struct { Databases []ProtocolDatabaseProvider } +// ProtocolDatabaseProvider is a simple protocol database interface, which only provides open/close and retrieving the contents type ProtocolDatabaseProvider interface { + // Open opens a new database Open(path string) error + // Close closes a database (only internal flag set) Close() error - Protocols() map[string]protocol.DOPMeta + // Protocols returns the content of the database as map, an error if the first read of the database failed + Protocols() (map[string]protocol.DOPMeta, error) } +// ProtocolDatabaseManager is a complex protocol database interface, which allows adding, updating and refreshing of the content type ProtocolDatabaseManager interface { - Add(prot *protocol.ProtocolStructure, path string) - Update(prot *protocol.ProtocolStructure, path string) + Add(prot *protocol.ProtocolStructure) error + AddFile(path string) error + Update(prot *protocol.ProtocolStructure) error + UpdateFile(path string) error // no remove. UpdateDatabase() error // scans for new protocols } +// DatabaseEntry is a single entry in the file database, additionally to the meta data the path is required type DatabaseEntry struct { Path string Protocol protocol.DOPMeta } +// Get a full protocol from a database entry +func (de *DatabaseEntry) Get() (*protocol.ProtocolStructure, error) { + return protocolctl.LoadNew(de.Path) +} + // FileDatabase implements ProtocolDatabaseProvider and ProtocolDatabaseManager type FileDatabase struct { Path string @@ -39,11 +55,14 @@ type FileDatabase struct { closed bool } +// FileDatabaseFromGitRemote implements retrieving the latest stuff from an external git remote additionally to the FileDatabase functionality +// TODO type FileDatabaseFromGitRemote struct { FileDatabase RemoteGitRepository string } +// Open the database func (fd *FileDatabase) Open(path string) error { fileinfo, err := os.Stat(path) if err == os.ErrNotExist { @@ -57,6 +76,7 @@ func (fd *FileDatabase) Open(path string) error { return nil } +// Close the database and free the data func (fd *FileDatabase) Close() error { for k := range fd.protocols { delete(fd.protocols, k) @@ -65,30 +85,85 @@ func (fd *FileDatabase) Close() error { return nil } -func (fd *FileDatabase) Protocols() map[string]DatabaseEntry { - if !fd.closed { +// Protocols returns the map of protocols or an error if the first read failed +func (fd *FileDatabase) Protocols() (map[string]DatabaseEntry, error) { + if !fd.closed && len(fd.protocols) == 0 { fd.protocols = map[string]DatabaseEntry{} // recurse recursively through the path - filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error { + err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error { if !info.IsDir() { prot, err := protocolctl.LoadNew(path) - if err != nil { + if err == nil { // add to map fd.protocols[prot.Metadata.Name] = DatabaseEntry{path, prot.Metadata} } } return nil }) + if err != nil { + return nil, err + } } - return fd.protocols + return fd.protocols, nil } -func (fd *FileDatabase) Add(prot *protocol.ProtocolStructure, path string) { - +// Add puts a new protocol into the path of the file database +func (fd *FileDatabase) Add(prot *protocol.ProtocolStructure) error { + p := path.Join(fd.Path, prot.Metadata.Name, ".protocoljson") + err := protocolctl.Save(prot, p) + if err == nil { + fd.protocols[prot.Metadata.Name] = DatabaseEntry{p, prot.Metadata} + } + return err } -func (fd *FileDatabase) Update(prot *protocol.ProtocolStructure, path string) { +// AddFile copies a external protocoljson file into the database directory and updates the internal data +func (fd *FileDatabase) AddFile(p string) error { + prot, err := protocolctl.LoadNew(p) + if err == nil { + if !strings.HasPrefix(p, fd.Path) { + // add it to the database if not existing there + fd.Add(prot) + } + p = path.Join(fd.Path, prot.Metadata.Name, ".protocoljson") + fd.protocols[prot.Metadata.Name] = DatabaseEntry{p, prot.Metadata} + } + return err } + +// Update updates an existing entry through saving the contents of the protocol to the file, or just adding it anew +func (fd *FileDatabase) Update(prot *protocol.ProtocolStructure) error { + if v, ok := fd.protocols[prot.Metadata.Name]; ok { + v.Protocol = prot.Metadata + return protocolctl.Save(prot, v.Path) + } + return fd.Add(prot) +} + +// UpdateFile simply adds a file if it is outside the database, or updates the internal storage with the contents of the file +func (fd *FileDatabase) UpdateFile(p string) error { + if !strings.HasPrefix(p, fd.Path) { + return fd.AddFile(p) + } + prot, err := protocolctl.LoadNew(p) + if err == nil { + fd.protocols[prot.Metadata.Name] = DatabaseEntry{p, prot.Metadata} + } + return err +} + +// UpdateDatabase just rereads all files func (fd *FileDatabase) UpdateDatabase() error { - + // recurse recursively through the path + err := filepath.Walk(fd.Path, func(path string, info fs.FileInfo, err error) error { + if !info.IsDir() { + prot, err := protocolctl.LoadNew(path) + if err == nil { + // add to map + fd.protocols[prot.Metadata.Name] = DatabaseEntry{path, prot.Metadata} + } + } + return nil + }) + return err }