1/*
2 * LegacyClonk
3 *
4 * Copyright (c) RedWolf Design
5 * Copyright (c) 2008, guenther
6 * Copyright (c) 2017-2023, The LegacyClonk Team and contributors
7 *
8 * Distributed under the terms of the ISC license; see accompanying file
9 * "COPYING" for details.
10 *
11 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12 * See accompanying file "TRADEMARK" for details.
13 *
14 * To redistribute this file separately, substitute the full license texts
15 * for the above references.
16 */
17
18#pragma once
19
20#include "C4InteractiveThread.h"
21#include "StdBuf.h"
22#include "StdScheduler.h"
23#include "StdSync.h"
24
25#include <any>
26#include <array>
27#include <functional>
28#include <map>
29
30#ifdef _WIN32
31#include "C4ThreadPool.h"
32#include "C4WinRT.h"
33#elif defined(__APPLE__)
34#include <CoreServices/CoreServices.h>
35#elif defined(__linux__)
36#include "C4Coroutine.h"
37#endif
38
39class C4FileMonitor : public C4InteractiveThread::Callback
40{
41public:
42 using ChangeNotifyCallback = std::function<void(const char *)>;
43
44private:
45 using TaskType = C4Task::Task<void, C4Task::TaskTraitsColdWaitOnDestruction, C4Task::PromiseTraitsTerminateOnException>;
46
47#ifdef _WIN32
48private:
49 class MonitoredDirectory
50 {
51 public:
52 MonitoredDirectory(winrt::file_handle &&handle, std::string path);
53
54 MonitoredDirectory(MonitoredDirectory &&) = delete;
55 MonitoredDirectory &operator=(MonitoredDirectory &&) = delete;
56
57 public:
58 void StartMonitoring();
59
60 private:
61 TaskType Execute();
62
63 private:
64 winrt::file_handle handle;
65 std::string path;
66 TaskType task;
67 std::array<char, 1024> buffer{};
68
69 static constexpr DWORD NotificationFilter{FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE};
70 };
71#elif defined(__APPLE__)
72 template<typename T>
73 struct CFRefDeleter
74 {
75 using pointer = T;
76
77 void operator()(T ref)
78 {
79 CFRelease(ref);
80 }
81 };
82
83 template<typename T>
84 using CFUniquePtr = std::unique_ptr<T, CFRefDeleter<T>>;
85#endif
86
87public:
88 C4FileMonitor(ChangeNotifyCallback &&callback);
89 ~C4FileMonitor();
90
91 void StartMonitoring();
92 void AddDirectory(const char *path);
93
94 // C4InteractiveThread::Callback:
95 virtual void OnThreadEvent(C4InteractiveEventType event, const std::any &eventData) override;
96
97#ifdef __linux__
98 TaskType Execute();
99#endif
100
101private:
102 ChangeNotifyCallback callback;
103#ifndef __linux__
104 bool started{false};
105#endif
106
107#if defined(__linux__)
108 int fd;
109 TaskType task;
110 std::map<int, std::string> watchDescriptors;
111#elif defined(_WIN32)
112 std::vector<std::unique_ptr<MonitoredDirectory>> directories;
113#elif defined(__APPLE__)
114 std::vector<CFUniquePtr<CFStringRef>> paths;
115 FSEventStreamRef eventStream;
116#endif
117};
118