Merge branch 'master' into lida_Dev

This commit is contained in:
AnonymousDotNet 2024-11-25 14:03:13 +08:00
commit effb9d8839
8 changed files with 186 additions and 32 deletions

View file

@ -7,4 +7,5 @@ public enum BroswerActionEnum
Typing = 3,
Hover = 4,
Scroll = 5,
DragAndDrop = 6
}

View file

@ -5,4 +5,9 @@ public class ElementPosition
public float X { get; set; } = default!;
public float Y { get; set; } = default!;
public override string ToString()
{
return $"[{X}, {Y}]";
}
}

View file

@ -0,0 +1,8 @@
namespace BotSharp.Abstraction.Infrastructures.Enums;
public enum EventPriority
{
Low = 1,
Medium = 2,
High = 3
}

View file

@ -10,7 +10,7 @@ public interface IEventPublisher
/// <returns></returns>
Task BroadcastAsync(string channel, string message);
Task PublishAsync(string channel, string message);
Task PublishAsync(string channel, string message, EventPriority? priority = null);
Task ReDispatchAsync(string channel, int count = 10, string order = "asc");

View file

@ -4,5 +4,5 @@ public interface IEventSubscriber
{
Task SubscribeAsync(string channel, Func<string, string, Task> received);
Task SubscribeAsync(string channel, string group, Func<string, string, Task> received);
Task SubscribeAsync(string channel, string group, bool priorityEnabled, Func<string, string, Task> received);
}

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Infrastructures.Enums;
using StackExchange.Redis;
namespace BotSharp.Core.Infrastructures.Events;
@ -20,10 +21,16 @@ public class RedisPublisher : IEventPublisher
await _subscriber.PublishAsync(channel, message);
}
public async Task PublishAsync(string channel, string message)
public async Task PublishAsync(string channel, string message, EventPriority? priority = null)
{
var db = _redis.GetDatabase();
// convert to apporiate channel by priority
if (priority != null)
{
channel = $"{channel}-{priority}";
}
if (CheckMessageExists(db, channel, "message", message))
{
_logger.LogError($"The message already exists {channel} {message}");
@ -41,7 +48,7 @@ public class RedisPublisher : IEventPublisher
_logger.LogInformation($"Published message {channel} {message} ({messageId})");
}
private bool CheckMessageExists(IDatabase db, string streamName, string fieldName, string desiredValue)
private bool CheckMessageExists(IDatabase db, string channel, string fieldName, string desiredValue)
{
// Define the range to fetch all messages
RedisValue start = "-"; // Start from the smallest ID
@ -49,7 +56,7 @@ public class RedisPublisher : IEventPublisher
int count = 10; // Number of messages to retrieve
// Fetch the latest 10 messages
var streamEntries = db.StreamRange(streamName, start, end, count, Order.Descending);
var streamEntries = db.StreamRange(channel, start, end, count, Order.Descending);
if (streamEntries.Length == 0)
{
@ -84,7 +91,10 @@ public class RedisPublisher : IEventPublisher
try
{
var messageId = await db.StreamAddAsync(channel, "message", entry.Values[0].Value);
var messageId = await db.StreamAddAsync(channel, [
new NameValueEntry("message", entry.Values[0].Value),
new NameValueEntry("timestamp", DateTime.UtcNow.ToString("o"))
]);
_logger.LogWarning($"ReDispatched message: {channel} {entry.Values[0].Value} ({messageId})");

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Infrastructures.Enums;
using StackExchange.Redis;
namespace BotSharp.Core.Infrastructures.Events;
@ -24,10 +25,72 @@ public class RedisSubscriber : IEventSubscriber
});
}
public async Task SubscribeAsync(string channel, string group, Func<string, string, Task> received)
public async Task SubscribeAsync(string channel, string group, bool priorityEnabled, Func<string, string, Task> received)
{
var db = _redis.GetDatabase();
if (priorityEnabled)
{
await CreateConsumerGroup(db, $"{channel}-{EventPriority.Low}", group);
await CreateConsumerGroup(db, $"{channel}-{EventPriority.Medium}", group);
await CreateConsumerGroup(db, $"{channel}-{EventPriority.High}", group);
}
else
{
await CreateConsumerGroup(db, channel, group);
}
while (true)
{
await Task.Delay(100);
if (priorityEnabled)
{
if (await HandleGroupMessage(db, $"{channel}-{EventPriority.High}", group, received) > 0)
{
continue;
}
if (await HandleGroupMessage(db, $"{channel}-{EventPriority.Medium}", group, received) > 0)
{
continue;
}
await HandleGroupMessage(db, $"{channel}-{EventPriority.Low}", group, received);
}
else
{
await HandleGroupMessage(db, channel, group, received);
}
}
}
private async Task<int> HandleGroupMessage(IDatabase db, string channel, string group, Func<string, string, Task> received)
{
var entries = await db.StreamReadGroupAsync(channel, group, Environment.MachineName, count: 1);
foreach (var entry in entries)
{
_logger.LogInformation($"Consumer {Environment.MachineName} received: {channel} {entry.Values[0].Value}");
await db.StreamAcknowledgeAsync(channel, group, entry.Id);
try
{
await received(channel, entry.Values[0].Value);
// Optionally delete the message to save space
await db.StreamDeleteAsync(channel, [entry.Id]);
}
catch (Exception ex)
{
_logger.LogError($"Error processing message: {ex.Message}, event id: {channel} {entry.Id}\r\n{ex}");
}
}
return entries.Length;
}
private async Task CreateConsumerGroup(IDatabase db, string channel, string group)
{
// Create the consumer group if it doesn't exist
try
{
@ -43,30 +106,5 @@ public class RedisSubscriber : IEventSubscriber
_logger.LogError($"Error creating consumer group: '{group}' {ex.Message}");
throw;
}
while (true)
{
var entries = await db.StreamReadGroupAsync(channel, group, Environment.MachineName, count: 1);
foreach (var entry in entries)
{
_logger.LogInformation($"Consumer {Environment.MachineName} received: {channel} {entry.Values[0].Value}");
await db.StreamAcknowledgeAsync(channel, group, entry.Id);
try
{
await received(channel, entry.Values[0].Value);
// Optionally delete the message to save space
await db.StreamDeleteAsync(channel, [entry.Id]);
}
catch (Exception ex)
{
_logger.LogError($"Error processing message: {ex.Message}, event id: {channel} {entry.Id}\r\n{ex}");
}
}
await Task.Delay(Random.Shared.Next(1, 11) * 100);
}
}
}

View file

@ -79,10 +79,102 @@ public partial class PlaywrightWebDriver
{
await locator.HoverAsync();
}
else if (action.Action == BroswerActionEnum.DragAndDrop)
{
// Locate the element to drag
var box = await locator.BoundingBoxAsync();
if (box != null)
{
// Calculate start position
float startX = box.X + box.Width / 2; // Start at the center of the element
float startY = box.Y + box.Height / 2;
// Drag offsets
float offsetX = action.Position.X;
// Move horizontally
if (action.Position.Y == 0)
{
// Perform drag-and-move
// Move mouse to the start position
var mouse = page.Mouse;
await mouse.MoveAsync(startX, startY);
await mouse.DownAsync();
// Move mouse smoothly in increments
var tracks = GetVelocityTrack(offsetX);
foreach (var track in tracks)
{
startX += track;
await page.Mouse.MoveAsync(startX, 0, new MouseMoveOptions
{
Steps = 3
});
}
// Release mouse button
await mouse.UpAsync();
}
else
{
throw new NotImplementedException();
}
}
}
if (action.WaitTime > 0)
{
await Task.Delay(1000 * action.WaitTime);
}
}
public static List<int> GetVelocityTrack(float distance)
{
// Initialize the track list to store the movement distances
List<int> track = new List<int>();
// Initialize variables
float current = 0; // Current position
float mid = distance * 4 / 5; // Deceleration threshold
float t = 0.2f; // Time interval
float v = 1; // Initial velocity
// Generate the track
while (current < distance)
{
float a; // Acceleration
// Determine acceleration based on position
if (current < mid)
{
a = 4; // Accelerate
}
else
{
a = -3; // Decelerate
}
// Calculate new velocity
float v0 = v;
v = v0 + a * t;
// Calculate the movement during this interval
float move = v0 * t + 0.5f * a * t * t;
// Update current position
if (current + move > distance)
{
move = distance - current;
track.Add((int)Math.Round(move));
break;
}
current += move;
// Add rounded movement to the track
track.Add((int)Math.Round(move));
}
return track;
}
}