github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/extension/data_handler.go (about) 1 package extension 2 3 import ( 4 "encoding/json" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 9 "github.com/kisexp/xdchain/common" 10 "github.com/kisexp/xdchain/core/types" 11 "github.com/kisexp/xdchain/log" 12 ) 13 14 /* 15 The file can have two formats: 16 17 1. 18 { 19 "psiContracts": { 20 "psi1": { 21 "contract1address": ..., 22 "contract2address": ..., 23 }, 24 ... 25 } 26 } 27 28 2. 29 { 30 "contract1address": ..., 31 "contract2address": ..., 32 } 33 34 */ 35 36 const extensionContractData = "activeExtensions.json" 37 38 type DataHandler interface { 39 Load() (map[types.PrivateStateIdentifier]map[common.Address]*ExtensionContract, error) 40 41 Save(extensionContracts map[types.PrivateStateIdentifier]map[common.Address]*ExtensionContract) error 42 } 43 44 type JsonFileDataHandler struct { 45 saveFile string 46 } 47 48 func NewJsonFileDataHandler(dataDirectory string) *JsonFileDataHandler { 49 return &JsonFileDataHandler{ 50 saveFile: filepath.Join(dataDirectory, extensionContractData), 51 } 52 } 53 54 /* 55 The strategy when loading the save file is too check if the newer "psiContracts" field is present. 56 If so, then everything should exist under that key, and so we can unmarshal and return immediately. 57 58 If not, then the save file was made from a previous version. Load up all the data as before and 59 put it under the "private" PSI. 60 61 It should never be the case the file contains both types of data at once. 62 */ 63 func (handler *JsonFileDataHandler) Load() (map[types.PrivateStateIdentifier]map[common.Address]*ExtensionContract, error) { 64 if _, err := os.Stat(handler.saveFile); !(err == nil || !os.IsNotExist(err)) { 65 return map[types.PrivateStateIdentifier]map[common.Address]*ExtensionContract{types.DefaultPrivateStateIdentifier: {}}, nil 66 } 67 68 blob, err := ioutil.ReadFile(handler.saveFile) 69 if err != nil { 70 return nil, err 71 } 72 73 var untyped map[string]json.RawMessage 74 if err := json.Unmarshal(blob, &untyped); err != nil { 75 return nil, err 76 } 77 78 if psiContracts, ok := untyped["psiContracts"]; ok { 79 var contracts map[types.PrivateStateIdentifier]map[common.Address]*ExtensionContract 80 json.Unmarshal(psiContracts, &contracts) 81 return contracts, nil 82 } 83 84 currentContracts := make(map[common.Address]*ExtensionContract) 85 for key, val := range untyped { 86 extAddress := common.HexToAddress(key) 87 var ext ExtensionContract 88 json.Unmarshal(val, &ext) 89 currentContracts[extAddress] = &ext 90 } 91 return map[types.PrivateStateIdentifier]map[common.Address]*ExtensionContract{types.DefaultPrivateStateIdentifier: currentContracts}, nil 92 } 93 94 func (handler *JsonFileDataHandler) Save(extensionContracts map[types.PrivateStateIdentifier]map[common.Address]*ExtensionContract) error { 95 //we want to put the map under "psiContracts" key to distinguish from existing data 96 saveData := make(map[string]interface{}) 97 saveData["psiContracts"] = extensionContracts 98 99 //no unmarshallable types, so can't error 100 output, _ := json.Marshal(&saveData) 101 102 if errSaving := ioutil.WriteFile(handler.saveFile, output, 0644); errSaving != nil { 103 log.Error("Couldn't save outstanding extension contract details") 104 return errSaving 105 } 106 return nil 107 }