mirror of
https://github.com/bitwarden/server.git
synced 2024-11-22 12:15:36 +01:00
metadata repository for table storage
This commit is contained in:
parent
e1e147b78f
commit
3037b95920
138
src/Core/Models/Data/DictionaryEntity.cs
Normal file
138
src/Core/Models/Data/DictionaryEntity.cs
Normal file
@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Table;
|
||||
|
||||
namespace Bit.Core.Models.Data
|
||||
{
|
||||
public class DictionaryEntity : TableEntity, IDictionary<string, EntityProperty>
|
||||
{
|
||||
private IDictionary<string, EntityProperty> _properties = new Dictionary<string, EntityProperty>();
|
||||
|
||||
public ICollection<EntityProperty> Values => _properties.Values;
|
||||
|
||||
public EntityProperty this[string key]
|
||||
{
|
||||
get => _properties[key];
|
||||
set => _properties[key] = value;
|
||||
}
|
||||
|
||||
public int Count => _properties.Count;
|
||||
|
||||
public bool IsReadOnly => _properties.IsReadOnly;
|
||||
|
||||
public ICollection<string> Keys => _properties.Keys;
|
||||
|
||||
public override void ReadEntity(IDictionary<string, EntityProperty> properties,
|
||||
OperationContext operationContext)
|
||||
{
|
||||
_properties = properties;
|
||||
}
|
||||
|
||||
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
|
||||
{
|
||||
return _properties;
|
||||
}
|
||||
|
||||
public void Add(string key, EntityProperty value)
|
||||
{
|
||||
_properties.Add(key, value);
|
||||
}
|
||||
|
||||
public void Add(string key, bool value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, byte[] value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, DateTime? value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, DateTimeOffset? value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, double value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, Guid value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, int value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, long value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(string key, string value)
|
||||
{
|
||||
_properties.Add(key, new EntityProperty(value));
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, EntityProperty> item)
|
||||
{
|
||||
_properties.Add(item);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return _properties.ContainsKey(key);
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
return _properties.Remove(key);
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out EntityProperty value)
|
||||
{
|
||||
return _properties.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_properties.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, EntityProperty> item)
|
||||
{
|
||||
return _properties.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<string, EntityProperty>[] array, int arrayIndex)
|
||||
{
|
||||
_properties.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, EntityProperty> item)
|
||||
{
|
||||
return _properties.Remove(item);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, EntityProperty>> GetEnumerator()
|
||||
{
|
||||
return _properties.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _properties.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
14
src/Core/Repositories/IMetaDataRespository.cs
Normal file
14
src/Core/Repositories/IMetaDataRespository.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Repositories
|
||||
{
|
||||
public interface IMetaDataRespository
|
||||
{
|
||||
Task DeleteAsync(string id);
|
||||
Task<IDictionary<string, string>> GetAsync(string id);
|
||||
Task<string> GetAsync(string id, string prop);
|
||||
Task UpsertAsync(string id, IDictionary<string, string> dict);
|
||||
Task UpsertAsync(string id, KeyValuePair<string, string> keyValuePair);
|
||||
}
|
||||
}
|
97
src/Core/Repositories/TableStorage/MetaDataRespository.cs
Normal file
97
src/Core/Repositories/TableStorage/MetaDataRespository.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Models.Data;
|
||||
using Microsoft.WindowsAzure.Storage;
|
||||
using Microsoft.WindowsAzure.Storage.Table;
|
||||
|
||||
namespace Bit.Core.Repositories.TableStorage
|
||||
{
|
||||
public class MetaDataRespository : IMetaDataRespository
|
||||
{
|
||||
private readonly CloudTable _table;
|
||||
|
||||
public MetaDataRespository(GlobalSettings globalSettings)
|
||||
: this(globalSettings.Events.ConnectionString)
|
||||
{ }
|
||||
|
||||
public MetaDataRespository(string storageConnectionString)
|
||||
{
|
||||
var storageAccount = CloudStorageAccount.Parse(storageConnectionString);
|
||||
var tableClient = storageAccount.CreateCloudTableClient();
|
||||
_table = tableClient.GetTableReference("metadata");
|
||||
}
|
||||
|
||||
public async Task<IDictionary<string, string>> GetAsync(string id)
|
||||
{
|
||||
var query = new TableQuery<DictionaryEntity>().Where(
|
||||
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, id));
|
||||
var queryResults = await _table.ExecuteQuerySegmentedAsync(query, null);
|
||||
return queryResults.Results.FirstOrDefault()?.ToDictionary(d => d.Key, d => d.Value.StringValue);
|
||||
}
|
||||
|
||||
public async Task<string> GetAsync(string id, string prop)
|
||||
{
|
||||
var dict = await GetAsync(id);
|
||||
if(dict != null && dict.ContainsKey(prop))
|
||||
{
|
||||
return dict[prop];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task UpsertAsync(string id, KeyValuePair<string, string> keyValuePair)
|
||||
{
|
||||
var query = new TableQuery<DictionaryEntity>().Where(
|
||||
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, id));
|
||||
var queryResults = await _table.ExecuteQuerySegmentedAsync(query, null);
|
||||
var entity = queryResults.Results.FirstOrDefault();
|
||||
if(entity == null)
|
||||
{
|
||||
entity = new DictionaryEntity
|
||||
{
|
||||
PartitionKey = id
|
||||
};
|
||||
}
|
||||
if(entity.ContainsKey(keyValuePair.Key))
|
||||
{
|
||||
entity.Remove(keyValuePair.Key);
|
||||
}
|
||||
entity.Add(keyValuePair.Key, keyValuePair.Value);
|
||||
await _table.ExecuteAsync(TableOperation.InsertOrReplace(entity));
|
||||
}
|
||||
|
||||
public async Task UpsertAsync(string id, IDictionary<string, string> dict)
|
||||
{
|
||||
var entity = new DictionaryEntity
|
||||
{
|
||||
PartitionKey = id
|
||||
};
|
||||
foreach(var item in dict)
|
||||
{
|
||||
entity.Add(item.Key, item.Value);
|
||||
}
|
||||
await _table.ExecuteAsync(TableOperation.InsertOrReplace(entity));
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(string id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _table.ExecuteAsync(TableOperation.Delete(new DictionaryEntity
|
||||
{
|
||||
PartitionKey = id,
|
||||
ETag = "*"
|
||||
}));
|
||||
}
|
||||
catch(StorageException e)
|
||||
{
|
||||
if(e.RequestInformation.HttpStatusCode != (int)HttpStatusCode.NotFound)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user