fabric-samples/off_chain_data/application-go/store.go
Stanislav Jakuschevskij f6858cc7e1
Add second batch of pull request rework
- switch to ClientConnInterface
- use command type alias for map of commands
- add error return to command functions and handle in app.go
- inline formatJSON function in getAllAssets.go
- replace most panics with error returns
- remove error wrapping in listen.go and further down the line
- use strconv.ParseUint instead of ParseFloat
- use WithCancelCause in transact.go to grab and propagate error from
  go routine
- unmarshal and return []Asset in atb.GetAllAssets
- switch to rand package
- remove dependency to protobuf reflect package
- switch to sync.OnceValues for caching parser
- fixed typo in events sample connect.go

Signed-off-by: Stanislav Jakuschevskij <stas@two-giants.com>
2025-02-24 13:14:48 +01:00

93 lines
2.3 KiB
Go

package main
import (
"encoding/json"
"errors"
"fmt"
"os"
"strconv"
"strings"
)
var storeFile = envOrDefault("STORE_FILE", "store.log")
var simulatedFailureCount = getSimulatedFailureCount()
var transactionCount uint = 0 // Used only to simulate failures
// Apply writes for a given transaction to off-chain data store, ideally in a single operation for fault tolerance.
type writer = func(data ledgerUpdate) error
// Ledger update made by a specific transaction.
type ledgerUpdate struct {
BlockNumber uint64
TransactionID string
Writes []write
}
// Description of a ledger Write that can be applied to an off-chain data store.
type write struct {
// Channel whose ledger is being updated.
ChannelName string `json:"channelName"`
// Namespace within the ledger.
Namespace string `json:"namespace"`
// Key name within the ledger namespace.
Key string `json:"key"`
// Whether the key and associated value are being deleted.
IsDelete bool `json:"isDelete"`
// If `isDelete` is false, the Value written to the key; otherwise ignored.
Value string `json:"value"`
}
// Apply writes for a given transaction to off-chain data store, ideally in a single operation for fault tolerance.
// This implementation just writes to a file.
func applyWritesToOffChainStore(data ledgerUpdate) error {
if err := simulateFailureIfRequired(); err != nil {
return err
}
writes := []string{}
for _, write := range data.Writes {
marshaled, err := json.Marshal(write)
if err != nil {
return err
}
writes = append(writes, string(marshaled))
}
f, err := os.OpenFile(storeFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
if _, err := f.Write([]byte(strings.Join(writes, "\n") + "\n")); err != nil {
f.Close()
return err
}
if err := f.Close(); err != nil {
return err
}
return nil
}
func simulateFailureIfRequired() error {
if simulatedFailureCount > 0 && transactionCount >= simulatedFailureCount {
transactionCount = 0
return errors.New("expected error: simulated write failure")
}
transactionCount += 1
return nil
}
func getSimulatedFailureCount() uint {
valueAsString := envOrDefault("SIMULATED_FAILURE_COUNT", "0")
result, err := strconv.ParseUint(valueAsString, 10, 0)
if err != nil {
panic(fmt.Errorf("invalid SIMULATED_FAILURE_COUNT value: %s", valueAsString))
}
return uint(result)
}