submodule对gitea不管用,所以直接拉了一份拉格兰
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
namespace Lagrange.OneBot.Message;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class CQPropertyAttribute : Attribute;
|
||||
33
Lagrange.Core/Lagrange.OneBot/Message/Entity/AtSegment.cs
Normal file
33
Lagrange.Core/Lagrange.OneBot/Message/Entity/AtSegment.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class AtSegment(uint at, string? name)
|
||||
{
|
||||
public AtSegment() : this(0, null) { }
|
||||
|
||||
public AtSegment(uint at) : this(at, null) { }
|
||||
|
||||
[JsonPropertyName("qq")] [CQProperty] public string At { get; set; } = at.ToString();
|
||||
|
||||
[JsonPropertyName("name")] [CQProperty] public string? Name { get; set; } = name;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(MentionEntity), "at")]
|
||||
public partial class AtSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is AtSegment atSegment) builder.Mention(atSegment.At == "all" ? 0 : uint.Parse(atSegment.At), atSegment.At == "all" ? "@\u5168\u4f53\u6210\u5458" : null);
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not MentionEntity mentionEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new AtSegment(mentionEntity.Uin, mentionEntity.Name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
public static class CommonResolver
|
||||
{
|
||||
private static readonly HttpClient Client = new();
|
||||
|
||||
public static byte[]? Resolve(string url)
|
||||
{
|
||||
if (url.StartsWith("base64://")) return Convert.FromBase64String(url.Replace("base64://", ""));
|
||||
|
||||
Uri uri = new(url);
|
||||
|
||||
return uri.Scheme switch
|
||||
{
|
||||
"http" or "https" => Client.GetAsync(uri).Result.Content.ReadAsByteArrayAsync().Result,
|
||||
"file" => File.ReadAllBytes(Path.GetFullPath(uri.LocalPath)),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
public static Stream? ResolveStream(string url)
|
||||
{
|
||||
if (url.StartsWith("base64://")) return new MemoryStream(Convert.FromBase64String(url.Replace("base64://", "")));
|
||||
|
||||
Uri uri = new(url);
|
||||
|
||||
return uri.Scheme switch
|
||||
{
|
||||
"http" or "https" => Client.GetAsync(uri).Result.Content.ReadAsStreamAsync().Result,
|
||||
"file" => new FileStream(Path.GetFullPath(uri.LocalPath), FileMode.Open, FileAccess.Read, FileShare.Read),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
26
Lagrange.Core/Lagrange.OneBot/Message/Entity/DiceSegment.cs
Normal file
26
Lagrange.Core/Lagrange.OneBot/Message/Entity/DiceSegment.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class DiceSegment
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(FaceEntity), "dice")]
|
||||
public partial class DiceSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is DiceSegment) builder.Face(358, true);
|
||||
}
|
||||
|
||||
public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is FaceEntity { IsLargeFace: true, FaceId: 358 }) return new DiceSegment();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
33
Lagrange.Core/Lagrange.OneBot/Message/Entity/FaceSegment.cs
Normal file
33
Lagrange.Core/Lagrange.OneBot/Message/Entity/FaceSegment.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class FaceSegment(int id)
|
||||
{
|
||||
public FaceSegment() : this(0) { }
|
||||
|
||||
[JsonPropertyName("id")] [CQProperty] public string Id { get; set; } = id.ToString();
|
||||
|
||||
[JsonPropertyName("large")] [CQProperty] public bool? IsLarge { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(FaceEntity), "face")]
|
||||
public partial class FaceSegment : SegmentBase
|
||||
{
|
||||
private static readonly ushort[] Excluded = [358, 359];
|
||||
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is FaceSegment faceSegment) builder.Face(ushort.Parse(faceSegment.Id), faceSegment.IsLarge ?? false);
|
||||
}
|
||||
|
||||
public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not FaceEntity faceEntity) throw new ArgumentException("Invalid entity type.");
|
||||
return Excluded.Contains(faceEntity.FaceId) ? null : new FaceSegment(faceEntity.FaceId);
|
||||
}
|
||||
}
|
||||
45
Lagrange.Core/Lagrange.OneBot/Message/Entity/FileSegment.cs
Normal file
45
Lagrange.Core/Lagrange.OneBot/Message/Entity/FileSegment.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class FileSegment(string fileName, string fileHash, string fileId, string url)
|
||||
{
|
||||
public FileSegment() : this("", "", "", "") { }
|
||||
|
||||
[JsonPropertyName("file_name")] public string Filename { get; set; } = fileName;
|
||||
|
||||
[JsonPropertyName("file_hash")] public string Filehash { get; set; } = fileHash;
|
||||
|
||||
[JsonPropertyName("file_id")] public string Fileid { get; set; } = fileId;
|
||||
|
||||
[JsonPropertyName("url")] public string Url { get; set; } = url;
|
||||
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(FileEntity), "file")]
|
||||
public partial class FileSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is FileSegment fileSegment and not { Fileid: "" })
|
||||
{
|
||||
builder.Add(new FileEntity
|
||||
{
|
||||
FileName = fileSegment.Filename,
|
||||
FileUrl = fileSegment.Url,
|
||||
FileId = fileSegment.Fileid,
|
||||
FileHash = fileSegment.Filehash
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not FileEntity fileEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new FileSegment(fileEntity.FileName, fileEntity.FileHash ?? "", fileEntity.FileId ?? fileEntity.FileUuid ?? "", fileEntity.FileUrl ?? "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class ForwardSegment(string name)
|
||||
{
|
||||
public ForwardSegment() : this("") { }
|
||||
|
||||
[JsonPropertyName("id")] [CQProperty] public string Name { get; set; } = name;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(MultiMsgEntity), "forward")]
|
||||
public partial class ForwardSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is ForwardSegment forward) builder.Add(new MultiMsgEntity(forward.Name));
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not MultiMsgEntity multiMsg) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new ForwardSegment(multiMsg.ResId ?? "");
|
||||
}
|
||||
}
|
||||
46
Lagrange.Core/Lagrange.OneBot/Message/Entity/ImageSegment.cs
Normal file
46
Lagrange.Core/Lagrange.OneBot/Message/Entity/ImageSegment.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class ImageSegment(string url, string filename, string summary = "[图片]", int subType = 0)
|
||||
{
|
||||
public ImageSegment() : this("", "") { }
|
||||
|
||||
[JsonPropertyName("file")] [CQProperty] public string File { get; set; } = url;
|
||||
|
||||
[JsonPropertyName("filename")] public string Filename { get; set; } = filename;
|
||||
|
||||
[JsonPropertyName("url")] public string Url { get; set; } = url;
|
||||
|
||||
[JsonPropertyName("summary")] public string Summary { get; set; } = summary;
|
||||
|
||||
[JsonPropertyName("subType")] public int SubType { get; set; } = subType;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(ImageEntity), "image")]
|
||||
public partial class ImageSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is ImageSegment imageSegment and not { File: "" } && CommonResolver.ResolveStream(imageSegment.File) is { } stream)
|
||||
{
|
||||
builder.Add(new ImageEntity
|
||||
{
|
||||
FilePath = imageSegment.Filename,
|
||||
ImageStream = new Lazy<Stream>(stream),
|
||||
Summary = imageSegment.Summary,
|
||||
SubType = imageSegment.SubType
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not ImageEntity imageEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new ImageSegment(imageEntity.ImageUrl, imageEntity.FilePath, imageEntity.ToPreviewText(), imageEntity.SubType);
|
||||
}
|
||||
}
|
||||
29
Lagrange.Core/Lagrange.OneBot/Message/Entity/JsonSegment.cs
Normal file
29
Lagrange.Core/Lagrange.OneBot/Message/Entity/JsonSegment.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class JsonSegment(string data)
|
||||
{
|
||||
public JsonSegment(): this("") { }
|
||||
|
||||
[JsonPropertyName("data")] [CQProperty] public string Data { get; set; } = data;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(LightAppEntity), "json")]
|
||||
public partial class JsonSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is JsonSegment json) builder.LightApp(json.Data);
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not LightAppEntity lightAppEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new JsonSegment(lightAppEntity.Payload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class KeyboardSegment(KeyboardData content)
|
||||
{
|
||||
public KeyboardSegment(): this(new KeyboardData()) { }
|
||||
|
||||
[JsonPropertyName("content")] public KeyboardData Content { get; set; } = content;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(KeyboardEntity), "keyboard")]
|
||||
public partial class KeyboardSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is KeyboardSegment keyboard) builder.Keyboard(keyboard.Content);
|
||||
}
|
||||
|
||||
public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
using Lagrange.OneBot.Core.Entity.Common;
|
||||
using Lagrange.OneBot.Core.Operation.Converters;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class LocationSegment(float latitude, float longitude)
|
||||
{
|
||||
public LocationSegment() : this(0f, 0f) { }
|
||||
|
||||
[JsonPropertyName("lat")][CQProperty] public string Latitude { get; set; } = latitude.ToString("F5");
|
||||
|
||||
[JsonPropertyName("lon")][CQProperty] public string Longitude { get; set; } = longitude.ToString("F5");
|
||||
|
||||
[JsonPropertyName("title")] public string Title { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("content")] public string Content { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(LightAppEntity), "location")]
|
||||
public partial class LocationSegment : SegmentBase
|
||||
{
|
||||
private static readonly JsonSerializerOptions Options = new() { Converters = { new AutosizeConverter(), new ForwardConverter() }, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull };
|
||||
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is not LocationSegment location) return;
|
||||
|
||||
var json = new LightApp
|
||||
{
|
||||
App = "com.tencent.map",
|
||||
// Config = new Config
|
||||
// {
|
||||
// Autosize = false,
|
||||
// Ctime = DateTimeOffset.UtcNow.Second,
|
||||
// Token = "626399d3453d0693fe19e12cd3747c56",
|
||||
// Type = "normal",
|
||||
// },
|
||||
Desc = "",
|
||||
From = 1,
|
||||
Meta = new Meta
|
||||
{
|
||||
LocationSearch = new LocationSearch
|
||||
{
|
||||
EnumRelationType = 1,
|
||||
From = "plusPanel",
|
||||
Id = "",
|
||||
Lat = location.Latitude,
|
||||
Lng = location.Longitude,
|
||||
Name = location.Title,
|
||||
Address = location.Content
|
||||
}
|
||||
},
|
||||
Prompt = $"[Location]{location.Content}",
|
||||
Ver = "1.1.2.21",
|
||||
View = "LocationShare"
|
||||
};
|
||||
|
||||
builder.LightApp(JsonSerializer.Serialize(json, Options));
|
||||
}
|
||||
|
||||
public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not LightAppEntity lightApp) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
if (JsonSerializer.Deserialize<LightApp>(lightApp.Payload, Options) is { App: "com.tencent.map" } app)
|
||||
{
|
||||
return new LocationSegment
|
||||
{
|
||||
Latitude = app.Meta.LocationSearch.Lat,
|
||||
Longitude = app.Meta.LocationSearch.Lng,
|
||||
Content = app.Meta.LocationSearch.Address,
|
||||
Title = app.Meta.LocationSearch.Name,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class LongMsgSegment(string name)
|
||||
{
|
||||
public LongMsgSegment() : this("") { }
|
||||
|
||||
[JsonPropertyName("id")] [CQProperty] public string Name { get; set; } = name;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(LongMsgSegment), "longmsg")]
|
||||
public partial class LongMsgSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is LongMsgSegment longMsg) builder.Add(new LongMsgEntity(longMsg.Name));
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not LongMsgEntity longMsg) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new ForwardSegment(longMsg.ResId ?? "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class MarkdownSegment(string content)
|
||||
{
|
||||
public MarkdownSegment(): this("") { }
|
||||
|
||||
[JsonPropertyName("content")] [CQProperty] public string Content { get; set; } = content;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(MarkdownEntity), "markdown")]
|
||||
public partial class MarkdownSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is MarkdownSegment markdown) builder.Markdown(markdown.Content);
|
||||
}
|
||||
|
||||
public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
61
Lagrange.Core/Lagrange.OneBot/Message/Entity/MfaceSegment.cs
Normal file
61
Lagrange.Core/Lagrange.OneBot/Message/Entity/MfaceSegment.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
using Lagrange.Core.Utility.Network;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class MfaceSegment(string? url, string emojiId, int emojiPackageId, string key, string? summary)
|
||||
{
|
||||
[JsonPropertyName("url")] public string? Url { get; set; } = url;
|
||||
|
||||
[JsonPropertyName("emoji_package_id")] public int EmojiPackageId { get; set; } = emojiPackageId;
|
||||
|
||||
[JsonPropertyName("emoji_id")] public string EmojiId { get; set; } = emojiId;
|
||||
|
||||
[JsonPropertyName("key")] public string Key { get; set; } = key;
|
||||
|
||||
[JsonPropertyName("summary")] public string? Summary { get; set; } = summary;
|
||||
|
||||
public MfaceSegment() : this(null, string.Empty, default, string.Empty, null) { }
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(MarketfaceEntity), "mface")]
|
||||
public partial class MfaceSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is not MfaceSegment mfs) return;
|
||||
|
||||
if (mfs.Summary == null)
|
||||
{
|
||||
JsonElement tabJson = JsonDocument.Parse(
|
||||
Http.GetAsync(
|
||||
$"https://i.gtimg.cn/club/item/parcel/{mfs.EmojiPackageId % 10}/{mfs.EmojiPackageId}.json"
|
||||
).Result
|
||||
).RootElement;
|
||||
|
||||
foreach (JsonElement imgJson in tabJson.GetProperty("imgs").EnumerateArray())
|
||||
{
|
||||
if (imgJson.GetProperty("id").GetString() == mfs.EmojiId)
|
||||
{
|
||||
mfs.Summary = $"[{imgJson.GetProperty("name").GetString()}]" ?? "[\u5546\u57ce\u8868\u60c5]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mfs.Summary ??= "[\u5546\u57ce\u8868\u60c5]";
|
||||
}
|
||||
|
||||
builder.Add(new MarketfaceEntity(mfs.EmojiId, mfs.EmojiPackageId, mfs.Key, mfs.Summary));
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not MarketfaceEntity mfe) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new MfaceSegment($"https://gxh.vip.qq.com/club/item/parcel/item/{mfe.EmojiId[..2]}/{mfe.EmojiId}/raw300.gif", mfe.EmojiId, mfe.EmojiPackageId, mfe.Key, mfe.Summary);
|
||||
}
|
||||
}
|
||||
52
Lagrange.Core/Lagrange.OneBot/Message/Entity/MusicSegment.cs
Normal file
52
Lagrange.Core/Lagrange.OneBot/Message/Entity/MusicSegment.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Lagrange.Core.Message.Entity;
|
||||
using Lagrange.Core.Message;
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.OneBot.Utility;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class MusicSegment(string? type, string url, string audio, string title, string image, string content, string appid, string sign, string packageName)
|
||||
{
|
||||
public MusicSegment() : this(null, "", "", "", "", "", "", "", "") { }
|
||||
|
||||
[JsonPropertyName("type")][CQProperty] public string? Type { get; set; } = type;
|
||||
|
||||
[JsonPropertyName("id")][CQProperty] public string Id { get; set; } = String.Empty;
|
||||
|
||||
[JsonPropertyName("url")][CQProperty] public string Url { get; set; } = url;
|
||||
|
||||
[JsonPropertyName("audio")][CQProperty] public string Audio { get; set; } = audio;
|
||||
|
||||
[JsonPropertyName("title")][CQProperty] public string Title { get; set; } = title;
|
||||
|
||||
[JsonPropertyName("content")][CQProperty] public string Content { get; set; } = content;
|
||||
|
||||
[JsonPropertyName("image")][CQProperty] public string Image { get; set; } = image;
|
||||
|
||||
[JsonPropertyName("appid")] public string Appid { get; set; } = appid;
|
||||
|
||||
[JsonPropertyName("sign")] public string Sign { get; set; } = sign;
|
||||
|
||||
[JsonPropertyName("package_name")] public string PackageName { get; set; } = packageName;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(ImageEntity), "music")]
|
||||
public partial class MusicSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is MusicSegment musicSegment)
|
||||
{
|
||||
var content = MusicSigner.Sign(musicSegment);
|
||||
if (string.IsNullOrEmpty(content))
|
||||
throw new ArgumentNullException("music SignerServer response Errors!");
|
||||
builder.LightApp(content);
|
||||
}
|
||||
}
|
||||
|
||||
public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
33
Lagrange.Core/Lagrange.OneBot/Message/Entity/PokeSegment.cs
Normal file
33
Lagrange.Core/Lagrange.OneBot/Message/Entity/PokeSegment.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class PokeSegment(uint type, uint strength)
|
||||
{
|
||||
public PokeSegment() : this(0, 0) { }
|
||||
|
||||
[JsonPropertyName("type")] [CQProperty] public string Type { get; set; } = type.ToString();
|
||||
|
||||
[JsonPropertyName("strength")] public string? Strength { get; set; } = strength.ToString();
|
||||
|
||||
[JsonPropertyName("id")] [CQProperty] public string Id { get; set; } = "-1"; // can not get id
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(PokeEntity), "poke")]
|
||||
public partial class PokeSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is PokeSegment pokeSegment) builder.Poke(uint.Parse(pokeSegment.Type), pokeSegment.Strength == null ? 0 : uint.Parse(pokeSegment.Strength));
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not PokeEntity pokeEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new PokeSegment(pokeEntity.Type, pokeEntity.Strength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Konata.Codec.Audio;
|
||||
using Konata.Codec.Audio.Codecs;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
using Lagrange.OneBot.Utility;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class RecordSegment(string url)
|
||||
{
|
||||
public RecordSegment() : this("") { }
|
||||
|
||||
[JsonPropertyName("file")][CQProperty] public string File { get; set; } = url;
|
||||
|
||||
[JsonPropertyName("url")] public string Url { get; set; } = url;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(RecordEntity), "record")]
|
||||
public partial class RecordSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is RecordSegment recordSegment and not { File: "" } && CommonResolver.Resolve(recordSegment.File) is { } record)
|
||||
{
|
||||
byte[] silk = ConvertFormat(record, out double time);
|
||||
builder.Record(silk, (int)Math.Ceiling(time));
|
||||
}
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not RecordEntity recordEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new RecordSegment(recordEntity.AudioUrl);
|
||||
}
|
||||
|
||||
private static byte[] ConvertFormat(byte[] audio, out double audioTime)
|
||||
{
|
||||
var format = AudioHelper.DetectAudio(audio);
|
||||
switch (format) // Process
|
||||
{
|
||||
// Silk v3 for tx use
|
||||
case AudioHelper.AudioFormat.TenSilkV3:
|
||||
{
|
||||
audioTime = AudioHelper.GetTenSilkTime(audio);
|
||||
return audio;
|
||||
}
|
||||
|
||||
// Amr format
|
||||
// We no need to convert it
|
||||
case AudioHelper.AudioFormat.Amr:
|
||||
{
|
||||
audioTime = audio.Length / 1607.0;
|
||||
return audio;
|
||||
}
|
||||
|
||||
// Normal silk v3
|
||||
// We need to append a header 0x02
|
||||
// and remove 0xFFFF end for it
|
||||
case AudioHelper.AudioFormat.SilkV3:
|
||||
{
|
||||
audio = [0x02, .. audio.AsSpan(0, audio.Length - 2)];
|
||||
audioTime = AudioHelper.GetTenSilkTime(audio);
|
||||
return audio;
|
||||
}
|
||||
|
||||
// Need to convert
|
||||
case AudioHelper.AudioFormat.Wav:
|
||||
case AudioHelper.AudioFormat.Ogg:
|
||||
case AudioHelper.AudioFormat.Mp3:
|
||||
{
|
||||
var input = new MemoryStream(audio);
|
||||
var output = new MemoryStream();
|
||||
|
||||
var pipeline = new AudioPipeline() {
|
||||
format switch {
|
||||
AudioHelper.AudioFormat.Wav => new WavCodec.Decoder(input),
|
||||
AudioHelper.AudioFormat.Ogg => new VorbisCodec.Decoder(input),
|
||||
AudioHelper.AudioFormat.Mp3 => new Mp3Codec.Decoder(input),
|
||||
_ => throw new Exception("Unknown Fromat")
|
||||
},
|
||||
new AudioResampler(AudioInfo.SilkV3()),
|
||||
new SilkV3Codec.Encoder(),
|
||||
output
|
||||
};
|
||||
if (!pipeline.Start().Result) throw new Exception("Encode failed");
|
||||
|
||||
audioTime = pipeline.GetAudioTime();
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
// Cannot convert unknown type
|
||||
default: throw new Exception("Unknown Fromat");
|
||||
}
|
||||
}
|
||||
}
|
||||
50
Lagrange.Core/Lagrange.OneBot/Message/Entity/ReplySegment.cs
Normal file
50
Lagrange.Core/Lagrange.OneBot/Message/Entity/ReplySegment.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
using Lagrange.OneBot.Database;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class ReplySegment(uint messageId)
|
||||
{
|
||||
public ReplySegment() : this(0) { }
|
||||
|
||||
[JsonPropertyName("id")][CQProperty] public string MessageId { get; set; } = messageId.ToString();
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(ForwardEntity), "reply")]
|
||||
public partial class ReplySegment : SegmentBase
|
||||
{
|
||||
internal MessageChain? TargetChain { get; set; }
|
||||
|
||||
internal uint Sequence { get; private set; }
|
||||
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is ReplySegment reply && Database is not null)
|
||||
{
|
||||
var messageRecord = Database.GetCollection<MessageRecord>().FindById(int.Parse(reply.MessageId));
|
||||
reply.TargetChain ??= (MessageChain)messageRecord;
|
||||
|
||||
var build = MessagePacker.Build(reply.TargetChain, "");
|
||||
var virtualElem = build.Body?.RichText?.Elems;
|
||||
if (virtualElem != null) reply.TargetChain.Elements.AddRange(virtualElem);
|
||||
|
||||
builder.Forward(reply.TargetChain);
|
||||
}
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not ForwardEntity forward || Database is null) throw new ArgumentException("The entity is not a forward entity.");
|
||||
|
||||
var collection = Database.GetCollection<MessageRecord>();
|
||||
|
||||
int hash = MessageRecord.CalcMessageHash(forward.MessageId, forward.Sequence);
|
||||
var query = collection.FindById(hash);
|
||||
return query == null
|
||||
? new ReplySegment { MessageId = 0.ToString() }
|
||||
: new ReplySegment { MessageId = query.MessageHash.ToString() };
|
||||
}
|
||||
}
|
||||
26
Lagrange.Core/Lagrange.OneBot/Message/Entity/RpsSegment.cs
Normal file
26
Lagrange.Core/Lagrange.OneBot/Message/Entity/RpsSegment.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class RpsSegment
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(FaceEntity), "rps")]
|
||||
public partial class RpsSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is RpsSegment) builder.Face(359, true);
|
||||
}
|
||||
|
||||
public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is FaceEntity { IsLargeFace: true, FaceId: 359 }) return new RpsSegment();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
Lagrange.Core/Lagrange.OneBot/Message/Entity/TextSegment.cs
Normal file
29
Lagrange.Core/Lagrange.OneBot/Message/Entity/TextSegment.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class TextSegment(string text)
|
||||
{
|
||||
public TextSegment() : this("") { }
|
||||
|
||||
[JsonPropertyName("text")] [CQProperty] public string Text { get; set; } = text;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(TextEntity), "text")]
|
||||
public partial class TextSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is TextSegment textSegment) builder.Text(textSegment.Text);
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not TextEntity textEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new TextSegment(textEntity.Text);
|
||||
}
|
||||
}
|
||||
34
Lagrange.Core/Lagrange.OneBot/Message/Entity/VideoSegment.cs
Normal file
34
Lagrange.Core/Lagrange.OneBot/Message/Entity/VideoSegment.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class VideoSegment(string url)
|
||||
{
|
||||
public VideoSegment() : this("") { }
|
||||
|
||||
[JsonPropertyName("file")] [CQProperty] public string File { get; set; } = url;
|
||||
|
||||
[JsonPropertyName("url")] public string Url { get; set; } = url;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(VideoEntity), "video")]
|
||||
public partial class VideoSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is VideoSegment videoSegment and not { File: "" } && CommonResolver.Resolve(videoSegment.File) is { } image)
|
||||
{
|
||||
builder.Video(image);
|
||||
}
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not VideoEntity videoEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new RecordSegment(videoEntity.VideoUrl);
|
||||
}
|
||||
}
|
||||
31
Lagrange.Core/Lagrange.OneBot/Message/Entity/XmlSegment.cs
Normal file
31
Lagrange.Core/Lagrange.OneBot/Message/Entity/XmlSegment.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Message.Entity;
|
||||
|
||||
namespace Lagrange.OneBot.Message.Entity;
|
||||
|
||||
[Serializable]
|
||||
public partial class XmlSegment(string xml, int serviceid)
|
||||
{
|
||||
public XmlSegment() : this("", 35) { }
|
||||
|
||||
[JsonPropertyName("data")] [CQProperty] public string Xml { get; set; } = xml;
|
||||
|
||||
[JsonPropertyName("service_id")] [CQProperty] public int ServiceId { get; set; } = serviceid;
|
||||
}
|
||||
|
||||
[SegmentSubscriber(typeof(XmlEntity), "xml")]
|
||||
public partial class XmlSegment : SegmentBase
|
||||
{
|
||||
public override void Build(MessageBuilder builder, SegmentBase segment)
|
||||
{
|
||||
if (segment is XmlSegment xml) builder.Xml(xml.Xml, xml.ServiceId);
|
||||
}
|
||||
|
||||
public override SegmentBase FromEntity(MessageChain chain, IMessageEntity entity)
|
||||
{
|
||||
if (entity is not XmlEntity xmlEntity) throw new ArgumentException("Invalid entity type.");
|
||||
|
||||
return new XmlSegment(xmlEntity.Xml, xmlEntity.ServiceId);
|
||||
}
|
||||
}
|
||||
197
Lagrange.Core/Lagrange.OneBot/Message/MessageService.cs
Normal file
197
Lagrange.Core/Lagrange.OneBot/Message/MessageService.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using Lagrange.Core;
|
||||
using Lagrange.Core.Event.EventArg;
|
||||
using Lagrange.Core.Message;
|
||||
using Lagrange.Core.Utility.Extension;
|
||||
using Lagrange.OneBot.Core.Entity.Message;
|
||||
using Lagrange.OneBot.Core.Network;
|
||||
using Lagrange.OneBot.Database;
|
||||
using Lagrange.OneBot.Message.Entity;
|
||||
using LiteDB;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
|
||||
namespace Lagrange.OneBot.Message;
|
||||
|
||||
/// <summary>
|
||||
/// The class that converts the OneBot message to/from MessageEntity of Lagrange.Core
|
||||
/// </summary>
|
||||
public sealed class MessageService
|
||||
{
|
||||
private readonly LagrangeWebSvcCollection _service;
|
||||
private readonly LiteDatabase _context;
|
||||
private readonly IConfiguration _config;
|
||||
private readonly Dictionary<Type, List<(string Type, SegmentBase Factory)>> _entityToFactory;
|
||||
private readonly bool _stringPost;
|
||||
|
||||
private static readonly JsonSerializerOptions Options;
|
||||
|
||||
static MessageService()
|
||||
{
|
||||
Options = new JsonSerializerOptions { TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { ModifyTypeInfo } } };
|
||||
}
|
||||
|
||||
public MessageService(BotContext bot, LagrangeWebSvcCollection service, LiteDatabase context, IConfiguration config)
|
||||
{
|
||||
_service = service;
|
||||
_context = context;
|
||||
_config = config;
|
||||
_stringPost = config.GetValue<bool>("Message:StringPost");
|
||||
|
||||
var invoker = bot.Invoker;
|
||||
|
||||
invoker.OnFriendMessageReceived += OnFriendMessageReceived;
|
||||
invoker.OnGroupMessageReceived += OnGroupMessageReceived;
|
||||
invoker.OnTempMessageReceived += OnTempMessageReceived;
|
||||
|
||||
_entityToFactory = new Dictionary<Type, List<(string, SegmentBase)>>();
|
||||
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
|
||||
{
|
||||
var attribute = type.GetCustomAttribute<SegmentSubscriberAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
var instance = (SegmentBase)type.CreateInstance(false);
|
||||
instance.Database = _context;
|
||||
|
||||
if (_entityToFactory.TryGetValue(attribute.Entity, out var factories)) factories.Add((attribute.Type, instance));
|
||||
else _entityToFactory[attribute.Entity] = [(attribute.Type, instance)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnFriendMessageReceived(BotContext bot, FriendMessageEvent e)
|
||||
{
|
||||
var record = (MessageRecord)e.Chain;
|
||||
_context.GetCollection<MessageRecord>().Insert(new BsonValue(record.MessageHash), record);
|
||||
|
||||
if (_config.GetValue<bool>("Message:IgnoreSelf") && e.Chain.FriendUin == bot.BotUin) return; // ignore self message
|
||||
|
||||
var request = ConvertToPrivateMsg(bot.BotUin, e.Chain);
|
||||
|
||||
_ = _service.SendJsonAsync(request);
|
||||
}
|
||||
|
||||
public object ConvertToPrivateMsg(uint uin, MessageChain chain)
|
||||
{
|
||||
var segments = Convert(chain);
|
||||
int hash = MessageRecord.CalcMessageHash(chain.MessageId, chain.Sequence);
|
||||
string raw = ToRawMessage(segments);
|
||||
object request = _stringPost ? new OneBotPrivateStringMsg(uin, new OneBotSender(chain.FriendUin, chain.FriendInfo?.Nickname ?? string.Empty), "friend", ((DateTimeOffset)chain.Time).ToUnixTimeSeconds())
|
||||
{
|
||||
MessageId = hash,
|
||||
UserId = chain.FriendUin,
|
||||
Message = raw,
|
||||
RawMessage = raw,
|
||||
TargetId = chain.TargetUin,
|
||||
} : new OneBotPrivateMsg(uin, new OneBotSender(chain.FriendUin, chain.FriendInfo?.Nickname ?? string.Empty), "friend", ((DateTimeOffset)chain.Time).ToUnixTimeSeconds())
|
||||
{
|
||||
MessageId = hash,
|
||||
UserId = chain.FriendUin,
|
||||
Message = segments,
|
||||
RawMessage = raw,
|
||||
TargetId = chain.TargetUin
|
||||
};
|
||||
return request;
|
||||
}
|
||||
|
||||
private void OnGroupMessageReceived(BotContext bot, GroupMessageEvent e)
|
||||
{
|
||||
var record = (MessageRecord)e.Chain;
|
||||
_context.GetCollection<MessageRecord>().Insert(new BsonValue(record.MessageHash), record);
|
||||
if (_config.GetValue<bool>("Message:IgnoreSelf") && e.Chain.FriendUin == bot.BotUin) return; // ignore self message
|
||||
|
||||
var request = ConvertToGroupMsg(bot.BotUin, e.Chain);
|
||||
|
||||
_ = _service.SendJsonAsync(request);
|
||||
}
|
||||
|
||||
public object ConvertToGroupMsg(uint uin, MessageChain chain)
|
||||
{
|
||||
var segments = Convert(chain);
|
||||
int hash = MessageRecord.CalcMessageHash(chain.MessageId, chain.Sequence);
|
||||
object request = _stringPost
|
||||
? new OneBotGroupStringMsg(uin, chain.GroupUin ?? 0, ToRawMessage(segments), chain.GroupMemberInfo ?? throw new Exception("Group member not found"), hash, ((DateTimeOffset)chain.Time).ToUnixTimeSeconds())
|
||||
: new OneBotGroupMsg(uin, chain.GroupUin ?? 0, segments, ToRawMessage(segments), chain.GroupMemberInfo ?? throw new Exception("Group member not found"), hash, ((DateTimeOffset)chain.Time).ToUnixTimeSeconds());
|
||||
return request;
|
||||
}
|
||||
|
||||
private void OnTempMessageReceived(BotContext bot, TempMessageEvent e)
|
||||
{
|
||||
var record = (MessageRecord)e.Chain;
|
||||
_context.GetCollection<MessageRecord>().Insert(new BsonValue(record.MessageHash), record);
|
||||
|
||||
var segments = Convert(e.Chain);
|
||||
var request = new OneBotPrivateMsg(bot.BotUin, new OneBotSender(e.Chain.FriendUin, e.Chain.FriendInfo?.Nickname ?? string.Empty), "group", ((DateTimeOffset)e.Chain.Time).ToUnixTimeSeconds())
|
||||
{
|
||||
MessageId = record.MessageHash,
|
||||
UserId = e.Chain.FriendUin,
|
||||
Message = segments,
|
||||
RawMessage = ToRawMessage(segments)
|
||||
};
|
||||
|
||||
_ = _service.SendJsonAsync(request);
|
||||
}
|
||||
|
||||
public List<OneBotSegment> Convert(MessageChain chain)
|
||||
{
|
||||
var result = new List<OneBotSegment>();
|
||||
|
||||
foreach (var entity in chain)
|
||||
{
|
||||
if (_entityToFactory.TryGetValue(entity.GetType(), out var instances))
|
||||
{
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
if (instance.Factory.FromEntity(chain, entity) is { } segment) result.Add(new OneBotSegment(instance.Type, segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string EscapeText(string str) => str
|
||||
.Replace("&", "&")
|
||||
.Replace("[", "[")
|
||||
.Replace("]", "]");
|
||||
|
||||
private static string EscapeCQ(string str) => EscapeText(str).Replace(",", ",");
|
||||
|
||||
private static string ToRawMessage(List<OneBotSegment> segments)
|
||||
{
|
||||
var rawMessageBuilder = new StringBuilder();
|
||||
foreach (var segment in segments)
|
||||
{
|
||||
if (segment.Data is TextSegment textSeg)
|
||||
{
|
||||
rawMessageBuilder.Append(EscapeText(textSeg.Text));
|
||||
}
|
||||
else
|
||||
{
|
||||
rawMessageBuilder.Append("[CQ:");
|
||||
rawMessageBuilder.Append(segment.Type);
|
||||
foreach (var property in JsonSerializer.SerializeToElement(segment.Data, Options).EnumerateObject())
|
||||
{
|
||||
rawMessageBuilder.Append(',');
|
||||
rawMessageBuilder.Append(property.Name);
|
||||
rawMessageBuilder.Append('=');
|
||||
rawMessageBuilder.Append(EscapeCQ(property.Value.ToString()));
|
||||
}
|
||||
rawMessageBuilder.Append(']');
|
||||
}
|
||||
}
|
||||
return rawMessageBuilder.ToString();
|
||||
}
|
||||
|
||||
private static void ModifyTypeInfo(JsonTypeInfo ti)
|
||||
{
|
||||
if (ti.Kind != JsonTypeInfoKind.Object) return;
|
||||
foreach (var info in ti.Properties.Where(x => x.AttributeProvider?.IsDefined(typeof(CQPropertyAttribute), false) == false).ToArray())
|
||||
{
|
||||
ti.Properties.Remove(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Lagrange.Core/Lagrange.OneBot/Message/SegmentBase.cs
Normal file
13
Lagrange.Core/Lagrange.OneBot/Message/SegmentBase.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Lagrange.Core.Message;
|
||||
using LiteDB;
|
||||
|
||||
namespace Lagrange.OneBot.Message;
|
||||
|
||||
public abstract class SegmentBase
|
||||
{
|
||||
public LiteDatabase? Database { protected get; set; }
|
||||
|
||||
public abstract void Build(MessageBuilder builder, SegmentBase segment);
|
||||
|
||||
public abstract SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Lagrange.OneBot.Message;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class SegmentSubscriberAttribute(Type entity, string type, string? sendType = null) : Attribute
|
||||
{
|
||||
public Type Entity { get; } = entity;
|
||||
|
||||
public string Type { get; } = type;
|
||||
|
||||
public string SendType { get; } = sendType ?? type;
|
||||
}
|
||||
Reference in New Issue
Block a user