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 }