-
Notifications
You must be signed in to change notification settings - Fork 24
WTI API Scoreboard Implementation
The PC² Web Team Interface (consisting of the WTI-API and WTI-UI projects) did not originally include a scoreboard (that is, there was no way in the original WTI project for teams to view the current contest standings). A subsequent effort added a Scoreboard link to the WTI-UI team interface, along with adding support for obtaining the current contest standings via the WTI-API.
The overall architecture of the Scoreboard component of the WTI-API portion of the WTI project is shown in the following diagram, whose elements are then described in the following sections. It may be helpful to compare the following diagram with the one at WTI-API Implementation, as both diagrams show different but related parts of the WTI-API implementation.
Note that the following diagram shows only the WTI-API portion of the Scoreboard implementation, which does not, by itself, actually display any scoreboard; rather, it provides infrastructure connecting the WTI-UI user-interface side to the PC² system, allowing the WTI-UI to display scoreboard information. See WTI UI Scoreboard Implementation for details regarding the UI side of the scoreboard implementation.
The ContestController
class (see also WTI-API Architecture) contains a static initialization block which, among other things, creates a PC2v9 API ServerConnection
and uses that object to login to the PC² server using a special WTI scoreboard login account. (The specific PC² account used for this scoreboard login is configurable via the WTI-API pc2v9.ini
file; if not configured it defaults to account scoreboard2
using password scoreboard2
.)
Once the WTI-API is successfully logged in to the PC² server scoreboard account, the ContestController
constructor creates an instance of class ScoreboardChangeListener
and adds it as a listener to the Contest object contained within the scoreboard ServerConnection
. (Note that the contest object within the ServerConnection
, which is the contest model, gets updated by the PC² server whenever any change in contest status occurs). The ScoreboardChangeListener
thus receives a callback whenever a contest event occurs which could (potentially) change the standings. Such events include run submissions (because new submissions are reflected on scoreboards as "pending"); changes in submission state (such as being judged, updated, or marked "deleted"); and changes in contest configuration items (such as a problem being deleted, a team being removed from or added to the scoreboard, or other similar configuration changes).
The WTI-API specification includes an endpoint /api/contest/scoreboard which can be invoked by clients to obtain current scoreboard standings information. Client references to this endpoint are forwarded by the Jetty server to the ContestController.getStandings()
method.
The single authoritative source for computing current contest standings in a PC² system is the class core.scoring.DefaultScoringAlgorithm
. The WTI-API ContestController
static initialization block creates an instance of DefaultScoringAlgorithm
when it first gets loaded during WTI-API startup; this instance is used by the /scoreboard endpoint (method ContestController.getStandings()
) to obtain updated standings whenever they are needed.
The DefaultScoringAlgorithm
instance is set to obey freeze mode, meaning it will (only) return results which respect any configured "scoreboard freeze period". The call to DefaultScoringAlgorithm.getStandings()
is protected by a synchronized
block to insure that at most one client at a time can generate updated standings.
Current standings are cached by both the WTI-API (server-side) and the WTI-UI (client-side) code, and both sides maintain flags indicating whether their cached copies are "current"; these flags are cleared whenever an event occurs which (potentially) changes the standings -- that is, whenever the ContestController
s ScoreboardChangeListener
receives a "potential-standings-change-event" callback.
When such a callback occurs, the ScoreboardChangeListener
invokes a method markStandingsNotCurrent
in the ContestController
. This method sets the WTI-API ContestController
's standingsAreCurrent flag to false (indicating that the WTI-API cached copy of the standings is no longer current), and then sends a Standings message to the client websocket of every logged-in team. This message causes the WTI-UI client-side browser code for each team to mark it's standings cache as "not current".
When a team clicks on their Scoreboard link the WTI-UI client-side (browser) code checks to see if the client-side cache is current, and if so displays the cached standings without contacting the WTI-API. However, if the client-side cache has been marked "no longer current", the WTI-UI code instead issues an HTTP request to the /scoreboard endpoint on the WTI-API server side, requesting a current copy of the standings.
When the WTI-API gets a client request for standings (because the client has become aware that its cached copy is no longer current), the WTI-API checks its flag to see if its cached standings are current, returning the cached copy if so. If the WTI-API gets a request for standings and its cached copy is not current, it first updates its cache by requesting current standings from its DefaultScoringAlgorithm
instance and then returns the (updated) standings (while also caching them for future use).
Utilizing the above caching scheme minimizes calls to the computationally-expensive DefaultScoringAlgorithm.getStandings()
method: standings are only actually computed if an event which could potentially change the standings has occurred and someone asks for the standings. Note that many consecutive "potentially-standings-changing-events" can occur under this scheme without the standings being constantly recomputed; new standings are calculated only when there has been a change-event and a client subsequently requests updated standings.
Taken together, the above describes how a client can obtain a current copy of the scoreboard standings at any time, using caching to avoid recomputing standings unnecessarily. However, it does not provide direct support for dynamically-updating scoreboards. That is, if a client wishes to show a scoreboard which automatically updates on every scoreboard change, the above by itself would only support this by having the client continually poll to obtain new standings every time some potentially-standings-changing event occurs; there is no direct support for "pushing scoreboard updates" to clients (only for notifying clients that scoreboard standings may have changed), nor for updating standings only when they are actually being viewed. This means clients might waste tremendous amounts of time fetching updated standings even when the user was not actively looking at the current standings.
Circumventing this problem is in essence a client-side issue, and it is solved in the WTI project on the WTI-UI side. See WTI UI Scoreboard Implementation for details on how dynamic scoreboard updates work.