campus-errand/server/Services/TencentIMService.cs
2026-04-01 12:50:17 +08:00

86 lines
3.2 KiB
C#

using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
namespace CampusErrand.Services;
/// <summary>
/// 腾讯 IM 服务,负责生成 UserSig 和调用服务端 REST API
/// </summary>
public class TencentIMService
{
private readonly long _sdkAppId;
private readonly string _secretKey;
private readonly HttpClient _httpClient;
private const string AdminAccount = "administrator";
public TencentIMService(IConfiguration configuration, IHttpClientFactory httpClientFactory)
{
var config = configuration.GetSection("TencentIM");
_sdkAppId = config.GetValue<long>("SDKAppId");
_secretKey = config["SecretKey"]!;
_httpClient = httpClientFactory.CreateClient();
}
public long SDKAppId => _sdkAppId;
/// <summary>
/// 生成 UserSig
/// </summary>
public string GenerateUserSig(string userId, int expireSeconds = 604800)
{
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var obj = new Dictionary<string, object>
{
["TLS.ver"] = "2.0",
["TLS.identifier"] = userId,
["TLS.sdkappid"] = _sdkAppId,
["TLS.expire"] = expireSeconds,
["TLS.time"] = now
};
var contentToSign = $"TLS.identifier:{userId}\nTLS.sdkappid:{_sdkAppId}\nTLS.time:{now}\nTLS.expire:{expireSeconds}\n";
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(_secretKey));
var sig = hmac.ComputeHash(Encoding.UTF8.GetBytes(contentToSign));
obj["TLS.sig"] = Convert.ToBase64String(sig);
var jsonBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(obj));
using var output = new MemoryStream();
using (var zlib = new System.IO.Compression.ZLibStream(output, System.IO.Compression.CompressionLevel.Optimal))
{
zlib.Write(jsonBytes, 0, jsonBytes.Length);
}
return Convert.ToBase64String(output.ToArray())
.Replace('+', '*')
.Replace('/', '-')
.Replace('=', '_');
}
/// <summary>
/// 通过服务端 REST API 拉取两个用户之间的漫游消息
/// </summary>
public async Task<JsonElement> GetRoamMessagesAsync(string fromUserId, string toUserId, int maxCnt = 100, long minTime = 0, long maxTime = 0)
{
var adminSig = GenerateUserSig(AdminAccount);
var random = Random.Shared.Next(100000, 999999);
var url = $"https://console.tim.qq.com/v4/openim/admin_getroammsg?sdkappid={_sdkAppId}&identifier={AdminAccount}&usersig={adminSig}&random={random}&contenttype=json";
var body = new
{
Operator_Account = fromUserId,
Peer_Account = toUserId,
MaxCnt = maxCnt,
MinTime = minTime,
MaxTime = maxTime > 0 ? maxTime : DateTimeOffset.UtcNow.ToUnixTimeSeconds()
};
var content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(url, content);
var json = await response.Content.ReadAsStringAsync();
Console.WriteLine($"[IM] 拉取漫游消息: {fromUserId} -> {toUserId}, 响应: {json}");
return JsonSerializer.Deserialize<JsonElement>(json);
}
}