github.com/mad-app/mattermost-server@v5.11.1+incompatible/store/sqlstore/plugin_store.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "database/sql" 8 "fmt" 9 "net/http" 10 11 "github.com/mattermost/mattermost-server/model" 12 "github.com/mattermost/mattermost-server/store" 13 ) 14 15 const ( 16 DEFAULT_PLUGIN_KEY_FETCH_LIMIT = 10 17 ) 18 19 type SqlPluginStore struct { 20 SqlStore 21 } 22 23 func NewSqlPluginStore(sqlStore SqlStore) store.PluginStore { 24 s := &SqlPluginStore{sqlStore} 25 26 for _, db := range sqlStore.GetAllConns() { 27 table := db.AddTableWithName(model.PluginKeyValue{}, "PluginKeyValueStore").SetKeys(false, "PluginId", "Key") 28 table.ColMap("PluginId").SetMaxSize(190) 29 table.ColMap("Key").SetMaxSize(50) 30 table.ColMap("Value").SetMaxSize(8192) 31 } 32 33 return s 34 } 35 36 func (ps SqlPluginStore) CreateIndexesIfNotExists() { 37 } 38 39 func (ps SqlPluginStore) SaveOrUpdate(kv *model.PluginKeyValue) store.StoreChannel { 40 return store.Do(func(result *store.StoreResult) { 41 if result.Err = kv.IsValid(); result.Err != nil { 42 return 43 } 44 45 if ps.DriverName() == model.DATABASE_DRIVER_POSTGRES { 46 // Unfortunately PostgreSQL pre-9.5 does not have an atomic upsert, so we use 47 // separate update and insert queries to accomplish our upsert 48 if rowsAffected, err := ps.GetMaster().Update(kv); err != nil { 49 result.Err = model.NewAppError("SqlPluginStore.SaveOrUpdate", "store.sql_plugin_store.save.app_error", nil, err.Error(), http.StatusInternalServerError) 50 return 51 } else if rowsAffected == 0 { 52 // No rows were affected by the update, so let's try an insert 53 if err := ps.GetMaster().Insert(kv); err != nil { 54 // If the error is from unique constraints violation, it's the result of a 55 // valid race and we can report success. Otherwise we have a real error and 56 // need to return it 57 if !IsUniqueConstraintError(err, []string{"PRIMARY", "PluginId", "Key", "PKey"}) { 58 result.Err = model.NewAppError("SqlPluginStore.SaveOrUpdate", "store.sql_plugin_store.save.app_error", nil, err.Error(), http.StatusInternalServerError) 59 return 60 } 61 } 62 } 63 } else if ps.DriverName() == model.DATABASE_DRIVER_MYSQL { 64 if _, err := ps.GetMaster().Exec("INSERT INTO PluginKeyValueStore (PluginId, PKey, PValue, ExpireAt) VALUES(:PluginId, :Key, :Value, :ExpireAt) ON DUPLICATE KEY UPDATE PValue = :Value, ExpireAt = :ExpireAt", map[string]interface{}{"PluginId": kv.PluginId, "Key": kv.Key, "Value": kv.Value, "ExpireAt": kv.ExpireAt}); err != nil { 65 result.Err = model.NewAppError("SqlPluginStore.SaveOrUpdate", "store.sql_plugin_store.save.app_error", nil, err.Error(), http.StatusInternalServerError) 66 return 67 } 68 } 69 70 result.Data = kv 71 }) 72 } 73 74 func (ps SqlPluginStore) Get(pluginId, key string) store.StoreChannel { 75 return store.Do(func(result *store.StoreResult) { 76 var kv *model.PluginKeyValue 77 currentTime := model.GetMillis() 78 if err := ps.GetReplica().SelectOne(&kv, "SELECT * FROM PluginKeyValueStore WHERE PluginId = :PluginId AND PKey = :Key AND (ExpireAt = 0 OR ExpireAt > :CurrentTime)", map[string]interface{}{"PluginId": pluginId, "Key": key, "CurrentTime": currentTime}); err != nil { 79 if err == sql.ErrNoRows { 80 result.Err = model.NewAppError("SqlPluginStore.Get", "store.sql_plugin_store.get.app_error", nil, fmt.Sprintf("plugin_id=%v, key=%v, err=%v", pluginId, key, err.Error()), http.StatusNotFound) 81 } else { 82 result.Err = model.NewAppError("SqlPluginStore.Get", "store.sql_plugin_store.get.app_error", nil, fmt.Sprintf("plugin_id=%v, key=%v, err=%v", pluginId, key, err.Error()), http.StatusInternalServerError) 83 } 84 } else { 85 result.Data = kv 86 } 87 }) 88 } 89 90 func (ps SqlPluginStore) Delete(pluginId, key string) store.StoreChannel { 91 return store.Do(func(result *store.StoreResult) { 92 if _, err := ps.GetMaster().Exec("DELETE FROM PluginKeyValueStore WHERE PluginId = :PluginId AND PKey = :Key", map[string]interface{}{"PluginId": pluginId, "Key": key}); err != nil { 93 result.Err = model.NewAppError("SqlPluginStore.Delete", "store.sql_plugin_store.delete.app_error", nil, fmt.Sprintf("plugin_id=%v, key=%v, err=%v", pluginId, key, err.Error()), http.StatusInternalServerError) 94 } else { 95 result.Data = true 96 } 97 }) 98 } 99 100 func (ps SqlPluginStore) DeleteAllForPlugin(pluginId string) store.StoreChannel { 101 return store.Do(func(result *store.StoreResult) { 102 if _, err := ps.GetMaster().Exec("DELETE FROM PluginKeyValueStore WHERE PluginId = :PluginId", map[string]interface{}{"PluginId": pluginId}); err != nil { 103 result.Err = model.NewAppError("SqlPluginStore.Delete", "store.sql_plugin_store.delete.app_error", nil, fmt.Sprintf("plugin_id=%v, err=%v", pluginId, err.Error()), http.StatusInternalServerError) 104 } else { 105 result.Data = true 106 } 107 }) 108 } 109 110 func (ps SqlPluginStore) DeleteAllExpired() store.StoreChannel { 111 return store.Do(func(result *store.StoreResult) { 112 currentTime := model.GetMillis() 113 if _, err := ps.GetMaster().Exec("DELETE FROM PluginKeyValueStore WHERE ExpireAt != 0 AND ExpireAt < :CurrentTime", map[string]interface{}{"CurrentTime": currentTime}); err != nil { 114 result.Err = model.NewAppError("SqlPluginStore.Delete", "store.sql_plugin_store.delete.app_error", nil, fmt.Sprintf("current_time=%v, err=%v", currentTime, err.Error()), http.StatusInternalServerError) 115 } else { 116 result.Data = true 117 } 118 }) 119 } 120 121 func (ps SqlPluginStore) List(pluginId string, offset int, limit int) store.StoreChannel { 122 if limit <= 0 { 123 limit = DEFAULT_PLUGIN_KEY_FETCH_LIMIT 124 } 125 126 if offset <= 0 { 127 offset = 0 128 } 129 130 return store.Do(func(result *store.StoreResult) { 131 var keys []string 132 _, err := ps.GetReplica().Select(&keys, "SELECT PKey FROM PluginKeyValueStore WHERE PluginId = :PluginId order by PKey limit :Limit offset :Offset", map[string]interface{}{"PluginId": pluginId, "Limit": limit, "Offset": offset}) 133 if err != nil { 134 result.Err = model.NewAppError("SqlPluginStore.List", "store.sql_plugin_store.list.app_error", nil, fmt.Sprintf("plugin_id=%v, err=%v", pluginId, err.Error()), http.StatusInternalServerError) 135 } else { 136 result.Data = keys 137 } 138 }) 139 }