Skip to content

Commit 6fd59f4

Browse files
authored
Batch 3: Framework upgrade to net8.0+net10.0, remove Netty ConstantPool, AOT prep (#366)
- Upgrade Core csproj: netstandard2.0 → netstandard2.0;net8.0;net10.0 with IsAotCompatible and EnableTrimAnalyzer for net8.0+ - Remove Netty-style ConstantPool/AbstractConstant/IConstant patterns from UpdateOption. Replace with simple ConcurrentDictionary registry. - UpdateOption<T> now carries DefaultValue; GetOption() returns it as fallback. - Remove PopulateDefaults() from AbstractBootstrap — defaults live on options. - Conditional IsExternalInit (only for netstandard2.0, built-in in net8.0+) - Conditional SignalR.Client package references per target framework - Comment out DrivelutionMiddleware references until project reference is added - Fix AppType name shadowing in UpdateOptions Closes #365
1 parent 1c26de8 commit 6fd59f4

9 files changed

Lines changed: 118 additions & 293 deletions

File tree

src/c#/GeneralUpdate.Core/Bootstrap/GeneralUpdateBootstrap.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,9 @@ private void InitializeFromEnvironment()
245245

246246
private void ApplyRuntimeOptions()
247247
{
248-
_configInfo.Encoding = GetOption(UpdateOption.Encoding) ?? Encoding.Default;
249-
_configInfo.Format = GetOption(UpdateOption.Format) ?? Format.ZIP;
250-
_configInfo.DownloadTimeOut = GetOption(UpdateOption.DownloadTimeOut) ?? 60;
248+
_configInfo.Encoding = GetOption(UpdateOptions.Encoding);
249+
_configInfo.Format = GetOption(UpdateOptions.Format);
250+
_configInfo.DownloadTimeOut = GetOption(UpdateOptions.DownloadTimeout) ?? 60;
251251
}
252252

253253
private void InitBlackList()

src/c#/GeneralUpdate.Core/Configuration/AbstractBootstrap.cs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,6 @@ public abstract class AbstractBootstrap<TBootstrap, TStrategy>
2323
protected internal AbstractBootstrap()
2424
{
2525
_options = new ConcurrentDictionary<UpdateOption, UpdateOptionValue>();
26-
PopulateDefaults();
27-
}
28-
29-
protected virtual void PopulateDefaults()
30-
{
31-
Option(UpdateOptions.MaxConcurrency, 3);
32-
Option(UpdateOptions.RetryCount, 3);
33-
Option(UpdateOptions.EnableResume, true);
34-
Option(UpdateOptions.VerifyChecksum, true);
35-
Option(UpdateOptions.SilentAutoInstall, false);
36-
Option(UpdateOptions.DownloadTimeout, 30);
3726
}
3827

3928
public abstract Task<TBootstrap> LaunchAsync();
@@ -50,19 +39,12 @@ public TBootstrap Option<T>(UpdateOption<T> option, T value)
5039
return (TBootstrap)this;
5140
}
5241

53-
protected T? GetOption<T>(UpdateOption<T>? option)
42+
protected T GetOption<T>(UpdateOption<T>? option)
5443
{
55-
try
56-
{
57-
Debug.Assert(option != null && _options.Count != 0);
58-
var val = _options[option];
59-
if (val != null) return (T)val.GetValue();
60-
return default;
61-
}
62-
catch
63-
{
64-
return default;
65-
}
44+
if (option == null) return default!;
45+
if (_options.TryGetValue(option, out var val) && val != null)
46+
return (T)val.GetValue();
47+
return option.DefaultValue;
6648
}
6749

6850
// ═══════════ Extension point registration ═══════════

src/c#/GeneralUpdate.Core/Configuration/IsExternalInit.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// ReSharper disable once CheckNamespace
12
namespace System.Runtime.CompilerServices
23
{
34
internal static class IsExternalInit { }
Lines changed: 40 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,240 +1,68 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Diagnostics.Contracts;
4-
using System.Text;
5-
using System.Threading;
6-
using GeneralUpdate.Core.Configuration;
2+
using System.Collections.Concurrent;
73

84
namespace GeneralUpdate.Core.Configuration
95
{
10-
public abstract class UpdateOption : AbstractConstant<UpdateOption>
6+
/// <summary>
7+
/// Base class for strongly-typed update option keys.
8+
/// Simple implementation using ConcurrentDictionary registry,
9+
/// replacing the earlier Netty ConstantPool pattern.
10+
/// </summary>
11+
public class UpdateOption
1112
{
12-
private class UpdateOptionPool : ConstantPool
13-
{
14-
protected override IConstant NewConstant<T>(int id, string name) => new UpdateOption<T>(id, name);
15-
}
16-
17-
private static readonly UpdateOptionPool Pool = new();
13+
private static readonly ConcurrentDictionary<string, UpdateOption> _registry = new();
14+
private static readonly object _lock = new();
1815

19-
public static UpdateOption<T> ValueOf<T>(string name) => (UpdateOption<T>)Pool.ValueOf<T>(name);
20-
21-
/// <summary>
22-
/// Update the file format of the package.
23-
/// </summary>
24-
public static readonly UpdateOption<string> Format = ValueOf<string>("COMPRESSFORMAT");
25-
26-
/// <summary>
27-
/// Compress encoding.
28-
/// </summary>
29-
public static readonly UpdateOption<Encoding> Encoding = ValueOf<Encoding>("COMPRESSENCODING");
30-
31-
/// <summary>
32-
/// Timeout period (unit: second). If this parameter is not specified, the default timeout period is 30 seconds.
33-
/// </summary>
34-
public static readonly UpdateOption<int?> DownloadTimeOut = ValueOf<int?>("DOWNLOADTIMEOUT");
35-
36-
/// <summary>
37-
/// Whether to enable the driver upgrade function.
38-
/// </summary>
39-
public static readonly UpdateOption<bool?> Drive = ValueOf<bool?>("DRIVE");
40-
41-
/// <summary>
42-
/// Whether to enable the patch function.
43-
/// </summary>
44-
public static readonly UpdateOption<bool?> Patch = ValueOf<bool?>("PATCH");
45-
46-
/// <summary>
47-
/// Whether to enable the backup function.
48-
/// </summary>
49-
public static readonly UpdateOption<bool?> BackUp = ValueOf<bool?>("BACKUP");
50-
51-
/// <summary>
52-
/// Specifies the update execution mode.
53-
/// </summary>
54-
public static readonly UpdateOption<UpdateMode?> Mode = ValueOf<UpdateMode?>("MODE");
55-
56-
/// <summary>
57-
/// Whether to enable silent update mode.
58-
/// </summary>
59-
public static readonly UpdateOption<bool> EnableSilentUpdate = ValueOf<bool>("ENABLESILENTUPDATE");
60-
61-
internal UpdateOption(int id, string name)
62-
: base(id, name) { }
63-
64-
public abstract bool Set(IUpdateConfiguration configuration, object value);
65-
}
66-
67-
public sealed class UpdateOption<T> : UpdateOption
68-
{
69-
internal UpdateOption(int id, string name)
70-
: base(id, name)
71-
{
72-
}
73-
74-
public void Validate(T value) => Contract.Requires(value != null);
75-
76-
public override bool Set(IUpdateConfiguration configuration, object value) => configuration.SetOption(this, (T)value);
77-
}
78-
79-
public abstract class ConstantPool
80-
{
81-
private readonly Dictionary<string, IConstant> constants = new Dictionary<string, IConstant>();
82-
private int nextId = 1;
83-
84-
/// <summary>Shortcut of <c>this.ValueOf(firstNameComponent.Name + "#" + secondNameComponent)</c>.</summary>
85-
public IConstant ValueOf<T>(Type firstNameComponent, string secondNameComponent)
86-
{
87-
Contract.Requires(firstNameComponent != null);
88-
Contract.Requires(secondNameComponent != null);
89-
return this.ValueOf<T>(firstNameComponent.Name + '#' + secondNameComponent);
90-
}
91-
92-
/// <summary>
93-
/// Returns the <see cref="IConstant" /> which is assigned to the specified <c>name</c>.
94-
/// If there's no such <see cref="IConstant" />, a new one will be created and returned.
95-
/// Once created, the subsequent calls with the same <c>name</c> will always return the previously created one
96-
/// (i.e. singleton.)
97-
/// </summary>
98-
/// <param name="name">the name of the <see cref="IConstant" /></param>
99-
public IConstant ValueOf<T>(string name)
100-
{
101-
IConstant constant;
102-
lock (this.constants)
103-
{
104-
if (this.constants.TryGetValue(name, out constant))
105-
{
106-
return constant;
107-
}
108-
else
109-
{
110-
constant = this.NewInstance0<T>(name);
111-
}
112-
}
113-
return constant;
114-
}
16+
/// <summary>Unique option name.</summary>
17+
public string Name { get; }
11518

116-
/// <summary>Returns <c>true</c> if a <see cref="AttributeKey{T}" /> exists for the given <c>name</c>.</summary>
117-
public bool Exists(string name)
19+
/// <summary>Protected constructor — use <see cref="ValueOf{T}(string, T)"/> to create instances.</summary>
20+
protected UpdateOption(string name)
11821
{
119-
CheckNotNullAndNotEmpty(name);
120-
lock (this.constants)
121-
return this.constants.ContainsKey(name);
22+
Name = name ?? throw new ArgumentNullException(nameof(name));
12223
}
12324

12425
/// <summary>
125-
/// Creates a new <see cref="IConstant" /> for the given <c>name</c> or fail with an
126-
/// <see cref="ArgumentException" /> if a <see cref="IConstant" /> for the given <c>name</c> exists.
26+
/// Returns the <see cref="UpdateOption{T}"/> for the given name, creating one with the
27+
/// provided default value if it does not exist. Subsequent calls with the same name
28+
/// return the same instance (singleton).
12729
/// </summary>
128-
public IConstant NewInstance<T>(string name)
30+
public static UpdateOption<T> ValueOf<T>(string name, T defaultValue = default!)
12931
{
130-
if (this.Exists(name)) throw new ArgumentException($"'{name}' is already in use");
131-
IConstant constant = this.NewInstance0<T>(name);
132-
return constant;
133-
}
134-
135-
// Be careful that this dose not check whether the argument is null or empty.
136-
private IConstant NewInstance0<T>(string name)
137-
{
138-
lock (this.constants)
32+
lock (_lock)
13933
{
140-
IConstant constant = this.NewConstant<T>(this.nextId, name);
141-
this.constants[name] = constant;
142-
this.nextId++;
143-
return constant;
144-
}
145-
}
146-
147-
private static void CheckNotNullAndNotEmpty(string name) => Contract.Requires(!string.IsNullOrEmpty(name));
148-
149-
protected abstract IConstant NewConstant<T>(int id, string name);
34+
if (_registry.TryGetValue(name, out var existing) && existing is UpdateOption<T> typed)
35+
return typed;
15036

151-
[Obsolete]
152-
public int NextId()
153-
{
154-
lock (this.constants)
155-
{
156-
int id = this.nextId;
157-
this.nextId++;
158-
return id;
37+
var option = new UpdateOption<T>(name, defaultValue);
38+
_registry[name] = option;
39+
return option;
15940
}
16041
}
161-
}
162-
163-
public interface IConstant
164-
{
165-
/// <summary>Returns the unique number assigned to this <see cref="IConstant" />.</summary>
166-
int Id { get; }
167-
168-
/// <summary>Returns the name of this <see cref="IConstant" />.</summary>
169-
string Name { get; }
170-
}
171-
172-
public interface IUpdateConfiguration
173-
{
174-
T GetOption<T>(UpdateOption<T> option);
175-
176-
bool SetOption(UpdateOption option, object value);
177-
178-
bool SetOption<T>(UpdateOption<T> option, T value);
179-
}
180-
181-
public abstract class AbstractConstant : IConstant
182-
{
183-
private static long nextUniquifier;
184-
private long volatileUniquifier;
185-
186-
protected AbstractConstant(int id, string name)
187-
{
188-
this.Id = id;
189-
this.Name = name;
190-
}
19142

192-
public int Id { get; }
43+
/// <summary>Returns the option name.</summary>
44+
public override string ToString() => Name;
19345

194-
public string Name { get; }
195-
196-
public override sealed string ToString() => this.Name;
46+
/// <summary>Hash code based on name.</summary>
47+
public override int GetHashCode() => Name.GetHashCode();
19748

198-
protected long Uniquifier
199-
{
200-
get
201-
{
202-
long result;
203-
if ((result = Volatile.Read(ref this.volatileUniquifier)) == 0)
204-
{
205-
result = Interlocked.Increment(ref nextUniquifier);
206-
long previousUniquifier = Interlocked.CompareExchange(ref this.volatileUniquifier, result, 0);
207-
if (previousUniquifier != 0) result = previousUniquifier;
208-
}
209-
return result;
210-
}
211-
}
49+
/// <summary>Equality based on name.</summary>
50+
public override bool Equals(object? obj)
51+
=> obj is UpdateOption other && Name == other.Name;
21252
}
21353

214-
public abstract class AbstractConstant<T> : AbstractConstant, IComparable<T>, IEquatable<T>
215-
where T : AbstractConstant<T>
54+
/// <summary>
55+
/// Strongly-typed update option key with a default value.
56+
/// Instances are obtained via <see cref="UpdateOption.ValueOf{T}(string, T)"/>.
57+
/// </summary>
58+
public sealed class UpdateOption<T> : UpdateOption
21659
{
217-
/// <summary>Creates a new instance.</summary>
218-
protected AbstractConstant(int id, string name)
219-
: base(id, name) { }
220-
221-
public override sealed int GetHashCode() => base.GetHashCode();
222-
223-
public override sealed bool Equals(object obj) => base.Equals(obj);
224-
225-
public bool Equals(T other) => ReferenceEquals(this, other);
60+
/// <summary>Default value used when the option is not explicitly set.</summary>
61+
public T DefaultValue { get; }
22662

227-
public int CompareTo(T o)
63+
internal UpdateOption(string name, T defaultValue) : base(name)
22864
{
229-
if (ReferenceEquals(this, o)) return 0;
230-
AbstractConstant<T> other = o;
231-
int returnCode = this.GetHashCode() - other.GetHashCode();
232-
if (returnCode != 0) return returnCode;
233-
long thisUV = this.Uniquifier;
234-
long otherUV = other.Uniquifier;
235-
if (thisUV < otherUV) return -1;
236-
if (thisUV > otherUV) return 1;
237-
throw new System.Exception("failed to compare two different constants");
65+
DefaultValue = defaultValue;
23866
}
23967
}
24068
}
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
namespace GeneralUpdate.Core.Configuration
22
{
3+
/// <summary>
4+
/// Wraps a concrete option value for storage in the options dictionary.
5+
/// </summary>
36
public abstract class UpdateOptionValue
47
{
8+
/// <summary>The option key this value belongs to.</summary>
59
public abstract UpdateOption Option { get; }
610

7-
public abstract bool Set(IUpdateConfiguration config);
8-
11+
/// <summary>Returns the stored value as an object.</summary>
912
public abstract object GetValue();
1013
}
1114

15+
/// <summary>
16+
/// Strongly-typed option value wrapper.
17+
/// </summary>
1218
public sealed class UpdateOptionValue<T> : UpdateOptionValue
1319
{
1420
public override UpdateOption Option { get; }
15-
private readonly T value;
21+
private readonly T _value;
1622

1723
public UpdateOptionValue(UpdateOption<T> option, T value)
1824
{
19-
this.Option = option;
20-
this.value = value;
25+
Option = option;
26+
_value = value;
2127
}
2228

23-
public override object GetValue() => this.value;
24-
25-
public override bool Set(IUpdateConfiguration config) => config.SetOption(this.Option, this.value);
29+
public override object GetValue() => _value!;
2630

27-
public override string ToString() => this.value.ToString();
31+
public override string ToString() => _value?.ToString() ?? string.Empty;
2832
}
29-
}
33+
}

0 commit comments

Comments
 (0)