z8018
2 天以前 d8dc91f9c1fece5711e38edd1b1274cb9e579015
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.BaseServices;
using WIDESEA_DTO.BasicInfo;
using WIDESEA_IBasicInfoServices;
using WIDESEA_Model.Models;
 
namespace WIDESEA_BasicInfoServices
{
    public class ActivationCodeService : ServiceBase<Dt_ActivationCode, IRepository<Dt_ActivationCode>>, IActivationCodeService
    {
        private readonly IRepository<Dt_CharMapping> _charMappingRepository;
        private readonly IRepository<Dt_RuntimeCode> _runtimeCodeRepository;
        private readonly IRepository<Dt_Products> _productRepository;
 
        public ActivationCodeService(IRepository<Dt_ActivationCode> BaseDal, IRepository<Dt_CharMapping> charMappingRepository, IRepository<Dt_RuntimeCode> runtimeCodeRepository, IRepository<Dt_Products> productRepository) : base(BaseDal)
        {
            _charMappingRepository = charMappingRepository;
            _runtimeCodeRepository = runtimeCodeRepository;
            _productRepository = productRepository;
        }
 
        /// <summary>
        /// 生成激活码
        /// </summary>
        /// <param name="activationDTO">包含运行码、设备ID和产品名称的数据传输对象</param>
        /// <returns>生成的激活码</returns>
        public string GenerateActivationCode(ActivationCodeDTO activationDTO)
        {
            // 查询运行码对应的模型
            Dt_RuntimeCode runtimeCodeModel = _runtimeCodeRepository.QueryFirst(x => x.RuntimeCode == activationDTO.RuntimeCode);
            // 1. 检查运行码是否已存在
            if (runtimeCodeModel == null)
            {
                throw new InvalidOperationException($"无效的运行码: {activationDTO.RuntimeCode}");
            }
 
            // 查询激活码对应的模型
            Dt_ActivationCode activationCodeModel = BaseDal.QueryFirst(x => x.RuntimeCode == activationDTO.RuntimeCode);
            // 2. 检查激活码是否已存在
            if (activationCodeModel != null)
            {
                return activationCodeModel.ActivationCode;
            }
 
            int productId = -1;
            // 查询产品对应的模型
            Dt_Products product = _productRepository.QueryFirst(x => x.ProductName == activationDTO.ProductName);
            if (product != null)
            {
                productId = product.Id;
            }
 
            // 3. 检查设备ID和产品ID是否匹配
            if (runtimeCodeModel.DeviceId != activationDTO.DeviceId || runtimeCodeModel.ProductId != productId)
            {
                throw new InvalidOperationException($"设备ID或产品ID不匹配: {activationDTO.DeviceId}, {productId}");
            }
 
            // 4. 生成激活码
            // 去除运行码中的"-"字符
            string baseRandom = activationDTO.RuntimeCode.Replace("-", string.Empty);
 
            // 查询字符映射字典
            Dictionary<char, (char output, int shift)> mappingDict = _charMappingRepository.QueryData().ToDictionary(x => x.InputChar.ToCharArray().FirstOrDefault(), x => (x.OutputChar.ToCharArray().FirstOrDefault(), x.ShiftFactor));
 
            char[] result = new char[baseRandom.Length];
            int length = baseRandom.Length;
 
            // 遍历运行码的每个字符进行转换
            for (int i = 0; i < length; i++)
            {
                char current = baseRandom[i];
                if (current == '-')
                    continue;
                if (!mappingDict.TryGetValue(current, out var mapping))
                    throw new InvalidOperationException($"无效字符: {current}");
 
                // 特殊变换:每5个字符增加复杂度
                char mappedChar = (i % 5 == 4)
                    ? ApplySpecialTransform(mapping.output, mapping.shift)
                    : mapping.output;
 
                result[i] = mappedChar;
            }
 
            // 格式化激活码
            string activationCode = FormatCode(new string(result));
 
            // 5. 存储激活码
            StoredActivationCode(activationDTO.DeviceId, baseRandom, activationCode, activationDTO.RuntimeCode, productId);
 
            return activationCode;
        }
 
        /// <summary>
        /// 对输入字符进行基于ASCII码的二次变换。
        /// </summary>
        /// <param name="c">要变换的字符。</param>
        /// <param name="position">字符的位置,用于计算变换值。</param>
        /// <returns>变换后的字符。</returns>
        private char ApplySpecialTransform(char c, int position)
        {
            // 将字符转换为ASCII码
            int ascii = (int)c;
            
            // 计算变换后的ASCII码值,基于字符的位置进行偏移,并确保结果在0-35范围内
            int transformed = (ascii + position) % 36 + 48;
            
            // 如果变换后的ASCII码值在':'到'@'之间(即字符'9'到字符'@'),则再偏移7个位置
            if (transformed >= ':' && transformed <= '@')
            {
                transformed += 7;
            }
            
            // 将变换后的ASCII码值转换回字符并返回
            return (char)transformed;
        }
 
        /// <summary>
        /// 将原始字符串格式化为XXXXX-XXXXX-XXXXX-XXXXX-XXXXX的形式
        /// </summary>
        /// <param name="raw">需要格式化的原始字符串,长度必须为25个字符</param>
        private string FormatCode(string raw)
        {
            // 格式化为XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
            return string.Join("-",
                raw.Substring(0, 5),
                raw.Substring(5, 5),
                raw.Substring(10, 5),
                raw.Substring(15, 5),
                raw.Substring(20, 5));
        }
 
        /// <summary>
        /// 存储激活码信息到数据库
        /// </summary>
        /// <param name="deviceId">设备ID,用于标识特定设备</param>
        /// <param name="baseRandom">基础随机码,用于生成激活码的随机字符串</param>
        /// <param name="activationCode">激活码,用于产品激活的唯一代码</param>
        /// <param name="runtimeCode">运行时码,用于验证激活状态的代码</param>
        /// <param name="productId">产品ID,用于标识不同的产品</param>
        private void StoredActivationCode(string deviceId, string baseRandom, string activationCode, string runtimeCode, int productId)
        {
            Dt_ActivationCode activationRecord = new Dt_ActivationCode
            {
                MappedRandom = baseRandom,
                ActivationCode = activationCode,
                DeviceId = deviceId,
                IsUsed = false,
                ProductId = productId,
                ExpiresTime = null,
                RuntimeCode = runtimeCode
            };
 
            BaseDal.AddData(activationRecord);
        }
    }
}