diff options
Diffstat (limited to 'load.go')
| -rw-r--r-- | load.go | 170 |
1 files changed, 170 insertions, 0 deletions
@@ -0,0 +1,170 @@ +package config + +import ( + "errors" + "fmt" + "os" + "strings" + + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" +) + +func LoadPB(pb proto.Message) error { + return ReLoad(pb) +} + +// uses the version to die. This is needed because loading binary +// protobuf files with rearranged messages is indeterminate +func ReLoad(pb proto.Message) error { + fullname, err := GetFilename(pb) + if (fullname == "") || (err != nil) { + panic("config.LoadPB() got blank filename = ''") + } + // this code needs work + newver, pbver, err := VersionCheckFile(pb, fullname) + if errors.Is(err, os.ErrNotExist) { + // + err = SaveToFilename(pb, fullname) + return err + } + if errors.Is(err, VersionMismatch) || (newver != pbver) { + fmt.Println("") + fmt.Printf("VERSION new '%s' != cur PB '%s'\n", newver, pbver) + fmt.Println("") + fmt.Println("Your protobuf file is old and can not be loaded") + fmt.Println("your application must decide how to handle this (delete or fix)") + fmt.Println("always die here. application is broken") + fmt.Println("You must delete or convert the file", fullname) + fmt.Println("") + // probably should ALWAYS PANIC HERE + // upon further study, always die here is better than not + s := fmt.Sprintf("protobuf version wrong. delete or fix %s", fullname) + panic(s) + } + if err != nil { + // return to let the application figure this out + return err + } + return nil +} + +func LoadFromFilename(pb proto.Message, fullname string) error { + if strings.HasSuffix(fullname, ".text") { + return loadTEXT(pb, fullname) + } + if strings.HasSuffix(fullname, ".json") { + return loadJSON(pb, fullname) + } + if strings.HasSuffix(fullname, ".pb") { + return loadPB(pb, fullname) + } + + return fmt.Errorf("unknown filetype '%s'", fullname) +} + +func loadPB(pb proto.Message, fullname string) error { + data, err := loadFile(fullname) + if err != nil { + // set pb.Filename that was attempted + return err + } + + if err = proto.Unmarshal(data, pb); err != nil { + return err + } + + return nil +} + +func loadTEXT(pb proto.Message, fullname string) error { + var data []byte + var err error + SetFilename(pb, fullname) + if data, err = loadFile(fullname); err != nil { + return err + } + + // don't even bother with Marshal() + if data == nil { + return ErrEmpty // file is empty + } + + // Unmarshal() + if err = prototext.Unmarshal(data, pb); err != nil { + return ErrMarshal + } + + if fn, err := GetFilename(pb); err != nil { + if fn != fullname { + SetFilename(pb, fullname) + } + } + return nil +} + +// json files are backup Marshal() data in case .text Unmarshal() fails +// they always should have the ".text" filename in them +func loadJSON(pb proto.Message, fullname string) error { + var data []byte + var err error + if data, err = loadFile(fullname); err != nil { + return err + } + + // don't even bother with Marshal() + if data == nil { + return ErrEmpty // file is empty + } + + // Unmarshal() + if err = protojson.Unmarshal(data, pb); err != nil { + return ErrMarshal + } + + if fn, err := GetFilename(pb); err != nil { + if fn != fullname { + SetFilename(pb, fullname) + } + } + return nil +} + +func loadFile(fullname string) ([]byte, error) { + data, err := os.ReadFile(fullname) + if errors.Is(err, os.ErrNotExist) { + // if file does not exist, just return nil. this + return nil, err + } + if err != nil { + return nil, err + } + if len(data) == 0 { + return data, ErrEmpty + } + return data, nil +} + +/* left this here to remind myself just how dumb I can be + +// dumb but simple to read logic +func missingConfig(fullname string) error { + data1, err1 := os.ReadFile(fullname) + if !errors.Is(err1, os.ErrNotExist) { + return err1 + } + + data2, err2 := os.ReadFile(fullname + ".json") + if !errors.Is(err2, os.ErrNotExist) { + return err2 + } + if errors.Is(err1, os.ErrNotExist) && errors.Is(err2, os.ErrNotExist) { + return os.ErrNotExist + } + if (len(data1) == 0) && (len(data2) == 0) { + return ErrEmpty + } + return nil +} +*/ |
