github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/manifest/manifest_read.go (about)

     1  package manifest
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
    11  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
    13  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
    14  )
    15  
    16  // LoadManifest reads the manifest from a file or from the Unchained Index smart contract.
    17  //
    18  // It first checks if the manifest file exists. If it does, it reads the manifest from the file.
    19  // If the caller requests the contract or the cached manifest does not exist, it reads the
    20  // manifest from the contract. It then checks if the new manifest has more chunks than the existing
    21  // one. If it does (or if the file didn't exist), it saves the new manifest to the file. Finally, it
    22  // creates a map of chunks for easy lookup and sets the specification if it is not already set.
    23  func LoadManifest(chain string, publisher base.Address, source Source) (man *Manifest, err error) {
    24  	manifestFn := config.PathToManifest(chain)
    25  	exists := file.FileExists(manifestFn)
    26  	man = &Manifest{}
    27  
    28  	if exists {
    29  		// We will either return this or use it to compare with the downlaoded manifest
    30  		// to see if we need to update the file.
    31  		man, err = readManifestFile(manifestFn)
    32  		if err != nil {
    33  			return nil, err
    34  		}
    35  		if man.Chain != chain {
    36  			msg := fmt.Sprintf("The remote manifest's chain (%s) does not match the cached manifest's chain (%s).", man.Chain, chain)
    37  			return man, errors.New(msg)
    38  		}
    39  	}
    40  
    41  	if source == TempContract || source == FromContract || !exists {
    42  		database := chain
    43  		cid, err := ReadUnchainedIndex(chain, publisher, database)
    44  		if err != nil {
    45  			return nil, err
    46  		} else if len(cid) == 0 {
    47  			return nil, fmt.Errorf("no record found in the Unchained Index for database %s from publisher %s", database, publisher.Hex())
    48  		}
    49  		gatewayUrl := config.GetChain(chain).IpfsGateway
    50  		logger.InfoTable("Chain:", chain)
    51  		logger.InfoTable("Database:", database)
    52  		logger.InfoTable("Publisher:", publisher)
    53  		logger.InfoTable("Gateway:", gatewayUrl)
    54  		logger.InfoTable("CID:", cid)
    55  
    56  		newManifest, err := downloadManifest(chain, gatewayUrl, cid)
    57  		if err != nil {
    58  			return nil, err
    59  		}
    60  		if newManifest.Chain != chain {
    61  			msg := fmt.Sprintf("The remote manifest's chain (%s) does not match the cached manifest's chain (%s).", newManifest.Chain, chain)
    62  			return newManifest, errors.New(msg)
    63  		}
    64  		if source != TempContract {
    65  			err = newManifest.SaveManifest(chain, manifestFn)
    66  			if err != nil {
    67  				return nil, err
    68  			}
    69  		}
    70  
    71  		man = newManifest
    72  	}
    73  
    74  	man.ChunkMap = make(map[string]*types.ChunkRecord)
    75  	for i := range man.Chunks {
    76  		man.ChunkMap[man.Chunks[i].Range] = &man.Chunks[i]
    77  	}
    78  
    79  	return man, nil
    80  }
    81  
    82  var specification = "QmUyyU8wKW57c3CuwphhMdZb2QA5bsjt9vVfTE6LcBKmE9"
    83  
    84  func Specification() string {
    85  	return specification
    86  }
    87  
    88  // readManifestFile reads the manifest from a file.
    89  //
    90  // It first reads the contents of the file into a string. It then decodes the string into the manifest.
    91  func readManifestFile(path string) (*Manifest, error) {
    92  	contents := file.AsciiFileToString(path)
    93  	if len(contents) == 0 {
    94  		return nil, ErrManifestNotFound
    95  	}
    96  
    97  	man := &Manifest{}
    98  	reader := bytes.NewReader([]byte(contents))
    99  	if err := json.NewDecoder(reader).Decode(man); err != nil {
   100  		return man, err
   101  	}
   102  
   103  	return man, nil
   104  }