diff --git a/openapi-docs/SpinApi.yaml b/openapi-docs/SpinApi.yaml index 5abe5ba..fcb478a 100644 --- a/openapi-docs/SpinApi.yaml +++ b/openapi-docs/SpinApi.yaml @@ -1,177 +1,249 @@ -openapi: "3.1.0" +openapi: 3.0.1 info: - title: "SlotsEngine API" - description: "SlotsEngine API" - version: "1.0.0" + title: OpenAPI definition + version: v0 servers: - - url: "https://SlotsEngine" + - url: http://localhost:8080 + description: Generated server url +tags: + - name: rest-api-controller + description: |- + The ApiController class is responsible for handling API requests related to a slot machine application. + It provides endpoints for retrieving server version information, loading the slot machine state, + performing spin operations, and managing the user's balance through deposit and withdrawal actions. + Each method is mapped to a specific HTTP request type and URL path, enabling interaction with the slot machine. +
+ The controller ensures that each endpoint is appropriately logged and handles exceptions that may occur + during operations, such as insufficient funds for a spin or withdrawal. +
+ The class leverages a SlotMachine instance to perform the core operations and depends on configuration
+ values for versioning information.
paths:
- /api:
- get:
- summary: "GET api"
- operationId: "indexAction"
- responses:
- "200":
- description: "OK"
- content:
- '*/*':
- schema:
- $ref: "#/components/schemas/ServerVersionMessage"
- /api/load:
- get:
- summary: "GET api/load"
- operationId: "load"
- responses:
- "200":
- description: "OK"
- content:
- '*/*':
- schema:
- $ref: "#/components/schemas/MachineStateMessage"
- /api/machine-stats:
- get:
- summary: "GET api/machine-stats"
- operationId: "getMachineStats"
+ /api/withdraw/{amount}:
+ post:
+ tags:
+ - rest-api-controller
+ summary: Handles the HTTP request to withdraw a specified amount from the slot
+ machine's balance.
+ description: Handles the HTTP request to withdraw a specified amount from the
+ slot machine's balance.
+ operationId: withdraw
+ parameters:
+ - name: amount
+ in: path
+ description: the amount to withdraw from the balance. Must be a positive Long
+ value.
+ required: true
+ schema:
+ type: integer
+ format: int64
responses:
"200":
- description: "OK"
+ description: "a {@link BalanceMessage BalanceMessage} object containing\
+ \ the updated balance after the withdrawal."
content:
'*/*':
schema:
- $ref: "#/components/schemas/MachineStatsMessage"
+ $ref: "#/components/schemas/BalanceMessage"
/api/spin/{amount}:
post:
- summary: "POST api/spin/{amount}"
- operationId: "spin"
+ tags:
+ - rest-api-controller
+ summary: Initiates a spin operation on the slot machine for the specified bet
+ amount.
+ description: Initiates a spin operation on the slot machine for the specified
+ bet amount.
+ operationId: spin
parameters:
- - name: "amount"
- in: "path"
+ - name: amount
+ in: path
+ description: the amount to bet on the spin.
required: true
schema:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
responses:
"200":
- description: "OK"
+ description: |-
+ a {@link BetResultMessage BetResultMessage} object containing the timestamp, bet amount, win amount,
+ balance after the spin, and the resulting symbol from the spin.
content:
'*/*':
schema:
$ref: "#/components/schemas/BetResultMessage"
/api/deposit/{amount}:
post:
- summary: "POST api/deposit/{amount}"
- operationId: "deposit"
+ tags:
+ - rest-api-controller
+ summary: Handles the HTTP request to deposit a specified amount into the slot
+ machine.
+ description: Handles the HTTP request to deposit a specified amount into the
+ slot machine.
+ operationId: deposit
parameters:
- - name: "amount"
- in: "path"
+ - name: amount
+ in: path
+ description: a positive Long value representing the amount to deposit.
required: true
schema:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
responses:
"200":
- description: "OK"
+ description: "a {@link BalanceMessage BalanceMessage} object containing\
+ \ the updated balance after the deposit."
content:
'*/*':
schema:
$ref: "#/components/schemas/BalanceMessage"
- /api/withdraw/{amount}:
- post:
- summary: "POST api/withdraw/{amount}"
- operationId: "withdraw"
- parameters:
- - name: "amount"
- in: "path"
- required: true
- schema:
- type: "integer"
- format: "int64"
+ /api:
+ get:
+ tags:
+ - rest-api-controller
+ summary: Handles the HTTP GET request for the root API endpoint and provides
+ the server version information.
+ description: Handles the HTTP GET request for the root API endpoint and provides
+ the server version information.
+ operationId: indexAction
responses:
"200":
- description: "OK"
+ description: "a {@link ServerVersionMessage ServerVersionMessage} object\
+ \ containing the current version of the application."
content:
'*/*':
schema:
- $ref: "#/components/schemas/BalanceMessage"
+ $ref: "#/components/schemas/ServerVersionMessage"
+ /api/machine-stats:
+ get:
+ tags:
+ - rest-api-controller
+ summary: "Retrieves the current machine statistics, including the timestamp,\
+ \ bet statistics, and win statistics."
+ description: "Retrieves the current machine statistics, including the timestamp,\
+ \ bet statistics, and win statistics."
+ operationId: getMachineStats
+ responses:
+ "200":
+ description: "a MachineStatsMessage object containing the current timestamp,\
+ \ bet statistics, and win statistics."
+ content:
+ '*/*':
+ schema:
+ $ref: "#/components/schemas/SpinStatsMessage"
+ /api/load:
+ get:
+ tags:
+ - rest-api-controller
+ summary: Handles the HTTP GET request for loading the current state of the slot
+ machine.
+ description: Handles the HTTP GET request for loading the current state of the
+ slot machine.
+ operationId: load
+ responses:
+ "200":
+ description: |-
+ a {@link StateMessage StateMessage} object containing the current timestamp,
+ machine's return to player (RTP), bet amount, win amount, balance, and result.
+ content:
+ '*/*':
+ schema:
+ $ref: "#/components/schemas/StateMessage"
components:
schemas:
- ServerVersionMessage:
- type: "object"
+ BalanceMessage:
+ type: object
properties:
- version:
- type: "string"
- MachineStateMessage:
- type: "object"
+ balance:
+ type: integer
+ format: int64
+ BetResultMessage:
+ type: object
properties:
- version:
- type: "string"
timestampMs:
- type: "integer"
- format: "int64"
- rtp:
- type: "number"
- format: "double"
+ type: integer
+ format: int64
betAmount:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
winAmount:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
balance:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
result:
- type: "integer"
- format: "int32"
- LongSummaryStatistics:
- type: "object"
+ type: integer
+ format: int32
+ ServerVersionMessage:
+ type: object
properties:
- count:
- type: "integer"
- format: "int64"
- sum:
- type: "integer"
- format: "int64"
- min:
- type: "integer"
- format: "int64"
- max:
- type: "integer"
- format: "int64"
- MachineStatsMessage:
- type: "object"
+ version:
+ type: string
+ SpinStatsMessage:
+ type: object
properties:
timestampMs:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
rtp:
- type: "number"
- format: "double"
+ type: number
+ format: double
betStats:
- $ref: "#/components/schemas/LongSummaryStatistics"
+ type: object
+ properties:
+ count:
+ type: integer
+ format: int64
+ sum:
+ type: integer
+ format: int64
+ min:
+ type: integer
+ format: int64
+ max:
+ type: integer
+ format: int64
+ average:
+ type: number
+ format: double
winStats:
- $ref: "#/components/schemas/LongSummaryStatistics"
- BetResultMessage:
- type: "object"
+ type: object
+ properties:
+ count:
+ type: integer
+ format: int64
+ sum:
+ type: integer
+ format: int64
+ min:
+ type: integer
+ format: int64
+ max:
+ type: integer
+ format: int64
+ average:
+ type: number
+ format: double
+ StateMessage:
+ type: object
properties:
+ version:
+ type: string
timestampMs:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
+ rtp:
+ type: number
+ format: double
betAmount:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
winAmount:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
balance:
- type: "integer"
- format: "int64"
+ type: integer
+ format: int64
result:
- type: "integer"
- format: "int32"
- BalanceMessage:
- type: "object"
- properties:
- balance:
- type: "integer"
- format: "int64"
\ No newline at end of file
+ type: integer
+ format: int32
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0376eda..4d7a3eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
Balance: 100 credits
⇛7⇚
+ ⇛7⇚
${prettyNumber(state.betAmount)} ${prettyNumber(state.winAmount)} ${state.result} ` + `${isWin() ? 'Win' : 'Loss'} `;
+ const newRow = document.createElement("tr");
+ newRow.innerHTML = `${prettyNumber(state.betAmount)}
+${prettyNumber(state.winAmount)}
+${state.result} `;
+ newRow.innerHTML += `
+${isWin() ? "Win" : "Loss"} `;
tabBody.prepend(newRow);
- lblDisplay.style.color = isWin() ? 'green' : 'red';
-
if (isWin() > 0) {
- setStatusLabel('WIN', prettyNumber(state.winAmount), 'text-bg-success');
+ setStatusLabel("WIN", prettyNumber(state.winAmount), "text-bg-success");
+ blkDisplay.className = "animate-spin-win";
} else {
- setStatusLabel('LOSS', prettyNumber(state.betAmount), 'text-bg-danger');
+ setStatusLabel("LOSS", prettyNumber(state.betAmount), "text-bg-danger");
+ blkDisplay.className = "animate-spin-loss";
}
+ setButtonsState(false);
+ btnSpin.disabled = machineState.betAmount > machineState.balance;
setTimeout(refreshStats, 0);
}
function spin() {
setButtonsState(true);
- lblDisplay.style.color = 'orange';
- let betAmount = machineState.betAmount;
- setStatusLabel('Spin', prettyNumber(machineState.betAmount), 'text-bg-warning');
+ blkDisplay.className = "animate-spin";
+ const betAmount = machineState.betAmount;
+ setStatusLabel("Spin", prettyNumber(machineState.betAmount), "text-bg-warning");
let count = 0;
- let animateDisplay = setInterval(() => {
+ const animateDisplay = setInterval(() => {
if (count++ < 7) {
lblDisplay.innerText = Math.floor(Math.random() * 10).toFixed(0);
} else {
- sendCall(data => {
+ sendCall((data) => {
clearInterval(animateDisplay);
updateMachineState(data);
}, `/api/spin/${betAmount}`, {
- method: 'POST'
+ method: "POST",
}).then();
}
}, 47);
}
function calcBetValues() {
- let tb = document.getElementById('payoutTable');
- let body = tb.getElementsByTagName("tbody")[0];
- let rows = body.getElementsByTagName("tr");
- for (let i = 0; i < rows.length; i++) {
- let cells = rows[i].getElementsByTagName("td");
- let value = cells[1];
+ let i;
+ for (i = 0; i < rows.length; i++) {
+ const cells = rows[i].getElementsByTagName("td");
+ const value = cells[1];
value.innerText = prettyNumber(((i >= 10) ? 100 : i) * machineState.betAmount);
}
-
}
function bindListeners() {
- btnDeposit.addEventListener('click', () => {
- let value = window.prompt("Enter deposit amount", "1000");
- sendCall(data => {
+ btnDeposit.addEventListener("click", () => {
+ const value = window.prompt("Enter deposit amount", "1000");
+ sendCall((data) => {
lblBalanceAmount.innerText = data.balance;
machineState.balance = data.balance;
btnSpin.disabled = machineState.betAmount > machineState.balance;
- }, '/api/deposit/' + value, {
- method: 'POST'
+ }, "/api/deposit/" + value, {
+ method: "POST",
}).then();
});
- btnWithdraw.addEventListener('click', () => {
- let value = window.prompt("Enter withdrawal amount", "1000");
- sendCall(data => {
+ btnWithdraw.addEventListener("click", () => {
+ const value = window.prompt("Enter withdrawal amount", "1000");
+ sendCall((data) => {
lblBalanceAmount.innerText = data.balance;
machineState.balance = data.balance;
btnSpin.disabled = machineState.betAmount > machineState.balance;
- }, '/api/withdraw/' + value, {
- method: 'POST'
+ }, "/api/withdraw/" + value, {
+ method: "POST",
}).then();
});
- btnSpin.addEventListener('click', () => {
+ btnSpin.addEventListener("click", () => {
spin();
});
- btnIncBet.addEventListener('click', () => {
+ btnIncBet.addEventListener("click", () => {
betPos = Math.min((betPos + 1), betRange.length - 1);
machineState.betAmount = betRange[betPos];
lblBetAmount.innerText = prettyNumber(machineState.betAmount);
@@ -190,23 +194,25 @@
btnSpin.disabled = machineState.betAmount > machineState.balance;
});
- btnDecBet.addEventListener('click', () => {
+ btnDecBet.addEventListener("click", () => {
betPos = Math.max((betPos - 1), 0);
machineState.betAmount = betRange[betPos];
lblBetAmount.innerText = prettyNumber(machineState.betAmount);
calcBetValues();
- btnSpin.disabled = !(machineState.balance > machineState.betAmount);
+ const isEnabled = (machineState.balance > machineState.betAmount);
+ /* This needs negation for the correct behaviour */
+ btnSpin.disabled = !isEnabled;
});
- document.addEventListener('keydown', (e) => {
+ document.addEventListener("keydown", (e) => {
switch (e.key) {
- case 's':
+ case "s":
btnSpin.click();
break;
- case 'a':
+ case "a":
btnIncBet.click();
break;
- case 'd':
+ case "d":
btnDecBet.click();
break;
}