github.com/decred/politeia@v1.4.0/politeiad/backendv2/tstorebe/plugins/plugins.go (about)

     1  // Copyright (c) 2020-2021 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 plugins
     6  
     7  import (
     8  	backend "github.com/decred/politeia/politeiad/backendv2"
     9  	"github.com/decred/politeia/politeiad/backendv2/tstorebe/store"
    10  )
    11  
    12  // HookT represents a plugin hook.
    13  type HookT int
    14  
    15  const (
    16  	// HookTypeInvalid is an invalid plugin hook.
    17  	HookTypeInvalid HookT = 0
    18  
    19  	// HookTypeNewRecordPre is called before a new record is saved to
    20  	// disk.
    21  	HookTypeNewRecordPre HookT = 1
    22  
    23  	// HookTypeNewRecordPost is called after a new record is saved to
    24  	// disk.
    25  	HookTypeNewRecordPost HookT = 2
    26  
    27  	// HookTypeEditRecordPre is called before a record update is saved
    28  	// to disk.
    29  	HookTypeEditRecordPre HookT = 3
    30  
    31  	// HookTypeEditRecordPost is called after a record update is saved
    32  	// to disk.
    33  	HookTypeEditRecordPost HookT = 4
    34  
    35  	// HookTypeEditMetadataPre is called before a metadata update is
    36  	// saved to disk.
    37  	HookTypeEditMetadataPre HookT = 5
    38  
    39  	// HookTypeEditMetadataPost is called after a metadata update is
    40  	// saved to disk.
    41  	HookTypeEditMetadataPost HookT = 6
    42  
    43  	// HookTypeSetRecordStatusPre is called before a record status
    44  	// change is saved to disk.
    45  	HookTypeSetRecordStatusPre HookT = 7
    46  
    47  	// HookTypeSetRecordStatusPost is called after a record status
    48  	// change is saved to disk.
    49  	HookTypeSetRecordStatusPost HookT = 8
    50  
    51  	// HookTypePluginPre is called before a plugin command is executed.
    52  	HookTypePluginPre HookT = 9
    53  
    54  	// HookTypePluginPost is called after a plugin command is executed.
    55  	HookTypePluginPost HookT = 10
    56  
    57  	// HookTypeLast unit test only
    58  	HookTypeLast HookT = 11
    59  )
    60  
    61  var (
    62  	// Hooks contains human readable descriptions of the plugin hooks.
    63  	Hooks = map[HookT]string{
    64  		HookTypeInvalid:             "invalid hook",
    65  		HookTypeNewRecordPre:        "new record pre",
    66  		HookTypeNewRecordPost:       "new record post",
    67  		HookTypeEditRecordPre:       "edit record pre",
    68  		HookTypeEditRecordPost:      "edit record post",
    69  		HookTypeEditMetadataPre:     "edit metadata pre",
    70  		HookTypeEditMetadataPost:    "edit metadata post",
    71  		HookTypeSetRecordStatusPre:  "set record status pre",
    72  		HookTypeSetRecordStatusPost: "set record status post",
    73  		HookTypePluginPre:           "plugin pre",
    74  		HookTypePluginPost:          "plugin post",
    75  	}
    76  )
    77  
    78  // HookNewRecordPre is the payload for the pre new record hook.
    79  type HookNewRecordPre struct {
    80  	Metadata []backend.MetadataStream `json:"metadata"`
    81  	Files    []backend.File           `json:"files"`
    82  }
    83  
    84  // HookNewRecordPost is the payload for the post new record hook.
    85  type HookNewRecordPost struct {
    86  	Metadata       []backend.MetadataStream `json:"metadata"`
    87  	Files          []backend.File           `json:"files"`
    88  	RecordMetadata backend.RecordMetadata   `json:"recordmetadata"`
    89  }
    90  
    91  // HookEditRecord is the payload for the pre and post edit record hooks.
    92  type HookEditRecord struct {
    93  	Record backend.Record `json:"record"` // Record pre update
    94  
    95  	// Updated fields
    96  	RecordMetadata backend.RecordMetadata   `json:"recordmetadata"`
    97  	Metadata       []backend.MetadataStream `json:"metadata"`
    98  	Files          []backend.File           `json:"files"`
    99  }
   100  
   101  // HookEditMetadata is the payload for the pre and post edit metadata hooks.
   102  type HookEditMetadata struct {
   103  	Record backend.Record `json:"record"` // Record pre update
   104  
   105  	// Updated fields
   106  	Metadata []backend.MetadataStream `json:"metadata"`
   107  }
   108  
   109  // HookSetRecordStatus is the payload for the pre and post set record status
   110  // hooks.
   111  type HookSetRecordStatus struct {
   112  	Record backend.Record `json:"record"` // Record pre update
   113  
   114  	// Updated fields
   115  	RecordMetadata backend.RecordMetadata   `json:"recordmetadata"`
   116  	Metadata       []backend.MetadataStream `json:"metadata"`
   117  }
   118  
   119  // HookPluginPre is the payload for the pre plugin hook.
   120  type HookPluginPre struct {
   121  	Token    []byte `json:"token"`
   122  	PluginID string `json:"pluginid"`
   123  	Cmd      string `json:"cmd"`
   124  	Payload  string `json:"payload"`
   125  }
   126  
   127  // HookPluginPost is the payload for the post plugin hook. The post plugin hook
   128  // includes the plugin reply.
   129  type HookPluginPost struct {
   130  	PluginID string `json:"pluginid"`
   131  	Cmd      string `json:"cmd"`
   132  	Payload  string `json:"payload"`
   133  	Reply    string `json:"reply"`
   134  }
   135  
   136  // PluginClient provides an API for a tstore instance to use when interacting
   137  // with a plugin. All tstore plugins must implement the PluginClient interface.
   138  type PluginClient interface {
   139  	// Setup performs any required plugin setup.
   140  	Setup() error
   141  
   142  	// Cmd executes a plugin command.
   143  	Cmd(token []byte, cmd, payload string) (string, error)
   144  
   145  	// Hook executes a plugin hook.
   146  	Hook(h HookT, payload string) error
   147  
   148  	// Fsck performs a plugin file system check. The plugin is
   149  	// provided with the tokens for all records in the backend.
   150  	Fsck(tokens [][]byte) error
   151  
   152  	// Settings returns the plugin settings.
   153  	Settings() []backend.PluginSetting
   154  }
   155  
   156  // TstoreClient provides an API for plugins to interact with a tstore instance.
   157  // Plugins are allowed to save, delete, and get plugin data to/from the tstore
   158  // backend. Editing plugin data is not allowed.
   159  type TstoreClient interface {
   160  	// BlobSave saves a BlobEntry to the tstore instance. The BlobEntry
   161  	// will be encrypted prior to being written to disk if the record
   162  	// is unvetted. The digest of the data, i.e. BlobEntry.Digest, can
   163  	// be thought of as the blob ID that can be used to get/del the
   164  	// blob from tstore.
   165  	BlobSave(token []byte, be store.BlobEntry) error
   166  
   167  	// BlobsDel deletes the blobs that correspond to the provided
   168  	// digests.
   169  	BlobsDel(token []byte, digests [][]byte) error
   170  
   171  	// Blobs returns the blobs that correspond to the provided digests.
   172  	// If a blob does not exist it will not be included in the returned
   173  	// map. If a record is vetted, only vetted blobs will be returned.
   174  	Blobs(token []byte, digests [][]byte) (map[string]store.BlobEntry, error)
   175  
   176  	// BlobsByDataDesc returns all blobs that match the provided data
   177  	// descriptor. The blobs will be ordered from oldest to newest. If
   178  	// a record is vetted then only vetted blobs will be returned.
   179  	BlobsByDataDesc(token []byte, dataDesc []string) ([]store.BlobEntry, error)
   180  
   181  	// DigestsByDataDesc returns the digests of all blobs that match
   182  	// the provided data descriptor. The digests will be ordered from
   183  	// oldest to newest. If a record is vetted, only the digests of
   184  	// vetted blobs will be returned.
   185  	DigestsByDataDesc(token []byte, dataDesc []string) ([][]byte, error)
   186  
   187  	// Timestamp returns the timestamp for the blob that correpsonds
   188  	// to the digest. If a record is vetted, only vetted timestamps
   189  	// will be returned.
   190  	Timestamp(token []byte, digest []byte) (*backend.Timestamp, error)
   191  
   192  	// Record returns a version of a record.
   193  	Record(token []byte, version uint32) (*backend.Record, error)
   194  
   195  	// RecordLatest returns the most recent version of a record.
   196  	RecordLatest(token []byte) (*backend.Record, error)
   197  
   198  	// RecordPartial returns a partial record. This method gives the
   199  	// caller fine grained control over what version and what files are
   200  	// returned. The only required field is the token. All other fields
   201  	// are optional.
   202  	//
   203  	// Version is used to request a specific version of a record. If no
   204  	// version is provided then the most recent version of the record
   205  	// will be returned.
   206  	//
   207  	// Filenames can be used to request specific files. If filenames is
   208  	// not empty then the specified files will be the only files that
   209  	// are returned.
   210  	//
   211  	// OmitAllFiles can be used to retrieve a record without any of the
   212  	// record files. This supersedes the filenames argument.
   213  	RecordPartial(token []byte, version uint32, filenames []string,
   214  		omitAllFiles bool) (*backend.Record, error)
   215  
   216  	// RecordState returns whether the record is unvetted or vetted.
   217  	RecordState(token []byte) (backend.StateT, error)
   218  
   219  	// CachePut saves the provided key-value pairs to the key-value store. It
   220  	// prefixes the keys with the plugin ID in order to limit the access of the
   221  	// plugins only to the data they own.
   222  	CachePut(blobs map[string][]byte, encrypt bool) error
   223  
   224  	// CacheDel deletes the provided blobs from the key-value store. This
   225  	// operation is performed atomically. It prefixes the keys with the plugin
   226  	// ID in order to limit the access of the plugins only to the data they own.
   227  	CacheDel(keys []string) error
   228  
   229  	// CacheGet returns blobs from the key-value store for the provided keys. An
   230  	// entry will not exist in the returned map if for any blobs that are not
   231  	// found. It is the responsibility of the caller to ensure a blob
   232  	// was returned for all provided keys. It prefixes the keys with the plugin
   233  	// ID in order to limit the access of the plugins only to the data they own.
   234  	CacheGet(keys []string) (map[string][]byte, error)
   235  }