aboutsummaryrefslogtreecommitdiff
path: root/include/dchat
diff options
context:
space:
mode:
Diffstat (limited to 'include/dchat')
-rw-r--r--include/dchat/Cache.hpp102
-rw-r--r--include/dchat/Clock.hpp16
-rw-r--r--include/dchat/Color.hpp24
-rw-r--r--include/dchat/Gif.hpp52
-rw-r--r--include/dchat/StringView.hpp95
-rw-r--r--include/dchat/Vec2.hpp32
-rw-r--r--include/dchat/WebPagePreview.hpp13
-rw-r--r--include/dchat/types.hpp22
8 files changed, 356 insertions, 0 deletions
diff --git a/include/dchat/Cache.hpp b/include/dchat/Cache.hpp
new file mode 100644
index 0000000..debcd5b
--- /dev/null
+++ b/include/dchat/Cache.hpp
@@ -0,0 +1,102 @@
+#pragma once
+
+#include "types.hpp"
+#include "WebPagePreview.hpp"
+#include "StringView.hpp"
+#include <boost/filesystem/path.hpp>
+#include <string>
+#include <unordered_map>
+#include <thread>
+#include <mutex>
+#include <vector>
+#include <chrono>
+#include <functional>
+
+namespace TinyProcessLib
+{
+ class Process;
+}
+
+namespace dchat
+{
+ class Gif;
+ class WebPagePreview;
+
+ struct ContentByUrlResult
+ {
+ enum class Type
+ {
+ CACHED,
+ DOWNLOADING,
+ FAILED_DOWNLOAD
+ };
+
+ enum class CachedType
+ {
+ NONE,
+ TEXTURE_FILEPATH,
+ GIF,
+ WEB_PAGE_PREVIEW
+ };
+
+ ContentByUrlResult() : textureFilePath(nullptr), type(Type::DOWNLOADING), cachedType(CachedType::NONE) {}
+ ContentByUrlResult(boost::filesystem::path *_textureFilePath, Type _type) : textureFilePath(_textureFilePath), type(_type), cachedType(CachedType::TEXTURE_FILEPATH) {}
+ ContentByUrlResult(Gif *_gif, Type _type) : gif(_gif), type(_type), cachedType(CachedType::GIF) {}
+ ContentByUrlResult(WebPagePreview *_webPagePreview, Type _type) : webPagePreview(_webPagePreview), type(_type), cachedType(CachedType::WEB_PAGE_PREVIEW) {}
+
+ // @texture is null if @type is DOWNLOADING or FAILED_DOWNLOAD
+ union
+ {
+ boost::filesystem::path *textureFilePath;
+ Gif *gif;
+ WebPagePreview *webPagePreview;
+ };
+
+ Type type;
+ CachedType cachedType;
+ i64 lastAccessed;
+ };
+
+ using LoadBindsCallbackFunc = std::function<void(const std::string &key, const std::string &value)>;
+ // @fileContent contains data allocated with new[], deallocate it with delete[] fileContent.data;
+ // Returned gif should be allocated with @new
+ using CreateGifFunc = std::function<Gif*(StringView fileContent)>;
+
+ class Cache
+ {
+ public:
+ // @createGifFunc can't be nullptr
+ Cache(CreateGifFunc createGifFunc);
+ ~Cache();
+
+ // Creates directory if it doesn't exist (recursively). Throws boost exception on failure
+ static boost::filesystem::path getDchatDir();
+
+ // Creates directory if it doesn't exist (recursively). Throws boost exception on failure
+ static boost::filesystem::path getImagesDir();
+
+ // @callbackFunc can't be nullptr
+ static void loadBindsFromFile(LoadBindsCallbackFunc callbackFunc);
+ static void replaceBindsInFile(const std::unordered_map<std::string, std::string> &binds);
+
+ // Get cached content or download it.
+ // Default download file limit is 12MB
+ // Returns ContentByUrlResult describing texture status.
+ const ContentByUrlResult getContentByUrl(const std::string &url, int downloadLimitBytes = 12582912);
+ private:
+ struct ImageDownloadInfo
+ {
+ TinyProcessLib::Process *process;
+ std::string url;
+ };
+
+ std::thread downloadWaitThread;
+ std::thread checkContentAccessTimeThread;
+ std::vector<ImageDownloadInfo> imageDownloadProcesses;
+ std::vector<ImageDownloadInfo> imageDownloadProcessesQueue;
+ std::mutex imageDownloadMutex;
+ bool alive;
+ std::unordered_map<std::string, ContentByUrlResult> contentUrlCache;
+ CreateGifFunc createGifFunc;
+ };
+}
diff --git a/include/dchat/Clock.hpp b/include/dchat/Clock.hpp
new file mode 100644
index 0000000..97f78a8
--- /dev/null
+++ b/include/dchat/Clock.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "types.hpp"
+
+namespace dchat
+{
+ class Clock
+ {
+ public:
+ Clock();
+ void restart();
+ i64 getElapsedTimeMillis() const;
+ private:
+ i64 startTime;
+ };
+} \ No newline at end of file
diff --git a/include/dchat/Color.hpp b/include/dchat/Color.hpp
new file mode 100644
index 0000000..2a5d121
--- /dev/null
+++ b/include/dchat/Color.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+namespace dchat
+{
+ class Color
+ {
+ public:
+ Color() : Color(255, 255, 255, 255) {}
+ Color(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha = 255)
+ {
+ data[0] = red;
+ data[1] = green;
+ data[2] = blue;
+ data[3] = alpha;
+ }
+
+ unsigned char red() const { return data[0]; }
+ unsigned char green() const { return data[1]; }
+ unsigned char blue() const { return data[2]; }
+ unsigned char alpha() const { return data[3]; }
+
+ unsigned char data[4];
+ };
+} \ No newline at end of file
diff --git a/include/dchat/Gif.hpp b/include/dchat/Gif.hpp
new file mode 100644
index 0000000..f97ff2f
--- /dev/null
+++ b/include/dchat/Gif.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "StringView.hpp"
+#include "Vec2.hpp"
+#include "Color.hpp"
+#include "Clock.hpp"
+#include <boost/filesystem/path.hpp>
+#include <stdexcept>
+extern "C"
+{
+#include <libnsgif.h>
+}
+
+namespace dchat
+{
+ class GifLoadException : public std::runtime_error
+ {
+ public:
+ GifLoadException(const std::string &errMsg) : std::runtime_error(errMsg) {}
+ };
+
+ class Gif
+ {
+ public:
+ // Throws GifLoadException on error
+ Gif(const boost::filesystem::path &filepath);
+ Gif(StringView fileContent);
+ virtual ~Gif();
+
+ Vec2u getSize() const;
+ void update();
+
+ static bool isDataGif(const StringView &data);
+ protected:
+ // Return false if texture creation failed
+ virtual bool createTexture(int width, int height) = 0;
+ virtual void setPosition(const Vec2f &position) = 0;
+ virtual Vec2f getPosition() const = 0;
+ virtual void setScale(const Vec2f &scale) = 0;
+ virtual void setColor(Color color) = 0;
+ // Size of texture data is same as the size that the texture was created with (also same size returned by @getSize function)
+ virtual void updateTexture(void *textureData) = 0;
+ private:
+ void init();
+ private:
+ gif_animation gif;
+ StringView fileContent;
+ unsigned int currentFrame;
+ double timeElapsedCs;
+ Clock frameTimer;
+ };
+}
diff --git a/include/dchat/StringView.hpp b/include/dchat/StringView.hpp
new file mode 100644
index 0000000..659610a
--- /dev/null
+++ b/include/dchat/StringView.hpp
@@ -0,0 +1,95 @@
+#pragma once
+
+#include "types.hpp"
+#include <string.h>
+#include <assert.h>
+
+namespace dchat
+{
+ template <typename CharType>
+ class BasicStringView
+ {
+ public:
+ BasicStringView() : data(nullptr), size(0)
+ {
+
+ }
+
+ BasicStringView(const BasicStringView<CharType> &other) : data(other.data), size(other.size)
+ {
+
+ }
+
+ BasicStringView(const CharType *_data) : data(_data), size(strlen(_data))
+ {
+
+ }
+
+ BasicStringView(const CharType *_data, usize _size) : data(_data), size(_size)
+ {
+
+ }
+
+ BasicStringView<CharType>& operator = (const BasicStringView<CharType> &other)
+ {
+ data = other.data;
+ size = other.size;
+ return *this;
+ }
+
+ BasicStringView(BasicStringView<CharType> &&other)
+ {
+ data = other.data;
+ size = other.size;
+
+ other.data = nullptr;
+ other.size = 0;
+ }
+
+ bool equals(const BasicStringView<CharType> &other) const
+ {
+ if(size != other.size) return false;
+ return memcmp(data, other.data, size * sizeof(CharType)) == 0;
+ }
+
+ bool operator == (const BasicStringView<CharType> &other) const
+ {
+ return equals(other);
+ }
+
+ bool operator != (const BasicStringView<CharType> &other) const
+ {
+ return !equals(other);
+ }
+
+ CharType operator [] (usize index) const
+ {
+ assert(index < size);
+ return data[index];
+ }
+
+ // Returns -1 if substr not found.
+ // TODO: Make this more efficient
+ usize find(const BasicStringView<CharType> &substr, usize offset = 0) const
+ {
+ if(substr.size == 0)
+ return -1;
+
+ if(offset + substr.size > size)
+ return -1;
+
+ for(usize i = offset; i < size - (substr.size - 1); ++i)
+ {
+ if(memcmp(data + i, substr.data, substr.size * sizeof(CharType)) == 0)
+ return i;
+ }
+ return -1;
+ }
+
+ const CharType *data;
+ usize size;
+ };
+
+ using StringView = BasicStringView<char>;
+ using StringViewUtf32 = BasicStringView<u32>;
+}
diff --git a/include/dchat/Vec2.hpp b/include/dchat/Vec2.hpp
new file mode 100644
index 0000000..cb5f8c0
--- /dev/null
+++ b/include/dchat/Vec2.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+namespace dchat
+{
+ template <typename T>
+ struct Vec2
+ {
+ T x, y;
+
+ Vec2() : x(), y() {}
+ Vec2(T _x, T _y) : x(_x), y(_y) {}
+/*
+ Vec2(const Vec2<T> &other)
+ {
+ x = other.x;
+ y = other.y;
+ }
+
+ Vec2<T>& operator = (const Vec2<T> &other)
+ {
+ x = other.x;
+ y = other.y;
+ return *this;
+ }
+*/
+ };
+
+ using Vec2f = Vec2<float>;
+ using Vec2d = Vec2<double>;
+ using Vec2i = Vec2<int>;
+ using Vec2u = Vec2<unsigned int>;
+} \ No newline at end of file
diff --git a/include/dchat/WebPagePreview.hpp b/include/dchat/WebPagePreview.hpp
new file mode 100644
index 0000000..df75419
--- /dev/null
+++ b/include/dchat/WebPagePreview.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <string>
+
+namespace dchat
+{
+ class WebPagePreview
+ {
+ public:
+ std::string title;
+ std::string description;
+ };
+}
diff --git a/include/dchat/types.hpp b/include/dchat/types.hpp
new file mode 100644
index 0000000..97bfc96
--- /dev/null
+++ b/include/dchat/types.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <stdint.h>
+
+namespace dchat
+{
+ typedef int8_t i8;
+ typedef int16_t i16;
+ typedef int32_t i32;
+ typedef int64_t i64;
+
+ typedef uint8_t u8;
+ typedef uint16_t u16;
+ typedef uint32_t u32;
+ typedef uint64_t u64;
+
+ typedef float f32;
+ typedef double f64;
+
+ typedef intptr_t ssize;
+ typedef uintptr_t usize;
+}