All checks were successful
continuous-integration/drone/push Build is passing
147 lines
5.7 KiB
C#
147 lines
5.7 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建 IM 群组(每个订单一个群)
|
|
/// </summary>
|
|
public async Task<string?> CreateGroupAsync(string groupId, string groupName, string ownerImId, string runnerImId)
|
|
{
|
|
var adminSig = GenerateUserSig(AdminAccount);
|
|
var random = Random.Shared.Next(100000, 999999);
|
|
var url = $"https://console.tim.qq.com/v4/group_open_http_svc/create_group?sdkappid={_sdkAppId}&identifier={AdminAccount}&usersig={adminSig}&random={random}&contenttype=json";
|
|
|
|
var body = new
|
|
{
|
|
Type = "Private",
|
|
GroupId = groupId,
|
|
Name = groupName,
|
|
Owner_Account = ownerImId,
|
|
MemberList = new[]
|
|
{
|
|
new { Member_Account = runnerImId }
|
|
}
|
|
};
|
|
|
|
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] 创建群组: {groupId}, 响应: {json}");
|
|
|
|
var result = JsonSerializer.Deserialize<JsonElement>(json);
|
|
var actionStatus = result.GetProperty("ActionStatus").GetString();
|
|
if (actionStatus == "OK")
|
|
return result.GetProperty("GroupId").GetString();
|
|
|
|
// 群已存在也算成功
|
|
var errorCode = result.GetProperty("ErrorCode").GetInt32();
|
|
if (errorCode == 10021)
|
|
return groupId;
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 拉取群漫游消息(管理后台用)
|
|
/// </summary>
|
|
public async Task<JsonElement> GetGroupMessagesAsync(string groupId, int reqMsgSeq = 0, int reqMsgNumber = 20)
|
|
{
|
|
var adminSig = GenerateUserSig(AdminAccount);
|
|
var random = Random.Shared.Next(100000, 999999);
|
|
var url = $"https://console.tim.qq.com/v4/group_open_http_svc/group_msg_get_simple?sdkappid={_sdkAppId}&identifier={AdminAccount}&usersig={adminSig}&random={random}&contenttype=json";
|
|
|
|
var body = new
|
|
{
|
|
GroupId = groupId,
|
|
ReqMsgSeq = reqMsgSeq,
|
|
ReqMsgNumber = reqMsgNumber
|
|
};
|
|
|
|
var content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
|
|
var response = await _httpClient.PostAsync(url, content);
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
return JsonSerializer.Deserialize<JsonElement>(json);
|
|
}
|
|
}
|