From 4656814c5f9a437d097af9ec08d824bc923edfba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20M=C3=BCller?= Date: Mon, 25 Aug 2025 20:31:34 +0200 Subject: [PATCH] Added CI build --- .gitlab-ci.yml | 155 ++++++++++++++++++++++ FritzCallMonitor.sln | 1 + README.md | 14 +- src/FritzCallMonitor/CallMonitorClient.cs | 12 +- src/FritzCallMonitor/README.md | 43 +++++- 5 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..7c9a229 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,155 @@ +image: mcr.microsoft.com/dotnet/sdk:8.0 + +variables: + TZ: "Europe/Berlin" + LANG: "de" + +stages: + - build + - test + - deploy + + + +debug-build: + stage: build + tags: + - docker + - lnx + - 64bit + rules: + - if: $CI_COMMIT_TAG == null + script: + - dotnet build -c Debug --nologo + - mkdir ./artifacts + - shopt -s globstar + - mv ./**/*.nupkg ./artifacts/ || true + - mv ./**/*.snupkg ./artifacts/ || true + artifacts: + paths: + - artifacts/*.nupkg + - artifacts/*.snupkg + expire_in: 1 days + +debug-test: + stage: test + dependencies: + - debug-build + tags: + - docker + - lnx + - 64bit + rules: + - if: $CI_COMMIT_TAG == null + coverage: /Branch coverage[\s\S].+%/ + before_script: + - dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools + script: + - dotnet test -c Debug --nologo /p:CoverletOutputFormat=Cobertura + - /dotnet-tools/reportgenerator "-reports:${CI_PROJECT_DIR}/**/coverage.cobertura.xml" "-targetdir:/reports" -reportType:TextSummary + - cat /reports/Summary.txt + artifacts: + when: always + reports: + coverage_report: + coverage_format: cobertura + path: ./**/coverage.cobertura.xml + +debug-deploy: + stage: deploy + dependencies: + - debug-build + - debug-test + tags: + - docker + - lnx + - server + rules: + - if: $CI_COMMIT_TAG == null + script: + - dotnet nuget push -k $BAGET_APIKEY -s https://nuget.am-wd.de/v3/index.json --skip-duplicate artifacts/*.nupkg || true + + + +release-build: + stage: build + tags: + - docker + - lnx + - 64bit + rules: + - if: $CI_COMMIT_TAG != null + script: + - dotnet build -c Release --nologo + - mkdir ./artifacts + - shopt -s globstar + - mv ./**/*.nupkg ./artifacts/ || true + - mv ./**/*.snupkg ./artifacts/ || true + artifacts: + paths: + - artifacts/*.nupkg + - artifacts/*.snupkg + expire_in: 1 days + +release-test: + stage: test + dependencies: + - release-build + tags: + - docker + - lnx + - 64bit + rules: + - if: $CI_COMMIT_TAG != null + before_script: + - dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools + script: + - dotnet test -c Release --nologo /p:CoverletOutputFormat=Cobertura + - /dotnet-tools/reportgenerator "-reports:${CI_PROJECT_DIR}/**/coverage.cobertura.xml" "-targetdir:/reports" -reportType:TextSummary + - cat /reports/Summary.txt + artifacts: + when: always + reports: + coverage_report: + coverage_format: cobertura + path: ./**/coverage.cobertura.xml + +release-deploy: + stage: deploy + dependencies: + - release-build + - release-test + tags: + - docker + - lnx + - server + rules: + - if: $CI_COMMIT_TAG != null + script: + - dotnet nuget push -k $NUGET_APIKEY -s https://api.nuget.org/v3/index.json --skip-duplicate artifacts/*.nupkg || true + + + +publish-docs: + variables: + DOCFX_SOURCE_REPOSITORY_URL: "https://github.com/AM-WD/FritzCallMonitor" + stage: deploy + tags: + - docker + - lnx + - server + rules: + - if: $CI_COMMIT_TAG != null + before_script: + - apt-get update + - apt-get -y install zip unzip + - dotnet tool install docfx --tool-path /dotnet-tools + script: + # Build the docs + - dotnet build -c Release --nologo + - /dotnet-tools/docfx metadata docs/docfx.json + - /dotnet-tools/docfx build docs/docfx.json + # Deploy the docs + - cd docs/_site + - zip -r ../docs.zip * + - curl --user "$DOCS_DEPLOY_USER:$DOCS_DEPLOY_PASS" -F docs=fritzcallmonitor -F dump=@../docs.zip "$DOCS_DEPLOY_URL" \ No newline at end of file diff --git a/FritzCallMonitor.sln b/FritzCallMonitor.sln index 9dbb9aa..b4305cb 100644 --- a/FritzCallMonitor.sln +++ b/FritzCallMonitor.sln @@ -21,6 +21,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Tests", "t EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{3DF1F30A-77F3-4F24-8739-CB89EE07BB8B}" ProjectSection(SolutionItems) = preProject + .gitlab-ci.yml = .gitlab-ci.yml Directory.Build.props = Directory.Build.props EndProjectSection EndProject diff --git a/README.md b/README.md index 81678d7..2030333 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,24 @@ # FRITZ!Box CallMonitor +The call monitor is a custom endpoint, which can be enabled in the FRITZ!Box using specific phone codes. + +When the endpoint is enabled, a raw TCP stream is opened on port 1012 of the FRITZ!Box, which sends information about incoming and outgoing calls in real-time. + +This can be used to integrate the FRITZ!Box call signaling into other applications or systems. + +## Enabling the Call Monitor + +To enable the call monitor, you need to dial the following code on a connected telephone: `#96*5*`. + +To disable the call monitor, dial: `#96*4*`. + --- Published under [MIT License] (see [choose a license]). -[![Buy me a Coffee](https://shields.am-wd.de/badge/PayPal-Buy_me_a_Coffee-yellow?style=flat&logo=paypal)](https://link.am-wd.de/donate) +[![Buy me a Coffee](https://shields.io/badge/PayPal-Buy_me_a_Coffee-yellow?style=flat&logo=paypal)](https://link.am-wd.de/donate) [MIT License]: LICENSE.txt diff --git a/src/FritzCallMonitor/CallMonitorClient.cs b/src/FritzCallMonitor/CallMonitorClient.cs index 4e4d157..da6197b 100644 --- a/src/FritzCallMonitor/CallMonitorClient.cs +++ b/src/FritzCallMonitor/CallMonitorClient.cs @@ -18,7 +18,7 @@ namespace AMWD.Net.Api.Fritz.CallMonitor private bool _isDisposed; private ILogger? _logger; - private readonly ReconnectTcpClient _client; + private readonly ReconnectTcpClient _tcpClient; private readonly CancellationTokenSource _disposeCts; private Task _monitorTask = Task.CompletedTask; @@ -39,10 +39,10 @@ namespace AMWD.Net.Api.Fritz.CallMonitor throw new ArgumentOutOfRangeException(nameof(port)); _disposeCts = new CancellationTokenSource(); - _client = new ReconnectTcpClient(host, port) { OnConnected = OnConnected }; + _tcpClient = new ReconnectTcpClient(host, port) { OnConnected = OnConnected }; // Start the client in the background - _client.StartAsync(_disposeCts.Token).Forget(); + _tcpClient.StartAsync(_disposeCts.Token).Forget(); } /// @@ -62,7 +62,7 @@ namespace AMWD.Net.Api.Fritz.CallMonitor set { _logger = value; - _client.Logger = value; + _tcpClient.Logger = value; } } @@ -85,7 +85,7 @@ namespace AMWD.Net.Api.Fritz.CallMonitor catch { } - _client.Dispose(); + _tcpClient.Dispose(); _disposeCts.Dispose(); GC.SuppressFinalize(this); @@ -93,6 +93,8 @@ namespace AMWD.Net.Api.Fritz.CallMonitor private Task OnConnected(ReconnectTcpClient client) { + Logger?.LogTrace($"Client connected"); + _monitorTask = Task.Run(async () => { try diff --git a/src/FritzCallMonitor/README.md b/src/FritzCallMonitor/README.md index 3df8431..f99e513 100644 --- a/src/FritzCallMonitor/README.md +++ b/src/FritzCallMonitor/README.md @@ -1,10 +1,51 @@ # FRITZ!Box Call Monitor +You can use this small library to connect to the FRITZ!Box Call Monitor and receive live call events. + + +## Router preparation + +Call `#96*5*` to enable the endpoint in your FRITZ!Box. +Call `#96*4*` to disable it again. + + +## In your code + +```csharp +using (var client = new CallMonitorClient(host, port)) +{ + client.OnEvent += (sender, e) => + { + switch (e.Event) + { + case EventType.Ring: + Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Incoming Call from {e.CallerNumber} to {e.CalleeNumber}"); + break; + + case EventType.Connect: + Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Call connected to {e.CallerNumber}"); + break; + + case EventType.Disconnect: + Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Call disconnected after {e.Duration}"); + break; + + case EventType.Call: + Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Outgoing Call from {e.CalleeNumber} to {e.CallerNumber}"); + break; + } + }; + + // Wait to terminate. +} +``` + + --- Published under MIT License (see [choose a license]). -[![Buy me a Coffee](https://shields.am-wd.de/badge/PayPal-Buy_me_a_Coffee-yellow?style=flat&logo=paypal)](https://link.am-wd.de/donate) +[![Buy me a Coffee](https://shields.io/badge/PayPal-Buy_me_a_Coffee-yellow?style=flat&logo=paypal)](https://link.am-wd.de/donate) [choose a license]: https://choosealicense.com/licenses/mit/