コード例 #1
0
 async void OnJudgerStatusUpdateMessage(string clientId, ClientStatusMsg msg)
 {
     using (await queueLock.LockAsync()) {
         // should we dispatch a new job for this judger?
         var remainingDispatches = msg.RequestForNewTask;
         using (await connectionLock.LockAsync()) {
             if (connections.TryGetValue(clientId, out var conn))
             {
                 conn.CanAcceptNewTask = msg.CanAcceptNewTask;
                 conn.ActiveTaskCount  = msg.ActiveTaskCount;
                 while (remainingDispatches > 0)
                 {
                     if (await TryDispatchJobFromDatabase(conn))
                     {
                         remainingDispatches--;
                     }
                     else
                     {
                         break;
                     }
                 }
             }
         }
         for (ulong i = 0; i < remainingDispatches; i++)
         {
             JudgerQueue.AddLast(clientId);
         }
         logger.LogInformation("Status::Judger: {0}", DEBUG_LogEnumerator(JudgerQueue));
     }
 }
コード例 #2
0
 private async Task <Judger?> TryGetNextUsableJudger(bool blockNewTasks)
 {
     using (await connectionLock.LockAsync()) {
         while (JudgerQueue.First != null)
         {
             var nextJudger = JudgerQueue.First;
             JudgerQueue.RemoveFirst();
             if (connections.TryGetValue(nextJudger.Value, out var conn))
             {
                 if (conn.CanAcceptNewTask)
                 {
                     // Change the status to false, until the judger reports
                     // it can accept new tasks again
                     conn.CanAcceptNewTask &= !blockNewTasks;
                     return(conn);
                 }
             }
         }
     }
     return(null);
 }
コード例 #3
0
        // readonly HashSet<string> vacantJudgers = new HashSet<string>();

        /// <summary>
        /// Try to use the provided HTTP connection to create a WebSocket connection
        /// between coordinator and judger.
        /// </summary>
        /// <param name="ctx">
        ///     The provided connection. Must be upgradable into websocket.
        /// </param>
        /// <returns>
        ///     True if the websocket connection was made.
        /// </returns>
        public async ValueTask <bool> TryUseConnection(HttpContext ctx)
        {
            if (ctx.Request.Query.TryGetValue("token", out var auth))
            {
                var tokenEntry = await Authenticate(auth);

                if (tokenEntry != null)
                {
                    // A connection id is passed to ensure that the client can safely
                    // replace a previous unfinished connection created by itself.
                    ctx.Request.Query.TryGetValue("conn", out var connId_);
                    var connId = connId_.FirstOrDefault();

                    var connLock = await connectionLock.LockAsync();

                    if (connections.TryGetValue(auth, out var lastConn))
                    {
                        if (lastConn.ConnectionId != null && connId != null && lastConn.ConnectionId == connId)
                        {
                            // replace this session
                            await lastConn.Socket.Close(System.Net.WebSockets.WebSocketCloseStatus.PolicyViolation, "Duplicate connection", CancellationToken.None);

                            connections.Remove(auth);
                        }
                        else
                        {
                            ctx.Response.StatusCode = StatusCodes.Status409Conflict;
                            connLock.Dispose();
                            return(false);
                        }
                    }
                    connLock.Dispose();

                    var ws = await ctx.WebSockets.AcceptWebSocketAsync();

                    var wrapper = new JudgerWebsocketWrapperTy(
                        ws,
                        jsonSerializerOptions,
                        4096);
                    var judger = new Judger(auth, tokenEntry, wrapper, connId);
                    {
                        using var _ = await connectionLock.LockAsync();

                        connections.Add(auth, judger);
                    }
                    logger.LogInformation($"Connected to judger {auth}");

                    /*
                     * Note:
                     *
                     * We do not add judger to judger queue upon creation,
                     * although it should be available. On the contrary, we rely
                     * on the judger to send a ClientStatusMessage to declare it
                     * is ready, and add it to queue at that time.
                     */

                    try {
                        using (var conn = judger.Socket.Messages.Connect())
                            using (var subscription = AssignObservables(auth, judger.Socket)) {
                                await wrapper.WaitUntilClose();
                            }
                    } catch (Exception e) {
                        logger.LogError(e, $"Aborted connection to judger {auth}");
                    }
                    logger.LogInformation($"Disconnected from judger {auth}");
                    {
                        using var __ = await queueLock.LockAsync();

                        if (JudgerQueue.First != null)
                        {
                            var curr = JudgerQueue.First;
                            while (curr != null)
                            {
                                if (curr.Value == auth)
                                {
                                    JudgerQueue.Remove(curr);
                                }
                                curr = curr.Next;
                            }
                        }
                    }
                    {
                        using var _ = await connectionLock.LockAsync();

                        connections.Remove(auth);
                    }
                    return(true);
                }
                else
                {
                    ctx.Response.StatusCode = 401; // unauthorized
                }
            }
            else
            {
                ctx.Response.StatusCode = 401; // unauthorized
            }
            return(false);
        }
コード例 #4
0
        // readonly HashSet<string> vacantJudgers = new HashSet<string>();

        /// <summary>
        /// Try to use the provided HTTP connection to create a WebSocket connection
        /// between coordinator and judger.
        /// </summary>
        /// <param name="ctx">
        ///     The provided connection. Must be upgradable into websocket.
        /// </param>
        /// <returns>
        ///     True if the websocket connection was made.
        /// </returns>
        public async ValueTask <bool> TryUseConnection(Microsoft.AspNetCore.Http.HttpContext ctx)
        {
            if (ctx.Request.Query.TryGetValue("token", out var auth))
            {
                var tokenEntry = await Authenticate(auth);

                if (tokenEntry != null)
                {
                    var ws = await ctx.WebSockets.AcceptWebSocketAsync();

                    var wrapper = new JudgerWebsocketWrapperTy(
                        ws,
                        jsonSerializerOptions,
                        4096,
                        wsLogger);
                    var judger = new Judger(auth, tokenEntry, wrapper);
                    {
                        using var _ = await connectionLock.LockAsync();

                        connections.Add(auth, judger);
                    }
                    logger.LogInformation($"Connected to judger {auth}");

                    /*
                     * Note:
                     *
                     * We do not add judger to judger queue upon creation,
                     * although it should be available. On the contrary, we rely
                     * on the judger to send a ClientStatusMessage to declare it
                     * is ready, and add it to queue at that time.
                     */

                    try {
                        using (var conn = judger.Socket.Messages.Connect())
                            using (var subscription = AssignObservables(auth, judger.Socket)) {
                                await wrapper.WaitUntilClose();
                            }
                    } catch (Exception e) {
                        logger.LogError(e, $"Aborted connection to judger {auth}");
                    }
                    logger.LogInformation($"Disconnected from judger {auth}");
                    {
                        using var __ = await queueLock.LockAsync();

                        if (JudgerQueue.First != null)
                        {
                            var curr = JudgerQueue.First;
                            while (curr != null)
                            {
                                if (curr.Value == auth)
                                {
                                    JudgerQueue.Remove(curr);
                                }
                                curr = curr.Next;
                            }
                        }
                    }
                    {
                        using var _ = await connectionLock.LockAsync();

                        connections.Remove(auth);
                    }
                    return(true);
                }
                else
                {
                    ctx.Response.StatusCode = 401; // unauthorized
                }
            }
            else
            {
                ctx.Response.StatusCode = 401; // unauthorized
            }
            return(false);
        }