Skip to content

Commit 50fa8a1

Browse files
committed
Rename FowardingChannelWrapper to ForwardingAuthenticationStrategy, since its primary purpose is to switch between transparent API key forwarding and shared-connection use
1 parent 62b65a8 commit 50fa8a1

11 files changed

+224
-140
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ dotnet tool install --global seqcli
1515
To set a default server URL and API key, run:
1616

1717
```
18-
seqcli config -k connection.serverUrl -v https://your-seq-server
19-
seqcli config -k connection.apiKey -v your-api-key
18+
seqcli config set -k connection.serverUrl -v https://your-seq-server
19+
seqcli config set -k connection.apiKey -v your-api-key
2020
```
2121

2222
The API key will be stored in your `SeqCli.json` configuration file; on Windows, this is encrypted using DPAPI; on Mac/Linux the key is stored in plain text unless an encryptor is defined in `encryption.encryptor`. As an alternative to storing the API key in configuration, it can be passed to each command via the `--apikey=` argument.

src/SeqCli/Forwarder/Channel/ApiKeyForwardingChannelWrapper.cs

Lines changed: 0 additions & 90 deletions
This file was deleted.

src/SeqCli/Forwarder/Channel/ForwardingChannelWrapper.cs renamed to src/SeqCli/Forwarder/Channel/ForwardingAuthenticationStrategy.cs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
// Copyright © Datalust Pty Ltd
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
116
using System.IO;
217
using System.Threading;
318
using System.Threading.Tasks;
@@ -9,13 +24,12 @@
924

1025
namespace SeqCli.Forwarder.Channel;
1126

12-
internal abstract class ForwardingChannelWrapper(string bufferPath, SeqConnection connection, SeqCliConfig config)
27+
abstract class ForwardingAuthenticationStrategy(string bufferPath, SeqConnection connection, SeqCliConfig config)
1328
{
14-
protected const string SeqCliConnectionChannelId = "SeqCliConnection";
29+
readonly CancellationTokenSource _shutdownTokenSource = new();
30+
1531
protected readonly string BufferPath = bufferPath;
1632
protected readonly SeqCliConfig Config = config;
17-
protected readonly CancellationTokenSource ShutdownTokenSource = new();
18-
protected readonly Lock ChannelsSync = new();
1933

2034
// <param name="id">The id used for the channel storage on the file system.</param>
2135
// <param name="apiKey">The apiKey that will be used to connect to the downstream Seq instance.</param>
@@ -24,7 +38,7 @@ protected ForwardingChannel OpenOrCreateChannel(string id, string? apiKey)
2438
var storePath = GetStorePath(id);
2539
var store = new SystemStoreDirectory(storePath);
2640

27-
Log.ForContext<ForwardingChannelWrapper>().Information("Opening local buffer in {StorePath}", storePath);
41+
Log.ForContext<ForwardingAuthenticationStrategy>().Information("Opening local buffer in {StorePath}", storePath);
2842

2943
return new ForwardingChannel(
3044
BufferAppender.Open(store),
@@ -35,15 +49,25 @@ protected ForwardingChannel OpenOrCreateChannel(string id, string? apiKey)
3549
Config.Forwarder.Storage.TargetChunkSizeBytes,
3650
Config.Forwarder.Storage.MaxChunks,
3751
Config.Connection.BatchSizeLimitBytes,
38-
ShutdownTokenSource.Token);
52+
_shutdownTokenSource.Token);
3953
}
4054

4155
public abstract ForwardingChannel GetForwardingChannel(string? requestApiKey);
4256

4357
public abstract Task StopAsync();
4458

59+
protected async Task OnStoppedAsync()
60+
{
61+
await _shutdownTokenSource.CancelAsync();
62+
}
63+
64+
protected void OnStopping()
65+
{
66+
_shutdownTokenSource.CancelAfter(TimeSpan.FromSeconds(30));
67+
}
68+
4569
protected string GetStorePath(string id)
4670
{
4771
return Path.Combine(BufferPath, id);
4872
}
49-
}
73+
}

src/SeqCli/Forwarder/Channel/ForwardingChannel.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright © Datalust Pty Ltd
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
using System;
216
using System.IO;
317
using System.Threading;

src/SeqCli/Forwarder/Channel/ForwardingChannelEntry.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright © Datalust Pty Ltd
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
using System;
216
using System.Threading.Tasks;
317

src/SeqCli/Forwarder/Channel/SeqCliConnectionForwardingChannelWrapper.cs

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright © Datalust Pty Ltd
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Threading.Tasks;
16+
using Seq.Api;
17+
using SeqCli.Config;
18+
using Serilog;
19+
20+
namespace SeqCli.Forwarder.Channel;
21+
22+
class SharedConnectionForwardingAuthenticationStrategy: ForwardingAuthenticationStrategy
23+
{
24+
public const string ChannelId = "SharedConnection";
25+
26+
readonly ForwardingChannel _sharedForwardingChannel;
27+
28+
public SharedConnectionForwardingAuthenticationStrategy(string bufferPath, SeqConnection connection, SeqCliConfig config, string? seqCliApiKey): base(bufferPath, connection, config)
29+
{
30+
_sharedForwardingChannel = OpenOrCreateChannel(ChannelId, seqCliApiKey);
31+
}
32+
33+
public override ForwardingChannel GetForwardingChannel(string? _)
34+
{
35+
return _sharedForwardingChannel;
36+
}
37+
38+
public override async Task StopAsync()
39+
{
40+
Log.ForContext<SharedConnectionForwardingAuthenticationStrategy>().Information("Flushing log buffer");
41+
OnStopping();
42+
43+
await _sharedForwardingChannel.StopAsync();
44+
await OnStoppedAsync();
45+
}
46+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright © Datalust Pty Ltd
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Collections.Generic;
17+
using System.IO;
18+
using System.Linq;
19+
using System.Threading;
20+
using System.Threading.Tasks;
21+
using Seq.Api;
22+
using SeqCli.Config;
23+
using SeqCli.Forwarder.Filesystem.System;
24+
using Serilog;
25+
26+
namespace SeqCli.Forwarder.Channel;
27+
28+
class TransparentForwardingAuthenticationStrategy : ForwardingAuthenticationStrategy
29+
{
30+
readonly Lock _channelsSync = new();
31+
readonly Dictionary<string, ForwardingChannel> _channelsByApiKey = new();
32+
const string EmptyApiKeyChannelId = "EmptyApiKey";
33+
34+
public TransparentForwardingAuthenticationStrategy(string bufferPath, SeqConnection connection, SeqCliConfig config) : base(bufferPath, connection, config)
35+
{
36+
LoadChannels();
37+
}
38+
39+
// Start forwarding channels found on the file system.
40+
void LoadChannels()
41+
{
42+
foreach (var directoryPath in Directory.EnumerateDirectories(BufferPath))
43+
{
44+
if (directoryPath.Equals(GetStorePath(SharedConnectionForwardingAuthenticationStrategy.ChannelId)))
45+
{
46+
Log.ForContext<TransparentForwardingAuthenticationStrategy>().Information(
47+
"Ignoring data stored in `{DirectoryPath}` prior to API key forwarding being enabled", directoryPath);
48+
continue;
49+
}
50+
51+
string apiKey, channelId;
52+
53+
if (new SystemStoreDirectory(directoryPath).TryReadApiKey(Config, out var key))
54+
{
55+
apiKey = key;
56+
channelId = directoryPath;
57+
}
58+
else
59+
{
60+
Log.ForContext<TransparentForwardingAuthenticationStrategy>().Information(
61+
"Directory `{DirectoryPath}` does not contain a readable API key and will be ignored", directoryPath);
62+
continue;
63+
}
64+
65+
var created = OpenOrCreateChannel(channelId, apiKey);
66+
_channelsByApiKey.Add(apiKey, created);
67+
}
68+
}
69+
70+
public override ForwardingChannel GetForwardingChannel(string? requestApiKey)
71+
{
72+
// Use an empty string to represent no api key, since `_channelsByApiKey` does not allow null keys.
73+
requestApiKey = string.IsNullOrWhiteSpace(requestApiKey) ? "" : requestApiKey;
74+
75+
lock (_channelsSync)
76+
{
77+
if (_channelsByApiKey.TryGetValue(requestApiKey, out var channel))
78+
{
79+
return channel;
80+
}
81+
82+
var channelId = requestApiKey == "" ? EmptyApiKeyChannelId : Guid.NewGuid().ToString("n");
83+
var created = OpenOrCreateChannel(channelId, requestApiKey);
84+
var store = new SystemStoreDirectory(GetStorePath(channelId));
85+
store.WriteApiKey(Config, requestApiKey);
86+
_channelsByApiKey.Add(requestApiKey, created);
87+
return created;
88+
}
89+
}
90+
91+
public override async Task StopAsync()
92+
{
93+
Log.ForContext<TransparentForwardingAuthenticationStrategy>().Information("Flushing log buffers");
94+
OnStopping();
95+
96+
Task[] stopChannels;
97+
lock (_channelsSync)
98+
{
99+
stopChannels = _channelsByApiKey.Values.Select(ch => ch.StopAsync()).ToArray();
100+
}
101+
102+
await Task.WhenAll(stopChannels);
103+
await OnStoppedAsync();
104+
}
105+
}

0 commit comments

Comments
 (0)