18 changed files with 343 additions and 5 deletions
@ -0,0 +1,19 @@ |
|||||||
|
# Sanhe.Abp.Hangfire.Dashboard |
||||||
|
|
||||||
|
Hangfire持久化PostgreSql |
||||||
|
|
||||||
|
|
||||||
|
## 配置使用 |
||||||
|
还需要配置中间件,需要在授权中间件后面。 |
||||||
|
|
||||||
|
```csharp |
||||||
|
[DependsOn(typeof(AbpHangfireStoragePostgreSqlModule))] |
||||||
|
public class YouProjectModule : AbpModule |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
## 注意事项 |
||||||
|
|
||||||
|
[作者wwwk] |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,12 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.Core" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
@ -0,0 +1,17 @@ |
|||||||
|
using Microsoft.Extensions.DependencyInjection; |
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions; |
||||||
|
using Sanhe.Abp.IdGenerator.Sanhe.Abp.IdGenerator.Snowflake; |
||||||
|
using Volo.Abp.Modularity; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.IdGenerator.Sanhe.Abp.IdGenerator; |
||||||
|
|
||||||
|
public class AbpIdGeneratorModule: AbpModule |
||||||
|
{ |
||||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||||
|
{ |
||||||
|
var snowflakeIdOptions = new SnowflakeIdOptions(); |
||||||
|
context.Services.ExecutePreConfiguredActions(snowflakeIdOptions); |
||||||
|
|
||||||
|
context.Services.TryAddSingleton<IDistributedIdGenerator>(SnowflakeIdGenerator.Create(snowflakeIdOptions)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
namespace Sanhe.Abp.IdGenerator.Sanhe.Abp.IdGenerator; |
||||||
|
|
||||||
|
public interface IDistributedIdGenerator |
||||||
|
{ |
||||||
|
long Create(); |
||||||
|
} |
@ -0,0 +1,133 @@ |
|||||||
|
using System; |
||||||
|
using Volo.Abp; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.IdGenerator.Sanhe.Abp.IdGenerator.Snowflake; |
||||||
|
|
||||||
|
// reference: https://github.com/dotnetcore/CAP |
||||||
|
// reference: https://blog.csdn.net/lq18050010830/article/details/89845790 |
||||||
|
public class SnowflakeIdGenerator : IDistributedIdGenerator |
||||||
|
{ |
||||||
|
public const long Twepoch = 1288834974657L; |
||||||
|
|
||||||
|
private static readonly object _lock = new object(); |
||||||
|
private long _lastTimestamp = -1L; |
||||||
|
|
||||||
|
protected long MaxWorkerId { get; set; } |
||||||
|
protected long MaxDatacenterId { get; set; } |
||||||
|
|
||||||
|
protected int WorkerIdShift { get; } |
||||||
|
protected int DatacenterIdShift { get; } |
||||||
|
protected int TimestampLeftShift { get; } |
||||||
|
protected long SequenceMask { get; } |
||||||
|
|
||||||
|
protected SnowflakeIdOptions Options { get; } |
||||||
|
|
||||||
|
private SnowflakeIdGenerator(SnowflakeIdOptions options) |
||||||
|
{ |
||||||
|
Options = options; |
||||||
|
WorkerIdShift = options.SequenceBits; |
||||||
|
DatacenterIdShift = options.SequenceBits + options.WorkerIdBits; |
||||||
|
TimestampLeftShift = options.SequenceBits + options.WorkerIdBits + options.DatacenterIdBits; |
||||||
|
SequenceMask = -1L ^ -1L << options.SequenceBits; |
||||||
|
} |
||||||
|
|
||||||
|
public static SnowflakeIdGenerator Create(SnowflakeIdOptions options) |
||||||
|
{ |
||||||
|
var idGenerator = new SnowflakeIdGenerator(options) |
||||||
|
{ |
||||||
|
WorkerId = options.WorkerId, |
||||||
|
DatacenterId = options.DatacenterId, |
||||||
|
Sequence = options.Sequence, |
||||||
|
MaxWorkerId = -1L ^ -1L << options.WorkerIdBits, |
||||||
|
MaxDatacenterId = -1L ^ -1L << options.DatacenterIdBits |
||||||
|
}; |
||||||
|
|
||||||
|
if (idGenerator.WorkerId == 0 || (int)Math.Log10(options.WorkerId) + 1 > idGenerator.MaxWorkerId) |
||||||
|
{ |
||||||
|
if (!int.TryParse(Environment.GetEnvironmentVariable("WORKERID", EnvironmentVariableTarget.Machine), out var workerId)) |
||||||
|
{ |
||||||
|
workerId = RandomHelper.GetRandom((int)idGenerator.MaxWorkerId); |
||||||
|
} |
||||||
|
|
||||||
|
if (workerId > idGenerator.MaxWorkerId || workerId < 0) |
||||||
|
{ |
||||||
|
throw new ArgumentException($"worker Id can't be greater than {idGenerator.MaxWorkerId} or less than 0"); |
||||||
|
} |
||||||
|
|
||||||
|
idGenerator.WorkerId = workerId; |
||||||
|
} |
||||||
|
|
||||||
|
if (idGenerator.DatacenterId == 0 || (int)Math.Log10(options.DatacenterId) + 1 > idGenerator.MaxDatacenterId) |
||||||
|
{ |
||||||
|
if (!int.TryParse(Environment.GetEnvironmentVariable("DATACENTERID", EnvironmentVariableTarget.Machine), out var datacenterId)) |
||||||
|
{ |
||||||
|
datacenterId = RandomHelper.GetRandom((int)idGenerator.MaxDatacenterId); |
||||||
|
} |
||||||
|
|
||||||
|
if (datacenterId > idGenerator.MaxDatacenterId || datacenterId < 0) |
||||||
|
{ |
||||||
|
throw new ArgumentException($"datacenter Id can't be greater than {idGenerator.MaxDatacenterId} or less than 0"); |
||||||
|
} |
||||||
|
|
||||||
|
idGenerator.DatacenterId = datacenterId; |
||||||
|
} |
||||||
|
|
||||||
|
return idGenerator; |
||||||
|
} |
||||||
|
|
||||||
|
public long WorkerId { get; internal set; } |
||||||
|
public long DatacenterId { get; internal set; } |
||||||
|
public long Sequence { get; internal set; } |
||||||
|
|
||||||
|
public virtual long Create() |
||||||
|
{ |
||||||
|
lock (_lock) |
||||||
|
{ |
||||||
|
var timestamp = TimeGen(); |
||||||
|
|
||||||
|
if (timestamp < _lastTimestamp) |
||||||
|
{ |
||||||
|
// 如果启用此选项, 发生时间回退时使用上一个时间戳 |
||||||
|
if (!Options.UsePreviousInTimeRollback) |
||||||
|
{ |
||||||
|
throw new Exception( |
||||||
|
$"InvalidSystemClock: Clock moved backwards, Refusing to generate id for {_lastTimestamp - timestamp} milliseconds"); |
||||||
|
} |
||||||
|
timestamp = _lastTimestamp; |
||||||
|
} |
||||||
|
|
||||||
|
if (_lastTimestamp == timestamp) |
||||||
|
{ |
||||||
|
Sequence = Sequence + 1 & SequenceMask; |
||||||
|
if (Sequence == 0L) |
||||||
|
{ |
||||||
|
timestamp = TilNextMillis(_lastTimestamp); |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
Sequence = 0; |
||||||
|
} |
||||||
|
|
||||||
|
_lastTimestamp = timestamp; |
||||||
|
var id = timestamp - Twepoch << TimestampLeftShift | |
||||||
|
DatacenterId << DatacenterIdShift | |
||||||
|
WorkerId << WorkerIdShift | |
||||||
|
Sequence; |
||||||
|
|
||||||
|
return id; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual long TilNextMillis(long lastTimestamp) |
||||||
|
{ |
||||||
|
var timestamp = TimeGen(); |
||||||
|
while (timestamp <= lastTimestamp) timestamp = TimeGen(); |
||||||
|
return timestamp; |
||||||
|
} |
||||||
|
|
||||||
|
protected virtual long TimeGen() |
||||||
|
{ |
||||||
|
return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
namespace Sanhe.Abp.IdGenerator.Sanhe.Abp.IdGenerator.Snowflake; |
||||||
|
|
||||||
|
public class SnowflakeIdOptions |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// 机器Id |
||||||
|
/// </summary> |
||||||
|
public int WorkerId { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 机器Id长度 |
||||||
|
/// </summary> |
||||||
|
public int WorkerIdBits { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 数据中心Id |
||||||
|
/// </summary> |
||||||
|
public int DatacenterId { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 数据中心Id长度 |
||||||
|
/// </summary> |
||||||
|
public int DatacenterIdBits { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 12bit 的序号 |
||||||
|
/// </summary> |
||||||
|
public long Sequence { get; set; } |
||||||
|
|
||||||
|
public int SequenceBits { get; set; } |
||||||
|
/// <summary> |
||||||
|
/// 发生时间回退时使用上一个ID |
||||||
|
/// </summary> |
||||||
|
public bool UsePreviousInTimeRollback { get; set; } |
||||||
|
|
||||||
|
public SnowflakeIdOptions() |
||||||
|
{ |
||||||
|
WorkerIdBits = 5; |
||||||
|
DatacenterIdBits = 5; |
||||||
|
Sequence = 0L; |
||||||
|
SequenceBits = 12; |
||||||
|
UsePreviousInTimeRollback = true; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||||
|
</Weavers> |
@ -0,0 +1,15 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
|
||||||
|
<Import Project="..\..\..\configureawait.props" /> |
||||||
|
<Import Project="..\..\..\common.props" /> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Volo.Abp.Core" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.Settings" Version="$(VoloAbpVersion)" /> |
||||||
|
<PackageReference Include="Volo.Abp.EventBus.Abstractions" Version="$(VoloAbpVersion)" /> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
@ -0,0 +1,9 @@ |
|||||||
|
using Volo.Abp.EventBus.Abstractions; |
||||||
|
using Volo.Abp.Modularity; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.RealTime.Sanhe.Abp.RealTime; |
||||||
|
|
||||||
|
[DependsOn(typeof(AbpEventBusAbstractionsModule))] |
||||||
|
public class AbpRealTimeModule : AbpModule |
||||||
|
{ |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.RealTime.Localization; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// The notification that needs to be localized |
||||||
|
/// </summary> |
||||||
|
public class LocalizableStringInfo |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Resource name |
||||||
|
/// </summary> |
||||||
|
public string ResourceName { get; } |
||||||
|
/// <summary> |
||||||
|
/// Properties |
||||||
|
/// </summary> |
||||||
|
public string Name { get; } |
||||||
|
/// <summary> |
||||||
|
/// Formatted data |
||||||
|
/// </summary> |
||||||
|
public Dictionary<object, object> Values { get; } |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Instantiate <see cref="LocalizableStringInfo"/> |
||||||
|
/// </summary> |
||||||
|
/// <param name="resourceName">Resource name</param> |
||||||
|
/// <param name="name">Properties</param> |
||||||
|
/// <param name="values">Formatted data</param> |
||||||
|
public LocalizableStringInfo( |
||||||
|
string resourceName, |
||||||
|
string name, |
||||||
|
Dictionary<object, object> values = null) |
||||||
|
{ |
||||||
|
ResourceName = resourceName; |
||||||
|
Name = name; |
||||||
|
Values = values; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
using System; |
||||||
|
using Volo.Abp.Domain.Entities.Events.Distributed; |
||||||
|
using Volo.Abp.EventBus; |
||||||
|
|
||||||
|
namespace Sanhe.Abp.RealTime.Sanhe.Abp.RealTime; |
||||||
|
|
||||||
|
[Serializable] |
||||||
|
[GenericEventName(Prefix = "abp.realtime.")] |
||||||
|
public class RealTimeEto<T> : EtoBase |
||||||
|
{ |
||||||
|
public T Data { get; set; } |
||||||
|
|
||||||
|
public RealTimeEto() : base() { } |
||||||
|
|
||||||
|
public RealTimeEto(T data) : base() |
||||||
|
{ |
||||||
|
Data = data; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue