diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-05-08 13:38:36 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-05-08 17:47:29 +1000 |
| commit | 16e6180ba7946119538d03463ea7d37fccc4dcb3 (patch) | |
| tree | 968483bfa477b43a72b8b6dfefaac3e771163e9e /src/database/records.cpp | |
| parent | fe19478e0f286191c3bf1b9946b89ed26d5c4bae (diff) | |
| download | tangara-fw-16e6180ba7946119538d03463ea7d37fccc4dcb3.tar.gz | |
Database init is now stable!
Diffstat (limited to 'src/database/records.cpp')
| -rw-r--r-- | src/database/records.cpp | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/database/records.cpp b/src/database/records.cpp new file mode 100644 index 00000000..e75e2316 --- /dev/null +++ b/src/database/records.cpp @@ -0,0 +1,203 @@ +#include "records.hpp" + +#include <cbor.h> +#include <esp_log.h> +#include <stdint.h> + +#include <sstream> +#include <vector> + +#include "song.hpp" + +namespace database { + +static const char* kTag = "RECORDS"; + +static const char kDataPrefix = 'D'; +static const char kHashPrefix = 'H'; +static const char kFieldSeparator = '\0'; + +template <typename T> +auto cbor_encode(uint8_t** out_buf, T fn) -> std::size_t { + CborEncoder size_encoder; + cbor_encoder_init(&size_encoder, NULL, 0, 0); + std::invoke(fn, &size_encoder); + std::size_t buf_size = cbor_encoder_get_extra_bytes_needed(&size_encoder); + *out_buf = new uint8_t[buf_size]; + + CborEncoder encoder; + cbor_encoder_init(&encoder, *out_buf, buf_size, 0); + std::invoke(fn, &encoder); + + return buf_size; +} + +OwningSlice::OwningSlice(std::string d) : data(d), slice(data) {} + +auto CreateDataPrefix() -> OwningSlice { + char data[2] = {kDataPrefix, kFieldSeparator}; + return OwningSlice({data, 2}); +} + +auto CreateDataKey(const SongId& id) -> OwningSlice { + std::ostringstream output; + output.put(kDataPrefix).put(kFieldSeparator); + output << SongIdToBytes(id).data; + return OwningSlice(output.str()); +} + +auto CreateDataValue(const SongData& song) -> OwningSlice { + uint8_t* buf; + std::size_t buf_len = cbor_encode(&buf, [&](CborEncoder* enc) { + CborEncoder array_encoder; + CborError err; + err = cbor_encoder_create_array(enc, &array_encoder, 5); + if (err != CborNoError && err != CborErrorOutOfMemory) { + ESP_LOGE(kTag, "encoding err %u", err); + return; + } + err = cbor_encode_int(&array_encoder, song.id()); + if (err != CborNoError && err != CborErrorOutOfMemory) { + ESP_LOGE(kTag, "encoding err %u", err); + return; + } + err = cbor_encode_text_string(&array_encoder, song.filepath().c_str(), + song.filepath().size()); + if (err != CborNoError && err != CborErrorOutOfMemory) { + ESP_LOGE(kTag, "encoding err %u", err); + return; + } + err = cbor_encode_uint(&array_encoder, song.tags_hash()); + if (err != CborNoError && err != CborErrorOutOfMemory) { + ESP_LOGE(kTag, "encoding err %u", err); + return; + } + err = cbor_encode_int(&array_encoder, song.play_count()); + if (err != CborNoError && err != CborErrorOutOfMemory) { + ESP_LOGE(kTag, "encoding err %u", err); + return; + } + err = cbor_encode_boolean(&array_encoder, song.is_tombstoned()); + if (err != CborNoError && err != CborErrorOutOfMemory) { + ESP_LOGE(kTag, "encoding err %u", err); + return; + } + err = cbor_encoder_close_container(enc, &array_encoder); + if (err != CborNoError && err != CborErrorOutOfMemory) { + ESP_LOGE(kTag, "encoding err %u", err); + return; + } + }); + std::string as_str(reinterpret_cast<char*>(buf), buf_len); + delete buf; + return OwningSlice(as_str); +} + +auto ParseDataValue(const leveldb::Slice& slice) -> std::optional<SongData> { + CborParser parser; + CborValue container; + CborError err; + err = cbor_parser_init(reinterpret_cast<const uint8_t*>(slice.data()), + slice.size(), 0, &parser, &container); + if (err != CborNoError) { + return {}; + } + + CborValue val; + err = cbor_value_enter_container(&container, &val); + if (err != CborNoError) { + return {}; + } + + uint64_t raw_int; + err = cbor_value_get_uint64(&val, &raw_int); + if (err != CborNoError) { + return {}; + } + SongId id = raw_int; + err = cbor_value_advance(&val); + if (err != CborNoError) { + return {}; + } + + char* raw_path; + std::size_t len; + err = cbor_value_dup_text_string(&val, &raw_path, &len, &val); + if (err != CborNoError) { + return {}; + } + std::string path(raw_path, len); + delete raw_path; + + err = cbor_value_get_uint64(&val, &raw_int); + if (err != CborNoError) { + return {}; + } + uint64_t hash = raw_int; + err = cbor_value_advance(&val); + if (err != CborNoError) { + return {}; + } + + err = cbor_value_get_uint64(&val, &raw_int); + if (err != CborNoError) { + return {}; + } + uint32_t play_count = raw_int; + err = cbor_value_advance(&val); + if (err != CborNoError) { + return {}; + } + + bool is_tombstoned; + err = cbor_value_get_boolean(&val, &is_tombstoned); + if (err != CborNoError) { + return {}; + } + + return SongData(id, path, hash, play_count, is_tombstoned); +} + +auto CreateHashKey(const uint64_t& hash) -> OwningSlice { + std::ostringstream output; + output.put(kHashPrefix).put(kFieldSeparator); + + uint8_t buf[16]; + CborEncoder enc; + cbor_encoder_init(&enc, buf, sizeof(buf), 0); + cbor_encode_uint(&enc, hash); + std::size_t len = cbor_encoder_get_buffer_size(&enc, buf); + output.write(reinterpret_cast<char*>(buf), len); + + return OwningSlice(output.str()); +} + +auto ParseHashValue(const leveldb::Slice& slice) -> std::optional<SongId> { + return BytesToSongId(slice.ToString()); +} + +auto CreateHashValue(SongId id) -> OwningSlice { + return SongIdToBytes(id); +} + +auto SongIdToBytes(SongId id) -> OwningSlice { + uint8_t buf[8]; + CborEncoder enc; + cbor_encoder_init(&enc, buf, sizeof(buf), 0); + cbor_encode_uint(&enc, id); + std::size_t len = cbor_encoder_get_buffer_size(&enc, buf); + std::string as_str(reinterpret_cast<char*>(buf), len); + return OwningSlice(as_str); +} + +auto BytesToSongId(const std::string& bytes) -> SongId { + CborParser parser; + CborValue val; + cbor_parser_init(reinterpret_cast<const uint8_t*>(bytes.data()), bytes.size(), + 0, &parser, &val); + uint64_t raw_id; + cbor_value_get_uint64(&val, &raw_id); + return raw_id; +} + +} // namespace database |
