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