github.com/decred/politeia@v1.4.0/politeiad/backend/backend.go (about)

     1  // Copyright (c) 2017-2019 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package backend
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"regexp"
    11  
    12  	v1 "github.com/decred/politeia/politeiad/api/v1"
    13  )
    14  
    15  var (
    16  	// ErrRecordNotFound is emitted when a record could not be found
    17  	ErrRecordNotFound = errors.New("record not found")
    18  
    19  	// ErrRecordFound is emitted when a record is found while none was
    20  	// expected.
    21  	ErrRecordFound = errors.New("record found")
    22  
    23  	// ErrFileNotFound is emitted when a file inside a record could not be
    24  	// found
    25  	ErrFileNotFound = errors.New("file not found")
    26  
    27  	// ErrShutdown is emitted when the backend is shutting down.
    28  	ErrShutdown = errors.New("backend is shutting down")
    29  
    30  	// ErrNoChanges there are no changes to the record.
    31  	ErrNoChanges = errors.New("no changes to record")
    32  
    33  	// ErrChangesRecord is returned when a record would change when not
    34  	// expected.
    35  	ErrChangesRecord = errors.New("changes record")
    36  
    37  	// ErrRecordArchived is returned when an update was attempted on a
    38  	// archived record.
    39  	ErrRecordArchived = errors.New("record is archived")
    40  
    41  	// ErrJournalsNotReplayed is returned when the journals have not been replayed
    42  	// and the subsequent code expect it to be replayed
    43  	ErrJournalsNotReplayed = errors.New("journals have not been replayed")
    44  
    45  	// Plugin names must be all lowercase letters and have a length of <20
    46  	PluginRE = regexp.MustCompile(`^[a-z]{1,20}$`)
    47  )
    48  
    49  // ContentVerificationError is returned when a submitted record contains
    50  // unacceptable file formats or corrupt data.
    51  type ContentVerificationError struct {
    52  	ErrorCode    v1.ErrorStatusT
    53  	ErrorContext []string
    54  }
    55  
    56  func (c ContentVerificationError) Error() string {
    57  	return fmt.Sprintf("%v: %v", v1.ErrorStatus[c.ErrorCode], c.ErrorContext)
    58  }
    59  
    60  type File struct {
    61  	Name    string // Basename of the file
    62  	MIME    string // MIME type
    63  	Digest  string // SHA256 of decoded Payload
    64  	Payload string // base64 encoded file
    65  }
    66  
    67  type MDStatusT int
    68  
    69  const (
    70  	// All possible MD status codes
    71  	MDStatusInvalid           MDStatusT = 0 // Invalid status, this is a bug
    72  	MDStatusUnvetted          MDStatusT = 1 // Unvetted record
    73  	MDStatusVetted            MDStatusT = 2 // Vetted record
    74  	MDStatusCensored          MDStatusT = 3 // Censored record
    75  	MDStatusIterationUnvetted MDStatusT = 4 // Unvetted record that has been changed
    76  	MDStatusArchived          MDStatusT = 5 // Vetted record that has been archived
    77  	MDStatusLast              MDStatusT = 6 // Unit test only
    78  )
    79  
    80  var (
    81  	// MDStatus converts a status code to a human readable error.
    82  	MDStatus = map[MDStatusT]string{
    83  		MDStatusInvalid:           "invalid",
    84  		MDStatusUnvetted:          "unvetted",
    85  		MDStatusVetted:            "vetted",
    86  		MDStatusCensored:          "censored",
    87  		MDStatusIterationUnvetted: "iteration unvetted",
    88  		MDStatusArchived:          "archived",
    89  	}
    90  )
    91  
    92  // StateTransitionError indicates an invalid record status transition.
    93  type StateTransitionError struct {
    94  	From MDStatusT
    95  	To   MDStatusT
    96  }
    97  
    98  func (s StateTransitionError) Error() string {
    99  	return fmt.Sprintf("invalid record status transition %v (%v) -> %v (%v)",
   100  		s.From, MDStatus[s.From], s.To, MDStatus[s.To])
   101  }
   102  
   103  // RecordMetadata is the metadata of a record.
   104  const VersionRecordMD = 1
   105  
   106  type RecordMetadata struct {
   107  	Version   uint64    `json:"version"`   // Version of the scruture
   108  	Iteration uint64    `json:"iteration"` // Iteration count of record
   109  	Status    MDStatusT `json:"status"`    // Current status of the record
   110  	Merkle    string    `json:"merkle"`    // Merkle root of all files in record
   111  	Timestamp int64     `json:"timestamp"` // Last updated
   112  	Token     string    `json:"token"`     // Record authentication token
   113  }
   114  
   115  // MetadataStream describes a single metada stream.  The ID determines how and
   116  // where it is stored.
   117  type MetadataStream struct {
   118  	ID      uint64 // Stream identity
   119  	Payload string // String encoded metadata
   120  }
   121  
   122  // Record is a permanent Record that includes the submitted files, metadata and
   123  // internal metadata.
   124  type Record struct {
   125  	RecordMetadata RecordMetadata   // Internal metadata
   126  	Version        string           // Version of Files
   127  	Metadata       []MetadataStream // User provided metadata
   128  	Files          []File           // User provided files
   129  }
   130  
   131  // PluginSettings
   132  type PluginSetting struct {
   133  	Key   string // Name of setting
   134  	Value string // Value of setting
   135  }
   136  
   137  // Plugin describes a plugin and its settings.
   138  type Plugin struct {
   139  	ID       string          // Identifier
   140  	Version  string          // Version
   141  	Settings []PluginSetting // Settings
   142  }
   143  
   144  type Backend interface {
   145  	// Create new record
   146  	New([]MetadataStream, []File) (*RecordMetadata, error)
   147  
   148  	// Update unvetted record (token, mdAppend, mdOverwrite, fAdd, fDelete)
   149  	UpdateUnvettedRecord([]byte, []MetadataStream, []MetadataStream, []File,
   150  		[]string) (*Record, error)
   151  
   152  	// Update vetted record (token, mdAppend, mdOverwrite, fAdd, fDelete)
   153  	UpdateVettedRecord([]byte, []MetadataStream, []MetadataStream, []File,
   154  		[]string) (*Record, error)
   155  
   156  	// Update vetted metadata (token, mdAppend, mdOverwrite)
   157  	UpdateVettedMetadata([]byte, []MetadataStream,
   158  		[]MetadataStream) error
   159  
   160  	// Update README.md file at the root of git repo
   161  	UpdateReadme(string) error
   162  
   163  	// Check if an unvetted record exists
   164  	UnvettedExists([]byte) bool
   165  
   166  	// Check if a vetted record exists
   167  	VettedExists([]byte) bool
   168  
   169  	// Get all unvetted record tokens
   170  	UnvettedTokens() ([][]byte, error)
   171  
   172  	// Get all vetted record tokens
   173  	VettedTokens() ([][]byte, error)
   174  
   175  	// Get unvetted record
   176  	GetUnvetted([]byte) (*Record, error)
   177  
   178  	// Get vetted record
   179  	GetVetted([]byte, string) (*Record, error)
   180  
   181  	// Set unvetted record status
   182  	SetUnvettedStatus([]byte, MDStatusT, []MetadataStream,
   183  		[]MetadataStream) (*Record, error)
   184  
   185  	// Set vetted record status
   186  	SetVettedStatus([]byte, MDStatusT, []MetadataStream,
   187  		[]MetadataStream) (*Record, error)
   188  
   189  	// Inventory retrieves various record records.
   190  	Inventory(uint, uint, uint, bool, bool) ([]Record, []Record, error)
   191  
   192  	// Obtain plugin settings
   193  	GetPlugins() ([]Plugin, error)
   194  
   195  	// Plugin pass-through command
   196  	Plugin(string, string) (string, string, error) // command type, payload, error
   197  
   198  	// Close performs cleanup of the backend.
   199  	Close()
   200  }