Skip to content

Commit 532f435

Browse files
committed
Sweet C#8 Part 2 NRT
1 parent 82a64c7 commit 532f435

File tree

198 files changed

+2671
-2034
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

198 files changed

+2671
-2034
lines changed

Directory.Build.targets

-8
This file was deleted.

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Download either one of the latest builds from our [nightly server](https://splam
4848
Will always have the latest and greatest but might not be fully stable or have broken features.
4949

5050
#### Linux
51-
1. dotnet core: Get the latest `dotnet core 2.2` version by following [this tutorial](https://dotnet.microsoft.com/download/linux-package-manager/ubuntu16-04/sdk-current) and follow the steps after choosing your platform
51+
1. dotnet core: Get the latest `dotnet core` version by following [this tutorial](https://dotnet.microsoft.com/download/linux-package-manager/ubuntu16-04/sdk-current) and follow the steps after choosing your platform
5252
1. Other dependencies:
5353
* on **Ubuntu**:
5454
Run `sudo apt-get install libopus-dev ffmpeg`
@@ -98,13 +98,13 @@ For further reading check out the [CommandSystem](https://github.com/Splamy/TS3A
9898
Download the git repository with `git clone --recurse-submodules https://github.com/Splamy/TS3AudioBot.git`.
9999

100100
#### Linux
101-
1. Get the latest `dotnet core 2.2` version by following [this tutorial](https://dotnet.microsoft.com/download/linux-package-manager/ubuntu16-04/sdk-current) and choose your platform
101+
1. Get the latest `dotnet core 3.0` version by following [this tutorial](https://docs.microsoft.com/dotnet/core/install/linux-package-managers) and choose your platform
102102
1. Go into the directory of the repository with `cd TS3AudioBot`
103-
1. Execute `dotnet build --framework netcoreapp2.2 --configuration Release TS3AudioBot` to build the AudioBot
104-
1. The binary will be in `./TS3AudioBot/bin/Release/netcoreapp2.2` and can be run with `dotnet TS3AudioBot.dll`
103+
1. Execute `dotnet build --framework netcoreapp3.0 --configuration Release TS3AudioBot` to build the AudioBot
104+
1. The binary will be in `./TS3AudioBot/bin/Release/netcoreapp3.0` and can be run with `dotnet TS3AudioBot.dll`
105105

106106
#### Windows
107-
1. Make sure you have installed `Visual Studio` with `.NET Framework 4.7.2` and the latest `dotnet core 2.2` or higher
107+
1. Make sure you have `Visual Studio` with the `dotnet core 3.0` development toolchain installed
108108
1. Build the AudioBot with Visual Studio.
109109

110110
## Community

TS3ABotUnitTests/TS3ABotUnitTests.csproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<OutputType>Library</OutputType>
5-
<TargetFrameworks>netcoreapp2.2;netcoreapp3.0</TargetFrameworks>
5+
<TargetFrameworks>netcoreapp3.0</TargetFrameworks>
66

77
<LangVersion>8.0</LangVersion>
88
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -12,7 +12,7 @@
1212
<ItemGroup>
1313
<PackageReference Include="NUnit" Version="3.12.0" />
1414
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
15-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
15+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
1616
</ItemGroup>
1717

1818
<ItemGroup>

TS3ABotUnitTests/TS3MessageParserTests.cs

+27-32
Large diffs are not rendered by default.

TS3ABotUnitTests/UnitTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ public void HistoryFileIntergrityTest()
3131
string testFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "history.test");
3232
if (File.Exists(testFile)) File.Delete(testFile);
3333

34-
var inv1 = new ClientList { ClientId = (ClientId)10, Uid = (Uid)"Uid1", Name = "Invoker1" };
35-
var inv2 = new ClientList { ClientId = (ClientId)20, Uid = (Uid)"Uid2", Name = "Invoker2" };
34+
var inv1 = new { ClientId = (ClientId)10, Uid = (Uid)"Uid1", Name = "Invoker1" };
35+
var inv2 = new { ClientId = (ClientId)20, Uid = (Uid)"Uid2", Name = "Invoker2" };
3636

3737
var ar1 = new AudioResource("asdf", "sc_ar1", "soundcloud");
3838
var ar2 = new AudioResource("./File.mp3", "me_ar2", "media");

TS3AudioBot.ruleset

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<RuleSet Name="Rules for TSAB Project" Description="Code analysis rules for the TSAB Project." ToolsVersion="16.0">
33
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
44
<Rule Id="CA1001" Action="Warning" />
@@ -84,6 +84,7 @@
8484
</Rules>
8585
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp" RuleNamespace="Microsoft.CodeAnalysis.CSharp">
8686
<Rule Id="CS8019" Action="Info" />
87+
<Rule Id="CS8020" Action="Info" />
8788
</Rules>
8889
<Rules AnalyzerId="Roslynator.CSharp.Analyzers" RuleNamespace="Roslynator.CSharp.Analyzers">
8990
<Rule Id="RCS1010" Action="Info" />
@@ -93,4 +94,4 @@
9394
<Rule Id="RCS1046" Action="Info" />
9495
<Rule Id="RCS1057" Action="None" />
9596
</Rules>
96-
</RuleSet>
97+
</RuleSet>

TS3AudioBot.sln

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ EndProject
1111
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ADAA5A65-0CE1-45FA-91F4-3D8D39073AB0}"
1212
ProjectSection(SolutionItems) = preProject
1313
.editorconfig = .editorconfig
14-
Directory.Build.targets = Directory.Build.targets
1514
README.md = README.md
1615
TS3AudioBot.ruleset = TS3AudioBot.ruleset
1716
EndProjectSection

TS3AudioBot/Algorithm/IFilterAlgorithm.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static class Filter
2121
{
2222
public static IFilter DefaultFilter { get; } = Ic3Filter.Instance;
2323

24-
public static IFilter GetFilterByName(string filter)
24+
public static IFilter? GetFilterByName(string filter)
2525
{
2626
return filter switch
2727
{

TS3AudioBot/Algorithm/LruCache.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
// program. If not, see <https://opensource.org/licenses/OSL-3.0>.
99

1010
using System.Collections.Generic;
11+
using System.Diagnostics.CodeAnalysis;
1112

1213
namespace TS3AudioBot.Algorithm
1314
{
14-
public class LruCache<TK, TV>
15+
public class LruCache<TK, TV> where TK : notnull
1516
{
1617
private readonly int maxCapacity;
1718
private readonly Dictionary<TK, LinkedListNode<(TK key, TV value)>> cacheDict = new Dictionary<TK, LinkedListNode<(TK, TV)>>();
@@ -22,15 +23,15 @@ public LruCache(int capacity)
2223
maxCapacity = capacity;
2324
}
2425

25-
public bool TryGetValue(TK key, out TV value)
26+
public bool TryGetValue(TK key, [MaybeNullWhen(false)] out TV value)
2627
{
2728
if (cacheDict.TryGetValue(key, out var node))
2829
{
2930
Renew(node);
3031
value = node.Value.value;
3132
return true;
3233
}
33-
value = default;
34+
value = default!;
3435
return false;
3536
}
3637

@@ -50,7 +51,7 @@ public void Set(TK key, TV value)
5051
cacheDict.Add(key, node);
5152
}
5253

53-
public void Remove(TK key) => cacheDict.Remove(key);
54+
public bool Remove(TK key) => cacheDict.Remove(key);
5455

5556
private void Renew(LinkedListNode<(TK, TV)> node)
5657
{
@@ -61,6 +62,8 @@ private void Renew(LinkedListNode<(TK, TV)> node)
6162
private void RemoveOldest()
6263
{
6364
var node = lruList.First;
65+
if (node is null)
66+
return;
6467
lruList.RemoveFirst();
6568
cacheDict.Remove(node.Value.key);
6669
}

TS3AudioBot/Algorithm/TimedCache.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99

1010
using System;
1111
using System.Collections.Concurrent;
12+
using System.Diagnostics.CodeAnalysis;
1213
using System.Linq;
1314
using TSLib.Helper;
1415

1516
namespace TS3AudioBot.Algorithm
1617
{
17-
public class TimedCache<TK, TV>
18+
public class TimedCache<TK, TV> where TK : notnull
1819
{
1920
public TimeSpan Timeout { get; }
2021
private readonly ConcurrentDictionary<TK, TimedData> cachedData;
@@ -27,13 +28,13 @@ public TimedCache(TimeSpan timeout)
2728
cachedData = new ConcurrentDictionary<TK, TimedData>();
2829
}
2930

30-
public bool TryGetValue(TK key, out TV value)
31+
public bool TryGetValue(TK key, [MaybeNullWhen(false)] out TV value)
3132
{
3233
if (!cachedData.TryGetValue(key, out var data)
3334
|| Tools.Now - Timeout > data.Timestamp)
3435
{
3536
CleanCache();
36-
value = default;
37+
value = default!;
3738
return false;
3839
}
3940
value = data.Data;

TS3AudioBot/Audio/CustomTargetPipe.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ public bool Active
5151

5252
private readonly Dictionary<ChannelId, bool> channelSubscriptionsSetup = new Dictionary<ChannelId, bool>();
5353
private readonly HashSet<ClientId> clientSubscriptionsSetup = new HashSet<ClientId>();
54-
private ChannelId[] channelSubscriptionsCache;
55-
private ClientId[] clientSubscriptionsCache;
54+
private ChannelId[] channelSubscriptionsCache = Array.Empty<ChannelId>();
55+
private ClientId[] clientSubscriptionsCache = Array.Empty<ClientId>();
5656
private bool subscriptionSetupChanged;
5757
private readonly object subscriptionLockObj = new object();
5858

@@ -64,7 +64,7 @@ public CustomTargetPipe(TsFullClient client)
6464
subscriptionSetupChanged = true;
6565
}
6666

67-
public void Write(Span<byte> data, Meta meta)
67+
public void Write(Span<byte> data, Meta? meta)
6868
{
6969
UpdatedSubscriptionCache();
7070

TS3AudioBot/Audio/FfmpegProducer.cs

+33-34
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ public class FfmpegProducer : IPlayerSource, ISampleInfo, IDisposable
3535

3636
private readonly ConfToolsFfmpeg config;
3737

38-
public event EventHandler OnSongEnd;
39-
public event EventHandler<SongInfoChanged> OnSongUpdated;
38+
public event EventHandler? OnSongEnd;
39+
public event EventHandler<SongInfoChanged>? OnSongUpdated;
4040

41-
private FfmpegInstance ffmpegInstance;
41+
private FfmpegInstance? ffmpegInstance;
4242

4343
public int SampleRate { get; } = 48000;
4444
public int Channels { get; } = 2;
@@ -68,9 +68,9 @@ public TimeSpan Position
6868
set => SetPosition(value);
6969
}
7070

71-
public int Read(byte[] buffer, int offset, int length, out Meta meta)
71+
public int Read(byte[] buffer, int offset, int length, out Meta? meta)
7272
{
73-
meta = null;
73+
meta = default;
7474
bool triggerEndSafe = false;
7575
int read;
7676

@@ -206,8 +206,7 @@ private R<FfmpegInstance, string> StartFfmpegProcess(string url, TimeSpan? offse
206206
new PreciseAudioTimer(this)
207207
{
208208
SongPositionOffset = offset,
209-
},
210-
false);
209+
});
211210

212211
return StartFfmpegProcessInternal(newInstance, arguments);
213212
}
@@ -219,7 +218,7 @@ private R<FfmpegInstance, string> StartFfmpegProcessIcy(string url)
219218

220219
try
221220
{
222-
var request = WebWrapper.CreateRequest(new Uri(url)).Unwrap();
221+
var request = WebWrapper.CreateRequest(url).Unwrap();
223222
request.Headers["Icy-MetaData"] = "1";
224223

225224
var response = request.GetResponse();
@@ -233,12 +232,9 @@ private R<FfmpegInstance, string> StartFfmpegProcessIcy(string url)
233232
var newInstance = new FfmpegInstance(
234233
url,
235234
new PreciseAudioTimer(this),
236-
true)
237-
{
238-
IcyStream = stream,
239-
IcyMetaInt = metaint,
240-
};
241-
newInstance.OnMetaUpdated = e => OnSongUpdated(this, e);
235+
stream,
236+
metaint);
237+
newInstance.OnMetaUpdated = e => OnSongUpdated?.Invoke(this, e);
242238

243239
new Thread(() => newInstance.ReadStreamLoop(id))
244240
{
@@ -259,20 +255,17 @@ private R<FfmpegInstance, string> StartFfmpegProcessInternal(FfmpegInstance inst
259255
{
260256
try
261257
{
262-
instance.FfmpegProcess = new Process
258+
instance.FfmpegProcess.StartInfo = new ProcessStartInfo
263259
{
264-
StartInfo = new ProcessStartInfo
265-
{
266-
FileName = config.Path.Value,
267-
Arguments = arguments,
268-
RedirectStandardOutput = true,
269-
RedirectStandardInput = true,
270-
RedirectStandardError = true,
271-
UseShellExecute = false,
272-
CreateNoWindow = true,
273-
},
274-
EnableRaisingEvents = true,
260+
FileName = config.Path.Value,
261+
Arguments = arguments,
262+
RedirectStandardOutput = true,
263+
RedirectStandardInput = true,
264+
RedirectStandardError = true,
265+
UseShellExecute = false,
266+
CreateNoWindow = true,
275267
};
268+
instance.FfmpegProcess.EnableRaisingEvents = true;
276269

277270
Log.Debug("Starting ffmpeg with {0}", arguments);
278271
instance.FfmpegProcess.ErrorDataReceived += instance.FfmpegProcess_ErrorDataReceived;
@@ -324,25 +317,28 @@ public void Dispose()
324317

325318
private class FfmpegInstance
326319
{
327-
public Process FfmpegProcess { get; set; }
320+
public Process FfmpegProcess { get; }
328321
public bool HasTriedToReconnect { get; set; }
329322
public string ReconnectUrl { get; }
330-
public bool IsIcyStream { get; }
323+
public bool IsIcyStream => IcyStream != null;
331324

332325
public PreciseAudioTimer AudioTimer { get; }
333326
public TimeSpan? ParsedSongLength { get; set; } = null;
334327

335-
public Stream IcyStream { get; set; }
336-
public int IcyMetaInt { get; set; }
328+
public Stream? IcyStream { get; }
329+
public int IcyMetaInt { get; }
337330
public bool Closed { get; set; }
338331

339-
public Action<SongInfoChanged> OnMetaUpdated;
332+
public Action<SongInfoChanged>? OnMetaUpdated;
340333

341-
public FfmpegInstance(string url, PreciseAudioTimer timer, bool isIcyStream)
334+
public FfmpegInstance(string url, PreciseAudioTimer timer) : this(url, timer, null!, 0) { }
335+
public FfmpegInstance(string url, PreciseAudioTimer timer, Stream icyStream, int icyMetaInt)
342336
{
337+
FfmpegProcess = new Process();
343338
ReconnectUrl = url;
344339
AudioTimer = timer;
345-
IsIcyStream = isIcyStream;
340+
IcyStream = icyStream;
341+
IcyMetaInt = icyMetaInt;
346342

347343
HasTriedToReconnect = false;
348344
}
@@ -373,7 +369,7 @@ public void FfmpegProcess_ErrorDataReceived(object sender, DataReceivedEventArgs
373369
if (sender != FfmpegProcess)
374370
throw new InvalidOperationException("Wrong process associated to event");
375371

376-
if (!ParsedSongLength.HasValue)
372+
if (ParsedSongLength is null)
377373
{
378374
var match = FindDurationMatch.Match(e.Data);
379375
if (!match.Success)
@@ -394,6 +390,9 @@ public void FfmpegProcess_ErrorDataReceived(object sender, DataReceivedEventArgs
394390

395391
public void ReadStreamLoop(Id id)
396392
{
393+
if (IcyStream is null)
394+
throw new InvalidOperationException("Instance is not an icy stream");
395+
397396
Tools.SetLogId(id.ToString());
398397
const int IcyMaxMeta = 255 * 16;
399398
const int ReadBufferSize = 4096;

TS3AudioBot/Audio/PlayInfoEventArgs.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ public sealed class PlayInfoEventArgs : EventArgs
1717
public InvokerData Invoker { get; }
1818
public PlayResource PlayResource { get; }
1919
public AudioResource ResourceData => PlayResource.BaseData;
20-
public MetaData MetaData => PlayResource.Meta;
21-
public string SourceLink { get; }
20+
public MetaData? MetaData => PlayResource.Meta;
21+
public string? SourceLink { get; }
2222

23-
public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, string sourceLink)
23+
public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, string? sourceLink)
2424
{
2525
Invoker = invoker;
2626
PlayResource = playResource;

0 commit comments

Comments
 (0)