• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bcpearce / hass-motion-detection-addon / 21126887229

19 Jan 2026 05:54AM UTC coverage: 17.99% (-32.0%) from 49.971%
21126887229

Pull #26

github

web-flow
Merge c98d1d60e into 0206cb867
Pull Request #26: Additional test coverage

292 of 1865 branches covered (15.66%)

Branch coverage included in aggregate %.

8 of 22 new or added lines in 3 files covered. (36.36%)

827 existing lines in 29 files now uncovered.

347 of 1687 relevant lines covered (20.57%)

28.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/include/Callback/AsyncFileSave.h
1
#pragma once
2

3
#include "WindowsWrapper.h"
4

5
#include "Callback/Context.h"
6

7
#include <deque>
8
#include <filesystem>
9
#include <memory>
10
#include <string_view>
11
#include <unordered_map>
12

13
#include <UsageEnvironment.hh>
14
#include <boost/circular_buffer.hpp>
15
#include <boost/url.hpp>
16
#include <gsl/gsl>
17

18
#include "Callback/AsyncDebouncer.h"
19
#include "Detector/Detector.h"
20
#include "Util/CurlMultiWrapper.h"
21
#include "Util/CurlWrapper.h"
22

23
#if __linux__
24
#include <aio.h>
25
#include <signal.h>
26
#endif
27

28
namespace callback {
29

30
class AsyncFileSave : protected AsyncDebouncer,
31
                      public std::enable_shared_from_this<AsyncFileSave> {
32

33
public:
34
  AsyncFileSave(std::shared_ptr<TaskScheduler> pSched,
35
                const std::filesystem::path &dstPath,
36
                const boost::url &url = {}, const std::string &user = {},
37
                const std::string &password = {});
38
  AsyncFileSave(const AsyncFileSave &) = delete;
39
  AsyncFileSave(AsyncFileSave &&) = delete;
40
  AsyncFileSave &operator=(const AsyncFileSave &) = delete;
41
  AsyncFileSave &operator=(AsyncFileSave &&) = delete;
42

43
  virtual ~AsyncFileSave() noexcept;
44

45
  void Register();
46
  void SaveFileAtEndpoint(const std::filesystem::path &dst = {});
47

48
  void operator()(detector::Payload data);
49

UNCOV
50
  [[nodiscard]] size_t GetPendingRequestOperations() const {
×
UNCOV
51
    return socketCtxs_.size();
×
52
  }
UNCOV
53
  [[nodiscard]] size_t GetPendingFileOperations() const {
×
UNCOV
54
    return easyCtxs_.size();
×
55
  }
56

57
  [[nodiscard]] const boost::circular_buffer<std::filesystem::path> &
58
  GetSavedFilePaths() const;
59
  [[nodiscard]] const std::filesystem::path &GetDstPath() const noexcept {
×
60
    return dstPath_;
×
61
  }
62

63
  void SetLimitSavedFilePaths(size_t limit);
64

65
  size_t defaultJpgBufferSize{2 * 1024 * 1024}; // default to 2Mb
66
  static constexpr size_t defaultSavedFilePathsSize{200};
67

UNCOV
68
  std::chrono::seconds debounceTime{30};
×
69

70
private:
71
  boost::url url_;
72
  std::string user_;
73
  std::string password_;
74
  std::filesystem::path dstPath_;
75

76
  boost::circular_buffer<std::filesystem::path> savedFilePaths_;
77

78
  gsl::not_null<std::shared_ptr<TaskScheduler>> pSched_;
79
  util::CurlMultiWrapper wCurlMulti_;
80
  TaskToken token_{};
81

82
#if _WIN32
83
  struct Win32Overlapped {
84
    HANDLE hFile{INVALID_HANDLE_VALUE};
85
    OVERLAPPED overlapped{.hEvent{0}};
86
    LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine{nullptr};
87
    std::vector<char> buf;
88
    std::filesystem::path dstPath;
89

90
    ~Win32Overlapped() noexcept;
91
  };
92
  using _CurlEasyContext =
93
      CurlEasyContext<Win32Overlapped, void *, AsyncFileSave>;
94
#elif __linux__
95
  struct LinuxAioFile {
96
    aiocb _aiocb{};
97
    std::vector<char> buf;
98
    std::filesystem::path dstPath;
99

100
    ~LinuxAioFile() noexcept;
101
  };
102
  using _CurlEasyContext = CurlEasyContext<LinuxAioFile, void *, AsyncFileSave>;
103
#endif
104
  using _CurlSocketContext = CurlSocketContext<AsyncFileSave>;
105

106
  std::unordered_map<size_t, std::shared_ptr<_CurlEasyContext>> easyCtxs_;
107
  std::vector<char> spareBuf_;
108
  std::unordered_map<curl_socket_t, std::shared_ptr<_CurlSocketContext>>
109
      socketCtxs_;
110

111
  void CheckMultiInfo();
112

113
  static int SocketCallback(CURL *easy, curl_socket_t s, int action,
114
                            AsyncFileSave *AsyncFileSave,
115
                            _CurlSocketContext *curlSocketContext);
116
  static int TimeoutCallback(CURLM *multi, int timeoutMs,
117
                             AsyncFileSave *AsyncFileSave);
118

119
  static void BackgroundHandlerProc(void *curlSocketContext_clientData,
120
                                    int mask);
121
  static void TimeoutHandlerProc(void *asyncFileSave_clientData);
122
  static void DebounceUpdateProc(void *asyncFileSave_clientData);
123

124
#ifdef __linux__
125
  static void AioSigHandler(int sig, siginfo_t *si, void *ucontext);
126
  static void InstallHandlers();
127
#endif //  __linux__
128

129
#if _WIN32
130
  static VOID
131
      CALLBACK FileIOCompletionRoutine(__in DWORD dwErrorCode,
132
                                       __in DWORD dwNumberOfBytesTransferred,
133
                                       __in LPOVERLAPPED lpOverlapped);
134
#endif
135

136
  static void RemoveContext(_CurlEasyContext *pCtx);
137
};
138

139
} // namespace callback
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc