feat: add SignalR integration for Face Embedding with client implementation and notification service
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace _0_Framework.Application.FaceEmbedding;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سرویس اطلاعرسانی تغییرات Face Embedding
|
||||||
|
/// </summary>
|
||||||
|
public interface IFaceEmbeddingNotificationService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// اطلاعرسانی ایجاد یا بهروزرسانی Embedding
|
||||||
|
/// </summary>
|
||||||
|
Task NotifyEmbeddingCreatedAsync(long workshopId, long employeeId, string employeeFullName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// اطلاعرسانی حذف Embedding
|
||||||
|
/// </summary>
|
||||||
|
Task NotifyEmbeddingDeletedAsync(long workshopId, long employeeId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// اطلاعرسانی بهبود Embedding
|
||||||
|
/// </summary>
|
||||||
|
Task NotifyEmbeddingRefinedAsync(long workshopId, long employeeId);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -20,12 +20,15 @@ public class FaceEmbeddingService : IFaceEmbeddingService
|
|||||||
{
|
{
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
private readonly ILogger<FaceEmbeddingService> _logger;
|
private readonly ILogger<FaceEmbeddingService> _logger;
|
||||||
|
private readonly IFaceEmbeddingNotificationService _notificationService;
|
||||||
private readonly string _apiBaseUrl;
|
private readonly string _apiBaseUrl;
|
||||||
|
|
||||||
public FaceEmbeddingService(IHttpClientFactory httpClientFactory, ILogger<FaceEmbeddingService> logger)
|
public FaceEmbeddingService(IHttpClientFactory httpClientFactory, ILogger<FaceEmbeddingService> logger,
|
||||||
|
IFaceEmbeddingNotificationService notificationService = null)
|
||||||
{
|
{
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_notificationService = notificationService;
|
||||||
_apiBaseUrl = "http://localhost:8000";
|
_apiBaseUrl = "http://localhost:8000";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +84,12 @@ public class FaceEmbeddingService : IFaceEmbeddingService
|
|||||||
_logger.LogInformation("Embeddings generated successfully for Employee {EmployeeId}, Workshop {WorkshopId}",
|
_logger.LogInformation("Embeddings generated successfully for Employee {EmployeeId}, Workshop {WorkshopId}",
|
||||||
employeeId, workshopId);
|
employeeId, workshopId);
|
||||||
|
|
||||||
|
// ارسال اطلاعرسانی به سایر سیستمها
|
||||||
|
if (_notificationService != null)
|
||||||
|
{
|
||||||
|
await _notificationService.NotifyEmbeddingCreatedAsync(workshopId, employeeId, employeeFullName);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult
|
return new OperationResult
|
||||||
{
|
{
|
||||||
IsSuccedded = true,
|
IsSuccedded = true,
|
||||||
@@ -151,6 +160,13 @@ public class FaceEmbeddingService : IFaceEmbeddingService
|
|||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Embeddings generated successfully from streams for Employee {EmployeeId}", employeeId);
|
_logger.LogInformation("Embeddings generated successfully from streams for Employee {EmployeeId}", employeeId);
|
||||||
|
|
||||||
|
// ارسال اطلاعرسانی به سایر سیستمها
|
||||||
|
if (_notificationService != null)
|
||||||
|
{
|
||||||
|
await _notificationService.NotifyEmbeddingCreatedAsync(workshopId, employeeId, employeeFullName);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult { IsSuccedded = true, Message = "Embedding با موفقیت ایجاد شد" };
|
return new OperationResult { IsSuccedded = true, Message = "Embedding با موفقیت ایجاد شد" };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -200,6 +216,13 @@ public class FaceEmbeddingService : IFaceEmbeddingService
|
|||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Embedding refined successfully for Employee {EmployeeId}", employeeId);
|
_logger.LogInformation("Embedding refined successfully for Employee {EmployeeId}", employeeId);
|
||||||
|
|
||||||
|
// ارسال اطلاعرسانی به سایر سیستمها
|
||||||
|
if (_notificationService != null)
|
||||||
|
{
|
||||||
|
await _notificationService.NotifyEmbeddingRefinedAsync(workshopId, employeeId);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult { IsSuccedded = true, Message = "Embedding بهبود یافت" };
|
return new OperationResult { IsSuccedded = true, Message = "Embedding بهبود یافت" };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -239,6 +262,13 @@ public class FaceEmbeddingService : IFaceEmbeddingService
|
|||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Embedding deleted successfully for Employee {EmployeeId}", employeeId);
|
_logger.LogInformation("Embedding deleted successfully for Employee {EmployeeId}", employeeId);
|
||||||
|
|
||||||
|
// ارسال اطلاعرسانی به سایر سیستمها
|
||||||
|
if (_notificationService != null)
|
||||||
|
{
|
||||||
|
await _notificationService.NotifyEmbeddingDeletedAsync(workshopId, employeeId);
|
||||||
|
}
|
||||||
|
|
||||||
return new OperationResult { IsSuccedded = true, Message = "Embedding حذف شد" };
|
return new OperationResult { IsSuccedded = true, Message = "Embedding حذف شد" };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using _0_Framework.Application.FaceEmbedding;
|
||||||
|
|
||||||
|
namespace _0_Framework.InfraStructure;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// پیادهسازی پیشفرض (بدون عملیات) برای IFaceEmbeddingNotificationService
|
||||||
|
/// این کلاس زمانی استفاده میشود که SignalR در دسترس نباشد
|
||||||
|
/// </summary>
|
||||||
|
public class NullFaceEmbeddingNotificationService : IFaceEmbeddingNotificationService
|
||||||
|
{
|
||||||
|
public Task NotifyEmbeddingCreatedAsync(long workshopId, long employeeId, string employeeFullName)
|
||||||
|
{
|
||||||
|
// هیچ عملیاتی انجام نمیدهد
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task NotifyEmbeddingDeletedAsync(long workshopId, long employeeId)
|
||||||
|
{
|
||||||
|
// هیچ عملیاتی انجام نمیدهد
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task NotifyEmbeddingRefinedAsync(long workshopId, long employeeId)
|
||||||
|
{
|
||||||
|
// هیچ عملیاتی انجام نمیدهد
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
624
ANDROID_SIGNALR_GUIDE.md
Normal file
624
ANDROID_SIGNALR_GUIDE.md
Normal file
@@ -0,0 +1,624 @@
|
|||||||
|
# راهنمای اتصال اپلیکیشن Android به SignalR برای Face Embedding
|
||||||
|
|
||||||
|
## 1. افزودن کتابخانه SignalR به پروژه Android
|
||||||
|
|
||||||
|
در فایل `build.gradle` (Module: app) خود، dependency زیر را اضافه کنید:
|
||||||
|
|
||||||
|
```gradle
|
||||||
|
dependencies {
|
||||||
|
// SignalR for Android
|
||||||
|
implementation 'com.microsoft.signalr:signalr:7.0.0'
|
||||||
|
|
||||||
|
// اگر از Kotlin استفاده میکنید:
|
||||||
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
|
||||||
|
|
||||||
|
// برای JSON پردازش:
|
||||||
|
implementation 'com.google.code.gson:gson:2.10.1'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. اضافه کردن Permission در AndroidManifest.xml
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. کد Java/Kotlin برای اتصال به SignalR
|
||||||
|
|
||||||
|
### نسخه Java:
|
||||||
|
|
||||||
|
```java
|
||||||
|
import com.microsoft.signalr.HubConnection;
|
||||||
|
import com.microsoft.signalr.HubConnectionBuilder;
|
||||||
|
import com.microsoft.signalr.HubConnectionState;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class FaceEmbeddingSignalRClient {
|
||||||
|
private static final String TAG = "FaceEmbeddingHub";
|
||||||
|
private HubConnection hubConnection;
|
||||||
|
private String serverUrl = "http://YOUR_SERVER_IP:PORT/trackingFaceEmbeddingHub"; // آدرس سرور خود را وارد کنید
|
||||||
|
private long workshopId;
|
||||||
|
|
||||||
|
public FaceEmbeddingSignalRClient(long workshopId) {
|
||||||
|
this.workshopId = workshopId;
|
||||||
|
initializeSignalR();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeSignalR() {
|
||||||
|
// ایجاد اتصال SignalR
|
||||||
|
hubConnection = HubConnectionBuilder
|
||||||
|
.create(serverUrl)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// دریافت رویداد ایجاد Embedding
|
||||||
|
hubConnection.on("EmbeddingCreated", (data) -> {
|
||||||
|
JsonObject jsonData = (JsonObject) data;
|
||||||
|
long employeeId = jsonData.get("employeeId").getAsLong();
|
||||||
|
String employeeFullName = jsonData.get("employeeFullName").getAsString();
|
||||||
|
String timestamp = jsonData.get("timestamp").getAsString();
|
||||||
|
|
||||||
|
Log.d(TAG, "Embedding Created - Employee: " + employeeFullName + " (ID: " + employeeId + ")");
|
||||||
|
|
||||||
|
// اینجا میتوانید دادههای جدید را از سرور بگیرید یا UI را بروزرسانی کنید
|
||||||
|
onEmbeddingCreated(employeeId, employeeFullName, timestamp);
|
||||||
|
|
||||||
|
}, JsonObject.class);
|
||||||
|
|
||||||
|
// دریافت رویداد حذف Embedding
|
||||||
|
hubConnection.on("EmbeddingDeleted", (data) -> {
|
||||||
|
JsonObject jsonData = (JsonObject) data;
|
||||||
|
long employeeId = jsonData.get("employeeId").getAsLong();
|
||||||
|
String timestamp = jsonData.get("timestamp").getAsString();
|
||||||
|
|
||||||
|
Log.d(TAG, "Embedding Deleted - Employee ID: " + employeeId);
|
||||||
|
onEmbeddingDeleted(employeeId, timestamp);
|
||||||
|
|
||||||
|
}, JsonObject.class);
|
||||||
|
|
||||||
|
// دریافت رویداد بهبود Embedding
|
||||||
|
hubConnection.on("EmbeddingRefined", (data) -> {
|
||||||
|
JsonObject jsonData = (JsonObject) data;
|
||||||
|
long employeeId = jsonData.get("employeeId").getAsLong();
|
||||||
|
String timestamp = jsonData.get("timestamp").getAsString();
|
||||||
|
|
||||||
|
Log.d(TAG, "Embedding Refined - Employee ID: " + employeeId);
|
||||||
|
onEmbeddingRefined(employeeId, timestamp);
|
||||||
|
|
||||||
|
}, JsonObject.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() {
|
||||||
|
if (hubConnection.getConnectionState() == HubConnectionState.DISCONNECTED) {
|
||||||
|
hubConnection.start()
|
||||||
|
.doOnComplete(() -> {
|
||||||
|
Log.d(TAG, "Connected to SignalR Hub");
|
||||||
|
joinWorkshopGroup();
|
||||||
|
})
|
||||||
|
.doOnError(error -> {
|
||||||
|
Log.e(TAG, "Error connecting to SignalR: " + error.getMessage());
|
||||||
|
})
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void joinWorkshopGroup() {
|
||||||
|
// عضویت در گروه مخصوص این کارگاه
|
||||||
|
hubConnection.send("JoinWorkshopGroup", workshopId);
|
||||||
|
Log.d(TAG, "Joined workshop group: " + workshopId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
if (hubConnection.getConnectionState() == HubConnectionState.CONNECTED) {
|
||||||
|
// خروج از گروه
|
||||||
|
hubConnection.send("LeaveWorkshopGroup", workshopId);
|
||||||
|
|
||||||
|
hubConnection.stop();
|
||||||
|
Log.d(TAG, "Disconnected from SignalR Hub");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// این متدها را در Activity/Fragment خود override کنید
|
||||||
|
protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) {
|
||||||
|
// اینجا UI را بروزرسانی کنید یا داده جدید را بگیرید
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onEmbeddingDeleted(long employeeId, String timestamp) {
|
||||||
|
// اینجا UI را بروزرسانی کنید
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onEmbeddingRefined(long employeeId, String timestamp) {
|
||||||
|
// اینجا UI را بروزرسانی کنید
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### نسخه Kotlin:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
import com.microsoft.signalr.HubConnection
|
||||||
|
import com.microsoft.signalr.HubConnectionBuilder
|
||||||
|
import com.microsoft.signalr.HubConnectionState
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import android.util.Log
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class FaceEmbeddingSignalRClient(private val workshopId: Long) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "FaceEmbeddingHub"
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var hubConnection: HubConnection
|
||||||
|
private val serverUrl = "http://YOUR_SERVER_IP:PORT/trackingFaceEmbeddingHub" // آدرس سرور خود را وارد کنید
|
||||||
|
|
||||||
|
init {
|
||||||
|
initializeSignalR()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeSignalR() {
|
||||||
|
hubConnection = HubConnectionBuilder
|
||||||
|
.create(serverUrl)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
// دریافت رویداد ایجاد Embedding
|
||||||
|
hubConnection.on("EmbeddingCreated", { data: JsonObject ->
|
||||||
|
val employeeId = data.get("employeeId").asLong
|
||||||
|
val employeeFullName = data.get("employeeFullName").asString
|
||||||
|
val timestamp = data.get("timestamp").asString
|
||||||
|
|
||||||
|
Log.d(TAG, "Embedding Created - Employee: $employeeFullName (ID: $employeeId)")
|
||||||
|
onEmbeddingCreated(employeeId, employeeFullName, timestamp)
|
||||||
|
}, JsonObject::class.java)
|
||||||
|
|
||||||
|
// دریافت رویداد حذف Embedding
|
||||||
|
hubConnection.on("EmbeddingDeleted", { data: JsonObject ->
|
||||||
|
val employeeId = data.get("employeeId").asLong
|
||||||
|
val timestamp = data.get("timestamp").asString
|
||||||
|
|
||||||
|
Log.d(TAG, "Embedding Deleted - Employee ID: $employeeId")
|
||||||
|
onEmbeddingDeleted(employeeId, timestamp)
|
||||||
|
}, JsonObject::class.java)
|
||||||
|
|
||||||
|
// دریافت رویداد بهبود Embedding
|
||||||
|
hubConnection.on("EmbeddingRefined", { data: JsonObject ->
|
||||||
|
val employeeId = data.get("employeeId").asLong
|
||||||
|
val timestamp = data.get("timestamp").asString
|
||||||
|
|
||||||
|
Log.d(TAG, "Embedding Refined - Employee ID: $employeeId")
|
||||||
|
onEmbeddingRefined(employeeId, timestamp)
|
||||||
|
}, JsonObject::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun connect() {
|
||||||
|
if (hubConnection.connectionState == HubConnectionState.DISCONNECTED) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
try {
|
||||||
|
hubConnection.start().blockingAwait()
|
||||||
|
Log.d(TAG, "Connected to SignalR Hub")
|
||||||
|
joinWorkshopGroup()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Error connecting to SignalR: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun joinWorkshopGroup() {
|
||||||
|
hubConnection.send("JoinWorkshopGroup", workshopId)
|
||||||
|
Log.d(TAG, "Joined workshop group: $workshopId")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disconnect() {
|
||||||
|
if (hubConnection.connectionState == HubConnectionState.CONNECTED) {
|
||||||
|
hubConnection.send("LeaveWorkshopGroup", workshopId)
|
||||||
|
hubConnection.stop()
|
||||||
|
Log.d(TAG, "Disconnected from SignalR Hub")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// این متدها را override کنید
|
||||||
|
open fun onEmbeddingCreated(employeeId: Long, employeeFullName: String, timestamp: String) {
|
||||||
|
// اینجا UI را بروزرسانی کنید یا داده جدید را بگیرید
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun onEmbeddingDeleted(employeeId: Long, timestamp: String) {
|
||||||
|
// اینجا UI را بروزرسانی کنید
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun onEmbeddingRefined(employeeId: Long, timestamp: String) {
|
||||||
|
// اینجا UI را بروزرسانی کنید
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. استفاده در Activity یا Fragment
|
||||||
|
|
||||||
|
### مثال با Login و دریافت WorkshopId
|
||||||
|
|
||||||
|
#### Java:
|
||||||
|
```java
|
||||||
|
public class LoginActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_login);
|
||||||
|
|
||||||
|
Button btnLogin = findViewById(R.id.btnLogin);
|
||||||
|
btnLogin.setOnClickListener(v -> performLogin());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performLogin() {
|
||||||
|
// فراخوانی API لاگین
|
||||||
|
// فرض کنید response شامل workshopId است
|
||||||
|
|
||||||
|
// مثال ساده (باید از Retrofit یا کتابخانه مشابه استفاده کنید):
|
||||||
|
// LoginResponse response = apiService.login(username, password);
|
||||||
|
// long workshopId = response.getWorkshopId();
|
||||||
|
|
||||||
|
long workshopId = 123; // این را از response دریافت کنید
|
||||||
|
|
||||||
|
// ذخیره workshopId
|
||||||
|
SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE);
|
||||||
|
prefs.edit().putLong("workshopId", workshopId).apply();
|
||||||
|
|
||||||
|
// رفتن به صفحه اصلی
|
||||||
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
private FaceEmbeddingSignalRClient signalRClient;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
// دریافت workshopId از SharedPreferences
|
||||||
|
SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE);
|
||||||
|
long workshopId = prefs.getLong("workshopId", 0);
|
||||||
|
|
||||||
|
if (workshopId == 0) {
|
||||||
|
// اگر workshopId وجود نداره، برگرد به صفحه لاگین
|
||||||
|
Intent intent = new Intent(this, LoginActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ایجاد و اتصال SignalR
|
||||||
|
signalRClient = new FaceEmbeddingSignalRClient(workshopId) {
|
||||||
|
@Override
|
||||||
|
protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
// بروزرسانی UI
|
||||||
|
Toast.makeText(MainActivity.this,
|
||||||
|
"Embedding ایجاد شد برای: " + employeeFullName,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
// دریافت دادههای جدید از API
|
||||||
|
refreshEmployeeList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEmbeddingDeleted(long employeeId, String timestamp) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
// بروزرسانی UI
|
||||||
|
refreshEmployeeList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEmbeddingRefined(long employeeId, String timestamp) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
// بروزرسانی UI
|
||||||
|
refreshEmployeeList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
signalRClient.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (signalRClient != null) {
|
||||||
|
signalRClient.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshEmployeeList() {
|
||||||
|
// دریافت لیست جدید کارمندان از API
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Kotlin:
|
||||||
|
```kotlin
|
||||||
|
class LoginActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_login)
|
||||||
|
|
||||||
|
val btnLogin = findViewById<Button>(R.id.btnLogin)
|
||||||
|
btnLogin.setOnClickListener { performLogin() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun performLogin() {
|
||||||
|
// فراخوانی API لاگین
|
||||||
|
// فرض کنید response شامل workshopId است
|
||||||
|
|
||||||
|
// مثال ساده (باید از Retrofit یا کتابخانه مشابه استفاده کنید):
|
||||||
|
// val response = apiService.login(username, password)
|
||||||
|
// val workshopId = response.workshopId
|
||||||
|
|
||||||
|
val workshopId = 123L // این را از response دریافت کنید
|
||||||
|
|
||||||
|
// ذخیره workshopId
|
||||||
|
val prefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
|
||||||
|
prefs.edit().putLong("workshopId", workshopId).apply()
|
||||||
|
|
||||||
|
// رفتن به صفحه اصلی
|
||||||
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
private lateinit var signalRClient: FaceEmbeddingSignalRClient
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
// دریافت workshopId از SharedPreferences
|
||||||
|
val prefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
|
||||||
|
val workshopId = prefs.getLong("workshopId", 0L)
|
||||||
|
|
||||||
|
if (workshopId == 0L) {
|
||||||
|
// اگر workshopId وجود نداره، برگرد به صفحه لاگین
|
||||||
|
val intent = Intent(this, LoginActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ایجاد و اتصال SignalR
|
||||||
|
signalRClient = object : FaceEmbeddingSignalRClient(workshopId) {
|
||||||
|
override fun onEmbeddingCreated(employeeId: Long, employeeFullName: String, timestamp: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
// بروزرسانی UI
|
||||||
|
Toast.makeText(this@MainActivity,
|
||||||
|
"Embedding ایجاد شد برای: $employeeFullName",
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
|
// دریافت دادههای جدید از API
|
||||||
|
refreshEmployeeList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEmbeddingDeleted(employeeId: Long, timestamp: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
// بروزرسانی UI
|
||||||
|
refreshEmployeeList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEmbeddingRefined(employeeId: Long, timestamp: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
// بروزرسانی UI
|
||||||
|
refreshEmployeeList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signalRClient.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
signalRClient.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshEmployeeList() {
|
||||||
|
// دریافت لیست جدید کارمندان از API
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### مثال ساده بدون Login:
|
||||||
|
اگر workshopId را از قبل میدانید:
|
||||||
|
|
||||||
|
#### Java:
|
||||||
|
```java
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
private FaceEmbeddingSignalRClient signalRClient;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
long workshopId = 123; // شناسه کارگاه خود را وارد کنید
|
||||||
|
|
||||||
|
signalRClient = new FaceEmbeddingSignalRClient(workshopId) {
|
||||||
|
@Override
|
||||||
|
protected void onEmbeddingCreated(long employeeId, String employeeFullName, String timestamp) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
// بروزرسانی UI
|
||||||
|
Toast.makeText(MainActivity.this,
|
||||||
|
"Embedding ایجاد شد برای: " + employeeFullName,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
// دریافت دادههای جدید از API
|
||||||
|
refreshEmployeeList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onEmbeddingDeleted(long employeeId, String timestamp) {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
// بروزرسانی UI
|
||||||
|
refreshEmployeeList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
signalRClient.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (signalRClient != null) {
|
||||||
|
signalRClient.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshEmployeeList() {
|
||||||
|
// دریافت لیست جدید کارمندان از API
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Kotlin:
|
||||||
|
```kotlin
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
private lateinit var signalRClient: FaceEmbeddingSignalRClient
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
val workshopId = 123L // شناسه کارگاه خود را وارد کنید
|
||||||
|
|
||||||
|
signalRClient = object : FaceEmbeddingSignalRClient(workshopId) {
|
||||||
|
override fun onEmbeddingCreated(employeeId: Long, employeeFullName: String, timestamp: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
// بروزرسانی UI
|
||||||
|
Toast.makeText(this@MainActivity,
|
||||||
|
"Embedding ایجاد شد برای: $employeeFullName",
|
||||||
|
Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
|
// دریافت دادههای جدید از API
|
||||||
|
refreshEmployeeList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEmbeddingDeleted(employeeId: Long, timestamp: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
// بروزرسانی UI
|
||||||
|
refreshEmployeeList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signalRClient.connect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
signalRClient.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshEmployeeList() {
|
||||||
|
// دریافت لیست جدید کارمندان از API
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. نکات مهم
|
||||||
|
|
||||||
|
### آدرس سرور
|
||||||
|
- اگر روی شبیهساز اندروید تست میکنید و سرور روی localhost اجرا میشود، از آدرس `http://10.0.2.2:PORT` استفاده کنید
|
||||||
|
- اگر روی دستگاه فیزیکی تست میکنید، از آدرس IP شبکه محلی سرور استفاده کنید (مثل `http://192.168.1.100:PORT`)
|
||||||
|
- PORT پیشفرض معمولاً 5000 یا 5001 است (بسته به کانفیگ پروژه شما)
|
||||||
|
|
||||||
|
### دریافت WorkshopId از Login
|
||||||
|
بعد از login موفق، workshopId را از سرور دریافت کنید و در SharedPreferences یا یک Singleton ذخیره کنید:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// بعد از login موفق
|
||||||
|
SharedPreferences prefs = getSharedPreferences("AppPrefs", MODE_PRIVATE);
|
||||||
|
prefs.edit().putLong("workshopId", workshopId).apply();
|
||||||
|
|
||||||
|
// استفاده در Activity
|
||||||
|
long workshopId = prefs.getLong("workshopId", 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
یا در Kotlin:
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// بعد از login موفق
|
||||||
|
val prefs = getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
|
||||||
|
prefs.edit().putLong("workshopId", workshopId).apply()
|
||||||
|
|
||||||
|
// استفاده در Activity
|
||||||
|
val workshopId = prefs.getLong("workshopId", 0L)
|
||||||
|
```
|
||||||
|
|
||||||
|
### مدیریت اتصال
|
||||||
|
برای reconnection خودکار:
|
||||||
|
|
||||||
|
```java
|
||||||
|
hubConnection.onClosed(exception -> {
|
||||||
|
Log.e(TAG, "Connection closed. Attempting to reconnect...");
|
||||||
|
new Handler().postDelayed(() -> connect(), 5000); // تلاش مجدد بعد از 5 ثانیه
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Thread Safety
|
||||||
|
همیشه UI updates را در main thread انجام دهید:
|
||||||
|
|
||||||
|
```java
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
// UI updates here
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. تست اتصال
|
||||||
|
|
||||||
|
برای تست میتوانید:
|
||||||
|
1. اپلیکیشن را اجرا کنید
|
||||||
|
2. از طریق Postman یا Swagger یک Embedding ایجاد کنید
|
||||||
|
3. باید در Logcat پیام "Embedding Created" را ببینید
|
||||||
|
|
||||||
|
## 7. خطایابی (Debugging)
|
||||||
|
|
||||||
|
برای دیدن جزئیات بیشتر:
|
||||||
|
|
||||||
|
```java
|
||||||
|
hubConnection = HubConnectionBuilder
|
||||||
|
.create(serverUrl)
|
||||||
|
.withHttpConnectionOptions(options -> {
|
||||||
|
options.setLogging(LogLevel.TRACE);
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## خلاصه Endpoints
|
||||||
|
|
||||||
|
| نوع رویداد | متد SignalR | پارامترهای دریافتی |
|
||||||
|
|-----------|-------------|---------------------|
|
||||||
|
| ایجاد Embedding | `EmbeddingCreated` | workshopId, employeeId, employeeFullName, timestamp |
|
||||||
|
| حذف Embedding | `EmbeddingDeleted` | workshopId, employeeId, timestamp |
|
||||||
|
| بهبود Embedding | `EmbeddingRefined` | workshopId, employeeId, timestamp |
|
||||||
|
|
||||||
|
| متد ارسالی | پارامتر | توضیحات |
|
||||||
|
|-----------|---------|---------|
|
||||||
|
| `JoinWorkshopGroup` | workshopId | عضویت در گروه کارگاه |
|
||||||
|
| `LeaveWorkshopGroup` | workshopId | خروج از گروه کارگاه |
|
||||||
|
|
||||||
@@ -228,6 +228,9 @@ using CompanyManagement.Infrastructure.Mongo.InstitutionContractInsertTempRepo;
|
|||||||
using CompanyManagment.App.Contracts.EmployeeFaceEmbedding;
|
using CompanyManagment.App.Contracts.EmployeeFaceEmbedding;
|
||||||
using CompanyManagment.App.Contracts.Law;
|
using CompanyManagment.App.Contracts.Law;
|
||||||
using CompanyManagment.EFCore.Repository;
|
using CompanyManagment.EFCore.Repository;
|
||||||
|
using _0_Framework.Application.FaceEmbedding;
|
||||||
|
using _0_Framework.Infrastructure;
|
||||||
|
using _0_Framework.InfraStructure;
|
||||||
|
|
||||||
namespace PersonalContractingParty.Config;
|
namespace PersonalContractingParty.Config;
|
||||||
|
|
||||||
@@ -611,6 +614,10 @@ public class PersonalBootstrapper
|
|||||||
services.AddTransient<IInsuranceApplication, InsuranceApplication>();
|
services.AddTransient<IInsuranceApplication, InsuranceApplication>();
|
||||||
services.AddTransient<IInsuranceRepository, InsuranceRepository>();
|
services.AddTransient<IInsuranceRepository, InsuranceRepository>();
|
||||||
|
|
||||||
|
// Face Embedding Services
|
||||||
|
services.AddTransient<IFaceEmbeddingService, FaceEmbeddingService>();
|
||||||
|
services.AddTransient<IFaceEmbeddingNotificationService, NullFaceEmbeddingNotificationService>();
|
||||||
|
|
||||||
services.AddDbContext<CompanyContext>(x => x.UseSqlServer(connectionString));
|
services.AddDbContext<CompanyContext>(x => x.UseSqlServer(connectionString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,10 @@ public class CameraController : CameraBaseController
|
|||||||
public IActionResult CameraLogin([FromBody] CameraLoginRequest request)
|
public IActionResult CameraLogin([FromBody] CameraLoginRequest request)
|
||||||
{
|
{
|
||||||
_accountApplication.CameraLogin(request);
|
_accountApplication.CameraLogin(request);
|
||||||
return Ok();
|
return Ok(new
|
||||||
|
{
|
||||||
|
WorkshopId = _workshopId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Transactions;
|
using System.Transactions;
|
||||||
|
using _0_Framework.Application.FaceEmbedding;
|
||||||
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
|
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
|
||||||
using _0_Framework.Infrastructure;
|
using _0_Framework.Infrastructure;
|
||||||
using CompanyManagment.App.Contracts.CustomizeWorkshopSettings;
|
using CompanyManagment.App.Contracts.CustomizeWorkshopSettings;
|
||||||
@@ -52,6 +53,7 @@ namespace ServiceHost.Areas.Client.Pages.Company.RollCall
|
|||||||
private readonly IEmployeeDocumentsApplication _employeeDocumentsApplication;
|
private readonly IEmployeeDocumentsApplication _employeeDocumentsApplication;
|
||||||
private readonly IJobApplication _jobApplication;
|
private readonly IJobApplication _jobApplication;
|
||||||
private readonly IHttpClientFactory _httpClientFactory;
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
private readonly IFaceEmbeddingService _faceEmbeddingService;
|
||||||
|
|
||||||
private readonly long _workshopId;
|
private readonly long _workshopId;
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ namespace ServiceHost.Areas.Client.Pages.Company.RollCall
|
|||||||
IHttpContextAccessor contextAccessor, IPersonnelCodeApplication personnelCodeApplication,
|
IHttpContextAccessor contextAccessor, IPersonnelCodeApplication personnelCodeApplication,
|
||||||
IEmployeeClientTempApplication employeeClientTempApplication,
|
IEmployeeClientTempApplication employeeClientTempApplication,
|
||||||
IEmployeeDocumentsApplication employeeDocumentsApplication,
|
IEmployeeDocumentsApplication employeeDocumentsApplication,
|
||||||
IHttpClientFactory httpClientFactory)
|
IHttpClientFactory httpClientFactory, IFaceEmbeddingService faceEmbeddingService)
|
||||||
{
|
{
|
||||||
_workshopApplication = workshopApplication;
|
_workshopApplication = workshopApplication;
|
||||||
_passwordHasher = passwordHasher;
|
_passwordHasher = passwordHasher;
|
||||||
@@ -81,6 +83,7 @@ namespace ServiceHost.Areas.Client.Pages.Company.RollCall
|
|||||||
_employeeDocumentsApplication = employeeDocumentsApplication;
|
_employeeDocumentsApplication = employeeDocumentsApplication;
|
||||||
_jobApplication = jobApplication;
|
_jobApplication = jobApplication;
|
||||||
_httpClientFactory = httpClientFactory;
|
_httpClientFactory = httpClientFactory;
|
||||||
|
_faceEmbeddingService = faceEmbeddingService;
|
||||||
|
|
||||||
var workshopHash = _contextAccessor.HttpContext?.User.FindFirstValue("WorkshopSlug");
|
var workshopHash = _contextAccessor.HttpContext?.User.FindFirstValue("WorkshopSlug");
|
||||||
_workshopId = _passwordHasher.SlugDecrypt(workshopHash);
|
_workshopId = _passwordHasher.SlugDecrypt(workshopHash);
|
||||||
@@ -386,6 +389,8 @@ namespace ServiceHost.Areas.Client.Pages.Company.RollCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = _rollCallEmployeeApplication.UploadedImage(employeeId, workshopId);
|
result = _rollCallEmployeeApplication.UploadedImage(employeeId, workshopId);
|
||||||
|
|
||||||
|
|
||||||
if (result.IsSuccedded == false)
|
if (result.IsSuccedded == false)
|
||||||
{
|
{
|
||||||
return new JsonResult(new
|
return new JsonResult(new
|
||||||
@@ -398,7 +403,15 @@ namespace ServiceHost.Areas.Client.Pages.Company.RollCall
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var faceEmbeddingRes = _faceEmbeddingService.GenerateEmbeddingsAsync(employeeId, workshopId, employee.EmployeeFullName, filePath1, filePath2).GetAwaiter().GetResult();
|
||||||
|
if (!faceEmbeddingRes.IsSuccedded)
|
||||||
|
{
|
||||||
|
return new JsonResult(new
|
||||||
|
{
|
||||||
|
isSuccedded = faceEmbeddingRes.IsSuccedded,
|
||||||
|
message = faceEmbeddingRes.Message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (command.GroupId != 0)
|
if (command.GroupId != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
58
ServiceHost/FaceEmbeddingNotificationService.cs
Normal file
58
ServiceHost/FaceEmbeddingNotificationService.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using _0_Framework.Application.FaceEmbedding;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using ServiceHost.Hubs;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ServiceHost
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// پیادهسازی سرویس اطلاعرسانی Face Embedding با استفاده از SignalR
|
||||||
|
/// </summary>
|
||||||
|
public class FaceEmbeddingNotificationService : IFaceEmbeddingNotificationService
|
||||||
|
{
|
||||||
|
private readonly IHubContext<FaceEmbeddingHub> _hubContext;
|
||||||
|
|
||||||
|
public FaceEmbeddingNotificationService(IHubContext<FaceEmbeddingHub> hubContext)
|
||||||
|
{
|
||||||
|
_hubContext = hubContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyEmbeddingCreatedAsync(long workshopId, long employeeId, string employeeFullName)
|
||||||
|
{
|
||||||
|
var groupName = FaceEmbeddingHub.GetGroupName(workshopId);
|
||||||
|
|
||||||
|
await _hubContext.Clients.Group(groupName).SendAsync("EmbeddingCreated", new
|
||||||
|
{
|
||||||
|
workshopId,
|
||||||
|
employeeId,
|
||||||
|
employeeFullName,
|
||||||
|
timestamp = System.DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyEmbeddingDeletedAsync(long workshopId, long employeeId)
|
||||||
|
{
|
||||||
|
var groupName = FaceEmbeddingHub.GetGroupName(workshopId);
|
||||||
|
|
||||||
|
await _hubContext.Clients.Group(groupName).SendAsync("EmbeddingDeleted", new
|
||||||
|
{
|
||||||
|
workshopId,
|
||||||
|
employeeId,
|
||||||
|
timestamp = System.DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task NotifyEmbeddingRefinedAsync(long workshopId, long employeeId)
|
||||||
|
{
|
||||||
|
var groupName = FaceEmbeddingHub.GetGroupName(workshopId);
|
||||||
|
|
||||||
|
await _hubContext.Clients.Group(groupName).SendAsync("EmbeddingRefined", new
|
||||||
|
{
|
||||||
|
workshopId,
|
||||||
|
employeeId,
|
||||||
|
timestamp = System.DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
23
ServiceHost/Hubs/FaceEmbeddingHub.cs
Normal file
23
ServiceHost/Hubs/FaceEmbeddingHub.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace ServiceHost.Hubs
|
||||||
|
{
|
||||||
|
public class FaceEmbeddingHub : Hub
|
||||||
|
{
|
||||||
|
public async Task JoinWorkshopGroup(long workshopId)
|
||||||
|
{
|
||||||
|
await Groups.AddToGroupAsync(Context.ConnectionId, GetGroupName(workshopId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LeaveWorkshopGroup(long workshopId)
|
||||||
|
{
|
||||||
|
await Groups.RemoveFromGroupAsync(Context.ConnectionId, GetGroupName(workshopId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetGroupName(long workshopId)
|
||||||
|
{
|
||||||
|
return $"group-faceembedding-{workshopId}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ using ServiceHost.MiddleWare;
|
|||||||
using WorkFlow.Infrastructure.Config;
|
using WorkFlow.Infrastructure.Config;
|
||||||
using _0_Framework.Application.UID;
|
using _0_Framework.Application.UID;
|
||||||
using _0_Framework.Exceptions.Handler;
|
using _0_Framework.Exceptions.Handler;
|
||||||
|
using _0_Framework.Application.FaceEmbedding;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using ServiceHost.Test;
|
using ServiceHost.Test;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
@@ -73,6 +74,7 @@ builder.Services.AddTransient<IAuthHelper, AuthHelper>();
|
|||||||
builder.Services.AddTransient<IGoogleRecaptcha, GoogleRecaptcha>();
|
builder.Services.AddTransient<IGoogleRecaptcha, GoogleRecaptcha>();
|
||||||
builder.Services.AddTransient<ISmsService, SmsService>();
|
builder.Services.AddTransient<ISmsService, SmsService>();
|
||||||
builder.Services.AddTransient<IUidService, UidService>();
|
builder.Services.AddTransient<IUidService, UidService>();
|
||||||
|
builder.Services.AddTransient<IFaceEmbeddingNotificationService, FaceEmbeddingNotificationService>();
|
||||||
//services.AddSingleton<IWorkingTest, WorkingTest>();
|
//services.AddSingleton<IWorkingTest, WorkingTest>();
|
||||||
//services.AddHostedService<JobWorker>();
|
//services.AddHostedService<JobWorker>();
|
||||||
|
|
||||||
@@ -383,6 +385,7 @@ app.MapHub<CreateContractTarckingHub>("/trackingHub");
|
|||||||
app.MapHub<SendAccountMessage>("/trackingSmsHub");
|
app.MapHub<SendAccountMessage>("/trackingSmsHub");
|
||||||
app.MapHub<HolidayApiHub>("/trackingHolidayHub");
|
app.MapHub<HolidayApiHub>("/trackingHolidayHub");
|
||||||
app.MapHub<CheckoutHub>("/trackingCheckoutHub");
|
app.MapHub<CheckoutHub>("/trackingCheckoutHub");
|
||||||
|
app.MapHub<FaceEmbeddingHub>("/trackingFaceEmbeddingHub");
|
||||||
app.MapRazorPages();
|
app.MapRazorPages();
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"sqlDebugging": true,
|
"sqlDebugging": true,
|
||||||
"dotnetRunMessages": "true",
|
"dotnetRunMessages": "true",
|
||||||
"nativeDebugging": true,
|
"nativeDebugging": true,
|
||||||
"applicationUrl": "https://localhost:5004;http://localhost:5003;https://192.168.0.117:8080;http://192.168.0.117:8081",
|
"applicationUrl": "https://localhost:5004;http://localhost:5003;https://192.168.0.117:5005;http://192.168.0.117:5006",
|
||||||
"jsWebView2Debugging": false,
|
"jsWebView2Debugging": false,
|
||||||
"hotReloadEnabled": true
|
"hotReloadEnabled": true
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user