diff options
Diffstat (limited to 'overlays')
26 files changed, 722 insertions, 233 deletions
diff --git a/overlays/changedetection-io.nix b/overlays/changedetection-io.nix new file mode 100644 index 00000000..95e8985e --- /dev/null +++ b/overlays/changedetection-io.nix | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | { final, prev, ... }: { | ||
| 2 | changedetection-io = prev.changedetection-io.overrideAttrs (oldAttrs: { | ||
| 3 | propagatedBuildInputs = (oldAttrs.propagatedBuildInputs or []) ++ (with final.python3.pkgs; [ | ||
| 4 | playwright | ||
| 5 | ]); | ||
| 6 | }); | ||
| 7 | } | ||
diff --git a/overlays/etesync-dav.nix b/overlays/etesync-dav.nix index cec216e2..e0ced1e3 100644 --- a/overlays/etesync-dav.nix +++ b/overlays/etesync-dav.nix | |||
| @@ -1,55 +1,58 @@ | |||
| 1 | { final, prev, ... }: { | 1 | { final, prev, ... }: { |
| 2 | etesync-dav = prev.python3Packages.buildPythonApplication rec { | 2 | etesync-dav = final.python3Packages.buildPythonApplication rec { |
| 3 | pname = "etesync-dav"; | 3 | pname = "etesync-dav"; |
| 4 | version = "0.33.4"; | 4 | version = "0.35.1"; |
| 5 | pyproject = true; | ||
| 5 | 6 | ||
| 6 | src = prev.fetchFromGitHub { | 7 | src = prev.fetchFromGitHub { |
| 7 | owner = "etesync"; | 8 | owner = "etesync"; |
| 8 | repo = "etesync-dav"; | 9 | repo = "etesync-dav"; |
| 9 | rev = "v${version}"; | 10 | tag = "v${version}"; |
| 10 | hash = "sha256-g+rK762tSWPDaBsaTwpTzfK/lqVs+Z/Qrpq2HCpipQE="; | 11 | hash = "sha256-y4BhU2kSn+RWqc5+pJQFhbwfat9cMWD0ED0EXJp25cY="; |
| 11 | }; | 12 | }; |
| 12 | 13 | ||
| 13 | dependencies = with prev.python3Packages; [ | 14 | build-system = with final.python3Packages; [ setuptools ]; |
| 15 | |||
| 16 | dependencies = with final.python3Packages; [ | ||
| 14 | appdirs | 17 | appdirs |
| 15 | etebase | 18 | etebase |
| 16 | etesync | 19 | etesync |
| 17 | flask | 20 | flask |
| 18 | flask-wtf | 21 | flask-wtf |
| 19 | msgpack | 22 | msgpack |
| 20 | setuptools | 23 | requests |
| 21 | (toPythonModule (buildPythonApplication rec { | 24 | requests.optional-dependencies.socks |
| 25 | (buildPythonApplication rec { | ||
| 22 | pname = "radicale"; | 26 | pname = "radicale"; |
| 23 | version = "3.2.3"; | 27 | version = "3.2.0"; |
| 24 | pyproject = true; | 28 | pyproject = true; |
| 25 | 29 | ||
| 26 | src = prev.fetchFromGitHub { | 30 | src = prev.fetchFromGitHub { |
| 27 | owner = "Kozea"; | 31 | owner = "Kozea"; |
| 28 | repo = "Radicale"; | 32 | repo = "Radicale"; |
| 29 | rev = "refs/tags/v${version}"; | 33 | rev = "refs/tags/v${version}"; |
| 30 | hash = "sha256-1IlnXVetQQuKBt6+QVKNeMM6qBQAiUhqc+4x3xOnSdE="; | 34 | hash = "sha256-RxC8VOfdTXJZiAroDHTKjJqGWu65Z5uyb4WK1LOqubQ="; |
| 31 | }; | 35 | }; |
| 32 | 36 | ||
| 37 | postPatch = '' | ||
| 38 | sed -i '/addopts/d' setup.cfg | ||
| 39 | ''; | ||
| 40 | |||
| 33 | build-system = [ | 41 | build-system = [ |
| 34 | setuptools | 42 | setuptools |
| 35 | ]; | 43 | ]; |
| 36 | 44 | ||
| 37 | dependencies = | 45 | dependencies = [ |
| 38 | [ | 46 | defusedxml |
| 39 | defusedxml | 47 | passlib |
| 40 | passlib | 48 | vobject |
| 41 | vobject | 49 | pika |
| 42 | pika | 50 | python-dateutil |
| 43 | python-dateutil | 51 | pytz # https://github.com/Kozea/Radicale/issues/816 |
| 44 | pytz # https://github.com/Kozea/Radicale/issues/816 | 52 | ] ++ passlib.optional-dependencies.bcrypt; |
| 45 | ] | ||
| 46 | ++ passlib.optional-dependencies.bcrypt; | ||
| 47 | 53 | ||
| 48 | doCheck = false; | 54 | doCheck = false; |
| 49 | })) | 55 | }) |
| 50 | requests | ||
| 51 | types-setuptools | ||
| 52 | requests.optional-dependencies.socks | ||
| 53 | ]; | 56 | ]; |
| 54 | 57 | ||
| 55 | doCheck = false; | 58 | doCheck = false; |
diff --git a/overlays/nftables-prometheus-exporter/nftables-prometheus-exporter.py b/overlays/nftables-prometheus-exporter/nftables-prometheus-exporter.py index 484228c8..60ef4670 100644 --- a/overlays/nftables-prometheus-exporter/nftables-prometheus-exporter.py +++ b/overlays/nftables-prometheus-exporter/nftables-prometheus-exporter.py | |||
| @@ -42,7 +42,7 @@ class NFTMetrics: | |||
| 42 | cls._instance = cls.__new__(cls) | 42 | cls._instance = cls.__new__(cls) |
| 43 | cls._instance.attrs = None | 43 | cls._instance.attrs = None |
| 44 | return cls._instance | 44 | return cls._instance |
| 45 | 45 | ||
| 46 | 46 | ||
| 47 | def __init__(self): | 47 | def __init__(self): |
| 48 | raise RuntimeError('Call instance() instead') | 48 | raise RuntimeError('Call instance() instead') |
| @@ -62,7 +62,7 @@ class NFTMetrics: | |||
| 62 | raise RuntimeError(f'nftables json schema v{version} is not supported') | 62 | raise RuntimeError(f'nftables json schema v{version} is not supported') |
| 63 | queries[query_name] = data['nftables'][1:] | 63 | queries[query_name] = data['nftables'][1:] |
| 64 | 64 | ||
| 65 | 65 | ||
| 66 | def extract_query(query_name, type_name): | 66 | def extract_query(query_name, type_name): |
| 67 | return [ | 67 | return [ |
| 68 | item[type_name] | 68 | item[type_name] |
| @@ -98,21 +98,21 @@ class NFTMetrics: | |||
| 98 | metrics += _format_prom_metrics('nftables_counter_packets_count', 'counter', counter_packets) | 98 | metrics += _format_prom_metrics('nftables_counter_packets_count', 'counter', counter_packets) |
| 99 | 99 | ||
| 100 | map_counts = [] | 100 | map_counts = [] |
| 101 | for meter in self.attrs['maps']: | 101 | for item in self.attrs['maps']: |
| 102 | labels = { k: v for k, v in counter.items() if k not in set(['elem']) } | 102 | labels = { k: v for k, v in counter.items() if k not in set(['elem']) } |
| 103 | map_counts += [(labels, len(meter['elem']))] | 103 | map_counts += [(labels, len(item['elem']) if 'elem' in item else 0)] |
| 104 | metrics += _format_prom_metrics('nftables_map_elem_count', 'gauge', map_counts) | 104 | metrics += _format_prom_metrics('nftables_map_elem_count', 'gauge', map_counts) |
| 105 | 105 | ||
| 106 | meter_counts = [] | 106 | meter_counts = [] |
| 107 | for meter in self.attrs['meters']: | 107 | for item in self.attrs['meters']: |
| 108 | labels = { k: v for k, v in counter.items() if k not in set(['elem']) } | 108 | labels = { k: v for k, v in counter.items() if k not in set(['elem']) } |
| 109 | meter_counts += [(labels, len(meter['elem']))] | 109 | item_counts += [(labels, len(item['elem']) if 'elem' in item else 0)] |
| 110 | metrics += _format_prom_metrics('nftables_meter_elem_count', 'gauge', meter_counts) | 110 | metrics += _format_prom_metrics('nftables_meter_elem_count', 'gauge', meter_counts) |
| 111 | 111 | ||
| 112 | set_counts = [] | 112 | set_counts = [] |
| 113 | for meter in self.attrs['sets']: | 113 | for item in self.attrs['sets']: |
| 114 | labels = { k: v for k, v in counter.items() if k not in set(['elem']) } | 114 | labels = { k: v for k, v in counter.items() if k not in set(['elem']) } |
| 115 | set_counts += [(labels, len(meter['elem']))] | 115 | set_counts += [(labels, len(item['elem']) if 'elem' in item else 0)] |
| 116 | metrics += _format_prom_metrics('nftables_set_elem_count', 'gauge', set_counts) | 116 | metrics += _format_prom_metrics('nftables_set_elem_count', 'gauge', set_counts) |
| 117 | 117 | ||
| 118 | return metrics.encode('utf-8') | 118 | return metrics.encode('utf-8') |
| @@ -120,7 +120,7 @@ class NFTMetrics: | |||
| 120 | class NFTMetricsServer(BaseHTTPRequestHandler): | 120 | class NFTMetricsServer(BaseHTTPRequestHandler): |
| 121 | def log_message(self, format, *args): | 121 | def log_message(self, format, *args): |
| 122 | pass | 122 | pass |
| 123 | 123 | ||
| 124 | def do_GET(self): | 124 | def do_GET(self): |
| 125 | nft_metrics = NFTMetrics.instance() | 125 | nft_metrics = NFTMetrics.instance() |
| 126 | nft_metrics.update() | 126 | nft_metrics.update() |
| @@ -138,7 +138,7 @@ class NFTMetricsServer(BaseHTTPRequestHandler): | |||
| 138 | self.send_response(200) | 138 | self.send_response(200) |
| 139 | self.send_header("Content-type", "text/plain") | 139 | self.send_header("Content-type", "text/plain") |
| 140 | self.end_headers() | 140 | self.end_headers() |
| 141 | 141 | ||
| 142 | self.wfile.write(nft_metrics.prometheus()) | 142 | self.wfile.write(nft_metrics.prometheus()) |
| 143 | case _: | 143 | case _: |
| 144 | self.send_response(404) | 144 | self.send_response(404) |
diff --git a/overlays/niri.nix b/overlays/niri.nix index 9188ed7d..95a918b0 100644 --- a/overlays/niri.nix +++ b/overlays/niri.nix | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | (final: prev: { | 3 | (final: prev: { |
| 4 | niri-unstable = prev.niri-unstable.overrideAttrs (oldAttrs: { | 4 | niri-unstable = prev.niri-unstable.overrideAttrs (oldAttrs: { |
| 5 | buildInputs = (oldAttrs.buildInputs or []) ++ [ final.libgbm ]; | 5 | buildInputs = (oldAttrs.buildInputs or []) ++ [ final.libgbm ]; |
| 6 | doCheck = false; | ||
| 6 | }); | 7 | }); |
| 7 | }) | 8 | }) |
| 8 | final prev | 9 | final prev |
diff --git a/overlays/nix-output-monitor.nix b/overlays/nix-output-monitor.nix new file mode 100644 index 00000000..a15913ef --- /dev/null +++ b/overlays/nix-output-monitor.nix | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | { final, prev, sources, ... }: | ||
| 2 | { | ||
| 3 | nix-output-monitor = prev.nix-output-monitor.overrideAttrs (oldAttrs: prev.lib.optionalAttrs (prev.lib.versionAtLeast prev.ghc.version "9.10.1") { | ||
| 4 | inherit (sources.nix-output-monitor) version src; | ||
| 5 | }); | ||
| 6 | } | ||
diff --git a/overlays/postfix-mta-sts-resolver/default.nix b/overlays/postfix-mta-sts-resolver/default.nix index 52ab2d40..c210cf79 100644 --- a/overlays/postfix-mta-sts-resolver/default.nix +++ b/overlays/postfix-mta-sts-resolver/default.nix | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | projectDir = cleanPythonSources { | 11 | projectDir = cleanPythonSources { |
| 12 | src = prev.runCommand "sources" {} '' | 12 | src = prev.runCommand "sources" {} '' |
| 13 | mkdir $out | 13 | mkdir $out |
| 14 | cp -r ${sources.postfix-mta-sts-resolver.src}/. $out | 14 | cp -r --no-preserve=all ${sources.postfix-mta-sts-resolver.src}/. $out |
| 15 | 15 | ||
| 16 | cp ${./pyproject.toml} $out/pyproject.toml | 16 | cp ${./pyproject.toml} $out/pyproject.toml |
| 17 | cp ${./poetry.lock} $out/poetry.lock | 17 | cp ${./poetry.lock} $out/poetry.lock |
diff --git a/overlays/prometheus-lvm-exporter.nix b/overlays/prometheus-lvm-exporter.nix index 240f8d85..72d9c7ca 100644 --- a/overlays/prometheus-lvm-exporter.nix +++ b/overlays/prometheus-lvm-exporter.nix | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | pname = "prometheus-lvm-exporter"; | 3 | pname = "prometheus-lvm-exporter"; |
| 4 | inherit (sources.prometheus-lvm-exporter) version src; | 4 | inherit (sources.prometheus-lvm-exporter) version src; |
| 5 | 5 | ||
| 6 | vendorHash = "sha256-z/fV0PzoWSDTJ44En19o7zJPPPox5ymFw7sw0Ab9t00="; | 6 | vendorHash = "sha256-CoTNTCBBugbHWDsOuZY1t8HrpdmEbbSMyVb3+1u0q+g="; |
| 7 | 7 | ||
| 8 | doCheck = false; | 8 | doCheck = false; |
| 9 | 9 | ||
diff --git a/overlays/quickshell/default.nix b/overlays/quickshell/default.nix new file mode 100644 index 00000000..7c4a263d --- /dev/null +++ b/overlays/quickshell/default.nix | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | { final, prev, sources, ... }: | ||
| 2 | { | ||
| 3 | quickshell = prev.quickshell.overrideAttrs (oldAttrs: { | ||
| 4 | inherit (sources.quickshell) version src; | ||
| 5 | |||
| 6 | buildInputs = (oldAttrs.buildInputs or []) ++ [ final.polkit.dev ]; | ||
| 7 | |||
| 8 | patches = (oldAttrs.patches or []) ++ [ | ||
| 9 | ./lock-state-changed.patch | ||
| 10 | ./pipewire.patch | ||
| 11 | ./io.patch | ||
| 12 | ]; | ||
| 13 | }); | ||
| 14 | } | ||
diff --git a/overlays/quickshell/io.patch b/overlays/quickshell/io.patch new file mode 100644 index 00000000..961bdcaf --- /dev/null +++ b/overlays/quickshell/io.patch | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | diff --git i/src/io/socket.cpp w/src/io/socket.cpp | ||
| 2 | index 371f687..d12eaeb 100644 | ||
| 3 | --- i/src/io/socket.cpp | ||
| 4 | +++ w/src/io/socket.cpp | ||
| 5 | @@ -66,7 +66,7 @@ void Socket::onSocketDisconnected() { | ||
| 6 | } | ||
| 7 | |||
| 8 | void Socket::onSocketError(QLocalSocket::LocalSocketError error) { | ||
| 9 | - qCWarning(logSocket) << "Socket error for" << this << error; | ||
| 10 | + // qCWarning(logSocket) << "Socket error for" << this << error; | ||
| 11 | emit this->error(error); | ||
| 12 | } | ||
| 13 | |||
diff --git a/overlays/quickshell/lock-state-changed.patch b/overlays/quickshell/lock-state-changed.patch new file mode 100644 index 00000000..4be273fa --- /dev/null +++ b/overlays/quickshell/lock-state-changed.patch | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | diff --git i/src/wayland/session_lock.cpp w/src/wayland/session_lock.cpp | ||
| 2 | index 0ecf9ec..3dbd19b 100644 | ||
| 3 | --- i/src/wayland/session_lock.cpp | ||
| 4 | +++ w/src/wayland/session_lock.cpp | ||
| 5 | @@ -127,6 +127,7 @@ void WlSessionLock::realizeLockTarget(WlSessionLock* old) { | ||
| 6 | this->updateSurfaces(false); | ||
| 7 | |||
| 8 | if (!this->manager->lock()) this->lockTarget = false; | ||
| 9 | + emit this->lockStateChanged(); | ||
| 10 | |||
| 11 | this->updateSurfaces(true, old); | ||
| 12 | } else { | ||
diff --git a/overlays/quickshell/pipewire.patch b/overlays/quickshell/pipewire.patch new file mode 100644 index 00000000..2d98eefc --- /dev/null +++ b/overlays/quickshell/pipewire.patch | |||
| @@ -0,0 +1,488 @@ | |||
| 1 | diff --git i/src/services/pipewire/device.cpp w/src/services/pipewire/device.cpp | ||
| 2 | index 616e7d0..0c55008 100644 | ||
| 3 | --- i/src/services/pipewire/device.cpp | ||
| 4 | +++ w/src/services/pipewire/device.cpp | ||
| 5 | @@ -3,6 +3,7 @@ | ||
| 6 | #include <cstdint> | ||
| 7 | #include <functional> | ||
| 8 | #include <utility> | ||
| 9 | +#include <algorithm> | ||
| 10 | |||
| 11 | #include <pipewire/device.h> | ||
| 12 | #include <qcontainerfwd.h> | ||
| 13 | @@ -19,6 +20,8 @@ | ||
| 14 | #include <spa/pod/pod.h> | ||
| 15 | #include <spa/pod/vararg.h> | ||
| 16 | #include <spa/utils/type.h> | ||
| 17 | +#include <spa/monitor/device.h> | ||
| 18 | +#include <spa/utils/keys.h> | ||
| 19 | |||
| 20 | #include "../../core/logcat.hpp" | ||
| 21 | #include "core.hpp" | ||
| 22 | @@ -46,6 +49,25 @@ void PwDevice::unbindHooks() { | ||
| 23 | this->mWaitingForDevice = false; | ||
| 24 | } | ||
| 25 | |||
| 26 | +void PwDevice::initProps(const spa_dict* props) { | ||
| 27 | + if (const auto* deviceName = spa_dict_lookup(props, SPA_KEY_DEVICE_NAME)) { | ||
| 28 | + this->name = deviceName; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + if (const auto* deviceDesc = spa_dict_lookup(props, SPA_KEY_DEVICE_DESCRIPTION)) { | ||
| 32 | + this->description = deviceDesc; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + if (const auto* deviceNick = spa_dict_lookup(props, SPA_KEY_DEVICE_NICK)) { | ||
| 36 | + this->nick = deviceNick; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + if (const auto* mediaClass = spa_dict_lookup(props, SPA_KEY_MEDIA_CLASS)) { | ||
| 40 | + this->type = mediaClass; | ||
| 41 | + } | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | + | ||
| 45 | const pw_device_events PwDevice::EVENTS = { | ||
| 46 | .version = PW_VERSION_DEVICE_EVENTS, | ||
| 47 | .info = &PwDevice::onInfo, | ||
| 48 | @@ -71,6 +93,11 @@ void PwDevice::onInfo(void* data, const pw_device_info* info) { | ||
| 49 | } | ||
| 50 | |||
| 51 | break; | ||
| 52 | + } else if (param.id == SPA_PARAM_EnumProfile && param.flags & SPA_PARAM_INFO_READ) { | ||
| 53 | + self->validProfiles.clear(); | ||
| 54 | + pw_device_enum_params(self->proxy(), 0, param.id, 0, UINT32_MAX, nullptr); | ||
| 55 | + } else if (param.id == SPA_PARAM_Profile && param.flags & SPA_PARAM_INFO_READ) { | ||
| 56 | + pw_device_enum_params(self->proxy(), 0, param.id, 0, UINT32_MAX, nullptr); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | @@ -97,6 +124,15 @@ void PwDevice::onParam( | ||
| 61 | } | ||
| 62 | |||
| 63 | self->addDeviceIndexPairs(param); | ||
| 64 | + } else if (id == SPA_PARAM_EnumProfile) { | ||
| 65 | + PwProfile profile = PwProfile::parseSpaPod(param); | ||
| 66 | + self->profilesUpdated = true; | ||
| 67 | + self->profiles.insertOrAssign(profile.index, profile); | ||
| 68 | + self->validProfiles.insert(profile.index); | ||
| 69 | + } else if (id == SPA_PARAM_Profile) { | ||
| 70 | + PwProfile profile = PwProfile::parseSpaPod(param); | ||
| 71 | + self->currentProfileUpdated = true; | ||
| 72 | + self->currentProfile = profile; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | @@ -145,6 +181,21 @@ void PwDevice::polled() { | ||
| 77 | return false; | ||
| 78 | }); | ||
| 79 | } | ||
| 80 | + if (this->profilesUpdated) { | ||
| 81 | + this->profiles.removeIf([&](const std::pair<qint32, PwProfile>& entry) { | ||
| 82 | + return !this->validProfiles.contains(entry.first); | ||
| 83 | + }); | ||
| 84 | + this->profilesUpdated = false; | ||
| 85 | + QList<PwProfile> profiles = this->profiles.values(); | ||
| 86 | + std::sort(profiles.begin(), profiles.end(), [](const PwProfile& a, const PwProfile& b) { return a.index < b.index; }); | ||
| 87 | + emit this->profilesChanged(profiles); | ||
| 88 | + } | ||
| 89 | + if (this->currentProfileUpdated) { | ||
| 90 | + this->currentProfileUpdated = false; | ||
| 91 | + if (this->currentProfile) { | ||
| 92 | + emit this->currentProfileChanged(*this->currentProfile); | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | } | ||
| 96 | |||
| 97 | bool PwDevice::setVolumes(qint32 routeDevice, const QVector<float>& volumes) { | ||
| 98 | @@ -182,6 +233,15 @@ bool PwDevice::setMuted(qint32 routeDevice, bool muted) { | ||
| 99 | }); | ||
| 100 | } | ||
| 101 | |||
| 102 | +void PwDevice::setProfile(qint32 profileIndex) { | ||
| 103 | + auto buffer = std::array<uint8_t, 1024>(); | ||
| 104 | + auto builder = SPA_POD_BUILDER_INIT(buffer.data(), buffer.size()); | ||
| 105 | + auto* pod = spa_pod_builder_add_object(&builder, | ||
| 106 | + SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile, | ||
| 107 | + SPA_PARAM_PROFILE_index, SPA_POD_Int(profileIndex)); | ||
| 108 | + pw_device_set_param(this->proxy(), SPA_PARAM_Profile, 0, static_cast<spa_pod*>(pod)); | ||
| 109 | +} | ||
| 110 | + | ||
| 111 | void PwDevice::waitForDevice() { this->mWaitingForDevice = true; } | ||
| 112 | bool PwDevice::waitingForDevice() const { return this->mWaitingForDevice; } | ||
| 113 | |||
| 114 | @@ -222,4 +282,24 @@ bool PwDevice::setRouteProps( | ||
| 115 | return true; | ||
| 116 | } | ||
| 117 | |||
| 118 | +PwProfile PwProfile::parseSpaPod(const spa_pod* param) { | ||
| 119 | + PwProfile profile; | ||
| 120 | + | ||
| 121 | + const auto* indexProp = spa_pod_find_prop(param, nullptr, SPA_PARAM_PROFILE_index); | ||
| 122 | + const auto* descProp = spa_pod_find_prop(param, nullptr, SPA_PARAM_PROFILE_description); | ||
| 123 | + const auto* nameProp = spa_pod_find_prop(param, nullptr, SPA_PARAM_PROFILE_name); | ||
| 124 | + | ||
| 125 | + spa_pod_get_int(&indexProp->value, &profile.index); | ||
| 126 | + | ||
| 127 | + const char* desc_cstr = nullptr; | ||
| 128 | + spa_pod_get_string(&descProp->value, &desc_cstr); | ||
| 129 | + profile.description = QString(desc_cstr); | ||
| 130 | + | ||
| 131 | + const char* name_cstr = nullptr; | ||
| 132 | + spa_pod_get_string(&nameProp->value, &name_cstr); | ||
| 133 | + profile.name = QString(name_cstr); | ||
| 134 | + | ||
| 135 | + return profile; | ||
| 136 | +} | ||
| 137 | + | ||
| 138 | } // namespace qs::service::pipewire | ||
| 139 | diff --git i/src/services/pipewire/device.hpp w/src/services/pipewire/device.hpp | ||
| 140 | index 1a1f705..ee64858 100644 | ||
| 141 | --- i/src/services/pipewire/device.hpp | ||
| 142 | +++ w/src/services/pipewire/device.hpp | ||
| 143 | @@ -1,6 +1,7 @@ | ||
| 144 | #pragma once | ||
| 145 | |||
| 146 | #include <functional> | ||
| 147 | +#include <optional> | ||
| 148 | |||
| 149 | #include <pipewire/core.h> | ||
| 150 | #include <pipewire/device.h> | ||
| 151 | @@ -17,6 +18,20 @@ | ||
| 152 | |||
| 153 | namespace qs::service::pipewire { | ||
| 154 | |||
| 155 | +struct PwProfile { | ||
| 156 | + Q_GADGET; | ||
| 157 | + Q_PROPERTY(qint32 index MEMBER index) | ||
| 158 | + Q_PROPERTY(QString description MEMBER description) | ||
| 159 | + Q_PROPERTY(QString name MEMBER name) | ||
| 160 | + | ||
| 161 | +public: | ||
| 162 | + qint32 index; | ||
| 163 | + QString description; | ||
| 164 | + QString name; | ||
| 165 | + | ||
| 166 | + static PwProfile parseSpaPod(const spa_pod* param); | ||
| 167 | +}; | ||
| 168 | + | ||
| 169 | class PwDevice; | ||
| 170 | |||
| 171 | class PwDevice: public PwBindable<pw_device, PW_TYPE_INTERFACE_Device, PW_VERSION_DEVICE> { | ||
| 172 | @@ -25,6 +40,12 @@ class PwDevice: public PwBindable<pw_device, PW_TYPE_INTERFACE_Device, PW_VERSIO | ||
| 173 | public: | ||
| 174 | void bindHooks() override; | ||
| 175 | void unbindHooks() override; | ||
| 176 | + void initProps(const spa_dict* props) override; | ||
| 177 | + | ||
| 178 | + QString name; | ||
| 179 | + QString description; | ||
| 180 | + QString nick; | ||
| 181 | + QString type; | ||
| 182 | |||
| 183 | bool setVolumes(qint32 routeDevice, const QVector<float>& volumes); | ||
| 184 | bool setMuted(qint32 routeDevice, bool muted); | ||
| 185 | @@ -32,9 +53,16 @@ public: | ||
| 186 | void waitForDevice(); | ||
| 187 | [[nodiscard]] bool waitingForDevice() const; | ||
| 188 | |||
| 189 | + void setProfile(qint32 profileIndex); | ||
| 190 | + | ||
| 191 | + QHash<qint32, PwProfile> profiles; | ||
| 192 | + std::optional<PwProfile> currentProfile; | ||
| 193 | + | ||
| 194 | signals: | ||
| 195 | void deviceReady(); | ||
| 196 | void routeVolumesChanged(qint32 routeDevice, const PwVolumeProps& volumeProps); | ||
| 197 | + void profilesChanged(QList<PwProfile> profiles); | ||
| 198 | + void currentProfileChanged(PwProfile profile); | ||
| 199 | |||
| 200 | private slots: | ||
| 201 | void polled(); | ||
| 202 | @@ -49,6 +77,11 @@ private: | ||
| 203 | QList<qint32> stagingIndexes; | ||
| 204 | void addDeviceIndexPairs(const spa_pod* param); | ||
| 205 | |||
| 206 | + bool profilesUpdated = false; | ||
| 207 | + QSet<qint32> validProfiles; | ||
| 208 | + | ||
| 209 | + bool currentProfileUpdated = false; | ||
| 210 | + | ||
| 211 | bool | ||
| 212 | setRouteProps(qint32 routeDevice, const std::function<void*(spa_pod_builder*)>& propsCallback); | ||
| 213 | |||
| 214 | diff --git i/src/services/pipewire/node.cpp w/src/services/pipewire/node.cpp | ||
| 215 | index 3e68149..4721a58 100644 | ||
| 216 | --- i/src/services/pipewire/node.cpp | ||
| 217 | +++ w/src/services/pipewire/node.cpp | ||
| 218 | @@ -145,6 +145,10 @@ void PwNode::initProps(const spa_dict* props) { | ||
| 219 | this->type = PwNodeType::VideoSink; | ||
| 220 | } else if (strcmp(mediaClass, "Video/Source") == 0) { | ||
| 221 | this->type = PwNodeType::VideoSource; | ||
| 222 | + } else if (strcmp(mediaClass, "Stream/Output/Video") == 0) { | ||
| 223 | + this->type = PwNodeType::VideoOutStream; | ||
| 224 | + } else if (strcmp(mediaClass, "Stream/Input/Video") == 0) { | ||
| 225 | + this->type = PwNodeType::VideoInStream; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | diff --git i/src/services/pipewire/node.hpp w/src/services/pipewire/node.hpp | ||
| 230 | index 0d4c92e..ee6f223 100644 | ||
| 231 | --- i/src/services/pipewire/node.hpp | ||
| 232 | +++ w/src/services/pipewire/node.hpp | ||
| 233 | @@ -144,6 +144,8 @@ public: | ||
| 234 | // This is equivalent to the media class `Video/Sink` and is composed of the | ||
| 235 | // @@PwNodeType.Video and @@PwNodeType.Sink flags. | ||
| 236 | VideoSink = Video | Sink, | ||
| 237 | + VideoOutStream = Video | Sink | Stream, | ||
| 238 | + VideoInStream = Video | Source | Stream, | ||
| 239 | }; | ||
| 240 | Q_ENUM(Flag); | ||
| 241 | Q_DECLARE_FLAGS(Flags, Flag); | ||
| 242 | diff --git i/src/services/pipewire/qml.cpp w/src/services/pipewire/qml.cpp | ||
| 243 | index 9efb17e..921d12a 100644 | ||
| 244 | --- i/src/services/pipewire/qml.cpp | ||
| 245 | +++ w/src/services/pipewire/qml.cpp | ||
| 246 | @@ -9,6 +9,9 @@ | ||
| 247 | #include <qtypes.h> | ||
| 248 | #include <qvariant.h> | ||
| 249 | |||
| 250 | +#include <cstdint> | ||
| 251 | +#include <algorithm> | ||
| 252 | + | ||
| 253 | #include "../../core/model.hpp" | ||
| 254 | #include "connection.hpp" | ||
| 255 | #include "defaults.hpp" | ||
| 256 | @@ -54,6 +57,12 @@ Pipewire::Pipewire(QObject* parent): QObject(parent) { | ||
| 257 | |||
| 258 | QObject::connect(&connection->registry, &PwRegistry::nodeAdded, this, &Pipewire::onNodeAdded); | ||
| 259 | |||
| 260 | + for (auto* device: connection->registry.devices.values()) { | ||
| 261 | + this->onDeviceAdded(device); | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + QObject::connect(&connection->registry, &PwRegistry::deviceAdded, this, &Pipewire::onDeviceAdded); | ||
| 265 | + | ||
| 266 | for (auto* link: connection->registry.links.values()) { | ||
| 267 | this->onLinkAdded(link); | ||
| 268 | } | ||
| 269 | @@ -123,6 +132,19 @@ void Pipewire::onNodeRemoved(QObject* object) { | ||
| 270 | this->mNodes.removeObject(iface); | ||
| 271 | } | ||
| 272 | |||
| 273 | +ObjectModel<PwDeviceIface>* Pipewire::devices() { return &this->mDevices; } | ||
| 274 | + | ||
| 275 | +void Pipewire::onDeviceAdded(PwDevice* device) { | ||
| 276 | + auto* iface = PwDeviceIface::instance(device); | ||
| 277 | + QObject::connect(iface, &QObject::destroyed, this, &Pipewire::onDeviceRemoved); | ||
| 278 | + this->mDevices.insertObject(iface); | ||
| 279 | +} | ||
| 280 | + | ||
| 281 | +void Pipewire::onDeviceRemoved(QObject* object) { | ||
| 282 | + auto* iface = static_cast<PwDeviceIface*>(object); // NOLINT | ||
| 283 | + this->mDevices.removeObject(iface); | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | ObjectModel<PwLinkIface>* Pipewire::links() { return &this->mLinks; } | ||
| 287 | |||
| 288 | void Pipewire::onLinkAdded(PwLink* link) { | ||
| 289 | @@ -357,6 +379,8 @@ QVariantMap PwNodeIface::properties() const { | ||
| 290 | |||
| 291 | PwNodeAudioIface* PwNodeIface::audio() const { return this->audioIface; } | ||
| 292 | |||
| 293 | +PwDeviceIface* PwNodeIface::device() const { return PwDeviceIface::instance(this->mNode->device); } | ||
| 294 | + | ||
| 295 | PwNodeIface* PwNodeIface::instance(PwNode* node) { | ||
| 296 | if (node == nullptr) return nullptr; | ||
| 297 | |||
| 298 | @@ -481,4 +505,42 @@ void PwObjectTracker::objectDestroyed(QObject* object) { | ||
| 299 | emit this->objectsChanged(); | ||
| 300 | } | ||
| 301 | |||
| 302 | +PwDeviceIface::PwDeviceIface(PwDevice* device): PwObjectIface(device), mDevice(device) { | ||
| 303 | + QObject::connect(device, &PwDevice::profilesChanged, this, &PwDeviceIface::deviceProfilesChanged); | ||
| 304 | + QObject::connect(device, &PwDevice::currentProfileChanged, this, &PwDeviceIface::deviceCurrentProfileChanged); | ||
| 305 | +} | ||
| 306 | + | ||
| 307 | +void PwDeviceIface::deviceProfilesChanged(QList<PwProfile>) { emit this->profilesChanged(); } | ||
| 308 | +void PwDeviceIface::deviceCurrentProfileChanged(PwProfile) { emit this->currentProfileChanged(); } | ||
| 309 | + | ||
| 310 | +quint32 PwDeviceIface::id() const { return this->mDevice->id; } | ||
| 311 | +QString PwDeviceIface::name() const { return this->mDevice->name; } | ||
| 312 | +QString PwDeviceIface::description() const { return this->mDevice->description; } | ||
| 313 | +QString PwDeviceIface::nickname() const { return this->mDevice->nick; } | ||
| 314 | +QString PwDeviceIface::type() const { return this->mDevice->type; } | ||
| 315 | +QList<PwProfile> PwDeviceIface::profiles() const { | ||
| 316 | + QList<PwProfile> profiles = this->mDevice->profiles.values(); | ||
| 317 | + std::sort(profiles.begin(), profiles.end(), [](const PwProfile& a, const PwProfile& b) { return a.index < b.index; }); | ||
| 318 | + return profiles; | ||
| 319 | +} | ||
| 320 | +qint32 PwDeviceIface::currentProfile() const { return this->mDevice->currentProfile->index; } | ||
| 321 | + | ||
| 322 | +PwDeviceIface* PwDeviceIface::instance(PwDevice* device) { | ||
| 323 | + if (device == nullptr) return nullptr; | ||
| 324 | + | ||
| 325 | + auto v = device->property("iface"); | ||
| 326 | + if (v.canConvert<PwDeviceIface*>()) { | ||
| 327 | + return v.value<PwDeviceIface*>(); | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + auto* instance = new PwDeviceIface(device); | ||
| 331 | + device->setProperty("iface", QVariant::fromValue(instance)); | ||
| 332 | + | ||
| 333 | + return instance; | ||
| 334 | +} | ||
| 335 | + | ||
| 336 | +void PwDeviceIface::setProfile(qint32 profileIndex) { | ||
| 337 | + this->mDevice->setProfile(profileIndex); | ||
| 338 | +} | ||
| 339 | + | ||
| 340 | } // namespace qs::service::pipewire | ||
| 341 | diff --git i/src/services/pipewire/qml.hpp w/src/services/pipewire/qml.hpp | ||
| 342 | index e3489a1..e5e1891 100644 | ||
| 343 | --- i/src/services/pipewire/qml.hpp | ||
| 344 | +++ w/src/services/pipewire/qml.hpp | ||
| 345 | @@ -12,11 +12,13 @@ | ||
| 346 | #include "../../core/model.hpp" | ||
| 347 | #include "link.hpp" | ||
| 348 | #include "node.hpp" | ||
| 349 | +#include "device.hpp" | ||
| 350 | #include "registry.hpp" | ||
| 351 | |||
| 352 | namespace qs::service::pipewire { | ||
| 353 | |||
| 354 | class PwNodeIface; | ||
| 355 | +class PwDeviceIface; | ||
| 356 | class PwLinkIface; | ||
| 357 | class PwLinkGroupIface; | ||
| 358 | |||
| 359 | @@ -65,6 +67,8 @@ class Pipewire: public QObject { | ||
| 360 | /// - @@PwNode.audio - if non null the node is an audio node. | ||
| 361 | QSDOC_TYPE_OVERRIDE(ObjectModel<qs::service::pipewire::PwNodeIface>*); | ||
| 362 | Q_PROPERTY(UntypedObjectModel* nodes READ nodes CONSTANT); | ||
| 363 | + QSDOC_TYPE_OVERRIDE(ObjectModel<qs::service::pipewire::PwDeviceIface>*); | ||
| 364 | + Q_PROPERTY(UntypedObjectModel* devices READ devices CONSTANT); | ||
| 365 | /// All links present in pipewire. | ||
| 366 | /// | ||
| 367 | /// Links connect pipewire nodes to each other, and can be used to determine | ||
| 368 | @@ -134,6 +138,7 @@ public: | ||
| 369 | explicit Pipewire(QObject* parent = nullptr); | ||
| 370 | |||
| 371 | [[nodiscard]] ObjectModel<PwNodeIface>* nodes(); | ||
| 372 | + [[nodiscard]] ObjectModel<PwDeviceIface>* devices(); | ||
| 373 | [[nodiscard]] ObjectModel<PwLinkIface>* links(); | ||
| 374 | [[nodiscard]] ObjectModel<PwLinkGroupIface>* linkGroups(); | ||
| 375 | |||
| 376 | @@ -159,7 +164,9 @@ signals: | ||
| 377 | |||
| 378 | private slots: | ||
| 379 | void onNodeAdded(PwNode* node); | ||
| 380 | + void onDeviceAdded(PwDevice* node); | ||
| 381 | void onNodeRemoved(QObject* object); | ||
| 382 | + void onDeviceRemoved(QObject* object); | ||
| 383 | void onLinkAdded(PwLink* link); | ||
| 384 | void onLinkRemoved(QObject* object); | ||
| 385 | void onLinkGroupAdded(PwLinkGroup* group); | ||
| 386 | @@ -167,6 +174,7 @@ private slots: | ||
| 387 | |||
| 388 | private: | ||
| 389 | ObjectModel<PwNodeIface> mNodes {this}; | ||
| 390 | + ObjectModel<PwDeviceIface> mDevices {this}; | ||
| 391 | ObjectModel<PwLinkIface> mLinks {this}; | ||
| 392 | ObjectModel<PwLinkGroupIface> mLinkGroups {this}; | ||
| 393 | }; | ||
| 394 | @@ -315,6 +323,7 @@ class PwNodeIface: public PwObjectIface { | ||
| 395 | /// > [!NOTE] The node may be used before it is fully bound, but some data | ||
| 396 | /// > may be missing or incorrect. | ||
| 397 | Q_PROPERTY(bool ready READ isReady NOTIFY readyChanged); | ||
| 398 | + Q_PROPERTY(qs::service::pipewire::PwDeviceIface* device READ device CONSTANT); | ||
| 399 | QML_NAMED_ELEMENT(PwNode); | ||
| 400 | QML_UNCREATABLE("PwNodes cannot be created directly"); | ||
| 401 | |||
| 402 | @@ -332,6 +341,7 @@ public: | ||
| 403 | [[nodiscard]] PwNodeType::Flags type() const; | ||
| 404 | [[nodiscard]] QVariantMap properties() const; | ||
| 405 | [[nodiscard]] PwNodeAudioIface* audio() const; | ||
| 406 | + [[nodiscard]] PwDeviceIface* device() const; | ||
| 407 | |||
| 408 | static PwNodeIface* instance(PwNode* node); | ||
| 409 | |||
| 410 | @@ -344,6 +354,44 @@ private: | ||
| 411 | PwNodeAudioIface* audioIface = nullptr; | ||
| 412 | }; | ||
| 413 | |||
| 414 | +class PwDeviceIface: public PwObjectIface { | ||
| 415 | + Q_OBJECT; | ||
| 416 | + Q_PROPERTY(quint32 id READ id CONSTANT); | ||
| 417 | + Q_PROPERTY(QString name READ name CONSTANT); | ||
| 418 | + Q_PROPERTY(QString description READ description CONSTANT); | ||
| 419 | + Q_PROPERTY(QString nickname READ nickname CONSTANT); | ||
| 420 | + Q_PROPERTY(QString type READ type CONSTANT); | ||
| 421 | + Q_PROPERTY(QList<PwProfile> profiles READ profiles NOTIFY profilesChanged); | ||
| 422 | + Q_PROPERTY(qint32 currentProfile READ currentProfile NOTIFY currentProfileChanged); | ||
| 423 | + | ||
| 424 | + QML_NAMED_ELEMENT(PwDevice); | ||
| 425 | + QML_UNCREATABLE("PwDevices cannot be created directly"); | ||
| 426 | + | ||
| 427 | +signals: | ||
| 428 | + void profilesChanged(); | ||
| 429 | + void currentProfileChanged(); | ||
| 430 | + | ||
| 431 | +public: | ||
| 432 | + explicit PwDeviceIface(PwDevice* node); | ||
| 433 | + | ||
| 434 | + [[nodiscard]] quint32 id() const; | ||
| 435 | + [[nodiscard]] QString name() const; | ||
| 436 | + [[nodiscard]] QString description() const; | ||
| 437 | + [[nodiscard]] QString nickname() const; | ||
| 438 | + [[nodiscard]] QString type() const; | ||
| 439 | + QList<PwProfile> profiles() const; | ||
| 440 | + qint32 currentProfile() const; | ||
| 441 | + | ||
| 442 | + Q_INVOKABLE void setProfile(qint32 profileIndex); | ||
| 443 | + | ||
| 444 | + static PwDeviceIface* instance(PwDevice* node); | ||
| 445 | +private: | ||
| 446 | + PwDevice* mDevice; | ||
| 447 | + | ||
| 448 | + void deviceProfilesChanged(QList<PwProfile> profiles); | ||
| 449 | + void deviceCurrentProfileChanged(PwProfile profile); | ||
| 450 | +}; | ||
| 451 | + | ||
| 452 | ///! A connection between pipewire nodes. | ||
| 453 | /// Note that there is one link per *channel* of a connection between nodes. | ||
| 454 | /// You usually want @@PwLinkGroup. | ||
| 455 | diff --git i/src/services/pipewire/registry.cpp w/src/services/pipewire/registry.cpp | ||
| 456 | index c08fc1d..50c6d7a 100644 | ||
| 457 | --- i/src/services/pipewire/registry.cpp | ||
| 458 | +++ w/src/services/pipewire/registry.cpp | ||
| 459 | @@ -196,6 +196,7 @@ void PwRegistry::onGlobal( | ||
| 460 | device->initProps(props); | ||
| 461 | |||
| 462 | self->devices.emplace(id, device); | ||
| 463 | + emit self->deviceAdded(device); | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | @@ -211,6 +212,9 @@ void PwRegistry::onGlobalRemoved(void* data, quint32 id) { | ||
| 468 | } else if (auto* node = self->nodes.value(id)) { | ||
| 469 | self->nodes.remove(id); | ||
| 470 | node->safeDestroy(); | ||
| 471 | + } else if (auto* device = self->devices.value(id)) { | ||
| 472 | + self->devices.remove(id); | ||
| 473 | + device->safeDestroy(); | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | diff --git i/src/services/pipewire/registry.hpp w/src/services/pipewire/registry.hpp | ||
| 478 | index 8473f04..87e0766 100644 | ||
| 479 | --- i/src/services/pipewire/registry.hpp | ||
| 480 | +++ w/src/services/pipewire/registry.hpp | ||
| 481 | @@ -132,6 +132,7 @@ public: | ||
| 482 | |||
| 483 | signals: | ||
| 484 | void nodeAdded(PwNode* node); | ||
| 485 | + void deviceAdded(PwDevice* node); | ||
| 486 | void linkAdded(PwLink* link); | ||
| 487 | void linkGroupAdded(PwLinkGroup* group); | ||
| 488 | void metadataAdded(PwMetadata* metadata); | ||
diff --git a/overlays/spice-record.nix b/overlays/spice-record.nix index 06a114da..2d37079b 100644 --- a/overlays/spice-record.nix +++ b/overlays/spice-record.nix | |||
| @@ -8,5 +8,7 @@ | |||
| 8 | wrapProgram $out/bin/spice-record \ | 8 | wrapProgram $out/bin/spice-record \ |
| 9 | --prefix PATH : ${prev.lib.makeBinPath (with prev; [ ffmpeg-full ])} | 9 | --prefix PATH : ${prev.lib.makeBinPath (with prev; [ ffmpeg-full ])} |
| 10 | ''; | 10 | ''; |
| 11 | pyproject = true; | ||
| 12 | build-system = [ prev.python3Packages.setuptools ]; | ||
| 11 | }; | 13 | }; |
| 12 | } | 14 | } |
diff --git a/overlays/spm/default.nix b/overlays/spm/default.nix index ff135279..bd81ef82 100644 --- a/overlays/spm/default.nix +++ b/overlays/spm/default.nix | |||
| @@ -4,10 +4,11 @@ let | |||
| 4 | # defaultPackages = (import ./stackage.nix {}); | 4 | # defaultPackages = (import ./stackage.nix {}); |
| 5 | # haskellPackages = defaultPackages // argumentPackages; | 5 | # haskellPackages = defaultPackages // argumentPackages; |
| 6 | # haskellPackages = argumentPackages; | 6 | # haskellPackages = argumentPackages; |
| 7 | haskellPackages = final.haskell.packages.ghc96.override { | 7 | haskellPackages = final.haskell.packages.ghc912.override { |
| 8 | overrides = self: super: { | 8 | overrides = self: super: { |
| 9 | warp-systemd = final.haskell.lib.doJailbreak (super.warp-systemd.overrideAttrs (oldAttrs: { meta = oldAttrs.meta // { broken = false; }; })); | 9 | warp-systemd = final.haskell.lib.doJailbreak (super.warp-systemd.overrideAttrs (oldAttrs: { meta = oldAttrs.meta // { broken = false; }; })); |
| 10 | unliftio-pool = final.haskell.lib.doJailbreak super.unliftio-pool; | 10 | unliftio-pool = final.haskell.lib.doJailbreak super.unliftio-pool; |
| 11 | cryptonite = super.cryptonite.overrideAttrs (oldAttrs: { doCheck = false; }); | ||
| 11 | # servant-server = super.servant-server.overrideAttrs (oldAttrs: { | 12 | # servant-server = super.servant-server.overrideAttrs (oldAttrs: { |
| 12 | # patches = []; | 13 | # patches = []; |
| 13 | # }); | 14 | # }); |
diff --git a/overlays/spm/lib/Spm/Api.hs b/overlays/spm/lib/Spm/Api.hs index 8285cc55..3c22bfb6 100644 --- a/overlays/spm/lib/Spm/Api.hs +++ b/overlays/spm/lib/Spm/Api.hs | |||
| @@ -21,7 +21,6 @@ import Data.Text (Text) | |||
| 21 | import qualified Data.Text as Text | 21 | import qualified Data.Text as Text |
| 22 | 22 | ||
| 23 | import GHC.Generics (Generic) | 23 | import GHC.Generics (Generic) |
| 24 | import Type.Reflection (Typeable) | ||
| 25 | 24 | ||
| 26 | import Control.Lens | 25 | import Control.Lens |
| 27 | 26 | ||
| @@ -62,7 +61,7 @@ instance FromHttpApiData SpmStyle where | |||
| 62 | 61 | ||
| 63 | 62 | ||
| 64 | newtype SpmMailbox = SpmMailbox { unSpmMailbox :: CI Text } | 63 | newtype SpmMailbox = SpmMailbox { unSpmMailbox :: CI Text } |
| 65 | deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 64 | deriving stock (Eq, Ord, Read, Show, Generic) |
| 66 | deriving newtype (MimeRender PlainText) | 65 | deriving newtype (MimeRender PlainText) |
| 67 | makeWrapped ''SpmMailbox | 66 | makeWrapped ''SpmMailbox |
| 68 | 67 | ||
| @@ -70,7 +69,7 @@ instance MimeRender JSON SpmMailbox where | |||
| 70 | mimeRender p mbox = mimeRender p $ JSON.object [ "mailbox" JSON..= unSpmMailbox mbox ] | 69 | mimeRender p mbox = mimeRender p $ JSON.object [ "mailbox" JSON..= unSpmMailbox mbox ] |
| 71 | 70 | ||
| 72 | newtype SpmDomain = SpmDomain { unSpmDomain :: CI Text } | 71 | newtype SpmDomain = SpmDomain { unSpmDomain :: CI Text } |
| 73 | deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 72 | deriving stock (Eq, Ord, Read, Show, Generic) |
| 74 | deriving newtype (MimeRender PlainText) | 73 | deriving newtype (MimeRender PlainText) |
| 75 | makeWrapped ''SpmDomain | 74 | makeWrapped ''SpmDomain |
| 76 | 75 | ||
| @@ -79,17 +78,17 @@ instance MimeRender JSON SpmDomain where | |||
| 79 | 78 | ||
| 80 | newtype SpmLocal = SpmLocal | 79 | newtype SpmLocal = SpmLocal |
| 81 | { unSpmLocal :: CI Text | 80 | { unSpmLocal :: CI Text |
| 82 | } deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 81 | } deriving stock (Eq, Ord, Read, Show, Generic) |
| 83 | deriving newtype (ToJSON, FromJSON) | 82 | deriving newtype (ToJSON, FromJSON) |
| 84 | makeWrapped ''SpmLocal | 83 | makeWrapped ''SpmLocal |
| 85 | newtype SpmExtension = SpmExtension | 84 | newtype SpmExtension = SpmExtension |
| 86 | { unSpmExtension :: CI Text | 85 | { unSpmExtension :: CI Text |
| 87 | } deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 86 | } deriving stock (Eq, Ord, Read, Show, Generic) |
| 88 | deriving newtype (ToJSON, FromJSON) | 87 | deriving newtype (ToJSON, FromJSON) |
| 89 | makeWrapped ''SpmExtension | 88 | makeWrapped ''SpmExtension |
| 90 | 89 | ||
| 91 | data SpmMappingState = Valid | Reject | 90 | data SpmMappingState = Valid | Reject |
| 92 | deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic, Typeable) | 91 | deriving (Eq, Ord, Read, Show, Enum, Bounded, Generic) |
| 93 | instance MimeRender PlainText SpmMappingState where | 92 | instance MimeRender PlainText SpmMappingState where |
| 94 | mimeRender p = mimeRender @_ @Text p . \case | 93 | mimeRender p = mimeRender @_ @Text p . \case |
| 95 | Valid -> "valid" | 94 | Valid -> "valid" |
| @@ -109,15 +108,15 @@ _SpmMappingStateReject = iso toReject fromReject | |||
| 109 | data SpmMappingListingItem = SpmMappingListingItem | 108 | data SpmMappingListingItem = SpmMappingListingItem |
| 110 | { smlMapping :: SpmMapping | 109 | { smlMapping :: SpmMapping |
| 111 | , smlState :: SpmMappingState | 110 | , smlState :: SpmMappingState |
| 112 | } deriving (Eq, Ord, Read, Show, Generic, Typeable) | 111 | } deriving (Eq, Ord, Read, Show, Generic) |
| 113 | 112 | ||
| 114 | newtype SpmMappingListing = SpmMappingListing { unSpmMappingListing :: [SpmMappingListingItem] } | 113 | newtype SpmMappingListing = SpmMappingListing { unSpmMappingListing :: [SpmMappingListingItem] } |
| 115 | deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 114 | deriving stock (Eq, Ord, Read, Show, Generic) |
| 116 | 115 | ||
| 117 | data SpmMapping = SpmMapping | 116 | data SpmMapping = SpmMapping |
| 118 | { spmMappingLocal :: Maybe SpmLocal | 117 | { spmMappingLocal :: Maybe SpmLocal |
| 119 | , spmMappingExtension :: Maybe SpmExtension | 118 | , spmMappingExtension :: Maybe SpmExtension |
| 120 | } deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 119 | } deriving stock (Eq, Ord, Read, Show, Generic) |
| 121 | 120 | ||
| 122 | _SpmMappingText :: Iso' SpmMapping Text | 121 | _SpmMappingText :: Iso' SpmMapping Text |
| 123 | _SpmMappingText = iso toText fromText | 122 | _SpmMappingText = iso toText fromText |
| @@ -170,7 +169,7 @@ instance ToJSON SpmMappingListing where | |||
| 170 | data SpmJWTClaims = SpmJWTClaims | 169 | data SpmJWTClaims = SpmJWTClaims |
| 171 | { spmjwtStdClaims :: ClaimsSet | 170 | { spmjwtStdClaims :: ClaimsSet |
| 172 | , spmjwtLocal :: SpmLocal | 171 | , spmjwtLocal :: SpmLocal |
| 173 | } deriving stock (Eq, Show, Generic, Typeable) | 172 | } deriving stock (Eq, Show, Generic) |
| 174 | 173 | ||
| 175 | makeLensesFor [("spmjwtStdClaims", "_stdClaims"), ("spmjwtLocal", "_spmjwtLocal")] ''SpmJWTClaims | 174 | makeLensesFor [("spmjwtStdClaims", "_stdClaims"), ("spmjwtLocal", "_spmjwtLocal")] ''SpmJWTClaims |
| 176 | 175 | ||
diff --git a/overlays/spm/server/Spm/Server.hs b/overlays/spm/server/Spm/Server.hs index 8e7f8786..dc334729 100644 --- a/overlays/spm/server/Spm/Server.hs +++ b/overlays/spm/server/Spm/Server.hs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | {-# OPTIONS_GHC -Wno-orphans #-} | ||
| 2 | |||
| 1 | {-# LANGUAGE OverloadedStrings #-} | 3 | {-# LANGUAGE OverloadedStrings #-} |
| 2 | 4 | ||
| 3 | module Spm.Server | 5 | module Spm.Server |
| @@ -24,7 +26,6 @@ import Data.Attoparsec.Text | |||
| 24 | import qualified Data.ByteString.Lazy as LBS | 26 | import qualified Data.ByteString.Lazy as LBS |
| 25 | 27 | ||
| 26 | import GHC.Generics (Generic) | 28 | import GHC.Generics (Generic) |
| 27 | import Type.Reflection (Typeable) | ||
| 28 | 29 | ||
| 29 | import Control.Applicative | 30 | import Control.Applicative |
| 30 | import Control.Monad | 31 | import Control.Monad |
| @@ -101,7 +102,7 @@ hSslClientSDn = "SSL-Client-S-DN" | |||
| 101 | data SSLClientVerify | 102 | data SSLClientVerify |
| 102 | = SSLClientVerifySuccess | 103 | = SSLClientVerifySuccess |
| 103 | | SSLClientVerifyOther Text | 104 | | SSLClientVerifyOther Text |
| 104 | deriving (Eq, Ord, Read, Show, Generic, Typeable) | 105 | deriving (Eq, Ord, Read, Show, Generic) |
| 105 | instance FromHttpApiData SSLClientVerify where | 106 | instance FromHttpApiData SSLClientVerify where |
| 106 | parseUrlPiece = (left Text.pack .) . parseOnly $ p <* endOfInput | 107 | parseUrlPiece = (left Text.pack .) . parseOnly $ p <* endOfInput |
| 107 | where | 108 | where |
| @@ -163,7 +164,7 @@ data ServerCtxError | |||
| 163 | | ServerCtxNoCredentialsDirectory | 164 | | ServerCtxNoCredentialsDirectory |
| 164 | | ServerCtxJwkSetDecodeError String | 165 | | ServerCtxJwkSetDecodeError String |
| 165 | | ServerCtxJwkSetEmpty | 166 | | ServerCtxJwkSetEmpty |
| 166 | deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 167 | deriving stock (Eq, Ord, Read, Show, Generic) |
| 167 | deriving anyclass (Exception) | 168 | deriving anyclass (Exception) |
| 168 | 169 | ||
| 169 | mkSpmApp :: (MonadUnliftIO m, MonadThrow m) => m Application | 170 | mkSpmApp :: (MonadUnliftIO m, MonadThrow m) => m Application |
diff --git a/overlays/spm/server/Spm/Server/Ctx.hs b/overlays/spm/server/Spm/Server/Ctx.hs index 18452a0a..1d228043 100644 --- a/overlays/spm/server/Spm/Server/Ctx.hs +++ b/overlays/spm/server/Spm/Server/Ctx.hs | |||
| @@ -11,7 +11,6 @@ import Database.Persist.Postgresql | |||
| 11 | import UnliftIO.Pool | 11 | import UnliftIO.Pool |
| 12 | import Control.Lens.TH | 12 | import Control.Lens.TH |
| 13 | 13 | ||
| 14 | import Type.Reflection (Typeable) | ||
| 15 | import GHC.Generics (Generic) | 14 | import GHC.Generics (Generic) |
| 16 | 15 | ||
| 17 | 16 | ||
| @@ -19,6 +18,6 @@ data ServerCtx = ServerCtx | |||
| 19 | { _sctxSqlPool :: Pool SqlBackend | 18 | { _sctxSqlPool :: Pool SqlBackend |
| 20 | , _sctxInstanceId :: UUID | 19 | , _sctxInstanceId :: UUID |
| 21 | , _sctxJwkSet :: JWKSet | 20 | , _sctxJwkSet :: JWKSet |
| 22 | } deriving (Generic, Typeable) | 21 | } deriving (Generic) |
| 23 | makeLenses ''ServerCtx | 22 | makeLenses ''ServerCtx |
| 24 | 23 | ||
diff --git a/overlays/spm/server/Spm/Server/Database.hs b/overlays/spm/server/Spm/Server/Database.hs index 3156e920..4405452f 100644 --- a/overlays/spm/server/Spm/Server/Database.hs +++ b/overlays/spm/server/Spm/Server/Database.hs | |||
| @@ -13,7 +13,6 @@ import Database.Persist.Sql | |||
| 13 | import Database.Persist.TH | 13 | import Database.Persist.TH |
| 14 | 14 | ||
| 15 | import GHC.Generics (Generic) | 15 | import GHC.Generics (Generic) |
| 16 | import Type.Reflection (Typeable) | ||
| 17 | 16 | ||
| 18 | import Data.Text (Text) | 17 | import Data.Text (Text) |
| 19 | 18 | ||
| @@ -33,22 +32,22 @@ import Web.HttpApiData | |||
| 33 | 32 | ||
| 34 | newtype MailMailbox = MailMailbox | 33 | newtype MailMailbox = MailMailbox |
| 35 | { unMailMailbox :: CI Text | 34 | { unMailMailbox :: CI Text |
| 36 | } deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 35 | } deriving stock (Eq, Ord, Read, Show, Generic) |
| 37 | deriving newtype (PersistField, PersistFieldSql) | 36 | deriving newtype (PersistField, PersistFieldSql) |
| 38 | makeWrapped ''MailMailbox | 37 | makeWrapped ''MailMailbox |
| 39 | newtype MailLocal = MailLocal | 38 | newtype MailLocal = MailLocal |
| 40 | { unMailLocal :: CI Text | 39 | { unMailLocal :: CI Text |
| 41 | } deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 40 | } deriving stock (Eq, Ord, Read, Show, Generic) |
| 42 | deriving newtype (PersistField, PersistFieldSql) | 41 | deriving newtype (PersistField, PersistFieldSql) |
| 43 | makeWrapped ''MailLocal | 42 | makeWrapped ''MailLocal |
| 44 | newtype MailExtension = MailExtension | 43 | newtype MailExtension = MailExtension |
| 45 | { unMailExtension :: CI Text | 44 | { unMailExtension :: CI Text |
| 46 | } deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 45 | } deriving stock (Eq, Ord, Read, Show, Generic) |
| 47 | deriving newtype (PersistField, PersistFieldSql) | 46 | deriving newtype (PersistField, PersistFieldSql) |
| 48 | makeWrapped ''MailExtension | 47 | makeWrapped ''MailExtension |
| 49 | newtype MailDomain = MailDomain | 48 | newtype MailDomain = MailDomain |
| 50 | { unMailDomain :: CI Text | 49 | { unMailDomain :: CI Text |
| 51 | } deriving stock (Eq, Ord, Read, Show, Generic, Typeable) | 50 | } deriving stock (Eq, Ord, Read, Show, Generic) |
| 52 | deriving newtype (PersistField, PersistFieldSql) | 51 | deriving newtype (PersistField, PersistFieldSql) |
| 53 | makeWrapped ''MailDomain | 52 | makeWrapped ''MailDomain |
| 54 | 53 | ||
diff --git a/overlays/swayosd/default.nix b/overlays/swayosd/default.nix deleted file mode 100644 index b4601a03..00000000 --- a/overlays/swayosd/default.nix +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | { final, prev, sources, ... }: { | ||
| 2 | swayosd = prev.swayosd.overrideAttrs (oldAttrs: rec { | ||
| 3 | inherit (sources.swayosd) version src; | ||
| 4 | cargoDeps = prev.rustPlatform.fetchCargoVendor { | ||
| 5 | inherit (oldAttrs) pname; | ||
| 6 | inherit version src; | ||
| 7 | hash = "sha256-yWybf4GKxHrk4WrW5SmjfPD0Gv79tpXOwNLlWeykYy0="; | ||
| 8 | }; | ||
| 9 | patches = (oldAttrs.patches or []) ++ [ | ||
| 10 | ./exponential.patch | ||
| 11 | ]; | ||
| 12 | }); | ||
| 13 | } | ||
diff --git a/overlays/swayosd/exponential.patch b/overlays/swayosd/exponential.patch deleted file mode 100644 index eb90d739..00000000 --- a/overlays/swayosd/exponential.patch +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | diff --git a/src/brightness_backend/brightnessctl.rs b/src/brightness_backend/brightnessctl.rs | ||
| 2 | index ccb0e11..740fdb6 100644 | ||
| 3 | --- a/src/brightness_backend/brightnessctl.rs | ||
| 4 | +++ b/src/brightness_backend/brightnessctl.rs | ||
| 5 | @@ -107,10 +107,21 @@ impl VirtualDevice { | ||
| 6 | } | ||
| 7 | } | ||
| 8 | |||
| 9 | - fn set_percent(&mut self, mut val: u32) -> anyhow::Result<()> { | ||
| 10 | - val = val.clamp(0, 100); | ||
| 11 | - self.current = self.max.map(|max| val * max / 100); | ||
| 12 | - let _: String = self.run(("set", &*format!("{val}%")))?; | ||
| 13 | + fn val_to_percent(&mut self, val: u32) -> u32 { | ||
| 14 | + return ((val as f64 / self.get_max() as f64).powf(0.25) * 100_f64).round() as u32; | ||
| 15 | + } | ||
| 16 | + fn percent_to_val(&mut self, perc: u32) -> u32 { | ||
| 17 | + return ((perc as f64 / 100_f64).powf(4_f64) * self.get_max() as f64).round() as u32; | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + fn set_percent(&mut self, val: u32) -> anyhow::Result<()> { | ||
| 21 | + let new = self.percent_to_val(val); | ||
| 22 | + self.set_val(new) | ||
| 23 | + } | ||
| 24 | + fn set_val(&mut self, val: u32) -> anyhow::Result<()> { | ||
| 25 | + let curr = val.clamp(0, self.get_max()); | ||
| 26 | + self.current = Some(curr); | ||
| 27 | + let _: String = self.run(("set", &*format!("{curr}")))?; | ||
| 28 | Ok(()) | ||
| 29 | } | ||
| 30 | } | ||
| 31 | @@ -134,20 +145,18 @@ impl BrightnessBackend for BrightnessCtl { | ||
| 32 | |||
| 33 | fn lower(&mut self, by: u32) -> anyhow::Result<()> { | ||
| 34 | let curr = self.get_current(); | ||
| 35 | - let max = self.get_max(); | ||
| 36 | - | ||
| 37 | - let curr = curr * 100 / max; | ||
| 38 | + let mut new = self.device.val_to_percent(curr).saturating_sub(by); | ||
| 39 | + new = self.device.percent_to_val(new).min(curr.saturating_sub(1)); | ||
| 40 | |||
| 41 | - self.device.set_percent(curr.saturating_sub(by)) | ||
| 42 | + self.device.set_val(new) | ||
| 43 | } | ||
| 44 | |||
| 45 | fn raise(&mut self, by: u32) -> anyhow::Result<()> { | ||
| 46 | let curr = self.get_current(); | ||
| 47 | - let max = self.get_max(); | ||
| 48 | - | ||
| 49 | - let curr = curr * 100 / max; | ||
| 50 | + let mut new = self.device.val_to_percent(curr) + by; | ||
| 51 | + new = self.device.percent_to_val(new).max(curr + 1); | ||
| 52 | |||
| 53 | - self.device.set_percent(curr + by) | ||
| 54 | + self.device.set_val(new) | ||
| 55 | } | ||
| 56 | |||
| 57 | fn set(&mut self, val: u32) -> anyhow::Result<()> { | ||
diff --git a/overlays/uucp/default.nix b/overlays/uucp/default.nix deleted file mode 100644 index 4189dbcc..00000000 --- a/overlays/uucp/default.nix +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | { final, prev, ... }: { | ||
| 2 | uucp = prev.uucp.overrideAttrs (oldAttrs: { | ||
| 3 | configureFlags = (oldAttrs.configureFlags or []) ++ ["--with-newconfigdir=/etc/uucp"]; | ||
| 4 | patches = (oldAttrs.patches or []) ++ [ | ||
| 5 | ./mailprogram.patch | ||
| 6 | ]; | ||
| 7 | NIX_CFLAGS_COMPILE = "${oldAttrs.NIX_CFLAGS_COMPILE or ""} -Wno-error=incompatible-pointer-types"; | ||
| 8 | }); | ||
| 9 | } | ||
diff --git a/overlays/uucp/mailprogram.patch b/overlays/uucp/mailprogram.patch deleted file mode 100644 index 89ac8f31..00000000 --- a/overlays/uucp/mailprogram.patch +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | policy.h | 2 +- | ||
| 2 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
| 3 | |||
| 4 | diff --git a/policy.h b/policy.h | ||
| 5 | index 5afe34b..8e92c8b 100644 | ||
| 6 | --- a/policy.h | ||
| 7 | +++ b/policy.h | ||
| 8 | @@ -240,7 +240,7 @@ | ||
| 9 | the sendmail choice below. Otherwise, select one of the other | ||
| 10 | choices as appropriate. */ | ||
| 11 | #if 1 | ||
| 12 | -#define MAIL_PROGRAM "/usr/lib/sendmail -t" | ||
| 13 | +#define MAIL_PROGRAM "${config.security.wrapperDir}/sendmail -t" | ||
| 14 | /* #define MAIL_PROGRAM "/usr/sbin/sendmail -t" */ | ||
| 15 | #define MAIL_PROGRAM_TO_BODY 1 | ||
| 16 | #define MAIL_PROGRAM_SUBJECT_BODY 1 | ||
diff --git a/overlays/waybar.nix b/overlays/waybar.nix deleted file mode 100644 index e7e3b807..00000000 --- a/overlays/waybar.nix +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | { final, prev, flakeInputs, ... }: prev.lib.composeExtensions | ||
| 2 | flakeInputs.waybar.overlays.default | ||
| 3 | (final: prev: { | ||
| 4 | waybar = prev.waybar.overrideAttrs (oldAttrs: { | ||
| 5 | dontVersionCheck = true; | ||
| 6 | }); | ||
| 7 | }) | ||
| 8 | final prev | ||
diff --git a/overlays/worktime/worktime/__main__.py b/overlays/worktime/worktime/__main__.py index bf24bbec..ffeb1b84 100755 --- a/overlays/worktime/worktime/__main__.py +++ b/overlays/worktime/worktime/__main__.py | |||
| @@ -375,10 +375,7 @@ class Worktime(object): | |||
| 375 | parse_datestr(stripped_line) | 375 | parse_datestr(stripped_line) |
| 376 | 376 | ||
| 377 | for day in [fromDay + timedelta(days = x) for x in range(0, (toDay - fromDay).days + 1)]: | 377 | for day in [fromDay + timedelta(days = x) for x in range(0, (toDay - fromDay).days + 1)]: |
| 378 | if self.end_date.date() < day or day < self.start_date.date(): | 378 | if self.would_be_workday(day) and self.start_date.date() <= day and day <= self.end_date.date(): |
| 379 | continue | ||
| 380 | |||
| 381 | if self.would_be_workday(day): | ||
| 382 | if excused_kind == 'leave': | 379 | if excused_kind == 'leave': |
| 383 | self.leave_days.add(day) | 380 | self.leave_days.add(day) |
| 384 | elif time is not None and time >= self.time_per_day(day): | 381 | elif time is not None and time >= self.time_per_day(day): |
| @@ -393,9 +390,29 @@ class Worktime(object): | |||
| 393 | start_day = self.start_date.date() | 390 | start_day = self.start_date.date() |
| 394 | end_day = self.end_date.date() | 391 | end_day = self.end_date.date() |
| 395 | 392 | ||
| 393 | self.extra_days_to_work = dict() | ||
| 394 | |||
| 396 | try: | 395 | try: |
| 397 | with open(Path(config_dir) / "pull-forward", 'r') as excused: | 396 | with open(Path(config_dir) / "days-to-work", 'r') as extra_days_to_work_file: |
| 398 | for line in excused: | 397 | for line in extra_days_to_work_file: |
| 398 | stripped_line = line.strip() | ||
| 399 | if stripped_line: | ||
| 400 | splitLine = stripped_line.split(' ') | ||
| 401 | if len(splitLine) == 2: | ||
| 402 | [hours, datestr] = splitLine | ||
| 403 | day = datetime.strptime(datestr, date_format).replace(tzinfo=tzlocal()).date() | ||
| 404 | self.extra_days_to_work[day] = timedelta(hours = float(hours)) | ||
| 405 | else: | ||
| 406 | day = datetime.strptime(stripped_line, date_format).replace(tzinfo=tzlocal()).date() | ||
| 407 | self.extra_days_to_work[day] = self.time_per_day(day) | ||
| 408 | except IOError as e: | ||
| 409 | if e.errno != 2: | ||
| 410 | raise e | ||
| 411 | |||
| 412 | |||
| 413 | try: | ||
| 414 | with open(Path(config_dir) / "pull-forward", 'r') as pull_forward: | ||
| 415 | for line in pull_forward: | ||
| 399 | stripped_line = line.strip() | 416 | stripped_line = line.strip() |
| 400 | if stripped_line: | 417 | if stripped_line: |
| 401 | [hours, datestr] = stripped_line.split(' ') | 418 | [hours, datestr] = stripped_line.split(' ') |
| @@ -416,15 +433,22 @@ class Worktime(object): | |||
| 416 | if not d == datetime.strptime(c, date_format).replace(tzinfo=tzlocal()).date(): break | 433 | if not d == datetime.strptime(c, date_format).replace(tzinfo=tzlocal()).date(): break |
| 417 | else: | 434 | else: |
| 418 | if d >= self.end_date.date(): | 435 | if d >= self.end_date.date(): |
| 419 | self.pull_forward[d] = min(timedelta(hours = float(hours)), self.time_per_day(d) - (holidays[d] if d in holidays else timedelta())) | 436 | time_for_day = self.time_per_day(d) if d.isoweekday() in self.workdays else timedelta() |
| 437 | if d in self.extra_days_to_work: | ||
| 438 | time_for_day += self.extra_days_to_work[d] | ||
| 439 | self.pull_forward[d] = min(timedelta(hours = float(hours)), time_for_day) | ||
| 420 | except IOError as e: | 440 | except IOError as e: |
| 421 | if e.errno != 2: | 441 | if e.errno != 2: |
| 422 | raise e | 442 | raise e |
| 423 | 443 | ||
| 444 | if self.pull_forward: | ||
| 445 | for year in range(self.end_date.year + 1, max(self.pull_forward.keys()).year + 1): | ||
| 446 | holidays |= {k: v * timedelta(hours = hours_per_week(k)) / len(self.workdays) for k, v in Worktime.holidays(year).items()} | ||
| 447 | |||
| 424 | self.days_to_work = dict() | 448 | self.days_to_work = dict() |
| 425 | 449 | ||
| 426 | if self.pull_forward: | 450 | # if self.pull_forward: |
| 427 | end_day = max(end_day, max(list(self.pull_forward))) | 451 | # end_day = max(end_day, max(self.pull_forward.keys())) |
| 428 | 452 | ||
| 429 | for day in [start_day + timedelta(days = x) for x in range(0, (end_day - start_day).days + 1)]: | 453 | for day in [start_day + timedelta(days = x) for x in range(0, (end_day - start_day).days + 1)]: |
| 430 | if day.isoweekday() in self.workdays: | 454 | if day.isoweekday() in self.workdays: |
| @@ -432,26 +456,6 @@ class Worktime(object): | |||
| 432 | if time_to_work > timedelta(): | 456 | if time_to_work > timedelta(): |
| 433 | self.days_to_work[day] = time_to_work | 457 | self.days_to_work[day] = time_to_work |
| 434 | 458 | ||
| 435 | self.extra_days_to_work = dict() | ||
| 436 | |||
| 437 | try: | ||
| 438 | with open(Path(config_dir) / "days-to-work", 'r') as extra_days_to_work_file: | ||
| 439 | for line in extra_days_to_work_file: | ||
| 440 | stripped_line = line.strip() | ||
| 441 | if stripped_line: | ||
| 442 | splitLine = stripped_line.split(' ') | ||
| 443 | if len(splitLine) == 2: | ||
| 444 | [hours, datestr] = splitLine | ||
| 445 | day = datetime.strptime(datestr, date_format).replace(tzinfo=tzlocal()).date() | ||
| 446 | self.extra_days_to_work[day] = timedelta(hours = float(hours)) | ||
| 447 | else: | ||
| 448 | day = datetime.strptime(stripped_line, date_format).replace(tzinfo=tzlocal()).date() | ||
| 449 | self.extra_days_to_work[day] = self.time_per_day(day) | ||
| 450 | except IOError as e: | ||
| 451 | if e.errno != 2: | ||
| 452 | raise e | ||
| 453 | |||
| 454 | |||
| 455 | self.now_is_workday = self.is_workday(self.now.date()) | 459 | self.now_is_workday = self.is_workday(self.now.date()) |
| 456 | 460 | ||
| 457 | self.time_worked = timedelta() | 461 | self.time_worked = timedelta() |
| @@ -467,9 +471,9 @@ class Worktime(object): | |||
| 467 | 471 | ||
| 468 | self.time_to_work = sum([self.days_to_work[day] for day in self.days_to_work.keys() if day <= self.end_date.date()], timedelta()) | 472 | self.time_to_work = sum([self.days_to_work[day] for day in self.days_to_work.keys() if day <= self.end_date.date()], timedelta()) |
| 469 | for day in [d for d in list(self.pull_forward) if d > self.end_date.date()]: | 473 | for day in [d for d in list(self.pull_forward) if d > self.end_date.date()]: |
| 470 | days_forward = set([d for d in self.days_to_work.keys() if d >= self.end_date.date() and d < day and (not d in self.pull_forward or d == self.end_date.date())]) | 474 | days_forward = set([d for d in [start_day + timedelta(days = x) for x in range(0, (day - start_day).days + 1)] if d >= self.end_date.date() and d < day and (d not in self.pull_forward or d == self.end_date.date())]) |
| 471 | extra_days_forward = set([d for d in self.extra_days_to_work.keys() if d >= self.end_date.date() and d < day and (not d in self.pull_forward or d == self.end_date.date())]) | 475 | extra_days_forward = set([d for d in self.extra_days_to_work.keys() if d >= self.end_date.date() and d < day and (d not in self.pull_forward or d == self.end_date.date())]) |
| 472 | days_forward = days_forward.union(extra_days_forward) | 476 | days_forward |= extra_days_forward |
| 473 | 477 | ||
| 474 | extra_day_time_left = timedelta() | 478 | extra_day_time_left = timedelta() |
| 475 | for extra_day in extra_days_forward: | 479 | for extra_day in extra_days_forward: |
| @@ -482,15 +486,28 @@ class Worktime(object): | |||
| 482 | day_time = max(timedelta(), self.time_per_day(extra_day) - self.extra_days_to_work[extra_day]) | 486 | day_time = max(timedelta(), self.time_per_day(extra_day) - self.extra_days_to_work[extra_day]) |
| 483 | self.extra_days_to_work[extra_day] += extra_day_time * (day_time / extra_day_time_left) | 487 | self.extra_days_to_work[extra_day] += extra_day_time * (day_time / extra_day_time_left) |
| 484 | 488 | ||
| 485 | hours_per_day_forward = time_forward / len(days_forward) if len(days_forward) > 0 else timedelta() | 489 | def days_count(days_forward): |
| 490 | r = 0 | ||
| 491 | for day in sorted(days_forward): | ||
| 492 | day_time = timedelta() | ||
| 493 | if day in self.extra_days_to_work: | ||
| 494 | day_time += self.extra_days_to_work[day] | ||
| 495 | if day in holidays and not day in self.extra_days_to_work: | ||
| 496 | day_time -= holidays[day] | ||
| 497 | if day.isoweekday() in self.workdays: | ||
| 498 | day_time += timedelta(hours = hours_per_week(day)) / len(self.workdays) | ||
| 499 | r += max(timedelta(), day_time) / (timedelta(hours = hours_per_week(day)) / len(self.workdays)) | ||
| 500 | return r | ||
| 501 | |||
| 502 | hours_per_day_forward = time_forward / days_count(days_forward) if days_count(days_forward) > 0 else timedelta() | ||
| 486 | days_forward.discard(self.end_date.date()) | 503 | days_forward.discard(self.end_date.date()) |
| 487 | 504 | ||
| 488 | self.time_pulled_forward += time_forward - hours_per_day_forward * len(days_forward) | 505 | self.time_pulled_forward += time_forward - hours_per_day_forward * days_count(days_forward) |
| 489 | 506 | ||
| 490 | if self.end_date.date() in self.extra_days_to_work: | 507 | if self.end_date.date() in self.extra_days_to_work: |
| 491 | self.time_pulled_forward += self.extra_days_to_work[self.end_date.date()] | 508 | self.time_pulled_forward += self.extra_days_to_work[self.end_date.date()] |
| 492 | 509 | ||
| 493 | self.time_to_work += self.time_pulled_forward | 510 | # self.time_to_work += self.time_pulled_forward |
| 494 | 511 | ||
| 495 | self.time_worked += api.get_billable_hours(self.start_date, self.now) | 512 | self.time_worked += api.get_billable_hours(self.start_date, self.now) |
| 496 | 513 | ||
| @@ -569,7 +586,7 @@ def worktime(pull_forward_cutoff, waybar, **args): | |||
| 569 | pull_forward_sum = sum(worktime.pull_forward.values(), start=timedelta(milliseconds=0)) | 586 | pull_forward_sum = sum(worktime.pull_forward.values(), start=timedelta(milliseconds=0)) |
| 570 | if pull_forward_sum >= min(pull_forward_cutoff, timedelta(seconds = 1)): | 587 | if pull_forward_sum >= min(pull_forward_cutoff, timedelta(seconds = 1)): |
| 571 | worktime_no_pulled_forward = deepcopy(worktime) | 588 | worktime_no_pulled_forward = deepcopy(worktime) |
| 572 | worktime_no_pulled_forward.time_to_work -= worktime_no_pulled_forward.time_pulled_forward | 589 | # worktime_no_pulled_forward.time_to_work -= worktime_no_pulled_forward.time_pulled_forward |
| 573 | worktime_no_pulled_forward.time_pulled_forward = timedelta() | 590 | worktime_no_pulled_forward.time_pulled_forward = timedelta() |
| 574 | worktime_no_pulled_forward.pull_forward = dict() | 591 | worktime_no_pulled_forward.pull_forward = dict() |
| 575 | worktime.time_to_work += pull_forward_sum | 592 | worktime.time_to_work += pull_forward_sum |
| @@ -607,7 +624,7 @@ def time_worked(now, waybar, **args): | |||
| 607 | out_text = None | 624 | out_text = None |
| 608 | out_class = "running" if now.running_entry else "stopped" | 625 | out_class = "running" if now.running_entry else "stopped" |
| 609 | tooltip = tooltip_timedelta(worked) | 626 | tooltip = tooltip_timedelta(worked) |
| 610 | target_time = max(then.time_per_day(then.now.date()), now.time_per_day(now.now.date())) if then.time_per_day(then.now.date()) and now.time_per_day(now.now.date()) else (then.time_per_day(then.now.date()) if then.time_per_day(then.now.date()) else now.time_per_day(now.now.date())); | 627 | target_time = max(then.time_per_day(then.now.date()), now.time_per_day(now.now.date())) if then.time_per_day(then.now.date()) and now.time_per_day(now.now.date()) else (then.time_per_day(then.now.date()) if then.time_per_day(then.now.date()) else now.time_per_day(now.now.date())) |
| 611 | difference = target_time - worked | 628 | difference = target_time - worked |
| 612 | difference_pull_forward = difference + now.time_pulled_forward | 629 | difference_pull_forward = difference + now.time_pulled_forward |
| 613 | if now.running_entry and difference_pull_forward < timedelta(seconds=0): | 630 | if now.running_entry and difference_pull_forward < timedelta(seconds=0): |
diff --git a/overlays/yt-dlp.nix b/overlays/yt-dlp.nix index 94ab1fdd..1c9f77d8 100644 --- a/overlays/yt-dlp.nix +++ b/overlays/yt-dlp.nix | |||
| @@ -1,5 +1,13 @@ | |||
| 1 | { prev, sources, ... }: { | 1 | { prev, final, sources, ... }: { |
| 2 | yt-dlp = prev.yt-dlp.overrideAttrs (oldAttrs: { | 2 | yt-dlp = prev.yt-dlp.overrideAttrs (oldAttrs: { |
| 3 | inherit (sources.yt-dlp) pname version src; | 3 | inherit (sources.yt-dlp) pname version src; |
| 4 | }); | 4 | }); |
| 5 | python3 = prev.python3.override { | ||
| 6 | packageOverrides = python-self: python-super: { | ||
| 7 | yt-dlp-ejs = python-super.yt-dlp-ejs.overridePythonAttrs (oldAttrs: { | ||
| 8 | inherit (sources.yt-dlp-ejs) pname version src; | ||
| 9 | }); | ||
| 10 | }; | ||
| 11 | }; | ||
| 12 | python3Packages = final.python3.pkgs; | ||
| 5 | } | 13 | } |
diff --git a/overlays/zte-prometheus-exporter/default.nix b/overlays/zte-prometheus-exporter/default.nix index cd4207cd..6295567d 100644 --- a/overlays/zte-prometheus-exporter/default.nix +++ b/overlays/zte-prometheus-exporter/default.nix | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | { final, prev, ... }: | 1 | { final, prev, ... }: |
| 2 | let | 2 | let |
| 3 | packageOverrides = final.callPackage ./python-packages.nix {}; | 3 | packageOverrides = final.callPackage ./python-packages.nix {}; |
| 4 | inpPython = final.python310.override { inherit packageOverrides; }; | 4 | inpPython = final.python3.override { inherit packageOverrides; }; |
| 5 | python = inpPython.withPackages (ps: with ps; [pytimeparse requests]); | 5 | python = inpPython.withPackages (ps: with ps; [pytimeparse requests]); |
| 6 | in { | 6 | in { |
| 7 | zte-prometheus-exporter = prev.stdenv.mkDerivation rec { | 7 | zte-prometheus-exporter = prev.stdenv.mkDerivation rec { |
diff --git a/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py b/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py index fc719a96..1d150eda 100644 --- a/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py +++ b/overlays/zte-prometheus-exporter/zte-prometheus-exporter.py | |||
| @@ -54,13 +54,13 @@ class ZTEMetrics: | |||
| 54 | cls._instance.password = environ.get('ZTE_PASSWORD') | 54 | cls._instance.password = environ.get('ZTE_PASSWORD') |
| 55 | cls._instance.attrs = None | 55 | cls._instance.attrs = None |
| 56 | return cls._instance | 56 | return cls._instance |
| 57 | 57 | ||
| 58 | 58 | ||
| 59 | def __init__(self): | 59 | def __init__(self): |
| 60 | raise RuntimeError('Call instance() instead') | 60 | raise RuntimeError('Call instance() instead') |
| 61 | 61 | ||
| 62 | _error_pattern = re.compile('^IF_ERROR(PARAM|TYPE|STR|ID)$') | 62 | _error_pattern = re.compile(r'^IF_ERROR(PARAM|TYPE|STR|ID)$') |
| 63 | _obj_pattern = re.compile('^(?:OBJ_(.+)_ID)|(?:ID_(WAN_COMFIG))$') | 63 | _obj_pattern = re.compile(r'^(?:OBJ_(.+)_ID)|(?:ID_(WAN_COMFIG))$') |
| 64 | def update(self): | 64 | def update(self): |
| 65 | attrs = dict() | 65 | attrs = dict() |
| 66 | 66 | ||
| @@ -106,6 +106,8 @@ class ZTEMetrics: | |||
| 106 | value = child.text | 106 | value = child.text |
| 107 | case _: | 107 | case _: |
| 108 | pass | 108 | pass |
| 109 | if value == '0,0': | ||
| 110 | value = '0' | ||
| 109 | if not name is None and not value is None: | 111 | if not name is None and not value is None: |
| 110 | instance_dict[name] = value | 112 | instance_dict[name] = value |
| 111 | name = None | 113 | name = None |
| @@ -120,11 +122,21 @@ class ZTEMetrics: | |||
| 120 | def json_text(self): | 122 | def json_text(self): |
| 121 | return json.dumps(self.attrs) | 123 | return json.dumps(self.attrs) |
| 122 | 124 | ||
| 123 | _link_pattern = re.compile('^IGD\.WD1\.LINE([0-9]+)$') | 125 | _link_pattern = re.compile(r'^IGD\.WD1\.LINE([0-9]+)$') |
| 124 | _eth_pattern = re.compile('^IGD\.LD1\.ETH([0-9]+)$') | 126 | _eth_pattern = re.compile(r'^IGD\.LD1\.ETH([0-9]+)$') |
| 125 | def prometheus(self): | 127 | def prometheus(self): |
| 126 | metrics = '' | 128 | metrics = '' |
| 127 | 129 | ||
| 130 | metrics += _format_prom_metrics('info', 'gauge', [({ | ||
| 131 | "version_date": self.attrs['DEVINFO']['IGD']['VerDate'], | ||
| 132 | "software_version": self.attrs['DEVINFO']['IGD']['SoftwareVer'], | ||
| 133 | "model_name": self.attrs['DEVINFO']['IGD']['ModelName'], | ||
| 134 | "model_firmware_version": self.attrs['DEVINFO']['IGD']['ModelFirmwareVer'], | ||
| 135 | "hardware_version": self.attrs['DEVINFO']['IGD']['HardwareVer'], | ||
| 136 | "serial_number": self.attrs['DEVINFO']['IGD']['SerialNumber'], | ||
| 137 | "boot_version": self.attrs['DEVINFO']['IGD']['BootVer'], | ||
| 138 | }, 1)], 'Metadata about a given ZTE device') | ||
| 139 | |||
| 128 | uptime_seconds = timeparse(self.attrs['SYSTEMYIME']['IGD']['systemTime']) | 140 | uptime_seconds = timeparse(self.attrs['SYSTEMYIME']['IGD']['systemTime']) |
| 129 | metrics += _format_prom_metrics('uptime_seconds', 'gauge', [({}, uptime_seconds)], 'Seconds device has been running') | 141 | metrics += _format_prom_metrics('uptime_seconds', 'gauge', [({}, uptime_seconds)], 'Seconds device has been running') |
| 130 | 142 | ||
| @@ -133,34 +145,44 @@ class ZTEMetrics: | |||
| 133 | link_match = self._link_pattern.match(link) | 145 | link_match = self._link_pattern.match(link) |
| 134 | link_number = link_match.group(1) | 146 | link_number = link_match.group(1) |
| 135 | 147 | ||
| 136 | if 'crc_errors_count' not in link_metrics: | 148 | link_is_up = self.attrs['DSLINTERFACE'][link]['Status'] == 'Up' |
| 137 | link_metrics['crc_errors_count'] = {'type': 'counter', 'metrics': []} | 149 | |
| 138 | link_metrics['crc_errors_count']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['UpCrc_errors']))] | 150 | if link_is_up: |
| 139 | link_metrics['crc_errors_count']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['DownCrc_errors']))] | 151 | if 'crc_errors_count' not in link_metrics: |
| 140 | 152 | link_metrics['crc_errors_count'] = {'type': 'counter', 'metrics': []} | |
| 141 | if 'noise_margin_db' not in link_metrics: | 153 | link_metrics['crc_errors_count']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['UpCrc_errors']))] |
| 142 | link_metrics['noise_margin_db'] = {'type': 'gauge', 'metrics': []} | 154 | link_metrics['crc_errors_count']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['DownCrc_errors']))] |
| 143 | link_metrics['noise_margin_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_noise_margin']))] | 155 | |
| 144 | link_metrics['noise_margin_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_noise_margin']))] | 156 | if 'noise_margin_db' not in link_metrics: |
| 145 | 157 | link_metrics['noise_margin_db'] = {'type': 'gauge', 'metrics': []} | |
| 146 | if 'attenuation_db' not in link_metrics: | 158 | link_metrics['noise_margin_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_noise_margin']) / 10)] |
| 147 | link_metrics['attenuation_db'] = {'type': 'gauge', 'metrics': []} | 159 | link_metrics['noise_margin_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_noise_margin']) / 10)] |
| 148 | link_metrics['attenuation_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_attenuation']))] | 160 | |
| 149 | link_metrics['attenuation_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_attenuation']))] | 161 | if 'attenuation_db' not in link_metrics: |
| 150 | 162 | link_metrics['attenuation_db'] = {'type': 'gauge', 'metrics': []} | |
| 151 | if 'max_rate_kbps' not in link_metrics: | 163 | link_metrics['attenuation_db']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_attenuation']) / 10)] |
| 152 | link_metrics['max_rate_kbps'] = {'type': 'gauge', 'metrics': []} | 164 | link_metrics['attenuation_db']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_attenuation']) / 10)] |
| 153 | link_metrics['max_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_max_rate']))] | 165 | |
| 154 | link_metrics['max_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_max_rate']))] | 166 | if 'max_rate_kbps' not in link_metrics: |
| 155 | 167 | link_metrics['max_rate_kbps'] = {'type': 'gauge', 'metrics': []} | |
| 156 | if 'current_rate_kbps' not in link_metrics: | 168 | link_metrics['max_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_max_rate']))] |
| 157 | link_metrics['current_rate_kbps'] = {'type': 'gauge', 'metrics': []} | 169 | link_metrics['max_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_max_rate']))] |
| 158 | link_metrics['current_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_current_rate']))] | 170 | |
| 159 | link_metrics['current_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_current_rate']))] | 171 | if 'current_rate_kbps' not in link_metrics: |
| 160 | 172 | link_metrics['current_rate_kbps'] = {'type': 'gauge', 'metrics': []} | |
| 161 | if 'dsl_uptime_seconds' not in link_metrics: | 173 | link_metrics['current_rate_kbps']['metrics'] += [({"direction": "up", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Upstream_current_rate']))] |
| 162 | link_metrics['dsl_uptime_seconds'] = {'type': 'gauge', 'metrics': []} | 174 | link_metrics['current_rate_kbps']['metrics'] += [({"direction": "down", "link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Downstream_current_rate']))] |
| 163 | link_metrics['dsl_uptime_seconds']['metrics'] += [({"link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Showtime_start']))] | 175 | |
| 176 | if 'uptime_seconds' not in link_metrics: | ||
| 177 | link_metrics['uptime_seconds'] = {'type': 'gauge', 'metrics': []} | ||
| 178 | link_metrics['uptime_seconds']['metrics'] += [({"link": link_number}, int(self.attrs['DSLINTERFACE'][link]['Showtime_start']) if link_is_up else 0)] | ||
| 179 | |||
| 180 | if 'status' not in link_metrics: | ||
| 181 | link_metrics['status'] = {'type': 'gauge', 'metrics': []} | ||
| 182 | up_status, *status = self.attrs['DSLINTERFACE'][link]['Status'].split(',') | ||
| 183 | down_status = up_status if not status else status[0] | ||
| 184 | link_metrics['status']['metrics'] += [({"link": link_number, "direction": "up", "status": up_status}, 1)] | ||
| 185 | link_metrics['status']['metrics'] += [({"link": link_number, "direction": "down", "status": down_status}, 1)] | ||
| 164 | if link_metrics: | 186 | if link_metrics: |
| 165 | for metric_name in link_metrics: | 187 | for metric_name in link_metrics: |
| 166 | metrics += _format_prom_metrics(f'dsl_{metric_name}', link_metrics[metric_name]['type'], link_metrics[metric_name]['metrics']) | 188 | metrics += _format_prom_metrics(f'dsl_{metric_name}', link_metrics[metric_name]['type'], link_metrics[metric_name]['metrics']) |
| @@ -203,7 +225,7 @@ class ZTEMetricsServer(BaseHTTPRequestHandler): | |||
| 203 | self.send_response(200) | 225 | self.send_response(200) |
| 204 | self.send_header("Content-type", "text/plain") | 226 | self.send_header("Content-type", "text/plain") |
| 205 | self.end_headers() | 227 | self.end_headers() |
| 206 | 228 | ||
| 207 | self.wfile.write(zte_metrics.prometheus()) | 229 | self.wfile.write(zte_metrics.prometheus()) |
| 208 | case _: | 230 | case _: |
| 209 | self.send_response(404) | 231 | self.send_response(404) |
