Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b15cf87b3c | |||
| e8349924c0 | |||
| e0f57601c8 | |||
| 9ded50bf4c | |||
| 3740c87528 | |||
| 09199753e4 | |||
| e7d1b3a2d3 | |||
| a6c3df5d17 | |||
| 452fe47969 | |||
| 8f71e4dbe4 | |||
| 5949de6611 |
62
.gitea/workflows/branch-build.yml
Normal file
62
.gitea/workflows/branch-build.yml
Normal file
@@ -0,0 +1,62 @@
|
||||
name: Branch Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
env:
|
||||
TZ: 'Europe/Berlin'
|
||||
LANG: 'de'
|
||||
CONFIGURATION: 'Debug'
|
||||
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
||||
|
||||
jobs:
|
||||
build-test-deploy:
|
||||
runs-on: ubuntu
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout repository code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: 10.x
|
||||
cache: false
|
||||
|
||||
- name: Restore dependencies
|
||||
run: |
|
||||
set -ex
|
||||
dotnet restore -v q
|
||||
echo "CI_SERVER_HOST=${GITEA_SERVER_URL#https://}" >> "$GITEA_ENV"
|
||||
|
||||
- name: Setup tools
|
||||
run: |
|
||||
set -ex
|
||||
dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
|
||||
|
||||
- name: Build solution
|
||||
run: |
|
||||
set -ex
|
||||
shopt -s globstar
|
||||
mkdir /artifacts
|
||||
dotnet build -c ${CONFIGURATION} --no-restore --nologo
|
||||
mv ./**/*.nupkg /artifacts/
|
||||
mv ./**/*.snupkg /artifacts/
|
||||
|
||||
- name: Test solution
|
||||
run: |
|
||||
set -ex
|
||||
dotnet test -c ${CONFIGURATION} --no-build --nologo /p:CoverletOutputFormat=Cobertura
|
||||
/dotnet-tools/reportgenerator "-reports:${{ gitea.workspace }}/**/coverage.cobertura.xml" "-targetdir:/reports" "-reportType:TextSummary"
|
||||
cat /reports/Summary.txt
|
||||
|
||||
- name: Publish packages
|
||||
run: |
|
||||
set -ex
|
||||
dotnet nuget push -k "${{ secrets.BAGET_APIKEY }}" -s "https://nuget.am-wd.de/v3/index.json" --skip-duplicate /artifacts/*.nupkg
|
||||
80
.gitea/workflows/release-build.yml
Normal file
80
.gitea/workflows/release-build.yml
Normal file
@@ -0,0 +1,80 @@
|
||||
name: Release Build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
TZ: 'Europe/Berlin'
|
||||
LANG: 'de'
|
||||
CONFIGURATION: 'Release'
|
||||
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
||||
|
||||
jobs:
|
||||
build-test-deploy:
|
||||
runs-on: ubuntu
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout repository code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup dotnet
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: 10.x
|
||||
cache: false
|
||||
|
||||
- name: Restore dependencies
|
||||
run: |
|
||||
set -ex
|
||||
dotnet restore -v q
|
||||
echo "CI_SERVER_HOST=${GITEA_SERVER_URL#https://}" >> "$GITEA_ENV"
|
||||
|
||||
- name: Setup tools
|
||||
run: |
|
||||
set -ex
|
||||
dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
|
||||
dotnet tool install docfx --tool-path /dotnet-tools
|
||||
|
||||
- name: Build solution
|
||||
run: |
|
||||
set -ex
|
||||
shopt -s globstar
|
||||
mkdir /artifacts
|
||||
dotnet build -c ${CONFIGURATION} --no-restore --nologo
|
||||
mv ./**/*.nupkg /artifacts/
|
||||
mv ./**/*.snupkg /artifacts/
|
||||
|
||||
- name: Test solution
|
||||
run: |
|
||||
set -ex
|
||||
dotnet test -c ${CONFIGURATION} --no-build --nologo /p:CoverletOutputFormat=Cobertura
|
||||
/dotnet-tools/reportgenerator "-reports:${{ gitea.workspace }}/**/coverage.cobertura.xml" "-targetdir:/reports" "-reportType:TextSummary"
|
||||
|
||||
- name: Publish packages
|
||||
run: |
|
||||
set -ex
|
||||
dotnet nuget push -k "${{ secrets.NUGET_APIKEY }}" -s "https://api.nuget.org/v3/index.json" --skip-duplicate /artifacts/*.nupkg
|
||||
|
||||
- name: Publish documentation
|
||||
env:
|
||||
DOCFX_SOURCE_REPOSITORY_URL: 'https://github.com/AM-WD/FritzCallMonitor'
|
||||
run: |
|
||||
set -ex
|
||||
/dotnet-tools/docfx metadata docs/docfx.json
|
||||
/dotnet-tools/docfx build docs/docfx.json
|
||||
tar -C "${{ gitea.workspace }}/docs/_site" -czf "/artifacts/docs.tar.gz" .
|
||||
curl -sSL --no-progress-meter --user "${{ secrets.DOCS_DEPLOY_USER }}:${{ secrets.DOCS_DEPLOY_PASS }}" -F docs=fritzcallmonitor -F dump=@/artifacts/docs.tar.gz "${{ vars.DOCS_DEPLOY_URL }}"
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: artifacts
|
||||
path: |
|
||||
/artifacts/*
|
||||
/reports/Summary.txt
|
||||
42
CHANGELOG.md
42
CHANGELOG.md
@@ -2,12 +2,43 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
_nothing changed yet_
|
||||
### Added
|
||||
|
||||
- `FromNumber` and `ToNumber` properties to `CallMonitorEventArgs` to use when available
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed support for .NET 6.0 (EOL: 2024-11-12)
|
||||
|
||||
|
||||
## [v0.1.3] - 2026-01-12
|
||||
|
||||
### Changed
|
||||
|
||||
- Migrated main repository from Gitlab to Gitea (CI/CD)
|
||||
- Updated to VS 2026
|
||||
- Updated to .NET 10
|
||||
|
||||
|
||||
## [v0.1.2] - 2025-11-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Public elements are now `virtual` to allow mocking in unit tests
|
||||
|
||||
|
||||
## [v0.1.1] - 2025-10-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Property names of the event should be more descriptive:
|
||||
- From `CallerNumber` to `ExternalNumber`
|
||||
- From `CalleeNumber` to `InternalNumber`
|
||||
|
||||
|
||||
## [v0.1.0] - 2025-08-28
|
||||
@@ -17,7 +48,7 @@ _Inital release_
|
||||
### Added
|
||||
|
||||
- `CallMonitorClient` as client to connect to the call monitor endpoint
|
||||
- `CallMonitorEventArgs` are the custom arugments, when `OnEvent` is raised.
|
||||
- `CallMonitorEventArgs` are the custom arugments, when `OnEvent` is raised
|
||||
- Notifying about
|
||||
- `Ring`: An incoming call
|
||||
- `Call`: An outgoing call
|
||||
@@ -27,6 +58,9 @@ _Inital release_
|
||||
|
||||
|
||||
|
||||
[Unreleased]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.0...HEAD
|
||||
[Unreleased]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.3...HEAD
|
||||
|
||||
[v0.1.3]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.2...v0.1.3
|
||||
[v0.1.2]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.1...v0.1.2
|
||||
[v0.1.1]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.0...v0.1.1
|
||||
[v0.1.0]: https://github.com/AM-WD/FritzCallMonitor/commits/v0.1.0
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>12.0</LangVersion>
|
||||
<LangVersion>14.0</LangVersion>
|
||||
|
||||
<PublicKey>0024000004800000940000000602000000240000525341310004000001000100d9b40f5db1670c563c2e8be5dfd24ed66ad811b3ebba8a0ca0df9cbad3a115ca361b3de4b4d4ed990bf9874d2651e62565f56adb33af33819687021e263b02d6bf5b3cdacde4f09650cafe97467de4b9e4e9cc1d6c2d500a08759697bbe80940916c05533d172ca7e55e10434f9cc46fd189f26cefc100781a20e57f1bad65d5</PublicKey>
|
||||
<MoqPublicKey>0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7</MoqPublicKey>
|
||||
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>$(SolutionDir)/FritzCallMonitor.snk</AssemblyOriginatorKeyFile>
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36414.22
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor", "src\FritzCallMonitor\FritzCallMonitor.csproj", "{9951D44E-9511-40D0-84C1-6A7344389A05}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C386CB98-2D60-4E40-B869-73053972BD28}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\Directory.Build.props = src\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{DC8CE4B0-4CDD-4162-9CCD-FE711BC86EAB}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
test\Directory.Build.props = test\Directory.Build.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Tests", "test\FritzCallMonitor.Tests\FritzCallMonitor.Tests.csproj", "{7C5920EA-F4A8-4446-9645-3484DB13BCBD}"
|
||||
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
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{6FA27A08-FCE1-405E-A4A4-3A89FF4579F3}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.gitignore = .gitignore
|
||||
CodeMaid.config = CodeMaid.config
|
||||
nuget.config = nuget.config
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{B5851E79-416B-40CA-959C-ADCAFCC8BADB}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
CHANGELOG.md = CHANGELOG.md
|
||||
LICENSE.txt = LICENSE.txt
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Demo", "src\FritzCallMonitor.Demo\FritzCallMonitor.Demo.csproj", "{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9951D44E-9511-40D0-84C1-6A7344389A05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9951D44E-9511-40D0-84C1-6A7344389A05}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9951D44E-9511-40D0-84C1-6A7344389A05}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9951D44E-9511-40D0-84C1-6A7344389A05}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{9951D44E-9511-40D0-84C1-6A7344389A05} = {C386CB98-2D60-4E40-B869-73053972BD28}
|
||||
{7C5920EA-F4A8-4446-9645-3484DB13BCBD} = {DC8CE4B0-4CDD-4162-9CCD-FE711BC86EAB}
|
||||
{3DF1F30A-77F3-4F24-8739-CB89EE07BB8B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{6FA27A08-FCE1-405E-A4A4-3A89FF4579F3} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{B5851E79-416B-40CA-959C-ADCAFCC8BADB} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D} = {C386CB98-2D60-4E40-B869-73053972BD28}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {68E37BBB-3CC2-4B0B-8093-7F2F56345EF3}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
32
FritzCallMonitor.slnx
Normal file
32
FritzCallMonitor.slnx
Normal file
@@ -0,0 +1,32 @@
|
||||
<Solution>
|
||||
<Folder Name="/Solution Items/" />
|
||||
<Folder Name="/Solution Items/build/">
|
||||
<File Path="Directory.Build.props" />
|
||||
</Folder>
|
||||
<Folder Name="/Solution Items/build/workflows/">
|
||||
<File Path=".gitea/workflows/branch-build.yml" />
|
||||
<File Path=".gitea/workflows/release-build.yml" />
|
||||
</Folder>
|
||||
<Folder Name="/Solution Items/config/">
|
||||
<File Path=".editorconfig" />
|
||||
<File Path=".gitignore" />
|
||||
<File Path="CodeMaid.config" />
|
||||
<File Path="nuget.config" />
|
||||
</Folder>
|
||||
<Folder Name="/Solution Items/docs/">
|
||||
<File Path="CHANGELOG.md" />
|
||||
<File Path="LICENSE.txt" />
|
||||
<File Path="README.md" />
|
||||
<File Path="package-icon.png" />
|
||||
</Folder>
|
||||
<Folder Name="/src/">
|
||||
<Project Path="src/FritzCallMonitor/FritzCallMonitor.csproj" />
|
||||
<Project Path="src/FritzCallMonitor.Demo/FritzCallMonitor.Demo.csproj" />
|
||||
<File Path="src/Directory.Build.props" />
|
||||
</Folder>
|
||||
<Folder Name="/test/">
|
||||
<File Path="test/MSTestSettings.cs" />
|
||||
<Project Path="test/FritzCallMonitor.Tests/FritzCallMonitor.Tests.csproj" />
|
||||
<File Path="test/Directory.Build.props" />
|
||||
</Folder>
|
||||
</Solution>
|
||||
@@ -18,7 +18,6 @@ To disable the call monitor, dial: `#96*4*`.
|
||||
|
||||
Published under [MIT License] (see [choose a license]).
|
||||
|
||||
[](https://link.am-wd.de/donate)
|
||||
|
||||
|
||||
[MIT License]: LICENSE.txt
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
<NrtRevisionFormat>{semvertag:main}{!:-dev}</NrtRevisionFormat>
|
||||
<NrtContinuousIntegrationBuild>$(ContinuousIntegrationBuild)</NrtContinuousIntegrationBuild>
|
||||
<AssemblyOriginatorKeyFile>../../FritzCallMonitor.snk</AssemblyOriginatorKeyFile>
|
||||
|
||||
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
|
||||
@@ -18,7 +19,6 @@
|
||||
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<EmbedUntrackedSources>false</EmbedUntrackedSources>
|
||||
|
||||
<Title>CallMonitor implementation for FRITZ!Box</Title>
|
||||
<Company>AM.WD</Company>
|
||||
@@ -26,13 +26,14 @@
|
||||
<Copyright>© {copyright:2025-} AM.WD</Copyright>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(GITLAB_CI)' == 'true'">
|
||||
<PropertyGroup Condition="'$(CI)' == 'true'">
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="'$(GITLAB_CI)' == 'true'">
|
||||
<SourceLinkGitLabHost Include="$(CI_SERVER_HOST)" Version="$(CI_SERVER_VERSION)" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitLab" Version="8.0.0">
|
||||
<ItemGroup Condition="'$(CI)' == 'true'">
|
||||
<SourceLinkGiteaHost Include="$(CI_SERVER_HOST)" />
|
||||
<PackageReference Include="Microsoft.SourceLink.Gitea" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
@@ -40,11 +41,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="FritzCallMonitor.Tests" PublicKey="$(PublicKey)"/>
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" PublicKey="0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7"/>
|
||||
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" PublicKey="$(MoqPublicKey)"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AMWD.NetRevisionTask" Version="1.3.0">
|
||||
<PackageReference Include="AMWD.NetRevisionTask" Version="1.4.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -44,11 +44,11 @@ namespace FritzCallMonitor.Demo
|
||||
switch (e.Event)
|
||||
{
|
||||
case EventType.Ring:
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Incoming Call from {e.CallerNumber} to {e.CalleeNumber}");
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Incoming Call from {e.ExternalNumber} to {e.InternalNumber}");
|
||||
break;
|
||||
|
||||
case EventType.Connect:
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Call connected to {e.CallerNumber}");
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Call connected to {e.ExternalNumber}");
|
||||
break;
|
||||
|
||||
case EventType.Disconnect:
|
||||
@@ -56,7 +56,7 @@ namespace FritzCallMonitor.Demo
|
||||
break;
|
||||
|
||||
case EventType.Call:
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Outgoing Call from {e.CalleeNumber} to {e.CallerNumber}");
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Outgoing Call from {e.InternalNumber} to {e.ExternalNumber}");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,12 +51,12 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
|
||||
/// <remarks>
|
||||
/// The event provides details using the <see cref="CallMonitorEventArgs"/> parameter.
|
||||
/// </remarks>
|
||||
public event EventHandler<CallMonitorEventArgs>? OnEvent;
|
||||
public virtual event EventHandler<CallMonitorEventArgs>? OnEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a logger instance.
|
||||
/// </summary>
|
||||
public ILogger? Logger
|
||||
public virtual ILogger? Logger
|
||||
{
|
||||
get => _logger;
|
||||
set
|
||||
@@ -69,7 +69,7 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
|
||||
/// <summary>
|
||||
/// Releases all resources used by the current instance of the <see cref="CallMonitorClient"/>.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
|
||||
@@ -29,14 +29,46 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
|
||||
public int? LinePort { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the external number displayed in the FRITZ!Box.
|
||||
/// Gets the external phone number displayed in the FRITZ!Box.
|
||||
/// </summary>
|
||||
public string? CallerNumber { get; private set; }
|
||||
public string? ExternalNumber { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal number registered in the FRITZ!Box.
|
||||
/// Gets the internal phone number (part) registered in the FRITZ!Box.
|
||||
/// </summary>
|
||||
public string? CalleeNumber { get; private set; }
|
||||
public string? InternalNumber { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the phone number from which the call was initiated.
|
||||
/// </summary>
|
||||
public string? FromNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return Event switch
|
||||
{
|
||||
EventType.Ring => ExternalNumber,
|
||||
EventType.Call => InternalNumber,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the phone number to which the call was directed.
|
||||
/// </summary>
|
||||
public string? ToNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return Event switch
|
||||
{
|
||||
EventType.Ring => InternalNumber,
|
||||
EventType.Call => ExternalNumber,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the duration of the call (only on <see cref="EventType.Disconnect"/> event).
|
||||
@@ -71,13 +103,13 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
|
||||
switch (eventType)
|
||||
{
|
||||
case EventType.Ring:
|
||||
args.CallerNumber = columns[3];
|
||||
args.CalleeNumber = columns[4];
|
||||
args.ExternalNumber = columns[3];
|
||||
args.InternalNumber = columns[4];
|
||||
break;
|
||||
|
||||
case EventType.Connect:
|
||||
args.LinePort = int.TryParse(columns[3], out int connectLinePort) ? connectLinePort : null;
|
||||
args.CallerNumber = columns[4];
|
||||
args.ExternalNumber = columns[4];
|
||||
break;
|
||||
|
||||
case EventType.Disconnect:
|
||||
@@ -87,8 +119,8 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
|
||||
|
||||
case EventType.Call:
|
||||
args.LinePort = int.TryParse(columns[3], out int callLinePort) ? callLinePort : null;
|
||||
args.CalleeNumber = columns[4];
|
||||
args.CallerNumber = columns[5];
|
||||
args.InternalNumber = columns[4];
|
||||
args.ExternalNumber = columns[5];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
|
||||
<NrtTagMatch>v[0-9]*</NrtTagMatch>
|
||||
|
||||
<PackageId>AMWD.Net.Api.Fritz.CallMonitor</PackageId>
|
||||
@@ -22,11 +22,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<InternalsVisibleTo Include="FritzCallMonitor.Tests" PublicKey="$(PublicKey)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -19,11 +19,11 @@ using (var client = new CallMonitorClient(host, port))
|
||||
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}");
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Incoming Call from {e.ExternalNumber} to {e.InternalNumber}");
|
||||
break;
|
||||
|
||||
case EventType.Connect:
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Call connected to {e.CallerNumber}");
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Call connected to {e.ExternalNumber}");
|
||||
break;
|
||||
|
||||
case EventType.Disconnect:
|
||||
@@ -31,7 +31,7 @@ using (var client = new CallMonitorClient(host, port))
|
||||
break;
|
||||
|
||||
case EventType.Call:
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Outgoing Call from {e.CalleeNumber} to {e.CallerNumber}");
|
||||
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Outgoing Call from {e.InternalNumber} to {e.ExternalNumber}");
|
||||
break;
|
||||
}
|
||||
};
|
||||
@@ -46,6 +46,5 @@ using (var client = new CallMonitorClient(host, port))
|
||||
|
||||
Published under MIT License (see [choose a license]).
|
||||
|
||||
[](https://link.am-wd.de/donate)
|
||||
|
||||
[choose a license]: https://choosealicense.com/licenses/mit/
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace AMWD.Net.Api.Fritz.CallMonitor.Utils
|
||||
if (delay > 60 * 1000)
|
||||
delay = 60 * 1000;
|
||||
|
||||
Logger?.LogWarning(ex, $"Failed to connect to {_host}:{_port}. Retrying in {delay}ms...");
|
||||
Logger?.LogWarning(ex, "Failed to connect to {Hostname}:{RemotePort}. Retrying in {DelayMS}ms...", _host, _port, delay);
|
||||
try
|
||||
{
|
||||
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<CollectCoverage>true</CollectCoverage>
|
||||
@@ -9,18 +11,19 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.msbuild" Version="6.0.4">
|
||||
<PackageReference Include="coverlet.msbuild" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="3.10.0" />
|
||||
<PackageReference Include="MSTest" Version="4.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="AMWD.Net.Api.Fritz.CallMonitor" />
|
||||
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
|
||||
<Using Include="Moq" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)\..'))" />
|
||||
|
||||
@@ -4,11 +4,9 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AMWD.Net.Api.Fritz.CallMonitor;
|
||||
using AMWD.Net.Api.Fritz.CallMonitor.Utils;
|
||||
using AMWD.Net.Api.Fritz.CallMonitor.Wrappers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
|
||||
namespace FritzCallMonitor.Tests
|
||||
{
|
||||
@@ -21,10 +19,10 @@ namespace FritzCallMonitor.Tests
|
||||
|
||||
private const string HOST = "localhost";
|
||||
private const int PORT = 1012;
|
||||
private readonly DateTime _now = new(2025, 8, 25, 20, 15, 30, DateTimeKind.Local);
|
||||
|
||||
private string _dateOffset;
|
||||
|
||||
|
||||
private Mock<ReconnectTcpClient> _tcpClientMock;
|
||||
private Mock<NetworkStreamWrapper> _networkStreamMock;
|
||||
|
||||
@@ -34,7 +32,7 @@ namespace FritzCallMonitor.Tests
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
var offset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now);
|
||||
var offset = TimeZoneInfo.Local.GetUtcOffset(_now);
|
||||
_dateOffset = offset < TimeSpan.Zero
|
||||
? "-" + offset.ToString("hh\\:mm")
|
||||
: "+" + offset.ToString("hh\\:mm");
|
||||
@@ -43,7 +41,7 @@ namespace FritzCallMonitor.Tests
|
||||
|
||||
_readAsyncResponses = new Queue<(int, byte[])>();
|
||||
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;RING;2;012345678901;9876543;SIP0;\r\n")));
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;\r\n")));
|
||||
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
|
||||
}
|
||||
|
||||
@@ -82,7 +80,7 @@ namespace FritzCallMonitor.Tests
|
||||
// Arrange
|
||||
var loggerMock = new Mock<ILogger>();
|
||||
var client = GetClient();
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
// Act
|
||||
client.Logger = loggerMock.Object;
|
||||
@@ -106,7 +104,7 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
// Arrange
|
||||
var client = GetClient();
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
// Act
|
||||
client.Dispose();
|
||||
@@ -130,7 +128,7 @@ namespace FritzCallMonitor.Tests
|
||||
_tcpClientMock.Setup(m => m.GetStream()).Returns((NetworkStreamWrapper)null);
|
||||
|
||||
// Act
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
client.Dispose();
|
||||
|
||||
// Assert
|
||||
@@ -155,7 +153,7 @@ namespace FritzCallMonitor.Tests
|
||||
};
|
||||
|
||||
// Act
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
client.Dispose();
|
||||
|
||||
// Assert
|
||||
@@ -166,8 +164,8 @@ namespace FritzCallMonitor.Tests
|
||||
Assert.AreEqual(EventType.Ring, eventArgs.Event);
|
||||
Assert.AreEqual(2, eventArgs.ConnectionId);
|
||||
Assert.IsNull(eventArgs.LinePort);
|
||||
Assert.AreEqual("012345678901", eventArgs.CallerNumber);
|
||||
Assert.AreEqual("9876543", eventArgs.CalleeNumber);
|
||||
Assert.AreEqual("012345678901", eventArgs.ExternalNumber);
|
||||
Assert.AreEqual("9876543", eventArgs.InternalNumber);
|
||||
Assert.IsNull(eventArgs.Duration);
|
||||
|
||||
_tcpClientMock.VerifyGet(m => m.IsConnected, Times.Exactly(2));
|
||||
@@ -184,7 +182,7 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
// Arrange
|
||||
_readAsyncResponses.Clear();
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;RING;")));
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};RING;")));
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("2;012345678901;9876543;SIP0;\n")));
|
||||
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
|
||||
|
||||
@@ -198,7 +196,7 @@ namespace FritzCallMonitor.Tests
|
||||
};
|
||||
|
||||
// Act
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
client.Dispose();
|
||||
|
||||
// Assert
|
||||
@@ -209,8 +207,8 @@ namespace FritzCallMonitor.Tests
|
||||
Assert.AreEqual(EventType.Ring, eventArgs.Event);
|
||||
Assert.AreEqual(2, eventArgs.ConnectionId);
|
||||
Assert.IsNull(eventArgs.LinePort);
|
||||
Assert.AreEqual("012345678901", eventArgs.CallerNumber);
|
||||
Assert.AreEqual("9876543", eventArgs.CalleeNumber);
|
||||
Assert.AreEqual("012345678901", eventArgs.ExternalNumber);
|
||||
Assert.AreEqual("9876543", eventArgs.InternalNumber);
|
||||
Assert.IsNull(eventArgs.Duration);
|
||||
|
||||
_tcpClientMock.VerifyGet(m => m.IsConnected, Times.Exactly(3));
|
||||
@@ -227,7 +225,7 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
// Arrange
|
||||
_readAsyncResponses.Clear();
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;RING;2;012345678901;9876543;SIP0;\n25.08.25 20:15:30")));
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;\n{_now:dd.MM.yy HH:mm:ss}")));
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes(";RING;2;012345678901;9876543;SIP0;\r\n")));
|
||||
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
|
||||
|
||||
@@ -239,7 +237,7 @@ namespace FritzCallMonitor.Tests
|
||||
};
|
||||
|
||||
// Act
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
client.Dispose();
|
||||
|
||||
// Assert
|
||||
@@ -259,7 +257,7 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
// Arrange
|
||||
_readAsyncResponses.Clear();
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;TEST;2;012345678901;9876543;SIP0;\n25.08.25 20:15:30")));
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};TEST;2;012345678901;9876543;SIP0;\n{_now:dd.MM.yy HH:mm:ss}")));
|
||||
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes(";RING;2;012345678901;9876543;SIP0;\r\n")));
|
||||
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
|
||||
|
||||
@@ -271,7 +269,7 @@ namespace FritzCallMonitor.Tests
|
||||
};
|
||||
|
||||
// Act
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
client.Dispose();
|
||||
|
||||
// Assert
|
||||
@@ -327,9 +325,9 @@ namespace FritzCallMonitor.Tests
|
||||
tcpClientField.SetValue(client, _tcpClientMock.Object);
|
||||
|
||||
var onConnectedMethodInfo = client.GetType().GetMethod("OnConnected", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
_tcpClientMock.SetupGet(c => c.OnConnected).Returns((Func<ReconnectTcpClient, Task>)onConnectedMethodInfo.CreateDelegate(typeof(Func<ReconnectTcpClient, Task>), client));
|
||||
_tcpClientMock.SetupGet(c => c.OnConnected).Returns(onConnectedMethodInfo.CreateDelegate<Func<ReconnectTcpClient, Task>>(client));
|
||||
|
||||
_tcpClientMock.Object.OnConnected(_tcpClientMock.Object).Wait();
|
||||
_tcpClientMock.Object.OnConnected(_tcpClientMock.Object).Wait(TestContext.CancellationToken);
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using AMWD.Net.Api.Fritz.CallMonitor;
|
||||
|
||||
namespace FritzCallMonitor.Tests
|
||||
{
|
||||
@@ -8,10 +7,12 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
private string _dateOffset;
|
||||
|
||||
private readonly DateTime _now = new(2025, 8, 25, 20, 15, 30, DateTimeKind.Local);
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
var offset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now);
|
||||
var offset = TimeZoneInfo.Local.GetUtcOffset(_now);
|
||||
_dateOffset = offset < TimeSpan.Zero
|
||||
? "-" + offset.ToString("hh\\:mm")
|
||||
: "+" + offset.ToString("hh\\:mm");
|
||||
@@ -21,7 +22,7 @@ namespace FritzCallMonitor.Tests
|
||||
public void ShouldParseRingEvent()
|
||||
{
|
||||
// Arrange
|
||||
string line = "25.08.25 20:15:30;RING;2;012345678901;9876543;SIP0;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
@@ -29,15 +30,17 @@ namespace FritzCallMonitor.Tests
|
||||
Assert.AreEqual(EventType.Ring, result.Event);
|
||||
Assert.AreEqual(2, result.ConnectionId);
|
||||
Assert.IsNull(result.LinePort);
|
||||
Assert.AreEqual("012345678901", result.CallerNumber);
|
||||
Assert.AreEqual("9876543", result.CalleeNumber);
|
||||
Assert.AreEqual("012345678901", result.ExternalNumber);
|
||||
Assert.AreEqual("9876543", result.InternalNumber);
|
||||
Assert.AreEqual(result.ExternalNumber, result.FromNumber);
|
||||
Assert.AreEqual(result.InternalNumber, result.ToNumber);
|
||||
Assert.IsNull(result.Duration);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldParseConnectEvent()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;CONNECT;1;3;012345678901;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};CONNECT;1;3;012345678901;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
@@ -45,15 +48,17 @@ namespace FritzCallMonitor.Tests
|
||||
Assert.AreEqual(EventType.Connect, result.Event);
|
||||
Assert.AreEqual(1, result.ConnectionId);
|
||||
Assert.AreEqual(3, result.LinePort);
|
||||
Assert.AreEqual("012345678901", result.CallerNumber);
|
||||
Assert.IsNull(result.CalleeNumber);
|
||||
Assert.AreEqual("012345678901", result.ExternalNumber);
|
||||
Assert.IsNull(result.InternalNumber);
|
||||
Assert.IsNull(result.FromNumber);
|
||||
Assert.IsNull(result.ToNumber);
|
||||
Assert.IsNull(result.Duration);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldParseDisconnectEvent()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;DISCONNECT;2;42;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};DISCONNECT;2;42;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
@@ -61,15 +66,17 @@ namespace FritzCallMonitor.Tests
|
||||
Assert.AreEqual(EventType.Disconnect, result.Event);
|
||||
Assert.AreEqual(2, result.ConnectionId);
|
||||
Assert.IsNull(result.LinePort);
|
||||
Assert.IsNull(result.CallerNumber);
|
||||
Assert.IsNull(result.CalleeNumber);
|
||||
Assert.IsNull(result.ExternalNumber);
|
||||
Assert.IsNull(result.InternalNumber);
|
||||
Assert.IsNull(result.FromNumber);
|
||||
Assert.IsNull(result.ToNumber);
|
||||
Assert.AreEqual(TimeSpan.FromSeconds(42), result.Duration);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldParseCallEvent()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;CALL;4;7;9876543;012345678901;SIP0;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};CALL;4;7;9876543;012345678901;SIP0;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
@@ -77,8 +84,10 @@ namespace FritzCallMonitor.Tests
|
||||
Assert.AreEqual(EventType.Call, result.Event);
|
||||
Assert.AreEqual(4, result.ConnectionId);
|
||||
Assert.AreEqual(7, result.LinePort);
|
||||
Assert.AreEqual("012345678901", result.CallerNumber);
|
||||
Assert.AreEqual("9876543", result.CalleeNumber);
|
||||
Assert.AreEqual("012345678901", result.ExternalNumber);
|
||||
Assert.AreEqual("9876543", result.InternalNumber);
|
||||
Assert.AreEqual(result.InternalNumber, result.FromNumber);
|
||||
Assert.AreEqual(result.ExternalNumber, result.ToNumber);
|
||||
Assert.IsNull(result.Duration);
|
||||
}
|
||||
|
||||
@@ -93,7 +102,7 @@ namespace FritzCallMonitor.Tests
|
||||
[TestMethod]
|
||||
public void ShouldReturnNullOnUnknownEventType()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;UNKNOWN;2;012345678901;9876543;SIP0;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};UNKNOWN;2;012345678901;9876543;SIP0;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
@@ -101,7 +110,7 @@ namespace FritzCallMonitor.Tests
|
||||
[TestMethod]
|
||||
public void ShouldReturnNullOnInvalidConnectionId()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;RING;abc;012345678901;9876543;SIP0;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};RING;abc;012345678901;9876543;SIP0;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
@@ -109,25 +118,32 @@ namespace FritzCallMonitor.Tests
|
||||
[TestMethod]
|
||||
public void ShouldHandleInvalidLinePortInConnect()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;CONNECT;1;abc;012345678901;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};CONNECT;1;abc;012345678901;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsNull(result.LinePort);
|
||||
Assert.AreEqual("012345678901", result.ExternalNumber);
|
||||
Assert.IsNull(result.FromNumber);
|
||||
Assert.IsNull(result.ToNumber);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldHandleInvalidLinePortInCall()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;CALL;4;abc;9876543;012345678901;SIP0;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};CALL;4;abc;9876543;012345678901;SIP0;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsNull(result.LinePort);
|
||||
Assert.AreEqual("012345678901", result.ExternalNumber);
|
||||
Assert.AreEqual("9876543", result.InternalNumber);
|
||||
Assert.AreEqual(result.InternalNumber, result.FromNumber);
|
||||
Assert.AreEqual(result.ExternalNumber, result.ToNumber);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldHandleInvalidDurationInDisconnect()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;DISCONNECT;2;abc;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};DISCONNECT;2;abc;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsNull(result.Duration);
|
||||
@@ -136,7 +152,7 @@ namespace FritzCallMonitor.Tests
|
||||
[TestMethod]
|
||||
public void ShouldReturnNullOnTooFewColumns()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;RING;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};RING;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
Assert.IsNull(result);
|
||||
}
|
||||
@@ -144,11 +160,13 @@ namespace FritzCallMonitor.Tests
|
||||
[TestMethod]
|
||||
public void ShouldParseWithExtraColumns()
|
||||
{
|
||||
string line = "25.08.25 20:15:30;RING;2;012345678901;9876543;SIP0;EXTRA;COLUMN;";
|
||||
string line = $"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;EXTRA;COLUMN;";
|
||||
var result = CallMonitorEventArgs.Parse(line);
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual("012345678901", result.CallerNumber);
|
||||
Assert.AreEqual("9876543", result.CalleeNumber);
|
||||
Assert.AreEqual("012345678901", result.ExternalNumber);
|
||||
Assert.AreEqual("9876543", result.InternalNumber);
|
||||
Assert.AreEqual(result.ExternalNumber, result.FromNumber);
|
||||
Assert.AreEqual(result.InternalNumber, result.ToNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<NoWarn>$(NoWarn);CA1873</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="../MSTestSettings.cs" Link="MSTestSettings.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../src/FritzCallMonitor/FritzCallMonitor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Threading.Tasks;
|
||||
using AMWD.Net.Api.Fritz.CallMonitor.Utils;
|
||||
using AMWD.Net.Api.Fritz.CallMonitor.Wrappers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
|
||||
namespace FritzCallMonitor.Tests
|
||||
{
|
||||
@@ -80,8 +79,8 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
// Arrange
|
||||
var client = GetClient();
|
||||
await client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
// Act
|
||||
client.Dispose();
|
||||
@@ -105,8 +104,8 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
// Arrange
|
||||
using var client = GetClient();
|
||||
await client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
// Act
|
||||
client.Dispose();
|
||||
@@ -134,7 +133,7 @@ namespace FritzCallMonitor.Tests
|
||||
client.Dispose();
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StartAsync(TestContext.CancellationTokenSource.Token));
|
||||
await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StartAsync(TestContext.CancellationToken));
|
||||
|
||||
VerifyNoOtherCalls();
|
||||
}
|
||||
@@ -147,7 +146,7 @@ namespace FritzCallMonitor.Tests
|
||||
client.Dispose();
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StopAsync(TestContext.CancellationTokenSource.Token));
|
||||
await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StopAsync(TestContext.CancellationToken));
|
||||
|
||||
VerifyNoOtherCalls();
|
||||
}
|
||||
@@ -172,8 +171,8 @@ namespace FritzCallMonitor.Tests
|
||||
_tcpClientConnectTaskDelays.Enqueue(Timeout.Infinite);
|
||||
|
||||
var client = GetClient();
|
||||
await client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
// Act & Assert
|
||||
_tcpClientConnected = true;
|
||||
@@ -208,10 +207,10 @@ namespace FritzCallMonitor.Tests
|
||||
};
|
||||
|
||||
// Act
|
||||
await client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StopAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
await client.StopAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(callbackCalled);
|
||||
@@ -236,10 +235,10 @@ namespace FritzCallMonitor.Tests
|
||||
var client = GetClient();
|
||||
|
||||
// Act & Assert
|
||||
await client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StopAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
await client.StopAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
_socketMock.Verify(m => m.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true), Times.Once);
|
||||
|
||||
@@ -261,7 +260,7 @@ namespace FritzCallMonitor.Tests
|
||||
var client = GetClient();
|
||||
|
||||
// Act & Assert
|
||||
await client.StopAsync(TestContext.CancellationTokenSource.Token);
|
||||
await client.StopAsync(TestContext.CancellationToken);
|
||||
|
||||
VerifyNoOtherCalls();
|
||||
}
|
||||
@@ -271,8 +270,8 @@ namespace FritzCallMonitor.Tests
|
||||
{
|
||||
// Arrange
|
||||
var client = GetClient();
|
||||
await client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
|
||||
// Act
|
||||
var stream = client.GetStream();
|
||||
@@ -317,10 +316,10 @@ namespace FritzCallMonitor.Tests
|
||||
using var client = GetClient();
|
||||
|
||||
// Act
|
||||
var startTask = client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
await client.StopAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
var startTask = client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
await client.StopAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
await startTask;
|
||||
|
||||
// Assert
|
||||
@@ -350,10 +349,10 @@ namespace FritzCallMonitor.Tests
|
||||
.ThrowsAsync(new SocketException());
|
||||
|
||||
// Act
|
||||
var startTask = client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(1000, TestContext.CancellationTokenSource.Token); // Should try to connect two times.
|
||||
await client.StopAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
var startTask = client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(1000, TestContext.CancellationToken); // Should try to connect two times.
|
||||
await client.StopAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
await startTask;
|
||||
|
||||
// Assert
|
||||
@@ -394,10 +393,10 @@ namespace FritzCallMonitor.Tests
|
||||
.ThrowsAsync(new ObjectDisposedException("Test"));
|
||||
|
||||
// Act
|
||||
var startTask = client.StartAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(1000, TestContext.CancellationTokenSource.Token); // Should try to connect two times.
|
||||
await client.StopAsync(TestContext.CancellationTokenSource.Token);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token);
|
||||
var startTask = client.StartAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(1000, TestContext.CancellationToken); // Should try to connect two times.
|
||||
await client.StopAsync(TestContext.CancellationToken);
|
||||
await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
|
||||
await startTask;
|
||||
|
||||
// Assert
|
||||
|
||||
1
test/MSTestSettings.cs
Normal file
1
test/MSTestSettings.cs
Normal file
@@ -0,0 +1 @@
|
||||
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
|
||||
Reference in New Issue
Block a user