Merge branch 'master' of ssh://git.swordlost.top:222/SikongJueluo/FPGA_WebLab into dpp
This commit is contained in:
		@@ -95,6 +95,12 @@ try
 | 
			
		||||
            .AllowAnyMethod()
 | 
			
		||||
            .AllowAnyHeader()
 | 
			
		||||
        );
 | 
			
		||||
        options.AddPolicy("SignalR", policy => policy
 | 
			
		||||
            .WithOrigins("http://localhost:5173")
 | 
			
		||||
            .AllowAnyHeader()
 | 
			
		||||
            .AllowAnyMethod()
 | 
			
		||||
            .AllowCredentials()
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Use SignalR
 | 
			
		||||
@@ -201,12 +207,15 @@ try
 | 
			
		||||
        };
 | 
			
		||||
    });
 | 
			
		||||
    app.UseSwaggerUi();
 | 
			
		||||
 | 
			
		||||
    // SignalR
 | 
			
		||||
    app.UseWebSockets();
 | 
			
		||||
    app.UseSignalRHubSpecification();
 | 
			
		||||
    app.UseSignalRHubDevelopmentUI();
 | 
			
		||||
 | 
			
		||||
    // Router
 | 
			
		||||
    app.MapControllers();
 | 
			
		||||
    app.MapHub<server.Hubs.JtagHub.JtagHub>("hubs/JtagHub").RequireCors("Users");
 | 
			
		||||
    app.MapHub<server.Hubs.JtagHub.JtagHub>("hubs/JtagHub");
 | 
			
		||||
 | 
			
		||||
    // Setup Program
 | 
			
		||||
    MsgBus.Init();
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,19 @@ public interface IJtagReceiver
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[Authorize]
 | 
			
		||||
[EnableCors("Users")]
 | 
			
		||||
[EnableCors("SignalR")]
 | 
			
		||||
public class JtagHub : Hub<IJtagReceiver>, IJtagHub
 | 
			
		||||
{
 | 
			
		||||
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
			
		||||
    private ConcurrentDictionary<string, int> FreqTable = new();
 | 
			
		||||
    private ConcurrentDictionary<string, CancellationTokenSource> CancellationTokenSourceTable = new();
 | 
			
		||||
    private static ConcurrentDictionary<string, int> FreqTable = new();
 | 
			
		||||
    private static ConcurrentDictionary<string, CancellationTokenSource> CancellationTokenSourceTable = new();
 | 
			
		||||
 | 
			
		||||
    private readonly IHubContext<JtagHub, IJtagReceiver> _hubContext;
 | 
			
		||||
 | 
			
		||||
    public JtagHub(IHubContext<JtagHub, IJtagReceiver> hubContext)
 | 
			
		||||
    {
 | 
			
		||||
        _hubContext = hubContext;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Optional<Peripherals.JtagClient.Jtag> GetJtagClient(string userName)
 | 
			
		||||
    {
 | 
			
		||||
@@ -92,33 +99,40 @@ public class JtagHub : Hub<IJtagReceiver>, IJtagHub
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await SetBoundaryScanFreq(freq);
 | 
			
		||||
            var cts = CancellationTokenSource.CreateLinkedTokenSource();
 | 
			
		||||
            var cts = new CancellationTokenSource();
 | 
			
		||||
            CancellationTokenSourceTable.AddOrUpdate(userName, cts, (key, value) => cts);
 | 
			
		||||
 | 
			
		||||
            _ = Task
 | 
			
		||||
                .Run(
 | 
			
		||||
                    () => BoundaryScanLogicPorts(
 | 
			
		||||
                        Context.ConnectionId,
 | 
			
		||||
                        userName,
 | 
			
		||||
                        cts.Token),
 | 
			
		||||
            _ = Task.Run(
 | 
			
		||||
                    () => BoundaryScanLogicPorts(Context.ConnectionId, userName, cts.Token),
 | 
			
		||||
                    cts.Token)
 | 
			
		||||
                .ContinueWith((task) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (!task.IsFaulted)
 | 
			
		||||
                    if (task.IsFaulted)
 | 
			
		||||
                    {
 | 
			
		||||
                        return;
 | 
			
		||||
                        // 遍历所有异常
 | 
			
		||||
                        foreach (var ex in task.Exception.InnerExceptions)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (ex is OperationCanceledException)
 | 
			
		||||
                            {
 | 
			
		||||
                                logger.Info($"Boundary scan operation cancelled for user {userName}");
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                logger.Error($"Boundary scan operation failed for user {userName}: {ex}");
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (task.Exception.InnerException is OperationCanceledException)
 | 
			
		||||
                    else if (task.IsCanceled)
 | 
			
		||||
                    {
 | 
			
		||||
                        logger.Info($"Boundary scan operation cancelled for user {userName}");
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        logger.Error(task.Exception);
 | 
			
		||||
                        logger.Info($"Boundary scan completed successfully for user {userName}");
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            logger.Info($"Boundary scan started for user {userName}");
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception error)
 | 
			
		||||
@@ -144,10 +158,12 @@ public class JtagHub : Hub<IJtagReceiver>, IJtagHub
 | 
			
		||||
 | 
			
		||||
        cts.Cancel();
 | 
			
		||||
        cts.Token.WaitHandle.WaitOne();
 | 
			
		||||
 | 
			
		||||
        logger.Info($"Boundary scan stopped for user {userName}");
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async void BoundaryScanLogicPorts(string connectionID, string userName, CancellationToken cancellationToken)
 | 
			
		||||
    private async Task BoundaryScanLogicPorts(string connectionID, string userName, CancellationToken cancellationToken)
 | 
			
		||||
    {
 | 
			
		||||
        var jtagCtrl = GetJtagClient(userName).OrThrow(() => new InvalidOperationException("JTAG client not found"));
 | 
			
		||||
        var cntFail = 0;
 | 
			
		||||
@@ -161,9 +177,10 @@ public class JtagHub : Hub<IJtagReceiver>, IJtagHub
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"User {userName} boundary scan failed for device {jtagCtrl.address}: {ret.Error}");
 | 
			
		||||
                cntFail++;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await this.Clients.Client(connectionID).OnReceiveBoundaryScanData(ret.Value);
 | 
			
		||||
            await _hubContext.Clients.Client(connectionID).OnReceiveBoundaryScanData(ret.Value);
 | 
			
		||||
            // logger.Info($"User {userName} successfully completed boundary scan for device {jtagCtrl.address}");
 | 
			
		||||
 | 
			
		||||
            await Task.Delay(FreqTable.TryGetValue(userName, out var freq) ? 1000 / freq : 1000 / 100, cancellationToken);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import { ref, reactive, watchPostEffect, onMounted, onUnmounted } from "vue";
 | 
			
		||||
import { defineStore } from "pinia";
 | 
			
		||||
import { useLocalStorage } from "@vueuse/core";
 | 
			
		||||
import { isString, toNumber, type Dictionary } from "lodash";
 | 
			
		||||
import { isString, toNumber, isUndefined, type Dictionary } from "lodash";
 | 
			
		||||
import z from "zod";
 | 
			
		||||
import { isNumber } from "mathjs";
 | 
			
		||||
import { Mutex, withTimeout } from "async-mutex";
 | 
			
		||||
@@ -9,9 +9,10 @@ import { useConstraintsStore } from "@/stores/constraints";
 | 
			
		||||
import { useDialogStore } from "./dialog";
 | 
			
		||||
import { toFileParameterOrUndefined } from "@/utils/Common";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
import { HubConnectionBuilder } from "@microsoft/signalr";
 | 
			
		||||
import { HubConnection, HubConnectionBuilder } from "@microsoft/signalr";
 | 
			
		||||
import { getHubProxyFactory, getReceiverRegister } from "@/TypedSignalR.Client";
 | 
			
		||||
import type { ResourceInfo } from "@/APIClient";
 | 
			
		||||
import type { IJtagHub } from "@/TypedSignalR.Client/server.Hubs.JtagHub";
 | 
			
		||||
 | 
			
		||||
export const useEquipments = defineStore("equipments", () => {
 | 
			
		||||
  // Global Stores
 | 
			
		||||
@@ -30,22 +31,32 @@ export const useEquipments = defineStore("equipments", () => {
 | 
			
		||||
    1000,
 | 
			
		||||
    new Error("JtagClient Mutex Timeout!"),
 | 
			
		||||
  );
 | 
			
		||||
  const jtagHubConnection = new HubConnectionBuilder()
 | 
			
		||||
    .withUrl("http://localhost:5000/hubs/JtagHub")
 | 
			
		||||
    .withAutomaticReconnect()
 | 
			
		||||
    .build();
 | 
			
		||||
  const jtagHubProxy =
 | 
			
		||||
    getHubProxyFactory("IJtagHub").createHubProxy(jtagHubConnection);
 | 
			
		||||
  const jtagHubSubscription = getReceiverRegister("IJtagReceiver").register(
 | 
			
		||||
    jtagHubConnection,
 | 
			
		||||
    {
 | 
			
		||||
  const jtagHubConnection = ref<HubConnection>();
 | 
			
		||||
  const jtagHubProxy = ref<IJtagHub>();
 | 
			
		||||
 | 
			
		||||
  onMounted(async () => {
 | 
			
		||||
    // 每次挂载都重新创建连接
 | 
			
		||||
    jtagHubConnection.value =
 | 
			
		||||
      AuthManager.createAuthenticatedJtagHubConnection();
 | 
			
		||||
    jtagHubProxy.value = getHubProxyFactory("IJtagHub").createHubProxy(
 | 
			
		||||
      jtagHubConnection.value,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    getReceiverRegister("IJtagReceiver").register(jtagHubConnection.value, {
 | 
			
		||||
      onReceiveBoundaryScanData: async (msg) => {
 | 
			
		||||
        constrainsts.batchSetConstraintStates(msg);
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
  onMounted(() => {
 | 
			
		||||
    });
 | 
			
		||||
    await jtagHubConnection.value.start();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  onUnmounted(() => {
 | 
			
		||||
    // 断开连接,清理资源
 | 
			
		||||
    if (jtagHubConnection.value) {
 | 
			
		||||
      jtagHubConnection.value.stop();
 | 
			
		||||
      jtagHubConnection.value = undefined;
 | 
			
		||||
      jtagHubProxy.value = undefined;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // Matrix Key
 | 
			
		||||
@@ -89,13 +100,27 @@ export const useEquipments = defineStore("equipments", () => {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function jtagBoundaryScanSetOnOff(enable: boolean) {
 | 
			
		||||
    jtagHubConnection.start();
 | 
			
		||||
    enableJtagBoundaryScan.value = enable;
 | 
			
		||||
    if (enable) {
 | 
			
		||||
      jtagHubProxy.startBoundaryScan(jtagBoundaryScanFreq.value);
 | 
			
		||||
    } else {
 | 
			
		||||
      jtagHubProxy.stopBoundaryScan();
 | 
			
		||||
    if (isUndefined(jtagHubProxy.value)) {
 | 
			
		||||
      console.error("JtagHub Not Initialize...");
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (enable) {
 | 
			
		||||
      const ret = await jtagHubProxy.value.startBoundaryScan(
 | 
			
		||||
        jtagBoundaryScanFreq.value,
 | 
			
		||||
      );
 | 
			
		||||
      if (!ret) {
 | 
			
		||||
        console.error("Failed to start boundary scan");
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      const ret = await jtagHubProxy.value.stopBoundaryScan();
 | 
			
		||||
      if (!ret) {
 | 
			
		||||
        console.error("Failed to stop boundary scan");
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    enableJtagBoundaryScan.value = enable;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function jtagUploadBitstream(bitstream: File, examId?: string): Promise<number | null> {
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,10 @@ import {
 | 
			
		||||
  ExamClient,
 | 
			
		||||
  ResourceClient,
 | 
			
		||||
} from "@/APIClient";
 | 
			
		||||
import router from "@/router";
 | 
			
		||||
import { HubConnectionBuilder } from "@microsoft/signalr";
 | 
			
		||||
import axios, { type AxiosInstance } from "axios";
 | 
			
		||||
import { isNull } from "lodash";
 | 
			
		||||
 | 
			
		||||
// 支持的客户端类型联合类型
 | 
			
		||||
type SupportedClient =
 | 
			
		||||
@@ -119,7 +122,7 @@ export class AuthManager {
 | 
			
		||||
    if (!token) return null;
 | 
			
		||||
 | 
			
		||||
    const instance = axios.create();
 | 
			
		||||
    instance.interceptors.request.use(config => {
 | 
			
		||||
    instance.interceptors.request.use((config) => {
 | 
			
		||||
      config.headers = config.headers || {};
 | 
			
		||||
      (config.headers as any)["Authorization"] = `Bearer ${token}`;
 | 
			
		||||
      return config;
 | 
			
		||||
@@ -185,11 +188,11 @@ export class AuthManager {
 | 
			
		||||
  public static createAuthenticatedNetConfigClient(): NetConfigClient {
 | 
			
		||||
    return AuthManager.createAuthenticatedClient(NetConfigClient);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  public static createAuthenticatedOscilloscopeApiClient(): OscilloscopeApiClient {
 | 
			
		||||
    return AuthManager.createAuthenticatedClient(OscilloscopeApiClient);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
  public static createAuthenticatedDebuggerClient(): DebuggerClient {
 | 
			
		||||
    return AuthManager.createAuthenticatedClient(DebuggerClient);
 | 
			
		||||
  }
 | 
			
		||||
@@ -201,6 +204,21 @@ export class AuthManager {
 | 
			
		||||
  public static createAuthenticatedResourceClient(): ResourceClient {
 | 
			
		||||
    return AuthManager.createAuthenticatedClient(ResourceClient);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  public static createAuthenticatedJtagHubConnection() {
 | 
			
		||||
    const token = this.getToken();
 | 
			
		||||
    if (isNull(token)) {
 | 
			
		||||
      router.push("/login");
 | 
			
		||||
      throw Error("Token Null!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return new HubConnectionBuilder()
 | 
			
		||||
      .withUrl("http://127.0.0.1:5000/hubs/JtagHub", {
 | 
			
		||||
        accessTokenFactory: () => token,
 | 
			
		||||
      })
 | 
			
		||||
      .withAutomaticReconnect()
 | 
			
		||||
      .build();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 登录函数
 | 
			
		||||
  public static async login(
 | 
			
		||||
 
 | 
			
		||||
@@ -53,10 +53,6 @@ export default defineConfig({
 | 
			
		||||
        target: "http://localhost:5000",
 | 
			
		||||
        changeOrigin: true,
 | 
			
		||||
      },
 | 
			
		||||
      "/hubs": {
 | 
			
		||||
        target: "http://localhost:5000",
 | 
			
		||||
        changeOrigin: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    port: 5173,
 | 
			
		||||
  },
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user