mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-05 23:34:09 +02:00
Add core models, DTOs, and services for EchoHub chat application
- Created User, Channel, Message, and ServerInfo models with necessary properties. - Added DTOs for user profiles, server information, and message handling. - Implemented JWT authentication service for user login and token generation. - Developed Entity Framework Core DbContext for database interactions. - Introduced SignalR ChatHub for real-time messaging and presence tracking. - Implemented file storage and image to ASCII conversion services. - Set up CORS and middleware for API endpoints. - Created launch settings and development configuration for server and web projects.
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
namespace EchoHub.Server.Services;
|
||||
|
||||
public class FileStorageService
|
||||
{
|
||||
private readonly string _storagePath;
|
||||
|
||||
public FileStorageService(IConfiguration configuration)
|
||||
{
|
||||
_storagePath = configuration["Storage:Path"] ?? "./uploads";
|
||||
|
||||
if (!Directory.Exists(_storagePath))
|
||||
{
|
||||
Directory.CreateDirectory(_storagePath);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(string fileId, string filePath)> SaveFileAsync(Stream stream, string fileName)
|
||||
{
|
||||
var fileId = Guid.NewGuid().ToString();
|
||||
var extension = Path.GetExtension(fileName);
|
||||
var storedFileName = $"{fileId}{extension}";
|
||||
var filePath = Path.Combine(_storagePath, storedFileName);
|
||||
|
||||
using var fileStream = File.Create(filePath);
|
||||
await stream.CopyToAsync(fileStream);
|
||||
|
||||
return (fileId, filePath);
|
||||
}
|
||||
|
||||
public string? GetFilePath(string fileId)
|
||||
{
|
||||
var files = Directory.GetFiles(_storagePath, $"{fileId}.*");
|
||||
|
||||
return files.Length > 0 ? files[0] : null;
|
||||
}
|
||||
|
||||
public void DeleteFile(string fileId)
|
||||
{
|
||||
var filePath = GetFilePath(fileId);
|
||||
|
||||
if (filePath is not null && File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Text;
|
||||
using EchoHub.Core.Constants;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
|
||||
namespace EchoHub.Server.Services;
|
||||
|
||||
public class ImageToAsciiService
|
||||
{
|
||||
private static readonly char[] AsciiChars = " .:-=+*#%@".ToCharArray();
|
||||
|
||||
public string ConvertToAscii(Stream imageStream, int width = HubConstants.AsciiArtWidth, int height = HubConstants.AsciiArtHeight)
|
||||
{
|
||||
using var image = Image.Load<Rgba32>(imageStream);
|
||||
|
||||
image.Mutate(x => x.Resize(width, height));
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for (int y = 0; y < image.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < image.Width; x++)
|
||||
{
|
||||
var pixel = image[x, y];
|
||||
var brightness = 0.299 * pixel.R + 0.587 * pixel.G + 0.114 * pixel.B;
|
||||
|
||||
// Map brightness (0-255) to ASCII char index (inverted: dark pixels get dense chars)
|
||||
var index = (int)((brightness / 255.0) * (AsciiChars.Length - 1));
|
||||
sb.Append(AsciiChars[index]);
|
||||
}
|
||||
|
||||
if (y < image.Height - 1)
|
||||
{
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace EchoHub.Server.Services;
|
||||
|
||||
public class PresenceTracker
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, (Guid userId, string username)> _connections = new();
|
||||
private readonly ConcurrentDictionary<string, HashSet<string>> _userConnections = new();
|
||||
private readonly ConcurrentDictionary<string, HashSet<string>> _userChannels = new();
|
||||
|
||||
private readonly object _lock = new();
|
||||
|
||||
public void UserConnected(string connectionId, Guid userId, string username)
|
||||
{
|
||||
_connections[connectionId] = (userId, username);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_userConnections.TryGetValue(username, out var connections))
|
||||
{
|
||||
connections = new HashSet<string>();
|
||||
_userConnections[username] = connections;
|
||||
}
|
||||
|
||||
connections.Add(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
public string? UserDisconnected(string connectionId)
|
||||
{
|
||||
if (!_connections.TryRemove(connectionId, out var userInfo))
|
||||
return null;
|
||||
|
||||
var username = userInfo.username;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_userConnections.TryGetValue(username, out var connections))
|
||||
{
|
||||
connections.Remove(connectionId);
|
||||
|
||||
if (connections.Count == 0)
|
||||
{
|
||||
_userConnections.TryRemove(username, out _);
|
||||
_userChannels.TryRemove(username, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
public void JoinChannel(string username, string channelName)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_userChannels.TryGetValue(username, out var channels))
|
||||
{
|
||||
channels = new HashSet<string>();
|
||||
_userChannels[username] = channels;
|
||||
}
|
||||
|
||||
channels.Add(channelName);
|
||||
}
|
||||
}
|
||||
|
||||
public void LeaveChannel(string username, string channelName)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_userChannels.TryGetValue(username, out var channels))
|
||||
{
|
||||
channels.Remove(channelName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetOnlineUsersInChannel(string channelName)
|
||||
{
|
||||
var users = new List<string>();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var (username, channels) in _userChannels)
|
||||
{
|
||||
if (channels.Contains(channelName))
|
||||
{
|
||||
users.Add(username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
public List<string> GetChannelsForUser(string username)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_userChannels.TryGetValue(username, out var channels))
|
||||
{
|
||||
return channels.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public bool IsOnline(string username)
|
||||
{
|
||||
return _userConnections.TryGetValue(username, out var connections) && connections.Count > 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user