failedDecks = new ArrayList<>();
10 |
11 | public FailedLoadingSomeCardcastDecks() {
12 | }
13 |
14 | public JsonArray getFailedJson() {
15 | JsonArray array = new JsonArray(failedDecks.size());
16 | for (String id : failedDecks) array.add(id);
17 | return array;
18 | }
19 | }
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/BlackCard.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 |
6 | public abstract class BlackCard {
7 |
8 | public abstract int getId();
9 |
10 | public abstract String getText();
11 |
12 | public abstract String getWatermark();
13 |
14 | public abstract int getDraw();
15 |
16 | public abstract int getPick();
17 |
18 | @Override
19 | public final boolean equals(final Object other) {
20 | return other instanceof BlackCard && ((BlackCard) other).getId() == getId();
21 | }
22 |
23 | @Override
24 | public final int hashCode() {
25 | return getId();
26 | }
27 |
28 | public final JsonWrapper getClientDataJson() {
29 | JsonWrapper obj = new JsonWrapper();
30 | obj.add(Consts.GeneralKeys.CARD_ID, getId());
31 | obj.add(Consts.BlackCardData.TEXT, getText());
32 | obj.add(Consts.BlackCardData.DRAW, getDraw());
33 | obj.add(Consts.BlackCardData.PICK, getPick());
34 | obj.add(Consts.BlackCardData.WATERMARK, getWatermark());
35 | return obj;
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | return String.format("%s %s (id:%d, draw:%d, pick:%d, watermark:%s)", getClass().getName(), getText(), getId(), getDraw(), getPick(), getWatermark());
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/BlackDeck.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import com.gianlu.pyxreloaded.game.OutOfCardsException;
4 |
5 | import java.util.*;
6 |
7 |
8 | /**
9 | * Deck of Black Cards.
10 | *
11 | * This class is thread-safe.
12 | *
13 | * @author Andy Janata (ajanata@socialgamer.net)
14 | */
15 | public class BlackDeck {
16 | private final List deck;
17 | private final List discard;
18 |
19 | /**
20 | * Create a new black card deck, loading the cards from the database and shuffling them.
21 | */
22 | public BlackDeck(Collection cardSets) {
23 | Set allCards = new HashSet<>();
24 | for (CardSet cardSet : cardSets) allCards.addAll(cardSet.getBlackCards());
25 | deck = new ArrayList<>(allCards);
26 | Collections.shuffle(deck);
27 | discard = new ArrayList<>(deck.size());
28 | }
29 |
30 | /**
31 | * Get the next card from the top of deck.
32 | *
33 | * @return The next card.
34 | * @throws OutOfCardsException There are no more cards in the deck.
35 | */
36 | public synchronized BlackCard getNextCard() throws OutOfCardsException {
37 | if (deck.size() == 0) throw new OutOfCardsException();
38 | // we have an ArrayList here, so this is faster
39 | return deck.remove(deck.size() - 1);
40 | }
41 |
42 | /**
43 | * Add a card to the discard pile.
44 | *
45 | * @param card Card to add to discard pile.
46 | */
47 | public synchronized void discard(final BlackCard card) {
48 | if (card != null) discard.add(card);
49 | }
50 |
51 | /**
52 | * Shuffles the discard pile and puts the cards under the cards remaining in the deck.
53 | */
54 | public synchronized void reshuffle() {
55 | Collections.shuffle(discard);
56 | deck.addAll(0, discard);
57 | discard.clear();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/BlankWhiteCard.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import org.jetbrains.annotations.Nullable;
4 |
5 | public class BlankWhiteCard extends WhiteCard {
6 | private static final String BLANK_TEXT = "____";
7 | private final int id; // Always negative
8 | private String text = null;
9 |
10 | public BlankWhiteCard(int id) {
11 | this.id = id;
12 | clear();
13 | }
14 |
15 | @Override
16 | public int getId() {
17 | return id;
18 | }
19 |
20 | @Override
21 | @Nullable
22 | public String getText() {
23 | return text;
24 | }
25 |
26 | public void setText(@Nullable String text) {
27 | this.text = text;
28 | }
29 |
30 | public void clear() {
31 | setText(BLANK_TEXT);
32 | }
33 |
34 | @Override
35 | public String getWatermark() {
36 | return "____";
37 | }
38 |
39 | @Override
40 | public boolean isWriteIn() {
41 | return true;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/CardSet.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 |
6 | import java.util.Set;
7 |
8 |
9 | public abstract class CardSet {
10 |
11 | public abstract int getId();
12 |
13 | public abstract String getName();
14 |
15 | public abstract String getDescription();
16 |
17 | public abstract boolean isActive();
18 |
19 | public abstract boolean isBaseDeck();
20 |
21 | public abstract int getWeight();
22 |
23 | public abstract Set extends BlackCard> getBlackCards();
24 |
25 | public abstract Set extends WhiteCard> getWhiteCards();
26 |
27 | public final JsonWrapper getClientMetadataJson() {
28 | JsonWrapper obj = new JsonWrapper();
29 | obj.add(Consts.CardSetData.ID, getId());
30 | obj.add(Consts.CardSetData.CARD_SET_NAME, getName());
31 | obj.add(Consts.CardSetData.CARD_SET_DESCRIPTION, getDescription());
32 | obj.add(Consts.CardSetData.WEIGHT, getWeight());
33 | obj.add(Consts.CardSetData.BASE_DECK, isBaseDeck());
34 | obj.add(Consts.CardSetData.BLACK_CARDS_IN_DECK, getBlackCards().size());
35 | obj.add(Consts.CardSetData.WHITE_CARDS_IN_DECK, getWhiteCards().size());
36 | return obj;
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | return String.format("%s[name=%s, base=%b, id=%d, active=%b, weight=%d, black=%d, white=%d]",
42 | getClass().getName(), getName(), isBaseDeck(), getId(), isActive(), getWeight(),
43 | getBlackCards().size(), getWhiteCards().size());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/PyxBlackCard.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import java.sql.ResultSet;
4 | import java.sql.SQLException;
5 |
6 | public class PyxBlackCard extends BlackCard {
7 | private final int id;
8 | private final String text;
9 | private final int draw;
10 | private final int pick;
11 | private final String watermark;
12 |
13 | public PyxBlackCard(ResultSet resultSet) throws SQLException {
14 | id = resultSet.getInt("id");
15 | text = resultSet.getString("text");
16 | draw = resultSet.getInt("draw");
17 | pick = resultSet.getInt("pick");
18 | watermark = resultSet.getString("watermark");
19 | }
20 |
21 | @Override
22 | public int getId() {
23 | return id;
24 | }
25 |
26 | /**
27 | * @return Card text. HTML is allowed and entities are required.
28 | */
29 | @Override
30 | public String getText() {
31 | return text;
32 | }
33 |
34 | @Override
35 | public int getDraw() {
36 | return draw;
37 | }
38 |
39 | @Override
40 | public int getPick() {
41 | return pick;
42 | }
43 |
44 | @Override
45 | public String getWatermark() {
46 | return watermark == null ? "" : watermark;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/PyxCardSet.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import com.gianlu.pyxreloaded.singletons.LoadedCards;
4 |
5 | import java.sql.ResultSet;
6 | import java.sql.SQLException;
7 | import java.util.ArrayList;
8 | import java.util.HashSet;
9 | import java.util.List;
10 | import java.util.Set;
11 |
12 | public class PyxCardSet extends CardSet {
13 | private final Set blackCards;
14 | private final Set whiteCards;
15 | private final int id;
16 | private final String name;
17 | private final String description;
18 | private final boolean active;
19 | private final boolean base_deck;
20 | private final int weight;
21 |
22 | public PyxCardSet(ResultSet resultSet) throws SQLException {
23 | id = resultSet.getInt("id");
24 | name = resultSet.getString("name");
25 | active = resultSet.getInt("active") == 1;
26 | base_deck = resultSet.getInt("base_deck") == 1;
27 | description = resultSet.getString("description");
28 | weight = resultSet.getInt("weight");
29 |
30 | blackCards = new HashSet<>();
31 | whiteCards = new HashSet<>();
32 | }
33 |
34 | public static List loadCardSets(LoadedCards loadedCards, Set ids) {
35 | List sets = new ArrayList<>();
36 | for (PyxCardSet set : loadedCards.getLoadedSets())
37 | if (ids.contains(set.id)) sets.add(set);
38 |
39 | return sets;
40 | }
41 |
42 | @Override
43 | public String getName() {
44 | return name;
45 | }
46 |
47 | @Override
48 | public boolean isActive() {
49 | return active;
50 | }
51 |
52 | @Override
53 | public int getId() {
54 | return id;
55 | }
56 |
57 | @Override
58 | public Set getBlackCards() {
59 | return blackCards;
60 | }
61 |
62 | @Override
63 | public Set getWhiteCards() {
64 | return whiteCards;
65 | }
66 |
67 | @Override
68 | public boolean isBaseDeck() {
69 | return base_deck;
70 | }
71 |
72 | @Override
73 | public String getDescription() {
74 | return description;
75 | }
76 |
77 | @Override
78 | public int getWeight() {
79 | return weight;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/PyxWhiteCard.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import java.sql.ResultSet;
4 | import java.sql.SQLException;
5 |
6 | public class PyxWhiteCard extends WhiteCard {
7 | private final int id;
8 | private final String text;
9 | private final String watermark;
10 |
11 | public PyxWhiteCard(ResultSet resultSet) throws SQLException {
12 | id = resultSet.getInt("id");
13 | text = resultSet.getString("text");
14 | watermark = resultSet.getString("watermark");
15 | }
16 |
17 | @Override
18 | public int getId() {
19 | return id;
20 | }
21 |
22 | /**
23 | * @return Card text. HTML is allowed and entities are required.
24 | */
25 | @Override
26 | public String getText() {
27 | return text;
28 | }
29 |
30 | @Override
31 | public String getWatermark() {
32 | return watermark == null ? "" : watermark;
33 | }
34 |
35 | @Override
36 | public boolean isWriteIn() {
37 | return false;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/WhiteCard.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 |
6 |
7 | public abstract class WhiteCard {
8 | public static JsonWrapper getFaceDownCardClientDataJson() {
9 | JsonWrapper obj = new JsonWrapper();
10 | obj.add(Consts.GeneralKeys.CARD_ID, -1);
11 | obj.add(Consts.WhiteCardData.TEXT, "");
12 | obj.add(Consts.WhiteCardData.WATERMARK, "");
13 | obj.add(Consts.WhiteCardData.WRITE_IN, false);
14 | return obj;
15 | }
16 |
17 | public abstract int getId();
18 |
19 | public abstract String getText();
20 |
21 | public abstract String getWatermark();
22 |
23 | public abstract boolean isWriteIn();
24 |
25 | @Override
26 | public final boolean equals(final Object other) {
27 | return other instanceof WhiteCard && ((WhiteCard) other).getId() == getId();
28 | }
29 |
30 | @Override
31 | public final int hashCode() {
32 | return getId();
33 | }
34 |
35 | public final JsonWrapper getClientDataJson() {
36 | JsonWrapper obj = new JsonWrapper();
37 | obj.add(Consts.GeneralKeys.CARD_ID, getId());
38 | obj.add(Consts.WhiteCardData.TEXT, getText());
39 | obj.add(Consts.WhiteCardData.WATERMARK, getWatermark());
40 | obj.add(Consts.WhiteCardData.WRITE_IN, isWriteIn());
41 | return obj;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return String.format("%s %s (id:%d, watermark:%s)", getClass().getName(), getText(), getId(), getWatermark());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/cards/WhiteDeck.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.cards;
2 |
3 | import com.gianlu.pyxreloaded.game.OutOfCardsException;
4 |
5 | import java.util.*;
6 |
7 |
8 | /**
9 | * Deck of White Cards.
10 | *
11 | * This class is thread-safe.
12 | *
13 | * @author Andy Janata (ajanata@socialgamer.net)
14 | */
15 | public class WhiteDeck {
16 | private final List deck;
17 | private final List discard;
18 | private int lastBlankCardId = -1;
19 |
20 | /**
21 | * Create a new white card deck, loading the cards from the database and shuffling them.
22 | */
23 | public WhiteDeck(Collection cardSets, int numBlanks) {
24 | Set allCards = new HashSet<>();
25 | for (CardSet cardSet : cardSets) allCards.addAll(cardSet.getWhiteCards());
26 | deck = new ArrayList<>(allCards);
27 | for (int i = 0; i < numBlanks; i++) deck.add(createBlankCard());
28 | Collections.shuffle(deck);
29 | discard = new ArrayList<>(deck.size());
30 | }
31 |
32 | /**
33 | * Checks if a particular card is a blank card.
34 | *
35 | * @param card Card to check.
36 | * @return True if the card is a blank card.
37 | */
38 | public static boolean isBlankCard(WhiteCard card) {
39 | return card instanceof BlankWhiteCard;
40 | }
41 |
42 | /**
43 | * Get the next card from the top of deck.
44 | *
45 | * @return The next card.
46 | * @throws OutOfCardsException There are no more cards in the deck.
47 | */
48 | public synchronized WhiteCard getNextCard() throws OutOfCardsException {
49 | if (deck.size() == 0) throw new OutOfCardsException();
50 | // we have an ArrayList here, so this is faster
51 | return deck.remove(deck.size() - 1);
52 | }
53 |
54 | /**
55 | * Add a card to the discard pile.
56 | *
57 | * @param card Card to add to discard pile.
58 | */
59 | public synchronized void discard(WhiteCard card) {
60 | if (card != null) {
61 | // clear any player text
62 | if (isBlankCard(card)) ((BlankWhiteCard) card).clear();
63 |
64 | discard.add(card);
65 | }
66 | }
67 |
68 | /**
69 | * Shuffles the discard pile and puts the cards under the cards remaining in the deck.
70 | */
71 | public synchronized void reshuffle() {
72 | Collections.shuffle(discard);
73 | deck.addAll(0, discard);
74 | discard.clear();
75 | }
76 |
77 | /**
78 | * Creates a new blank card.
79 | *
80 | * @return A newly created blank card.
81 | */
82 | public WhiteCard createBlankCard() {
83 | return new BlankWhiteCard(--lastBlankCardId);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/EventWrapper.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.game.Game;
5 |
6 | public class EventWrapper extends JsonWrapper {
7 |
8 | public EventWrapper(Game game, Consts.Event event) {
9 | this(event);
10 | add(Consts.GeneralKeys.GAME_ID, game.getId());
11 | }
12 |
13 | public EventWrapper(Consts.Event event) {
14 | add(Consts.GeneralKeys.EVENT, event.toString());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/JsonWrapper.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.Utils;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonObject;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | import java.util.Map;
11 |
12 | public class JsonWrapper {
13 | public static final JsonWrapper EMPTY = new JsonWrapper();
14 | private final JsonObject obj;
15 |
16 | public JsonWrapper() {
17 | obj = new JsonObject();
18 | }
19 |
20 | public JsonWrapper(Consts.ReturnableKey data, JsonElement element) {
21 | this();
22 | add(data, element);
23 | }
24 |
25 | public JsonWrapper(Consts.ReturnableKey data, int i) {
26 | this();
27 | add(data, i);
28 | }
29 |
30 | public JsonWrapper(Consts.ReturnableKey data, String str) {
31 | this();
32 | add(data, str);
33 | }
34 |
35 | public JsonWrapper(Consts.ErrorCode code) {
36 | this();
37 | add(Consts.GeneralKeys.ERROR, true);
38 | add(Consts.GeneralKeys.ERROR_CODE, code.toString());
39 | }
40 |
41 | @NotNull
42 | public static JsonWrapper from(@NotNull Map map, @Nullable String[] keys) {
43 | JsonWrapper wrapper = new JsonWrapper();
44 | for (String key : map.keySet()) {
45 | if (keys == null || Utils.contains(keys, key))
46 | wrapper.obj.addProperty(key, map.get(key));
47 | }
48 | return wrapper;
49 | }
50 |
51 | public JsonObject obj() {
52 | return obj;
53 | }
54 |
55 | public JsonWrapper add(Consts.ReturnableKey data, JsonElement element) {
56 | obj.add(data.toString(), element);
57 | return this;
58 | }
59 |
60 | public JsonWrapper add(Consts.ReturnableKey data, JsonWrapper wrapper) {
61 | add(data, wrapper == null ? null : wrapper.obj());
62 | return this;
63 | }
64 |
65 | public JsonWrapper add(Consts.ReturnableKey data, boolean bool) {
66 | obj.addProperty(data.toString(), bool);
67 | return this;
68 | }
69 |
70 | public JsonWrapper add(Consts.ReturnableKey data, Number i) {
71 | obj.addProperty(data.toString(), i);
72 | return this;
73 | }
74 |
75 | public JsonWrapper add(Consts.ReturnableKey data, String str) {
76 | obj.addProperty(data.toString(), str);
77 | return this;
78 | }
79 |
80 | @Override
81 | public String toString() {
82 | return obj.toString();
83 | }
84 |
85 | public void addAll(JsonWrapper data) {
86 | if (data == null) return;
87 | for (String key : data.obj.keySet()) obj.add(key, data.obj.get(key));
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/QueuedMessage.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public class QueuedMessage implements Comparable {
6 | private final MessageType messageType;
7 | private final EventWrapper ev;
8 |
9 | /**
10 | * Create a new queued message.
11 | *
12 | * @param messageType Type of message to be queued. The type influences the priority in returning messages
13 | * to the client.
14 | * @param ev The data of the message to be queued.
15 | */
16 | public QueuedMessage(MessageType messageType, EventWrapper ev) {
17 | this.messageType = messageType;
18 | this.ev = ev;
19 | }
20 |
21 | /**
22 | * @return The data in the message.
23 | */
24 | public EventWrapper getData() {
25 | return ev;
26 | }
27 |
28 | /**
29 | * This is not guaranteed to be consistent with .equals() since we do not care about the data for
30 | * ordering.
31 | */
32 | @Override
33 | public int compareTo(@NotNull QueuedMessage qm) {
34 | return this.messageType.getWeight() - qm.messageType.getWeight();
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return messageType.toString() + "_" + ev.toString();
40 | }
41 |
42 | /**
43 | * Types of messages that can be queued. The numerical value is the priority that this message
44 | * should be delivered (lower = more important) compared to other queued messages.
45 | */
46 | public enum MessageType {
47 | SERVER(1), KICKED(2), PLAYER_EVENT(3), GAME_EVENT(4), GAME_PLAYER_EVENT(5), CHAT(6);
48 |
49 | private final int weight;
50 |
51 | MessageType(int weight) {
52 | this.weight = weight;
53 | }
54 |
55 | public int getWeight() {
56 | return weight;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/accounts/FacebookAccount.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data.accounts;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.socials.facebook.FacebookProfileInfo;
5 | import com.gianlu.pyxreloaded.socials.facebook.FacebookToken;
6 |
7 | import java.sql.ResultSet;
8 | import java.sql.SQLException;
9 | import java.text.ParseException;
10 |
11 | public class FacebookAccount extends UserAccount {
12 | public final String userId;
13 |
14 | public FacebookAccount(ResultSet user) throws SQLException, ParseException {
15 | super(user, true); // Cannot even register without a verified email
16 |
17 | userId = user.getString("facebook_user_id");
18 | }
19 |
20 | public FacebookAccount(String nickname, FacebookToken token, FacebookProfileInfo info) {
21 | super(nickname, info.email, Consts.AuthType.FACEBOOK, true, info.pictureUrl);
22 |
23 | userId = token.userId;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/accounts/GithubAccount.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data.accounts;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.socials.github.GithubProfileInfo;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.text.ParseException;
9 |
10 | public class GithubAccount extends UserAccount {
11 | public final String id;
12 |
13 | public GithubAccount(ResultSet user, GithubProfileInfo info) throws SQLException, ParseException {
14 | super(user, info.emails.isPrimaryEmailVerified());
15 |
16 | id = user.getString("github_user_id");
17 | }
18 |
19 | public GithubAccount(String nickname, GithubProfileInfo info) {
20 | super(nickname, info.email, Consts.AuthType.GITHUB, info.emails.isPrimaryEmailVerified(), info.avatarUrl);
21 |
22 | id = info.id;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/accounts/GoogleAccount.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data.accounts;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.text.ParseException;
9 |
10 | public class GoogleAccount extends UserAccount {
11 | public final String subject;
12 |
13 | public GoogleAccount(ResultSet user, GoogleIdToken.Payload token) throws SQLException, ParseException {
14 | super(user, token.getEmailVerified());
15 |
16 | subject = user.getString("google_sub");
17 | }
18 |
19 | public GoogleAccount(String nickname, GoogleIdToken.Payload token) {
20 | super(nickname, token.getEmail(), Consts.AuthType.GOOGLE, token.getEmailVerified(), (String) token.getOrDefault("picture", null));
21 |
22 | this.subject = token.getSubject();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/accounts/PasswordAccount.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data.accounts;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.text.ParseException;
9 |
10 | public class PasswordAccount extends UserAccount {
11 | public final String hashedPassword;
12 |
13 | public PasswordAccount(ResultSet user) throws SQLException, ParseException {
14 | super(user, user.getBoolean("email_verified"));
15 |
16 | hashedPassword = user.getString("password");
17 | }
18 |
19 | public PasswordAccount(String username, String email, boolean emailVerified, @NotNull String hashedPassword) {
20 | super(username, email, Consts.AuthType.PASSWORD, emailVerified, null); // TODO: Avatar
21 |
22 | this.hashedPassword = hashedPassword;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/accounts/TwitterAccount.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data.accounts;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.socials.twitter.TwitterProfileInfo;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | import java.sql.ResultSet;
8 | import java.sql.SQLException;
9 | import java.text.ParseException;
10 |
11 | public class TwitterAccount extends UserAccount {
12 | public final String id;
13 |
14 | public TwitterAccount(ResultSet user) throws SQLException, ParseException {
15 | super(user, true); // Cannot even register without a verified email
16 |
17 | id = user.getString("twitter_user_id");
18 | }
19 |
20 | public TwitterAccount(String nickname, @NotNull TwitterProfileInfo info) {
21 | super(nickname, info.email, Consts.AuthType.TWITTER, true, info.avatarUrl);
22 |
23 | id = info.id;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/data/accounts/UserAccount.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.data.accounts;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import org.jetbrains.annotations.NotNull;
6 | import org.jetbrains.annotations.Nullable;
7 |
8 | import java.sql.ResultSet;
9 | import java.sql.SQLException;
10 | import java.text.ParseException;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | public abstract class UserAccount {
15 | public final String username;
16 | public final boolean admin;
17 | public final String email;
18 | public final String avatarUrl;
19 | public final boolean emailVerified;
20 | public final Preferences preferences = new Preferences();
21 | private final Consts.AuthType auth;
22 |
23 | UserAccount(ResultSet set, boolean emailVerified) throws SQLException, ParseException {
24 | this.username = set.getString("username");
25 | this.email = set.getString("email");
26 | this.auth = Consts.AuthType.parse(set.getString("auth"));
27 | this.admin = set.getBoolean("admin");
28 | this.avatarUrl = set.getString("avatar_url");
29 | this.emailVerified = emailVerified;
30 | }
31 |
32 | UserAccount(String username, String email, Consts.AuthType auth, boolean emailVerified, @Nullable String avatarUrl) {
33 | this.username = username;
34 | this.email = email;
35 | this.auth = auth;
36 | this.avatarUrl = avatarUrl;
37 | this.admin = false;
38 | this.emailVerified = emailVerified;
39 | }
40 |
41 | public JsonWrapper toJson() {
42 | JsonWrapper obj = new JsonWrapper();
43 | obj.add(Consts.UserData.EMAIL, email);
44 | obj.add(Consts.GeneralKeys.AUTH_TYPE, auth.toString());
45 | obj.add(Consts.UserData.PICTURE, avatarUrl);
46 | obj.add(Consts.UserData.NICKNAME, username);
47 | obj.add(Consts.UserData.EMAIL_VERIFIED, emailVerified);
48 | obj.add(Consts.UserData.IS_ADMIN, admin);
49 | return obj;
50 | }
51 |
52 | public void loadPreferences(@NotNull ResultSet prefs) throws SQLException {
53 | preferences.load(prefs);
54 | }
55 |
56 | public void updatePreferences(@NotNull Map map) {
57 | preferences.update(map);
58 | }
59 |
60 | public class Preferences extends HashMap {
61 |
62 | private Preferences() {
63 | }
64 |
65 | private void load(@NotNull ResultSet set) throws SQLException {
66 | while (set.next()) put(set.getString("key"), set.getString("value"));
67 | }
68 |
69 | @NotNull
70 | public JsonWrapper toJson(@Nullable String[] keys) {
71 | return JsonWrapper.from(this, keys);
72 | }
73 |
74 | private void update(@NotNull Map map) {
75 | for (String key : map.keySet()) {
76 | if (Consts.isPreferenceKeyValid(key))
77 | put(key, map.get(key));
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/game/OutOfCardsException.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.game;
2 |
3 | /**
4 | * An exception to be thrown when a deck is out of cards in the draw stack.
5 | */
6 | public class OutOfCardsException extends Exception {
7 | private static final long serialVersionUID = -1797946826947407779L;
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/game/Player.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.game;
2 |
3 | import com.gianlu.pyxreloaded.cards.WhiteCard;
4 | import com.gianlu.pyxreloaded.data.User;
5 |
6 | import java.util.LinkedList;
7 | import java.util.List;
8 |
9 |
10 | /**
11 | * Data required for a player in a {@code Game}.
12 | *
13 | * @author Andy Janata (ajanata@socialgamer.net)
14 | */
15 | public class Player {
16 | public final List hand = new LinkedList<>();
17 | private final User user;
18 | private int score = 0;
19 | private int skipCount = 0;
20 |
21 | /**
22 | * Create a new player object.
23 | *
24 | * @param user The {@code User} associated with this player.
25 | */
26 | public Player(User user) {
27 | this.user = user;
28 | }
29 |
30 | /**
31 | * @return The {@code User} associated with this player.
32 | */
33 | public User getUser() {
34 | return user;
35 | }
36 |
37 | /**
38 | * @return The player's score.
39 | */
40 | public int getScore() {
41 | return score;
42 | }
43 |
44 | /**
45 | * Increase the player's score by 1 point.
46 | */
47 | public void increaseScore() {
48 | score++;
49 | }
50 |
51 | /**
52 | * Reset the player's score to 0.
53 | */
54 | public void resetScore() {
55 | score = 0;
56 | }
57 |
58 | /**
59 | * Increases this player's skipped round count.
60 | */
61 | public void skipped() {
62 | skipCount++;
63 | }
64 |
65 | /**
66 | * Reset this player's skipped round count to 0, because they have been back for a round.
67 | */
68 | public void resetSkipCount() {
69 | skipCount = 0;
70 | }
71 |
72 | /**
73 | * @return This player's skipped round count.
74 | */
75 | public int getSkipCount() {
76 | return skipCount;
77 | }
78 |
79 | @Override
80 | public String toString() {
81 | return String.format("%s (%dp, %ds)", user.toString(), score, skipCount);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/game/SuggestedGameOptions.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.game;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.singletons.Preferences;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | public class SuggestedGameOptions extends GameOptions {
10 | private final User suggester;
11 |
12 | public SuggestedGameOptions(Preferences preferences, @NotNull User user, String text) {
13 | super(preferences, text);
14 | suggester = user;
15 | }
16 |
17 | public User getSuggester() {
18 | return suggester;
19 | }
20 |
21 | public JsonWrapper toJson(String id, boolean includePassword) {
22 | JsonWrapper wrapper = new JsonWrapper();
23 | wrapper.add(Consts.GameOptionsData.OPTIONS, super.toJson(includePassword));
24 | wrapper.add(Consts.GameSuggestedOptionsData.ID, id);
25 | wrapper.add(Consts.GameSuggestedOptionsData.SUGGESTER, suggester.getNickname());
26 | return wrapper;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/BanHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.server.Annotations;
7 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class BanHandler extends BaseHandler {
14 | public static final String OP = Consts.Operation.BAN.toString();
15 | private final ConnectedUsers connectedUsers;
16 |
17 | public BanHandler(@Annotations.ConnectedUsers ConnectedUsers connectedUsers) {
18 | this.connectedUsers = connectedUsers;
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
24 | if (!user.isAdmin()) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_ADMIN);
25 |
26 | String nickname = params.getStringNotNull(Consts.UserData.NICKNAME);
27 | if (nickname.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
28 |
29 | User target = connectedUsers.getUser(nickname);
30 | if (target == null) throw new BaseCahHandler.CahException(Consts.ErrorCode.NO_SUCH_USER);
31 | connectedUsers.banUser(target);
32 |
33 | return JsonWrapper.EMPTY;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/BaseHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.data.JsonWrapper;
4 | import com.gianlu.pyxreloaded.data.User;
5 | import com.gianlu.pyxreloaded.server.BaseJsonHandler;
6 | import com.gianlu.pyxreloaded.server.Parameters;
7 | import io.undertow.server.HttpServerExchange;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | public abstract class BaseHandler {
11 | @NotNull
12 | public abstract JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseJsonHandler.StatusException;
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/CardcastAddCardsetHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.cardcast.CardcastDeck;
5 | import com.gianlu.pyxreloaded.cardcast.CardcastService;
6 | import com.gianlu.pyxreloaded.data.EventWrapper;
7 | import com.gianlu.pyxreloaded.data.JsonWrapper;
8 | import com.gianlu.pyxreloaded.data.QueuedMessage;
9 | import com.gianlu.pyxreloaded.data.User;
10 | import com.gianlu.pyxreloaded.game.Game;
11 | import com.gianlu.pyxreloaded.server.Annotations;
12 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
13 | import com.gianlu.pyxreloaded.server.Parameters;
14 | import com.gianlu.pyxreloaded.singletons.GamesManager;
15 | import io.undertow.server.HttpServerExchange;
16 | import org.jetbrains.annotations.NotNull;
17 |
18 | public class CardcastAddCardsetHandler extends GameWithPlayerHandler {
19 | public static final String OP = Consts.Operation.CARDCAST_ADD_CARDSET.toString();
20 | private final CardcastService cardcastService;
21 |
22 | public CardcastAddCardsetHandler(@Annotations.GameManager GamesManager gamesManager, @Annotations.CardcastService CardcastService cardcastService) {
23 | super(gamesManager);
24 | this.cardcastService = cardcastService;
25 | }
26 |
27 | @NotNull
28 | @Override
29 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
30 | if (game.getHost() != user) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_GAME_HOST);
31 | if (game.getState() != Consts.GameState.LOBBY)
32 | throw new BaseCahHandler.CahException(Consts.ErrorCode.ALREADY_STARTED);
33 |
34 | String deckId = params.getStringNotNull(Consts.GeneralKeys.CARDCAST_ID);
35 | if (deckId.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
36 | if (deckId.length() != 5) throw new BaseCahHandler.CahException(Consts.ErrorCode.CARDCAST_INVALID_ID);
37 | deckId = deckId.toUpperCase();
38 |
39 | CardcastDeck deck = cardcastService.loadSet(deckId);
40 | if (deck == null) throw new BaseCahHandler.CahException(Consts.ErrorCode.CARDCAST_CANNOT_FIND);
41 |
42 | if (game.getCardcastDeckCodes().add(deckId)) {
43 | EventWrapper ev = new EventWrapper(game, Consts.Event.CARDCAST_ADD_CARDSET);
44 | ev.add(Consts.GeneralKeys.CARDCAST_DECK_INFO, deck.getClientMetadataJson());
45 | game.broadcastToPlayers(QueuedMessage.MessageType.GAME_EVENT, ev);
46 | }
47 |
48 | return JsonWrapper.EMPTY;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/CardcastListCardsetsHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.cardcast.CardcastDeck;
5 | import com.gianlu.pyxreloaded.cardcast.CardcastService;
6 | import com.gianlu.pyxreloaded.cardcast.FailedLoadingSomeCardcastDecks;
7 | import com.gianlu.pyxreloaded.data.JsonWrapper;
8 | import com.gianlu.pyxreloaded.data.User;
9 | import com.gianlu.pyxreloaded.game.Game;
10 | import com.gianlu.pyxreloaded.server.Annotations;
11 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
12 | import com.gianlu.pyxreloaded.server.Parameters;
13 | import com.gianlu.pyxreloaded.singletons.GamesManager;
14 | import com.google.gson.JsonArray;
15 | import io.undertow.server.HttpServerExchange;
16 | import org.jetbrains.annotations.NotNull;
17 |
18 | public class CardcastListCardsetsHandler extends GameWithPlayerHandler {
19 | public static final String OP = Consts.Operation.CARDCAST_LIST_CARDSETS.toString();
20 | private final CardcastService cardcastService;
21 |
22 | public CardcastListCardsetsHandler(@Annotations.GameManager GamesManager gamesManager, @Annotations.CardcastService CardcastService cardcastService) {
23 | super(gamesManager);
24 | this.cardcastService = cardcastService;
25 | }
26 |
27 | @NotNull
28 | @Override
29 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
30 | JsonArray array = new JsonArray();
31 |
32 | FailedLoadingSomeCardcastDecks cardcastException = null;
33 | for (String deckId : game.getCardcastDeckCodes().toArray(new String[0])) {
34 | CardcastDeck deck = cardcastService.loadSet(deckId);
35 | if (deck == null) {
36 | if (cardcastException == null) cardcastException = new FailedLoadingSomeCardcastDecks();
37 | cardcastException.failedDecks.add(deckId);
38 | }
39 |
40 | if (deck != null) array.add(deck.getClientMetadataJson().obj());
41 | }
42 |
43 | if (cardcastException != null) {
44 | throw new BaseCahHandler.CahException(Consts.ErrorCode.CARDCAST_CANNOT_FIND,
45 | new JsonWrapper(Consts.GeneralKeys.CARDCAST_ID, cardcastException.getFailedJson()));
46 | } else {
47 | return new JsonWrapper(Consts.GameOptionsData.CARD_SETS, array);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/CardcastRemoveCardsetHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.cardcast.CardcastDeck;
5 | import com.gianlu.pyxreloaded.cardcast.CardcastService;
6 | import com.gianlu.pyxreloaded.data.EventWrapper;
7 | import com.gianlu.pyxreloaded.data.JsonWrapper;
8 | import com.gianlu.pyxreloaded.data.QueuedMessage;
9 | import com.gianlu.pyxreloaded.data.User;
10 | import com.gianlu.pyxreloaded.game.Game;
11 | import com.gianlu.pyxreloaded.server.Annotations;
12 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
13 | import com.gianlu.pyxreloaded.server.Parameters;
14 | import com.gianlu.pyxreloaded.singletons.GamesManager;
15 | import io.undertow.server.HttpServerExchange;
16 | import org.jetbrains.annotations.NotNull;
17 |
18 | public class CardcastRemoveCardsetHandler extends GameWithPlayerHandler {
19 | public static final String OP = Consts.Operation.CARDCAST_REMOVE_CARDSET.toString();
20 | private final CardcastService cardcastService;
21 |
22 | public CardcastRemoveCardsetHandler(@Annotations.GameManager GamesManager gamesManager, @Annotations.CardcastService CardcastService cardcastService) {
23 | super(gamesManager);
24 | this.cardcastService = cardcastService;
25 | }
26 |
27 | @NotNull
28 | @Override
29 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
30 | if (game.getHost() != user) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_GAME_HOST);
31 | if (game.getState() != Consts.GameState.LOBBY)
32 | throw new BaseCahHandler.CahException(Consts.ErrorCode.ALREADY_STARTED);
33 |
34 | String deckId = params.getStringNotNull(Consts.GeneralKeys.CARDCAST_ID);
35 | if (deckId.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
36 | if (deckId.length() != 5) throw new BaseCahHandler.CahException(Consts.ErrorCode.CARDCAST_INVALID_ID);
37 | deckId = deckId.toUpperCase();
38 |
39 | // Remove it from the set regardless if it loads or not.
40 | if (game.getCardcastDeckCodes().remove(deckId)) {
41 | CardcastDeck deck = cardcastService.loadSet(deckId);
42 | if (deck == null) throw new BaseCahHandler.CahException(Consts.ErrorCode.CARDCAST_CANNOT_FIND);
43 |
44 | EventWrapper ev = new EventWrapper(game, Consts.Event.CARDCAST_REMOVE_CARDSET);
45 | ev.add(Consts.GeneralKeys.CARDCAST_DECK_INFO, deck.getClientMetadataJson());
46 | game.broadcastToPlayers(QueuedMessage.MessageType.GAME_EVENT, ev);
47 | }
48 |
49 | return JsonWrapper.EMPTY;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/ChangeGameOptionsHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.game.GameOptions;
8 | import com.gianlu.pyxreloaded.game.SuggestedGameOptions;
9 | import com.gianlu.pyxreloaded.server.Annotations;
10 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
11 | import com.gianlu.pyxreloaded.server.Parameters;
12 | import com.gianlu.pyxreloaded.singletons.GamesManager;
13 | import com.gianlu.pyxreloaded.singletons.Preferences;
14 | import io.undertow.server.HttpServerExchange;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | public class ChangeGameOptionsHandler extends GameWithPlayerHandler {
18 | public static final String OP = Consts.Operation.CHANGE_GAME_OPTIONS.toString();
19 | private final Preferences preferences;
20 |
21 | public ChangeGameOptionsHandler(@Annotations.GameManager GamesManager gamesManager, @Annotations.Preferences Preferences preferences) {
22 | super(gamesManager);
23 | this.preferences = preferences;
24 | }
25 |
26 | @NotNull
27 | @Override
28 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
29 | if (game.getState() != Consts.GameState.LOBBY)
30 | throw new BaseCahHandler.CahException(Consts.ErrorCode.ALREADY_STARTED);
31 |
32 | User host = game.getHost();
33 | if (host == null) return JsonWrapper.EMPTY;
34 |
35 | String value = params.getStringNotNull(Consts.GameOptionsData.OPTIONS);
36 | if (value.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
37 |
38 | if (host == user) {
39 | game.updateGameSettings(new GameOptions(preferences, value));
40 | return JsonWrapper.EMPTY;
41 | } else {
42 | game.suggestGameOptionsModification(new SuggestedGameOptions(preferences, user, value));
43 | return new JsonWrapper(Consts.GameInfoData.HOST, host.getNickname());
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/ChatHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.EventWrapper;
5 | import com.gianlu.pyxreloaded.data.JsonWrapper;
6 | import com.gianlu.pyxreloaded.data.QueuedMessage.MessageType;
7 | import com.gianlu.pyxreloaded.data.User;
8 | import com.gianlu.pyxreloaded.server.Annotations;
9 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
10 | import com.gianlu.pyxreloaded.server.BaseJsonHandler;
11 | import com.gianlu.pyxreloaded.server.Parameters;
12 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
13 | import com.gianlu.pyxreloaded.singletons.Preferences;
14 | import io.undertow.server.HttpServerExchange;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | public class ChatHandler extends BaseHandler {
18 | public static final String OP = Consts.Operation.CHAT.toString();
19 | private final ConnectedUsers users;
20 | private final boolean registeredOnly;
21 |
22 | public ChatHandler(@Annotations.Preferences Preferences preferences,
23 | @Annotations.ConnectedUsers ConnectedUsers users) {
24 | this.users = users;
25 | this.registeredOnly = preferences.getBoolean("chat/registeredOnly", false);
26 | }
27 |
28 | @NotNull
29 | @Override
30 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseJsonHandler.StatusException {
31 | users.checkChatFlood(user);
32 |
33 | if (registeredOnly && !user.isEmailVerified())
34 | throw new BaseCahHandler.CahException(Consts.ErrorCode.ACCOUNT_NOT_VERIFIED);
35 |
36 | String msg = params.getStringNotNull(Consts.ChatData.MESSAGE);
37 | if (msg.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
38 |
39 | if (msg.length() > Consts.CHAT_MAX_LENGTH) {
40 | throw new BaseCahHandler.CahException(Consts.ErrorCode.MESSAGE_TOO_LONG);
41 | } else if (!users.runChatCommand(user, msg)) {
42 | user.getLastMessageTimes().add(System.currentTimeMillis());
43 | EventWrapper ev = new EventWrapper(Consts.Event.CHAT);
44 | ev.add(Consts.ChatData.FROM, user.getNickname());
45 | ev.add(Consts.ChatData.MESSAGE, msg);
46 | ev.add(Consts.ChatData.FROM_ADMIN, user.isAdmin());
47 | if (user.getAccount() != null) ev.add(Consts.UserData.PICTURE, user.getAccount().avatarUrl);
48 |
49 | users.broadcastToAll(MessageType.CHAT, ev);
50 | }
51 |
52 | return JsonWrapper.EMPTY;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/CreateGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.GameOptions;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.BaseJsonHandler;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.GamesManager;
11 | import com.gianlu.pyxreloaded.singletons.Preferences;
12 | import io.undertow.server.HttpServerExchange;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class CreateGameHandler extends BaseHandler {
16 | public static final String OP = Consts.Operation.CREATE_GAME.toString();
17 | private final Preferences preferences;
18 | private final GamesManager gamesManager;
19 |
20 | public CreateGameHandler(@Annotations.Preferences Preferences preferences, @Annotations.GameManager GamesManager gamesManager) {
21 | this.preferences = preferences;
22 | this.gamesManager = gamesManager;
23 | }
24 |
25 | @NotNull
26 | @Override
27 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseJsonHandler.StatusException {
28 | String value = params.getStringNotNull(Consts.GameOptionsData.OPTIONS);
29 | GameOptions options = new GameOptions(preferences, value);
30 | return new JsonWrapper(Consts.GeneralKeys.GAME_ID, gamesManager.createGameWithPlayer(user, options).getId());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/DislikeGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class DislikeGameHandler extends GameHandler {
14 | public static final String OP = Consts.Operation.DISLIKE.toString();
15 |
16 | public DislikeGameHandler(@Annotations.GameManager GamesManager gamesManager) {
17 | super(gamesManager);
18 | }
19 |
20 | @NotNull
21 | @Override
22 | public JsonWrapper handle(User user, Game game, Parameters params, HttpServerExchange exchange) {
23 | game.toggleDislikeGame(user);
24 | return game.getLikesInfoJson(user);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/FirstLoadHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.cards.PyxCardSet;
5 | import com.gianlu.pyxreloaded.data.JsonWrapper;
6 | import com.gianlu.pyxreloaded.data.User;
7 | import com.gianlu.pyxreloaded.game.GameOptions;
8 | import com.gianlu.pyxreloaded.server.Annotations;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.Emails;
11 | import com.gianlu.pyxreloaded.singletons.LoadedCards;
12 | import com.gianlu.pyxreloaded.singletons.Preferences;
13 | import com.gianlu.pyxreloaded.singletons.SocialLogin;
14 | import com.google.gson.JsonArray;
15 | import io.undertow.server.HttpServerExchange;
16 | import org.jetbrains.annotations.NotNull;
17 |
18 | import java.util.Set;
19 |
20 | public class FirstLoadHandler extends BaseHandler {
21 | public static final String OP = Consts.Operation.FIRST_LOAD.toString();
22 | private final JsonWrapper defaultGameOptions;
23 | private final JsonArray cards;
24 | private final JsonWrapper authConfig;
25 | private final String serverStatusPage;
26 |
27 | public FirstLoadHandler(@Annotations.LoadedCards LoadedCards loadedCards,
28 | @Annotations.Emails Emails emails,
29 | @Annotations.SocialLogin SocialLogin socials,
30 | @Annotations.Preferences Preferences preferences) {
31 | serverStatusPage = preferences.getStringNotEmpty("serverStatusPage", null);
32 |
33 | Set cardSets = loadedCards.getLoadedSets();
34 | cards = new JsonArray(cardSets.size());
35 | for (PyxCardSet cardSet : cardSets) cards.add(cardSet.getClientMetadataJson().obj());
36 |
37 | defaultGameOptions = GameOptions.getOptionsDefaultsJson(preferences);
38 |
39 | authConfig = new JsonWrapper();
40 | if (emails.enabled()) authConfig.add(Consts.AuthType.PASSWORD, emails.senderEmail());
41 | if (socials.googleEnabled()) authConfig.add(Consts.AuthType.GOOGLE, socials.googleAppId());
42 | if (socials.facebookEnabled()) authConfig.add(Consts.AuthType.FACEBOOK, socials.facebookAppId());
43 | if (socials.githubEnabled()) authConfig.add(Consts.AuthType.GITHUB, socials.githubAppId());
44 | if (socials.twitterEnabled()) authConfig.add(Consts.AuthType.TWITTER, socials.twitterAppId());
45 | }
46 |
47 | @NotNull
48 | @Override
49 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) {
50 | JsonWrapper obj = new JsonWrapper();
51 |
52 | if (user == null) {
53 | obj.add(Consts.GeneralKeys.IN_PROGRESS, Boolean.FALSE)
54 | .add(Consts.GeneralKeys.NEXT, Consts.Operation.REGISTER.toString());
55 | } else {
56 | // They already have a session in progress, we need to figure out what they were doing
57 | // and tell the client where to continue from.
58 | obj.add(Consts.GeneralKeys.IN_PROGRESS, Boolean.TRUE)
59 | .add(Consts.UserData.NICKNAME, user.getNickname());
60 |
61 | if (user.getGame() != null) {
62 | obj.add(Consts.GeneralKeys.NEXT, Consts.ReconnectNextAction.GAME.toString())
63 | .add(Consts.GeneralKeys.GAME_ID, user.getGame().getId());
64 | } else {
65 | obj.add(Consts.GeneralKeys.NEXT, Consts.ReconnectNextAction.NONE.toString());
66 | }
67 | }
68 |
69 | obj.add(Consts.GeneralKeys.AUTH_CONFIG, authConfig);
70 | obj.add(Consts.GameOptionsData.CARD_SETS, cards);
71 | obj.add(Consts.GameOptionsData.DEFAULT_OPTIONS, defaultGameOptions);
72 | obj.add(Consts.GeneralKeys.SERVER_STATUS_PAGE, serverStatusPage);
73 |
74 | return obj;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GameChatHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.EventWrapper;
5 | import com.gianlu.pyxreloaded.data.JsonWrapper;
6 | import com.gianlu.pyxreloaded.data.QueuedMessage.MessageType;
7 | import com.gianlu.pyxreloaded.data.User;
8 | import com.gianlu.pyxreloaded.game.Game;
9 | import com.gianlu.pyxreloaded.server.Annotations;
10 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
11 | import com.gianlu.pyxreloaded.server.Parameters;
12 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
13 | import com.gianlu.pyxreloaded.singletons.GamesManager;
14 | import io.undertow.server.HttpServerExchange;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | public class GameChatHandler extends GameWithPlayerHandler {
18 | public static final String OP = Consts.Operation.GAME_CHAT.toString();
19 | private final ConnectedUsers users;
20 |
21 | public GameChatHandler(
22 | @Annotations.ConnectedUsers ConnectedUsers users,
23 | @Annotations.GameManager GamesManager gamesManager) {
24 | super(gamesManager);
25 | this.users = users;
26 | }
27 |
28 | @NotNull
29 | @Override
30 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
31 | users.checkChatFlood(user);
32 |
33 | String msg = params.getStringNotNull(Consts.ChatData.MESSAGE);
34 | if (msg.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
35 |
36 | if (msg.length() > Consts.CHAT_MAX_LENGTH) {
37 | throw new BaseCahHandler.CahException(Consts.ErrorCode.MESSAGE_TOO_LONG);
38 | } else if (!users.runChatCommand(user, msg)) {
39 | user.getLastMessageTimes().add(System.currentTimeMillis());
40 | EventWrapper ev = new EventWrapper(game, Consts.Event.CHAT);
41 | ev.add(Consts.ChatData.FROM, user.getNickname());
42 | ev.add(Consts.ChatData.MESSAGE, msg);
43 | ev.add(Consts.GeneralKeys.GAME_ID, game.getId());
44 | ev.add(Consts.ChatData.FROM_ADMIN, user.isAdmin());
45 | game.broadcastToPlayers(MessageType.CHAT, ev);
46 | }
47 |
48 | return JsonWrapper.EMPTY;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public abstract class GameHandler extends BaseHandler {
14 | protected final GamesManager gamesManager;
15 |
16 | GameHandler(GamesManager gamesManager) {
17 | this.gamesManager = gamesManager;
18 | }
19 |
20 | @NotNull
21 | @Override
22 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
23 | String gameIdStr = params.getStringNotNull(Consts.GeneralKeys.GAME_ID);
24 | if (gameIdStr.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
25 |
26 | int gameId;
27 | try {
28 | gameId = Integer.parseInt(gameIdStr);
29 | } catch (NumberFormatException ex) {
30 | throw new BaseCahHandler.CahException(Consts.ErrorCode.INVALID_GAME, ex);
31 | }
32 |
33 | final Game game = gamesManager.getGame(gameId);
34 | if (game == null) throw new BaseCahHandler.CahException(Consts.ErrorCode.INVALID_GAME);
35 |
36 | return handle(user, game, params, exchange);
37 | }
38 |
39 | @NotNull
40 | public abstract JsonWrapper handle(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException;
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GameListHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import com.google.gson.JsonArray;
11 | import io.undertow.server.HttpServerExchange;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | public class GameListHandler extends BaseHandler {
15 | public static final String OP = Consts.Operation.GAME_LIST.toString();
16 | private final GamesManager gamesManager;
17 |
18 | public GameListHandler(@Annotations.GameManager GamesManager gamesManager) {
19 | this.gamesManager = gamesManager;
20 | }
21 |
22 | @NotNull
23 | @Override
24 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) {
25 | JsonWrapper json = new JsonWrapper();
26 |
27 | JsonArray infoArray = new JsonArray();
28 | for (Game game : gamesManager.getGameList()) {
29 | JsonWrapper info = game.getInfoJson(user, false);
30 | if (info != null) infoArray.add(info.obj());
31 | }
32 |
33 | json.add(Consts.GeneralKeys.GAMES, infoArray);
34 | json.add(Consts.GeneralKeys.MAX_GAMES, gamesManager.getMaxGames());
35 | return json;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GameOptionsSuggestionDecisionHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.GamesManager;
11 | import io.undertow.server.HttpServerExchange;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | public class GameOptionsSuggestionDecisionHandler extends GameWithPlayerHandler {
15 | public final static String OP = Consts.Operation.GAME_OPTIONS_SUGGESTION_DECISION.toString();
16 |
17 | public GameOptionsSuggestionDecisionHandler(@Annotations.GameManager GamesManager gamesManager) {
18 | super(gamesManager);
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
24 | if (game.getHost() != user) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_GAME_HOST);
25 |
26 | String suggestedId = params.getStringNotNull(Consts.GameSuggestedOptionsData.ID);
27 | if (suggestedId.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
28 |
29 | if (!params.has(Consts.GameSuggestedOptionsData.DECISION))
30 | throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
31 |
32 | if (params.getBoolean(Consts.GameSuggestedOptionsData.DECISION, false))
33 | game.applySuggestedOptions(suggestedId);
34 | else
35 | game.declineSuggestedOptions(suggestedId);
36 |
37 | return JsonWrapper.EMPTY;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GameWithPlayerHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public abstract class GameWithPlayerHandler extends GameHandler {
14 |
15 | public GameWithPlayerHandler(GamesManager gamesManager) {
16 | super(gamesManager);
17 | }
18 |
19 | @NotNull
20 | @Override
21 | public final JsonWrapper handle(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
22 | if (user.getGame() != game) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_IN_THAT_GAME);
23 | else return handleWithUserInGame(user, game, params, exchange);
24 | }
25 |
26 | @NotNull
27 | public abstract JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GetCardsHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class GetCardsHandler extends GameWithPlayerHandler {
14 | public static final String OP = Consts.Operation.GET_CARDS.toString();
15 |
16 | public GetCardsHandler(@Annotations.GameManager GamesManager gamesManager) {
17 | super(gamesManager);
18 | }
19 |
20 | @NotNull
21 | @Override
22 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) {
23 | JsonWrapper obj = new JsonWrapper();
24 | obj.add(Consts.OngoingGameData.HAND, game.getHandJson(user));
25 | obj.addAll(game.getPlayerToPlayCards(user));
26 | obj.add(Consts.OngoingGameData.BLACK_CARD, game.getBlackCardJson());
27 | obj.add(Consts.OngoingGameData.WHITE_CARDS, game.getWhiteCardsJson(user));
28 | obj.add(Consts.GeneralKeys.GAME_ID, game.getId());
29 |
30 | return obj;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GetGameInfoHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class GetGameInfoHandler extends GameWithPlayerHandler {
14 | public static final String OP = Consts.Operation.GET_GAME_INFO.toString();
15 |
16 | public GetGameInfoHandler(@Annotations.GameManager GamesManager gamesManager) {
17 | super(gamesManager);
18 | }
19 |
20 | @NotNull
21 | @Override
22 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) {
23 | JsonWrapper obj = new JsonWrapper();
24 | obj.add(Consts.GameInfoData.INFO, game.getInfoJson(user, true));
25 | obj.add(Consts.GamePlayerInfo.INFO, game.getAllPlayersInfoJson());
26 | return obj;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GetMeHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.server.Parameters;
7 | import io.undertow.server.HttpServerExchange;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | /**
11 | * Class to get user's nick for the game.html page - not safe to store/retrieve as a cookie.
12 | * This class returns a JSON string containing the user's nick to the client through AJAX.
13 | * More data will be added/used once user accounts are added.
14 | **/
15 | public class GetMeHandler extends BaseHandler {
16 | public static final String OP = Consts.Operation.ME.toString();
17 |
18 | public GetMeHandler() {
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) {
24 | JsonWrapper obj = new JsonWrapper();
25 | obj.add(Consts.UserData.NICKNAME, user.getNickname());
26 | if (user.getAccount() != null) obj.add(Consts.GeneralKeys.ACCOUNT, user.getAccount().toJson());
27 |
28 | if (user.getGame() != null) obj.add(Consts.GeneralKeys.GAME_ID, user.getGame().getId());
29 | else obj.add(Consts.GeneralKeys.GAME_ID, -1);
30 |
31 | return obj;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GetSuggestedGameOptionsHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.game.SuggestedGameOptions;
8 | import com.gianlu.pyxreloaded.server.Annotations;
9 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
10 | import com.gianlu.pyxreloaded.server.Parameters;
11 | import com.gianlu.pyxreloaded.singletons.GamesManager;
12 | import com.google.gson.JsonArray;
13 | import io.undertow.server.HttpServerExchange;
14 | import org.jetbrains.annotations.NotNull;
15 |
16 | import java.util.Map;
17 |
18 | public class GetSuggestedGameOptionsHandler extends GameWithPlayerHandler {
19 | public static final String OP = Consts.Operation.GET_SUGGESTED_GAME_OPTIONS.toString();
20 |
21 | public GetSuggestedGameOptionsHandler(@Annotations.GameManager GamesManager gamesManager) {
22 | super(gamesManager);
23 | }
24 |
25 | @NotNull
26 | @Override
27 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
28 | if (user != game.getHost()) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_GAME_HOST);
29 |
30 | JsonWrapper obj = new JsonWrapper();
31 | JsonArray array = new JsonArray();
32 | for (Map.Entry entry : game.getSuggestedGameOptions().entrySet())
33 | array.add(entry.getValue().toJson(entry.getKey(), true).obj());
34 |
35 | obj.add(Consts.GameSuggestedOptionsData.OPTIONS, array);
36 | return obj;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/GetUserPreferencesHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.data.accounts.UserAccount;
7 | import com.gianlu.pyxreloaded.server.Parameters;
8 | import io.undertow.server.HttpServerExchange;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | public class GetUserPreferencesHandler extends BaseHandler {
12 | public static final String OP = Consts.Operation.GET_USER_PREFERENCES.toString();
13 |
14 | @NotNull
15 | @Override
16 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) {
17 | UserAccount account = user.getAccount();
18 | if (account == null) return JsonWrapper.EMPTY;
19 |
20 | String[] keys;
21 | String keysStr = params.getString(Consts.GeneralKeys.USER_PREFERENCES);
22 | if (keysStr == null) keys = null;
23 | else keys = keysStr.split(",");
24 |
25 | return account.preferences.toJson(keys);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/JoinGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.GamesManager;
11 | import com.gianlu.pyxreloaded.singletons.PreparingShutdown;
12 | import io.undertow.server.HttpServerExchange;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class JoinGameHandler extends GameHandler {
16 | public static final String OP = Consts.Operation.JOIN_GAME.toString();
17 |
18 | public JoinGameHandler(@Annotations.GameManager GamesManager gamesManager) {
19 | super(gamesManager);
20 | }
21 |
22 | @NotNull
23 | @Override
24 | public JsonWrapper handle(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
25 | PreparingShutdown.get().check();
26 |
27 | if (!game.isPasswordCorrect(params.getString(Consts.GameOptionsData.PASSWORD)))
28 | throw new BaseCahHandler.CahException(Consts.ErrorCode.WRONG_PASSWORD);
29 |
30 | game.addPlayer(user);
31 | return JsonWrapper.EMPTY;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/JudgeSelectHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.GamesManager;
11 | import io.undertow.server.HttpServerExchange;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | public class JudgeSelectHandler extends GameWithPlayerHandler {
15 | public static final String OP = Consts.Operation.JUDGE_SELECT.toString();
16 |
17 | public JudgeSelectHandler(@Annotations.GameManager GamesManager gamesManager) {
18 | super(gamesManager);
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
24 | String cardIdStr = params.getStringNotNull(Consts.GeneralKeys.CARD_ID);
25 | if (cardIdStr.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
26 |
27 | int cardId;
28 | try {
29 | cardId = Integer.parseInt(cardIdStr);
30 | } catch (NumberFormatException ex) {
31 | throw new BaseCahHandler.CahException(Consts.ErrorCode.INVALID_CARD, ex);
32 | }
33 |
34 | game.judgeCard(user, cardId);
35 | return JsonWrapper.EMPTY;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/KickHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.server.Annotations;
7 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class KickHandler extends BaseHandler {
14 | public static final String OP = Consts.Operation.KICK.toString();
15 | private final ConnectedUsers connectedUsers;
16 |
17 | public KickHandler(@Annotations.ConnectedUsers ConnectedUsers connectedUsers) {
18 | this.connectedUsers = connectedUsers;
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
24 | if (!user.isAdmin()) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_ADMIN);
25 |
26 | String nickname = params.getStringNotNull(Consts.UserData.NICKNAME);
27 | if (nickname.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
28 |
29 | User target = connectedUsers.getUser(nickname);
30 | if (target == null) throw new BaseCahHandler.CahException(Consts.ErrorCode.NO_SUCH_USER);
31 | connectedUsers.kickUser(target);
32 |
33 | return JsonWrapper.EMPTY;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/LeaveGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 |
14 | public class LeaveGameHandler extends GameWithPlayerHandler {
15 | public static final String OP = Consts.Operation.LEAVE_GAME.toString();
16 |
17 | public LeaveGameHandler(@Annotations.GameManager GamesManager gamesManager) {
18 | super(gamesManager);
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) {
24 | game.removePlayer(user);
25 | game.removeSpectator(user);
26 | return JsonWrapper.EMPTY;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/LikeGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.GamesManager;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class LikeGameHandler extends GameHandler {
14 | public static final String OP = Consts.Operation.LIKE.toString();
15 |
16 | public LikeGameHandler(@Annotations.GameManager GamesManager gamesManager) {
17 | super(gamesManager);
18 | }
19 |
20 | @NotNull
21 | @Override
22 | public JsonWrapper handle(User user, Game game, Parameters params, HttpServerExchange exchange) {
23 | game.toggleLikeGame(user);
24 | return game.getLikesInfoJson(user);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/LogoutHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.server.Annotations;
7 | import com.gianlu.pyxreloaded.server.Parameters;
8 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
9 | import com.gianlu.pyxreloaded.singletons.Sessions;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class LogoutHandler extends BaseHandler {
14 | public final static String OP = Consts.Operation.LOG_OUT.toString();
15 | private final ConnectedUsers users;
16 |
17 | public LogoutHandler(@Annotations.ConnectedUsers ConnectedUsers users) {
18 | this.users = users;
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) {
24 | user.noLongerValid();
25 | users.removeUser(user, Consts.DisconnectReason.MANUAL);
26 | Sessions.get().invalidate(user.getSessionId());
27 | return JsonWrapper.EMPTY;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/NamesHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.server.Annotations;
7 | import com.gianlu.pyxreloaded.server.Parameters;
8 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
9 | import com.google.gson.JsonArray;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class NamesHandler extends BaseHandler {
14 | public static final String OP = Consts.Operation.NAMES.toString();
15 | private final ConnectedUsers users;
16 |
17 | public NamesHandler(@Annotations.ConnectedUsers ConnectedUsers users) {
18 | this.users = users;
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) {
24 | JsonArray array = new JsonArray();
25 | for (User item : users.getUsers()) array.add(item.toSmallJson().obj());
26 | return new JsonWrapper(Consts.GeneralKeys.NAMES, array);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/PlayCardHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.GamesManager;
11 | import io.undertow.server.HttpServerExchange;
12 | import org.apache.commons.lang3.StringEscapeUtils;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class PlayCardHandler extends GameWithPlayerHandler {
16 | public static final String OP = Consts.Operation.PLAY_CARD.toString();
17 |
18 | public PlayCardHandler(@Annotations.GameManager GamesManager gamesManager) {
19 | super(gamesManager);
20 | }
21 |
22 | @NotNull
23 | @Override
24 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
25 | String cardIdStr = params.getStringNotNull(Consts.GeneralKeys.CARD_ID);
26 | if (cardIdStr.isEmpty()) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
27 |
28 | int cardId;
29 | try {
30 | cardId = Integer.parseInt(cardIdStr);
31 | } catch (NumberFormatException ex) {
32 | throw new BaseCahHandler.CahException(Consts.ErrorCode.INVALID_CARD, ex);
33 | }
34 |
35 | String text = params.getString(Consts.GeneralKeys.WRITE_IN_TEXT);
36 | if (text != null && text.contains("<")) text = StringEscapeUtils.escapeXml11(text);
37 |
38 | return game.playCard(user, cardId, text);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/PongHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.server.Parameters;
7 | import io.undertow.server.HttpServerExchange;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | public class PongHandler extends BaseHandler {
11 | public static final String OP = Consts.Operation.PONG.toString();
12 |
13 | @NotNull
14 | @Override
15 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) {
16 | user.userReceivedEvents();
17 | return JsonWrapper.EMPTY;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/PrepareShutdownHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
7 | import com.gianlu.pyxreloaded.server.BaseJsonHandler;
8 | import com.gianlu.pyxreloaded.server.Parameters;
9 | import com.gianlu.pyxreloaded.singletons.PreparingShutdown;
10 | import io.undertow.server.HttpServerExchange;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class PrepareShutdownHandler extends BaseHandler {
14 | public static final String OP = Consts.Operation.PREPARE_SHUTDOWN.toString();
15 |
16 | public PrepareShutdownHandler() {
17 | }
18 |
19 | @NotNull
20 | @Override
21 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseJsonHandler.StatusException {
22 | if (!user.isAdmin()) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_ADMIN);
23 |
24 | PreparingShutdown.get().set(true);
25 |
26 | return JsonWrapper.EMPTY;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/SetUserPreferencesHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.Utils;
5 | import com.gianlu.pyxreloaded.data.JsonWrapper;
6 | import com.gianlu.pyxreloaded.data.User;
7 | import com.gianlu.pyxreloaded.data.accounts.UserAccount;
8 | import com.gianlu.pyxreloaded.server.Annotations;
9 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
10 | import com.gianlu.pyxreloaded.server.Parameters;
11 | import com.gianlu.pyxreloaded.singletons.UsersWithAccount;
12 | import com.google.gson.JsonObject;
13 | import com.google.gson.JsonParser;
14 | import com.google.gson.JsonSyntaxException;
15 | import io.undertow.server.HttpServerExchange;
16 | import org.jetbrains.annotations.NotNull;
17 |
18 | import java.util.Map;
19 |
20 | public class SetUserPreferencesHandler extends BaseHandler {
21 | public static final String OP = Consts.Operation.SET_USER_PREFERENCES.toString();
22 | private final JsonParser parser = new JsonParser();
23 | private final UsersWithAccount accounts;
24 |
25 | public SetUserPreferencesHandler(@Annotations.UsersWithAccount UsersWithAccount accounts) {
26 | this.accounts = accounts;
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public JsonWrapper handle(User user, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
32 | UserAccount account = user.getAccount();
33 | if (account == null) return JsonWrapper.EMPTY;
34 |
35 | try {
36 | JsonObject obj = parser.parse(params.getStringNotNull(Consts.GeneralKeys.USER_PREFERENCES)).getAsJsonObject();
37 | Map map = Utils.toMap(obj);
38 | account.updatePreferences(map);
39 | accounts.updatePreferences(account, map);
40 | return account.preferences.toJson(map.keySet().toArray(new String[0]));
41 | } catch (IllegalStateException | JsonSyntaxException ex) {
42 | throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST, ex);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/SpectateGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.GamesManager;
11 | import com.gianlu.pyxreloaded.singletons.PreparingShutdown;
12 | import io.undertow.server.HttpServerExchange;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class SpectateGameHandler extends GameHandler {
16 | public static final String OP = Consts.Operation.SPECTATE_GAME.toString();
17 |
18 | public SpectateGameHandler(@Annotations.GameManager GamesManager gamesManager) {
19 | super(gamesManager);
20 | }
21 |
22 | @NotNull
23 | @Override
24 | public JsonWrapper handle(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
25 | PreparingShutdown.get().check();
26 |
27 | if (!game.isPasswordCorrect(params.getString(Consts.GameOptionsData.PASSWORD)))
28 | throw new BaseCahHandler.CahException(Consts.ErrorCode.WRONG_PASSWORD);
29 |
30 | game.addSpectator(user);
31 | return JsonWrapper.EMPTY;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/StartGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.cardcast.FailedLoadingSomeCardcastDecks;
5 | import com.gianlu.pyxreloaded.cards.CardSet;
6 | import com.gianlu.pyxreloaded.data.JsonWrapper;
7 | import com.gianlu.pyxreloaded.data.User;
8 | import com.gianlu.pyxreloaded.game.Game;
9 | import com.gianlu.pyxreloaded.server.Annotations;
10 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
11 | import com.gianlu.pyxreloaded.server.Parameters;
12 | import com.gianlu.pyxreloaded.singletons.GamesManager;
13 | import com.gianlu.pyxreloaded.singletons.PreparingShutdown;
14 | import io.undertow.server.HttpServerExchange;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | import java.util.List;
18 |
19 | public class StartGameHandler extends GameWithPlayerHandler {
20 | public static final String OP = Consts.Operation.START_GAME.toString();
21 |
22 | public StartGameHandler(@Annotations.GameManager GamesManager gamesManager) {
23 | super(gamesManager);
24 | }
25 |
26 | @NotNull
27 | @Override
28 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
29 | if (game.getHost() != user) throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_GAME_HOST);
30 | if (game.getState() != Consts.GameState.LOBBY)
31 | throw new BaseCahHandler.CahException(Consts.ErrorCode.ALREADY_STARTED);
32 |
33 | PreparingShutdown.get().check();
34 |
35 | try {
36 | if (!game.hasEnoughCards()) {
37 | List cardSets = game.loadCardSets();
38 | JsonWrapper obj = new JsonWrapper();
39 | obj.add(Consts.GeneralGameData.BLACK_CARDS_PRESENT, game.blackCardsCount(cardSets));
40 | obj.add(Consts.GeneralGameData.BLACK_CARDS_REQUIRED, game.getRequiredBlackCardCount());
41 | obj.add(Consts.GeneralGameData.WHITE_CARDS_PRESENT, game.whiteCardsCount(cardSets));
42 | obj.add(Consts.GeneralGameData.WHITE_CARDS_REQUIRED, game.getRequiredWhiteCardCount());
43 | throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_ENOUGH_CARDS, obj);
44 | } else {
45 | game.start();
46 | return JsonWrapper.EMPTY;
47 | }
48 | } catch (FailedLoadingSomeCardcastDecks ex) {
49 | throw new BaseCahHandler.CahException(Consts.ErrorCode.CARDCAST_CANNOT_FIND,
50 | new JsonWrapper(Consts.GeneralKeys.CARDCAST_ID, ex.getFailedJson()));
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/handlers/StopGameHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.handlers;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.game.Game;
7 | import com.gianlu.pyxreloaded.server.Annotations;
8 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
9 | import com.gianlu.pyxreloaded.server.Parameters;
10 | import com.gianlu.pyxreloaded.singletons.GamesManager;
11 | import io.undertow.server.HttpServerExchange;
12 | import org.apache.log4j.Logger;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class StopGameHandler extends GameWithPlayerHandler {
16 | public static final String OP = Consts.Operation.STOP_GAME.toString();
17 | protected final Logger logger = Logger.getLogger(GameWithPlayerHandler.class);
18 |
19 | public StopGameHandler(@Annotations.GameManager GamesManager gamesManager) {
20 | super(gamesManager);
21 | }
22 |
23 | @NotNull
24 | @Override
25 | public JsonWrapper handleWithUserInGame(User user, Game game, Parameters params, HttpServerExchange exchange) throws BaseCahHandler.CahException {
26 | if (game.getHost() != user) {
27 | throw new BaseCahHandler.CahException(Consts.ErrorCode.NOT_GAME_HOST);
28 | } else if (game.getState() == Consts.GameState.LOBBY) {
29 | throw new BaseCahHandler.CahException(Consts.ErrorCode.ALREADY_STOPPED);
30 | } else {
31 | logger.info(String.format("Game %d stopped by host %s. Players: %s", game.getId(), user, game.getPlayers()));
32 | game.resetState(false);
33 | return JsonWrapper.EMPTY;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/paths/AjaxPath.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.paths;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.User;
5 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
6 | import com.gianlu.pyxreloaded.server.Parameters;
7 | import com.gianlu.pyxreloaded.singletons.Handlers;
8 | import com.google.gson.JsonElement;
9 | import io.undertow.server.HttpServerExchange;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | public class AjaxPath extends BaseCahHandler {
13 |
14 | @Override
15 | protected JsonElement handleRequest(@Nullable String op, @Nullable User user, Parameters params, HttpServerExchange exchange) throws StatusException {
16 | if (user != null) user.userDidSomething();
17 | if (op == null || op.isEmpty()) throw new CahException(Consts.ErrorCode.OP_NOT_SPECIFIED);
18 | return Handlers.obtain(op).handle(user, params, exchange).obj();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/paths/GithubCallbackPath.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.paths;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.Utils;
5 | import com.gianlu.pyxreloaded.socials.github.GithubAuthHelper;
6 | import io.undertow.server.HttpHandler;
7 | import io.undertow.server.HttpServerExchange;
8 | import io.undertow.server.handlers.CookieImpl;
9 | import io.undertow.util.Headers;
10 | import io.undertow.util.StatusCodes;
11 | import org.apache.log4j.Logger;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.concurrent.TimeUnit;
15 |
16 | public class GithubCallbackPath implements HttpHandler {
17 | private static final Logger logger = Logger.getLogger(GithubCallbackPath.class);
18 | private static final int COOKIE_MAX_AGE = (int) TimeUnit.MINUTES.toSeconds(5); // sec
19 | private static final String REDIRECT_LOCATION = "/?" + Consts.GeneralKeys.AUTH_TYPE + "=" + Consts.AuthType.GITHUB;
20 | private final GithubAuthHelper githubHelper;
21 |
22 | public GithubCallbackPath(@NotNull GithubAuthHelper githubHelper) {
23 | this.githubHelper = githubHelper;
24 | }
25 |
26 | @Override
27 | public void handleRequest(HttpServerExchange exchange) throws Exception {
28 | exchange.startBlocking();
29 | if (exchange.isInIoThread()) {
30 | exchange.dispatch(this);
31 | return;
32 | }
33 |
34 | String code = Utils.extractParam(exchange, "code");
35 | if (code == null) {
36 | exchange.setStatusCode(StatusCodes.BAD_REQUEST);
37 | return;
38 | }
39 |
40 | try {
41 | String accessToken = githubHelper.exchangeCode(code);
42 |
43 | CookieImpl cookie = new CookieImpl("PYX-Github-Token", accessToken);
44 | cookie.setMaxAge(COOKIE_MAX_AGE);
45 | exchange.setResponseCookie(cookie);
46 | exchange.getResponseHeaders().add(Headers.LOCATION, REDIRECT_LOCATION);
47 | exchange.setStatusCode(StatusCodes.TEMPORARY_REDIRECT);
48 | } catch (Throwable ex) {
49 | logger.error("Failed processing the request: " + exchange, ex);
50 | throw ex;
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/paths/TwitterCallbackPath.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.paths;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.Utils;
5 | import com.gianlu.pyxreloaded.socials.twitter.TwitterAuthHelper;
6 | import com.github.scribejava.core.model.OAuth1AccessToken;
7 | import com.github.scribejava.core.model.OAuth1RequestToken;
8 | import io.undertow.server.HttpHandler;
9 | import io.undertow.server.HttpServerExchange;
10 | import io.undertow.server.handlers.Cookie;
11 | import io.undertow.server.handlers.CookieImpl;
12 | import io.undertow.util.Headers;
13 | import io.undertow.util.StatusCodes;
14 | import org.apache.http.NameValuePair;
15 | import org.apache.http.client.utils.URLEncodedUtils;
16 | import org.apache.log4j.Logger;
17 | import org.jetbrains.annotations.NotNull;
18 |
19 | import java.nio.charset.Charset;
20 | import java.util.List;
21 | import java.util.Objects;
22 | import java.util.concurrent.TimeUnit;
23 |
24 | public class TwitterCallbackPath implements HttpHandler {
25 | private static final Logger logger = Logger.getLogger(TwitterCallbackPath.class);
26 | private static final int COOKIE_MAX_AGE = (int) TimeUnit.MINUTES.toSeconds(5); // sec
27 | private static final String REDIRECT_LOCATION = "/?" + Consts.GeneralKeys.AUTH_TYPE + "=" + Consts.AuthType.TWITTER;
28 | private final TwitterAuthHelper helper;
29 |
30 | public TwitterCallbackPath(@NotNull TwitterAuthHelper helper) {
31 | this.helper = helper;
32 | }
33 |
34 | @Override
35 | public void handleRequest(HttpServerExchange exchange) throws Exception {
36 | exchange.startBlocking();
37 | if (exchange.isInIoThread()) {
38 | exchange.dispatch(this);
39 | return;
40 | }
41 |
42 | try {
43 | String token = Utils.extractParam(exchange, "oauth_token");
44 | String verifier = Utils.extractParam(exchange, "oauth_verifier");
45 |
46 | if (token == null || verifier == null)
47 | throw new IllegalArgumentException("Missing token or verifier!");
48 |
49 | Cookie tokensCookie = exchange.getRequestCookies().get("PYX-Twitter-Token");
50 | if (tokensCookie == null)
51 | throw new IllegalArgumentException("Missing 'PYX-Twitter-Token' cookie!");
52 |
53 | List tokens = URLEncodedUtils.parse(tokensCookie.getValue(), Charset.forName("UTF-8"));
54 | if (!Objects.equals(token, Utils.get(tokens, "oauth_token")))
55 | throw new IllegalStateException("Missing token in cookie or tokens don't match!");
56 |
57 | String secret = Utils.get(tokens, "oauth_token_secret");
58 | if (secret == null)
59 | throw new IllegalArgumentException("Missing token secret in cookie!");
60 |
61 | OAuth1AccessToken accessToken = helper.accessToken(new OAuth1RequestToken(token, secret), verifier);
62 | CookieImpl cookie = new CookieImpl("PYX-Twitter-Token", accessToken.getRawResponse());
63 | cookie.setMaxAge(COOKIE_MAX_AGE);
64 | exchange.setResponseCookie(cookie);
65 | exchange.getResponseHeaders().add(Headers.LOCATION, REDIRECT_LOCATION);
66 | exchange.setStatusCode(StatusCodes.TEMPORARY_REDIRECT);
67 | } catch (Throwable ex) {
68 | logger.error("Failed processing the request: " + exchange, ex);
69 | throw ex;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/paths/TwitterStartAuthFlowPath.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.paths;
2 |
3 | import com.gianlu.pyxreloaded.socials.twitter.TwitterAuthHelper;
4 | import com.github.scribejava.core.model.OAuth1RequestToken;
5 | import io.undertow.server.HttpHandler;
6 | import io.undertow.server.HttpServerExchange;
7 | import io.undertow.server.handlers.CookieImpl;
8 | import io.undertow.util.Headers;
9 | import io.undertow.util.StatusCodes;
10 | import org.apache.log4j.Logger;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.util.concurrent.TimeUnit;
14 |
15 | public class TwitterStartAuthFlowPath implements HttpHandler {
16 | private static final Logger logger = Logger.getLogger(TwitterStartAuthFlowPath.class);
17 | private static final int COOKIE_MAX_AGE = (int) TimeUnit.MINUTES.toSeconds(5); // sec
18 | private final TwitterAuthHelper helper;
19 |
20 | public TwitterStartAuthFlowPath(@NotNull TwitterAuthHelper helper) {
21 | this.helper = helper;
22 | }
23 |
24 | @Override
25 | public void handleRequest(HttpServerExchange exchange) throws Exception {
26 | exchange.startBlocking();
27 | if (exchange.isInIoThread()) {
28 | exchange.dispatch(this);
29 | return;
30 | }
31 |
32 | try {
33 | OAuth1RequestToken token = helper.requestToken();
34 | CookieImpl cookie = new CookieImpl("PYX-Twitter-Token", token.getRawResponse());
35 | cookie.setMaxAge(COOKIE_MAX_AGE);
36 | exchange.setResponseCookie(cookie);
37 | exchange.getResponseHeaders().add(Headers.LOCATION, helper.authorizationUrl(token) + "&force_login=false");
38 | exchange.setStatusCode(StatusCodes.TEMPORARY_REDIRECT);
39 | } catch (Throwable ex) {
40 | logger.error("Failed processing the request." + exchange, ex);
41 | throw ex;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/paths/VerifyEmailPath.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.paths;
2 |
3 | import com.gianlu.pyxreloaded.Utils;
4 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
5 | import com.gianlu.pyxreloaded.singletons.Emails;
6 | import io.undertow.server.HttpHandler;
7 | import io.undertow.server.HttpServerExchange;
8 | import io.undertow.util.Headers;
9 | import io.undertow.util.StatusCodes;
10 | import org.apache.log4j.Logger;
11 |
12 | import java.sql.SQLException;
13 |
14 | public class VerifyEmailPath implements HttpHandler {
15 | private static final Logger logger = Logger.getLogger(VerifyEmailPath.class);
16 | private final Emails emails;
17 |
18 | public VerifyEmailPath(Emails emails) {
19 | this.emails = emails;
20 | }
21 |
22 | @Override
23 | public void handleRequest(HttpServerExchange exchange) {
24 | exchange.startBlocking();
25 | if (exchange.isInIoThread()) {
26 | exchange.dispatch(this);
27 | return;
28 | }
29 |
30 | try {
31 | String token = Utils.extractParam(exchange, "token");
32 | if (token == null) {
33 | exchange.setStatusCode(StatusCodes.BAD_REQUEST);
34 | exchange.getResponseSender().send("Missing token!");
35 | return;
36 | }
37 |
38 | exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, "text/html");
39 |
40 | try {
41 | emails.tryVerify(token);
42 | exchange.setStatusCode(StatusCodes.OK);
43 | exchange.getResponseSender().send("Your email has been verified. You'll be redirected in a few seconds...");
44 | } catch (SQLException ex) {
45 | exchange.setStatusCode(StatusCodes.FORBIDDEN);
46 | exchange.getResponseSender().send("Invalid token. Failed to verify your email or already verified.");
47 | } catch (BaseCahHandler.CahException ex) {
48 | exchange.setStatusCode(StatusCodes.BAD_REQUEST);
49 | exchange.getResponseSender().send(ex.getMessage());
50 | }
51 | } catch (Throwable ex) {
52 | logger.error("Failed verifying email.", ex);
53 | throw ex;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/paths/VersionPath.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.paths;
2 |
3 | import com.gianlu.pyxreloaded.Utils;
4 | import com.google.gson.JsonObject;
5 | import io.undertow.server.HttpHandler;
6 | import io.undertow.server.HttpServerExchange;
7 | import io.undertow.util.Headers;
8 |
9 | public class VersionPath implements HttpHandler {
10 | private final String json;
11 |
12 | public VersionPath() {
13 | JsonObject obj = new JsonObject();
14 | Package pkg = Package.getPackage("com.gianlu.pyxreloaded");
15 | obj.addProperty("version", Utils.getServerVersion(pkg));
16 | json = obj.toString();
17 | }
18 |
19 | @Override
20 | public void handleRequest(HttpServerExchange exchange) {
21 | exchange.startBlocking();
22 | if (exchange.isInIoThread()) {
23 | exchange.dispatch(this);
24 | return;
25 | }
26 |
27 | exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, "application/json");
28 | exchange.getResponseSender().send(json);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/paths/WebManifestPath.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.paths;
2 |
3 | import com.gianlu.pyxreloaded.singletons.Preferences;
4 | import com.google.gson.JsonObject;
5 | import com.google.gson.JsonParser;
6 | import io.undertow.server.HttpHandler;
7 | import io.undertow.server.HttpServerExchange;
8 | import io.undertow.server.handlers.Cookie;
9 | import io.undertow.util.Headers;
10 | import org.apache.log4j.Logger;
11 |
12 | import java.io.File;
13 | import java.io.FileInputStream;
14 | import java.io.FileNotFoundException;
15 | import java.io.InputStreamReader;
16 | import java.net.URLDecoder;
17 |
18 | public class WebManifestPath implements HttpHandler {
19 | private static final Logger logger = Logger.getLogger(WebManifestPath.class);
20 | private final JsonObject baseManifest;
21 | private final String baseManifestString;
22 |
23 | public WebManifestPath(Preferences preferences) throws FileNotFoundException {
24 | File manifest = new File(preferences.getString("webContent", "./WebContent"), "manifest.json");
25 | if (!manifest.exists() && !manifest.canRead()) {
26 | logger.error("Missing base manifest file. Loading empty.");
27 | baseManifest = new JsonObject();
28 | } else {
29 | baseManifest = new JsonParser().parse(new InputStreamReader(new FileInputStream(manifest))).getAsJsonObject();
30 | }
31 |
32 | baseManifestString = baseManifest.toString();
33 | }
34 |
35 | @Override
36 | public void handleRequest(HttpServerExchange exchange) throws Exception {
37 | exchange.startBlocking();
38 | if (exchange.isInIoThread()) {
39 | exchange.dispatch(this);
40 | return;
41 | }
42 |
43 | exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, "application/json");
44 |
45 | Cookie primaryColor = exchange.getRequestCookies().get("PYX-Theme-Primary");
46 | if (primaryColor == null) {
47 | exchange.getResponseSender().send(baseManifestString);
48 | } else {
49 | JsonObject manifest = baseManifest.deepCopy();
50 | manifest.addProperty("theme_color", URLDecoder.decode(primaryColor.getValue(), "UTF-8"));
51 | exchange.getResponseSender().send(manifest.toString());
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/server/Annotations.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.server;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | public final class Annotations {
9 | @Target(ElementType.PARAMETER)
10 | @Retention(RetentionPolicy.RUNTIME)
11 | public @interface ConnectedUsers {
12 | }
13 |
14 | @Target(ElementType.PARAMETER)
15 | @Retention(RetentionPolicy.RUNTIME)
16 | public @interface GameManager {
17 | }
18 |
19 | @Target(ElementType.PARAMETER)
20 | @Retention(RetentionPolicy.RUNTIME)
21 | public @interface CardcastService {
22 | }
23 |
24 | @Target(ElementType.PARAMETER)
25 | @Retention(RetentionPolicy.RUNTIME)
26 | public @interface Preferences {
27 | }
28 |
29 | @Target(ElementType.PARAMETER)
30 | @Retention(RetentionPolicy.RUNTIME)
31 | public @interface LoadedCards {
32 | }
33 |
34 | @Target(ElementType.PARAMETER)
35 | @Retention(RetentionPolicy.RUNTIME)
36 | public @interface BanList {
37 | }
38 |
39 | @Target(ElementType.PARAMETER)
40 | @Retention(RetentionPolicy.RUNTIME)
41 | public @interface UsersWithAccount {
42 | }
43 |
44 | @Target(ElementType.PARAMETER)
45 | @Retention(RetentionPolicy.RUNTIME)
46 | public @interface SocialLogin {
47 | }
48 |
49 | @Target(ElementType.PARAMETER)
50 | @Retention(RetentionPolicy.RUNTIME)
51 | public @interface Emails {
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/server/BaseCahHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.server;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.JsonWrapper;
5 | import com.gianlu.pyxreloaded.data.User;
6 | import com.gianlu.pyxreloaded.singletons.Handlers;
7 | import com.gianlu.pyxreloaded.singletons.Sessions;
8 | import com.google.gson.JsonElement;
9 | import io.undertow.server.HttpServerExchange;
10 | import io.undertow.server.handlers.Cookie;
11 | import io.undertow.util.StatusCodes;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import java.io.IOException;
15 |
16 | public abstract class BaseCahHandler extends BaseJsonHandler {
17 |
18 | @Override
19 | protected JsonElement handle(HttpServerExchange exchange) throws StatusException {
20 | Cookie sid = exchange.getRequestCookies().get("PYX-Session");
21 | User user = null;
22 | if (sid != null) user = Sessions.get().getUser(sid.getValue());
23 |
24 | Parameters params;
25 | try {
26 | params = Parameters.fromExchange(exchange);
27 | } catch (IOException ex) {
28 | ex.printStackTrace();
29 | throw new StatusException(StatusCodes.INTERNAL_SERVER_ERROR, ex);
30 | }
31 |
32 | String op = params.getStringNotNull(Consts.GeneralKeys.OP);
33 | if (!Handlers.skipUserCheck(op) && user == null) {
34 | throw new CahException(Consts.ErrorCode.NOT_REGISTERED);
35 | } else if (user != null && !user.isValid()) {
36 | Sessions.get().invalidate(sid.getValue());
37 | throw new CahException(Consts.ErrorCode.SESSION_EXPIRED);
38 | } else {
39 | return handleRequest(op, user, params, exchange);
40 | }
41 | }
42 |
43 | protected abstract JsonElement handleRequest(@Nullable String op, @Nullable User user, Parameters params, HttpServerExchange exchange) throws StatusException;
44 |
45 | public static class CahException extends StatusException {
46 | public final Consts.ErrorCode code;
47 | public final JsonWrapper data;
48 |
49 | public CahException(Consts.ErrorCode code) {
50 | super(StatusCodes.CONFLICT);
51 | this.code = code;
52 | this.data = null;
53 | }
54 |
55 | public CahException(Consts.ErrorCode code, Throwable cause) {
56 | super(StatusCodes.CONFLICT, cause);
57 | this.code = code;
58 | this.data = null;
59 | }
60 |
61 | public CahException(Consts.ErrorCode code, JsonWrapper data) {
62 | super(StatusCodes.CONFLICT);
63 | this.code = code;
64 | this.data = data;
65 | }
66 |
67 | @Override
68 | public String getMessage() {
69 | return code + (data != null ? (": " + data.toString()) : "");
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/server/BaseJsonHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.server;
2 |
3 | import com.gianlu.pyxreloaded.data.JsonWrapper;
4 | import com.google.gson.JsonElement;
5 | import io.undertow.server.HttpHandler;
6 | import io.undertow.server.HttpServerExchange;
7 | import io.undertow.util.Headers;
8 | import io.undertow.util.Methods;
9 | import io.undertow.util.StatusCodes;
10 | import org.apache.log4j.Logger;
11 |
12 | import java.nio.charset.Charset;
13 |
14 | public abstract class BaseJsonHandler implements HttpHandler {
15 | protected final static Logger logger = Logger.getLogger(BaseJsonHandler.class);
16 |
17 | @Override
18 | public void handleRequest(HttpServerExchange exchange) {
19 | if (exchange.getRequestMethod() == Methods.POST) {
20 | exchange.startBlocking();
21 | if (exchange.isInIoThread()) {
22 | exchange.dispatch(this);
23 | return;
24 | }
25 |
26 | exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
27 |
28 | try {
29 | JsonElement json = handle(exchange);
30 | exchange.setStatusCode(StatusCodes.OK);
31 | exchange.getResponseSender().send(json.toString(), Charset.forName("UTF-8"));
32 | } catch (StatusException ex) {
33 | exchange.setStatusCode(ex.status);
34 |
35 | if (ex instanceof BaseCahHandler.CahException) {
36 | JsonWrapper obj = new JsonWrapper(((BaseCahHandler.CahException) ex).code);
37 | obj.addAll(((BaseCahHandler.CahException) ex).data);
38 | exchange.getResponseSender().send(obj.toString());
39 | }
40 | } catch (Throwable ex) {
41 | logger.error("Failed processing the request: " + exchange, ex);
42 | }
43 | } else {
44 | exchange.setStatusCode(StatusCodes.METHOD_NOT_ALLOWED);
45 | }
46 | }
47 |
48 | protected abstract JsonElement handle(HttpServerExchange exchange) throws StatusException;
49 |
50 | public static class StatusException extends Exception {
51 | private final int status;
52 |
53 | StatusException(int status) {
54 | super(status + ": " + StatusCodes.getReason(status));
55 | this.status = status;
56 | }
57 |
58 | StatusException(int status, Throwable cause) {
59 | super(status + ": " + StatusCodes.getReason(status), cause);
60 | cause.printStackTrace();
61 | this.status = status;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/server/CustomResourceHandler.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.server;
2 |
3 | import com.gianlu.pyxreloaded.Utils;
4 | import com.gianlu.pyxreloaded.singletons.Preferences;
5 | import io.undertow.server.HttpServerExchange;
6 | import io.undertow.server.handlers.resource.PathResourceManager;
7 | import io.undertow.server.handlers.resource.ResourceHandler;
8 | import io.undertow.server.handlers.resource.ResourceManager;
9 | import io.undertow.util.ETag;
10 | import io.undertow.util.HeaderMap;
11 | import io.undertow.util.Headers;
12 | import org.apache.log4j.Logger;
13 | import org.jetbrains.annotations.Nullable;
14 |
15 | import java.nio.file.Path;
16 | import java.nio.file.Paths;
17 |
18 | public class CustomResourceHandler extends ResourceHandler {
19 | private final boolean cacheEnabled;
20 |
21 | public CustomResourceHandler(Preferences preferences) {
22 | super(buildResourceManager(preferences));
23 |
24 | cacheEnabled = preferences.getBoolean("cacheEnabled", true);
25 | setCachable(value -> cacheEnabled);
26 | }
27 |
28 | private static ResourceManager buildResourceManager(Preferences preferences) {
29 | Path root = Paths.get(preferences.getString("webContent", "./WebContent")).toAbsolutePath();
30 | boolean cacheEnabled = preferences.getBoolean("cacheEnabled", true);
31 |
32 | return PathResourceManager.builder()
33 | .setBase(root)
34 | .setAllowResourceChangeListeners(false)
35 | .setETagFunction(new ETagSupplier(cacheEnabled, Utils.generateAlphanumericString(5)))
36 | .build();
37 | }
38 |
39 | @Override
40 | public void handleRequest(HttpServerExchange exchange) throws Exception {
41 | super.handleRequest(exchange);
42 |
43 | HeaderMap headers = exchange.getResponseHeaders();
44 | if (cacheEnabled) headers.add(Headers.CACHE_CONTROL, "private, no-cache");
45 | else headers.add(Headers.CACHE_CONTROL, "private, no-store, no-cache");
46 | }
47 |
48 | private static class ETagSupplier implements PathResourceManager.ETagFunction {
49 | private static final Logger logger = Logger.getLogger(ETagSupplier.class);
50 | private final boolean cacheEnabled;
51 | private final String serverTag;
52 |
53 | ETagSupplier(boolean cacheEnabled, String serverTag) {
54 | this.cacheEnabled = cacheEnabled;
55 | this.serverTag = serverTag;
56 |
57 | logger.info("ETag supplier: " + serverTag);
58 | }
59 |
60 | @Override
61 | @Nullable
62 | public ETag generate(Path path) {
63 | if (!cacheEnabled) return null;
64 | return new ETag(false, serverTag);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/server/HttpsRedirect.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.server;
2 |
3 | import io.undertow.server.HttpHandler;
4 | import io.undertow.server.HttpServerExchange;
5 | import io.undertow.util.Headers;
6 | import io.undertow.util.StatusCodes;
7 | import org.apache.http.client.utils.URIBuilder;
8 |
9 | public class HttpsRedirect implements HttpHandler {
10 | @Override
11 | public void handleRequest(HttpServerExchange exchange) throws Exception {
12 | URIBuilder builder = new URIBuilder(exchange.getRequestURL());
13 | builder.setScheme("https");
14 |
15 | exchange.setStatusCode(StatusCodes.MOVED_PERMANENTLY);
16 | exchange.getResponseHeaders().add(Headers.LOCATION, builder.toString());
17 | exchange.endExchange();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/server/Parameters.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.server;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import io.undertow.server.HttpServerExchange;
5 | import io.undertow.util.QueryParameterUtils;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.util.Deque;
13 | import java.util.HashMap;
14 | import java.util.Map;
15 |
16 | public class Parameters extends HashMap {
17 |
18 | private Parameters() {
19 | }
20 |
21 | public static Parameters fromExchange(HttpServerExchange exchange) throws IOException {
22 | ByteArrayOutputStream out = new ByteArrayOutputStream();
23 |
24 | InputStream in = exchange.getInputStream();
25 | byte[] buffer = new byte[8 * 1024];
26 |
27 | int read;
28 | while ((read = in.read(buffer)) != -1)
29 | out.write(buffer, 0, read);
30 |
31 | Parameters params = new Parameters();
32 | Map> rawParams = QueryParameterUtils.parseQueryString(new String(out.toByteArray()), "UTF-8");
33 | for (Map.Entry> entry : rawParams.entrySet())
34 | params.put(entry.getKey(), entry.getValue().getFirst());
35 |
36 | return params;
37 | }
38 |
39 | public boolean has(Consts.ReceivableKey key) {
40 | return get(key.toString()) != null;
41 | }
42 |
43 | @Nullable
44 | public String getString(Consts.ReceivableKey key) {
45 | return get(key.toString());
46 | }
47 |
48 | @NotNull
49 | public String getStringNotNull(Consts.ReceivableKey key) throws BaseCahHandler.CahException {
50 | String val = getString(key);
51 | if (val == null) throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_REQUEST);
52 | else return val;
53 | }
54 |
55 | public boolean getBoolean(Consts.ReceivableKey key, boolean fallback) {
56 | return getBoolean(key.toString(), fallback);
57 | }
58 |
59 | private boolean getBoolean(String key, boolean fallback) {
60 | String val = get(key);
61 | if (val == null) return false;
62 |
63 | try {
64 | return Boolean.parseBoolean(val);
65 | } catch (IllegalArgumentException | NullPointerException ex) {
66 | return fallback;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/server/Provider.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.server;
2 |
3 | public interface Provider {
4 | E get();
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/singletons/BanList.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.singletons;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | import java.sql.ResultSet;
6 | import java.sql.SQLException;
7 |
8 | public final class BanList {
9 | private final ServerDatabase db;
10 |
11 | public BanList(ServerDatabase db) {
12 | this.db = db;
13 | }
14 |
15 | public synchronized void add(@NotNull String ip) {
16 | try {
17 | db.statement().execute("INSERT OR IGNORE INTO ban_list (ip) VALUES ('" + ip + "')");
18 | } catch (SQLException ex) {
19 | throw new RuntimeException(ex);
20 | }
21 | }
22 |
23 | public synchronized boolean contains(String ip) {
24 | try (ResultSet set = db.statement().executeQuery("SELECT * FROM ban_list WHERE ip='" + ip + "'")) {
25 | return set.next();
26 | } catch (SQLException ex) {
27 | throw new RuntimeException(ex);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/singletons/Handlers.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.singletons;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.handlers.*;
5 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | import java.lang.reflect.Constructor;
9 | import java.lang.reflect.InvocationTargetException;
10 | import java.lang.reflect.Parameter;
11 | import java.util.ArrayList;
12 | import java.util.HashMap;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | public final class Handlers {
17 | private final static Map> LIST;
18 | private final static List SKIP_USER_CHECK;
19 | private static final Map, BaseHandler> handlers = new HashMap<>();
20 |
21 | static {
22 | LIST = new HashMap<>();
23 | LIST.put(BanHandler.OP, BanHandler.class);
24 | LIST.put(CardcastAddCardsetHandler.OP, CardcastAddCardsetHandler.class);
25 | LIST.put(CardcastListCardsetsHandler.OP, CardcastListCardsetsHandler.class);
26 | LIST.put(CardcastRemoveCardsetHandler.OP, CardcastRemoveCardsetHandler.class);
27 | LIST.put(ChangeGameOptionsHandler.OP, ChangeGameOptionsHandler.class);
28 | LIST.put(ChatHandler.OP, ChatHandler.class);
29 | LIST.put(CreateGameHandler.OP, CreateGameHandler.class);
30 | LIST.put(FirstLoadHandler.OP, FirstLoadHandler.class);
31 | LIST.put(GameChatHandler.OP, GameChatHandler.class);
32 | LIST.put(GameListHandler.OP, GameListHandler.class);
33 | LIST.put(GetCardsHandler.OP, GetCardsHandler.class);
34 | LIST.put(GetGameInfoHandler.OP, GetGameInfoHandler.class);
35 | LIST.put(JoinGameHandler.OP, JoinGameHandler.class);
36 | LIST.put(JudgeSelectHandler.OP, JudgeSelectHandler.class);
37 | LIST.put(KickHandler.OP, KickHandler.class);
38 | LIST.put(LeaveGameHandler.OP, LeaveGameHandler.class);
39 | LIST.put(LogoutHandler.OP, LogoutHandler.class);
40 | LIST.put(NamesHandler.OP, NamesHandler.class);
41 | LIST.put(PlayCardHandler.OP, PlayCardHandler.class);
42 | LIST.put(RegisterHandler.OP, RegisterHandler.class);
43 | LIST.put(SpectateGameHandler.OP, SpectateGameHandler.class);
44 | LIST.put(StartGameHandler.OP, StartGameHandler.class);
45 | LIST.put(StopGameHandler.OP, StopGameHandler.class);
46 | LIST.put(LikeGameHandler.OP, LikeGameHandler.class);
47 | LIST.put(DislikeGameHandler.OP, DislikeGameHandler.class);
48 | LIST.put(GetMeHandler.OP, GetMeHandler.class);
49 | LIST.put(PongHandler.OP, PongHandler.class);
50 | LIST.put(GameOptionsSuggestionDecisionHandler.OP, GameOptionsSuggestionDecisionHandler.class);
51 | LIST.put(GetSuggestedGameOptionsHandler.OP, GetSuggestedGameOptionsHandler.class);
52 | LIST.put(CreateAccountHandler.OP, CreateAccountHandler.class);
53 | LIST.put(PrepareShutdownHandler.OP, PrepareShutdownHandler.class);
54 | LIST.put(GetUserPreferencesHandler.OP, GetUserPreferencesHandler.class);
55 | LIST.put(SetUserPreferencesHandler.OP, SetUserPreferencesHandler.class);
56 |
57 | SKIP_USER_CHECK = new ArrayList<>();
58 | SKIP_USER_CHECK.add(RegisterHandler.OP);
59 | SKIP_USER_CHECK.add(FirstLoadHandler.OP);
60 | SKIP_USER_CHECK.add(CreateAccountHandler.OP);
61 | }
62 |
63 | public static boolean skipUserCheck(String op) {
64 | return SKIP_USER_CHECK.contains(op);
65 | }
66 |
67 | @NotNull
68 | public static BaseHandler obtain(String op) throws BaseCahHandler.CahException {
69 | BaseHandler handler;
70 | Class extends BaseHandler> cls = Handlers.LIST.get(op);
71 | if (cls != null) {
72 | handler = handlers.get(cls);
73 | if (handler == null) {
74 | try {
75 | Constructor> constructor = cls.getConstructors()[0];
76 | Parameter[] parameters = constructor.getParameters();
77 | Object[] objects = new Object[parameters.length];
78 |
79 | for (int i = 0; i < parameters.length; i++)
80 | objects[i] = Providers.get(parameters[i].getAnnotations()[0].annotationType()).get();
81 |
82 | handler = (BaseHandler) constructor.newInstance(objects);
83 | handlers.put(cls, handler);
84 | } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
85 | throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_OP, ex);
86 | }
87 | }
88 | } else {
89 | throw new BaseCahHandler.CahException(Consts.ErrorCode.BAD_OP);
90 | }
91 |
92 | return handler;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/singletons/LoadedCards.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.singletons;
2 |
3 | import com.gianlu.pyxreloaded.cards.PyxBlackCard;
4 | import com.gianlu.pyxreloaded.cards.PyxCardSet;
5 | import com.gianlu.pyxreloaded.cards.PyxWhiteCard;
6 | import org.apache.log4j.Logger;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | import java.sql.*;
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | public final class LoadedCards {
14 | private static final Logger logger = Logger.getLogger(LoadedCards.class);
15 | private final Set sets = new HashSet<>();
16 | private final Set whiteCards = new HashSet<>();
17 | private final Set blackCards = new HashSet<>();
18 | private final Connection conn;
19 |
20 | public LoadedCards(Preferences preferences) throws SQLException {
21 | conn = DriverManager.getConnection(preferences.getString("pyxDbUrl", "jdbc:sqlite:pyx.sqlite"));
22 | loadWhiteCards();
23 | loadBlackCards();
24 | loadSets();
25 | logger.info("Successfully loaded " + sets.size() + " card sets, " + whiteCards.size() + " white cards and " + blackCards.size() + " black cards.");
26 | }
27 |
28 | @Override
29 | protected void finalize() throws Throwable {
30 | conn.close();
31 | }
32 |
33 | @NotNull
34 | public Set getLoadedSets() {
35 | return sets;
36 | }
37 |
38 | private void loadWhiteCards() throws SQLException {
39 | try (Statement statement = conn.createStatement();
40 | ResultSet resultSet = statement.executeQuery("SELECT * FROM white_cards")) {
41 |
42 | synchronized (whiteCards) {
43 | whiteCards.clear();
44 | while (resultSet.next()) {
45 | whiteCards.add(new PyxWhiteCard(resultSet));
46 | }
47 | }
48 | }
49 | }
50 |
51 | private void loadBlackCards() throws SQLException {
52 | try (Statement statement = conn.createStatement();
53 | ResultSet resultSet = statement.executeQuery("SELECT * FROM black_cards")) {
54 |
55 | synchronized (blackCards) {
56 | blackCards.clear();
57 | while (resultSet.next()) {
58 | blackCards.add(new PyxBlackCard(resultSet));
59 | }
60 | }
61 | }
62 | }
63 |
64 | private Set getBlackCardIdsFor(int setId) throws SQLException {
65 | try (Statement statement = conn.createStatement();
66 | ResultSet resultSet = statement.executeQuery("SELECT black_card_id FROM card_set_black_card WHERE card_set_id='" + setId + "'")) {
67 |
68 | Set ids = new HashSet<>();
69 | while (resultSet.next()) ids.add(resultSet.getInt(1));
70 | return ids;
71 | }
72 | }
73 |
74 | private Set getWhiteCardIdsFor(int setId) throws SQLException {
75 | try (Statement statement = conn.createStatement();
76 | ResultSet resultSet = statement.executeQuery("SELECT white_card_id FROM card_set_white_card WHERE card_set_id='" + setId + "'")) {
77 |
78 | Set ids = new HashSet<>();
79 | while (resultSet.next()) ids.add(resultSet.getInt(1));
80 | return ids;
81 | }
82 | }
83 |
84 | private void loadSets() throws SQLException {
85 | try (Statement statement = conn.createStatement();
86 | ResultSet resultSet = statement.executeQuery("SELECT * FROM card_set ORDER BY weight, id")) {
87 |
88 | synchronized (sets) {
89 | sets.clear();
90 | while (resultSet.next()) {
91 | PyxCardSet set = new PyxCardSet(resultSet);
92 |
93 | Set blackCardIds = getBlackCardIdsFor(set.getId());
94 | for (PyxBlackCard blackCard : blackCards)
95 | if (blackCardIds.contains(blackCard.getId()))
96 | set.getBlackCards().add(blackCard);
97 |
98 |
99 | Set whiteCardIds = getWhiteCardIdsFor(set.getId());
100 | for (PyxWhiteCard whiteCard : whiteCards)
101 | if (whiteCardIds.contains(whiteCard.getId()))
102 | set.getWhiteCards().add(whiteCard);
103 |
104 | sets.add(set);
105 | }
106 | }
107 | }
108 | }
109 |
110 | public void close() throws SQLException {
111 | conn.close();
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/singletons/PreparingShutdown.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.singletons;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.EventWrapper;
5 | import com.gianlu.pyxreloaded.data.QueuedMessage;
6 | import com.gianlu.pyxreloaded.server.BaseCahHandler;
7 | import io.undertow.Undertow;
8 | import org.apache.log4j.Logger;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | import java.io.IOException;
12 | import java.sql.SQLException;
13 | import java.util.concurrent.ScheduledThreadPoolExecutor;
14 | import java.util.concurrent.TimeUnit;
15 |
16 | public final class PreparingShutdown {
17 | private static final Logger logger = Logger.getLogger(PreparingShutdown.class);
18 | private static PreparingShutdown instance;
19 | private final Undertow server;
20 | private final ScheduledThreadPoolExecutor globalTimer;
21 | private final ConnectedUsers users;
22 | private final SocialLogin socials;
23 | private final LoadedCards loadedCards;
24 | private final ServerDatabase serverDatabase;
25 | private final Object waitForEventsToBeSent = new Object();
26 | private boolean value = false;
27 | private long shutdownTime = -1;
28 |
29 | private PreparingShutdown(Undertow server, ScheduledThreadPoolExecutor globalTimer, ConnectedUsers users, SocialLogin socials, LoadedCards loadedCards, ServerDatabase serverDatabase) {
30 | this.server = server;
31 | this.globalTimer = globalTimer;
32 | this.users = users;
33 | this.socials = socials;
34 | this.loadedCards = loadedCards;
35 | this.serverDatabase = serverDatabase;
36 | }
37 |
38 | @NotNull
39 | public static PreparingShutdown get() {
40 | if (instance == null) throw new IllegalStateException();
41 | return instance;
42 | }
43 |
44 | public static void setup(Undertow server, ScheduledThreadPoolExecutor globalTimer, ConnectedUsers users, SocialLogin socials, LoadedCards loadedCards, ServerDatabase serverDatabase) {
45 | instance = new PreparingShutdown(server, globalTimer, users, socials, loadedCards, serverDatabase);
46 | }
47 |
48 | public synchronized void check() throws BaseCahHandler.CahException {
49 | if (value) throw new BaseCahHandler.CahException(Consts.ErrorCode.PREPARING_SHUTDOWN);
50 | }
51 |
52 | public synchronized boolean is() {
53 | return value;
54 | }
55 |
56 | public synchronized void set(boolean set) {
57 | if (!value) {
58 | value = set;
59 | shutdownTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10);
60 |
61 | globalTimer.schedule(this::kickAndShutdown, shutdownTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
62 | users.broadcastToAll(QueuedMessage.MessageType.SERVER, getEvent());
63 |
64 | logger.info("Shutdown will happen at " + shutdownTime);
65 | }
66 | }
67 |
68 | public EventWrapper getEvent() {
69 | EventWrapper ev = new EventWrapper(Consts.Event.PREPARING_SHUTDOWN);
70 | ev.add(Consts.GeneralKeys.BEFORE_SHUTDOWN, shutdownTime - System.currentTimeMillis());
71 | return ev;
72 | }
73 |
74 | public void allEventsSent() {
75 | synchronized (waitForEventsToBeSent) {
76 | waitForEventsToBeSent.notifyAll();
77 | }
78 | }
79 |
80 | private void kickAndShutdown() {
81 | users.preShutdown();
82 | shutdownNow();
83 | }
84 |
85 | /**
86 | * Shutdown the server if it can be done safely
87 | */
88 | public void tryShutdown() {
89 | if (value && users.canShutdown()) {
90 | shutdownNow();
91 | }
92 | }
93 |
94 | /**
95 | * Shutdown the server independently of its status
96 | */
97 | private void shutdownNow() {
98 | logger.info("Waiting for events to be sent...");
99 |
100 | synchronized (waitForEventsToBeSent) {
101 | try {
102 | waitForEventsToBeSent.wait();
103 | } catch (InterruptedException ignored) {
104 | }
105 | }
106 |
107 | logger.info("Shutting down the server!");
108 |
109 | try {
110 | server.stop();
111 | socials.close();
112 | loadedCards.close();
113 | serverDatabase.close();
114 | System.exit(0);
115 | } catch (SQLException | IOException ex) {
116 | logger.error("Shutdown wasn't clear.", ex);
117 | System.exit(1);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/singletons/Providers.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.singletons;
2 |
3 | import com.gianlu.pyxreloaded.server.Provider;
4 | import org.apache.log4j.Logger;
5 |
6 | import java.lang.annotation.Annotation;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public final class Providers {
11 | private final static Logger logger = Logger.getLogger(Providers.class);
12 | private final static Map, Provider>> providers = new HashMap, Provider>>() {
13 | @Override
14 | public Provider> put(Class extends Annotation> key, Provider> value) {
15 | logger.trace("Added provider for " + key);
16 | return super.put(key, value);
17 | }
18 | };
19 |
20 | private Providers() {
21 | throw new UnsupportedOperationException();
22 | }
23 |
24 | @SuppressWarnings("unchecked")
25 | public static Provider
get(Class extends Annotation> cls) {
26 | return (Provider
) providers.get(cls);
27 | }
28 |
29 | public static void add(Class extends Annotation> cls, Provider> provider) {
30 | providers.put(cls, provider);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/singletons/ServerDatabase.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.singletons;
2 |
3 | import java.sql.Connection;
4 | import java.sql.DriverManager;
5 | import java.sql.SQLException;
6 | import java.sql.Statement;
7 |
8 | public final class ServerDatabase {
9 | private final Connection conn;
10 |
11 | public ServerDatabase(Preferences preferences) throws SQLException {
12 | String username = preferences.getString("serverDb/username", null);
13 | String password = preferences.getString("serverDb/password", null);
14 |
15 | if (username != null && !username.isEmpty() && password != null)
16 | conn = DriverManager.getConnection(preferences.getString("serverDb/url", "jdbc:sqlite:server.sqlite"), username, password);
17 | else
18 | conn = DriverManager.getConnection(preferences.getString("serverDb/url", "jdbc:sqlite:server.sqlite"));
19 | }
20 |
21 | public Statement statement() throws SQLException {
22 | return conn.createStatement();
23 | }
24 |
25 | public void close() throws SQLException {
26 | conn.close();
27 | }
28 |
29 | @Override
30 | protected void finalize() throws Throwable {
31 | conn.close();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/singletons/Sessions.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.singletons;
2 |
3 | import com.gianlu.pyxreloaded.Utils;
4 | import com.gianlu.pyxreloaded.data.User;
5 | import org.jetbrains.annotations.Contract;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | public final class Sessions {
13 | private static final int SID_LENGTH = 24;
14 | private static Sessions instance;
15 | private final Map sessions;
16 |
17 | private Sessions() {
18 | sessions = new HashMap<>();
19 | }
20 |
21 | @NotNull
22 | public static Sessions get() {
23 | if (instance == null) instance = new Sessions();
24 | return instance;
25 | }
26 |
27 | @NotNull
28 | public static String generateNewId() {
29 | return Utils.generateAlphanumericString(SID_LENGTH);
30 | }
31 |
32 | @Contract("null -> null")
33 | @Nullable
34 | public synchronized User getUser(String sid) {
35 | if (sid == null || sid.isEmpty() || sid.length() != SID_LENGTH) return null;
36 | return sessions.get(sid);
37 | }
38 |
39 | public synchronized void invalidate(String sid) {
40 | sessions.remove(sid);
41 | }
42 |
43 | @NotNull
44 | public synchronized String add(@NotNull User user) {
45 | sessions.put(user.getSessionId(), user);
46 | return user.getSessionId();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/facebook/FacebookAuthHelper.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.facebook;
2 |
3 | import com.gianlu.pyxreloaded.singletons.Preferences;
4 | import com.google.gson.JsonElement;
5 | import com.google.gson.JsonObject;
6 | import com.google.gson.JsonParseException;
7 | import com.google.gson.JsonParser;
8 | import org.apache.http.HttpEntity;
9 | import org.apache.http.HttpResponse;
10 | import org.apache.http.client.methods.HttpGet;
11 | import org.apache.http.impl.client.CloseableHttpClient;
12 | import org.apache.http.impl.client.HttpClients;
13 | import org.jetbrains.annotations.NotNull;
14 | import org.jetbrains.annotations.Nullable;
15 |
16 | import java.io.IOException;
17 | import java.io.InputStreamReader;
18 |
19 | public class FacebookAuthHelper {
20 | private static final String DEBUG_TOKEN = "https://graph.facebook.com/debug_token";
21 | private static final String GRAPH = "https://graph.facebook.com/";
22 | private final CloseableHttpClient client;
23 | private final String appToken;
24 | private final JsonParser parser = new JsonParser();
25 | private final String appId;
26 |
27 | private FacebookAuthHelper(@NotNull String appId, @NotNull String appSecret) {
28 | this.client = HttpClients.createDefault();
29 | this.appId = appId;
30 | this.appToken = appId + "%7C" + appSecret; // URL encoded
31 | }
32 |
33 | @Nullable
34 | public static FacebookAuthHelper instantiate(Preferences preferences) {
35 | String appId = preferences.getString("socials/facebookAppId", null);
36 | if (appId == null || appId.isEmpty()) return null;
37 |
38 | String appSecret = preferences.getString("socials/facebookAppSecret", null);
39 | if (appSecret == null || appSecret.isEmpty()) return null;
40 |
41 | return new FacebookAuthHelper(appId, appSecret);
42 | }
43 |
44 | @NotNull
45 | public String appId() {
46 | return appId;
47 | }
48 |
49 | @Nullable
50 | public FacebookToken verify(@NotNull String accessToken) throws IOException, FacebookOAuthException {
51 | HttpGet get = new HttpGet(DEBUG_TOKEN + "?input_token=" + accessToken + "&access_token=" + appToken);
52 | try {
53 | HttpResponse resp = client.execute(get);
54 |
55 | HttpEntity entity = resp.getEntity();
56 | if (entity == null) throw new IOException(new NullPointerException("HttpEntity is null"));
57 |
58 | JsonElement element = parser.parse(new InputStreamReader(entity.getContent()));
59 | if (!element.isJsonObject()) throw new IOException("Response is not of type JsonObject");
60 |
61 | JsonObject obj = element.getAsJsonObject();
62 | if (obj.has("data")) {
63 | FacebookToken token = new FacebookToken(obj.getAsJsonObject("data"));
64 | if (token.valid && appId.equals(token.appId)) return token;
65 | else return null;
66 | } else if (obj.has("error")) {
67 | throw new FacebookOAuthException(obj.getAsJsonObject("error"));
68 | } else {
69 | throw new IOException("What is that? " + obj);
70 | }
71 | } catch (JsonParseException | NullPointerException ex) {
72 | throw new IOException(ex);
73 | } finally {
74 | get.releaseConnection();
75 | }
76 | }
77 |
78 | @NotNull
79 | public FacebookProfileInfo info(String userId) throws FacebookOAuthException, IOException, FacebookEmailNotVerifiedException {
80 | HttpGet get = new HttpGet(GRAPH + userId + "/?fields=picture.type(large),email&access_token=" + appToken);
81 | try {
82 | HttpResponse resp = client.execute(get);
83 |
84 | HttpEntity entity = resp.getEntity();
85 | if (entity == null) throw new IOException(new NullPointerException("HttpEntity is null"));
86 |
87 | JsonElement element = parser.parse(new InputStreamReader(entity.getContent()));
88 | if (!element.isJsonObject()) throw new IOException("Response is not of type JsonObject");
89 |
90 | JsonObject obj = element.getAsJsonObject();
91 | if (obj.has("error")) throw new FacebookOAuthException(obj.getAsJsonObject("error"));
92 | else return new FacebookProfileInfo(obj);
93 | } catch (JsonParseException | NullPointerException ex) {
94 | throw new IOException(ex);
95 | } finally {
96 | get.releaseConnection();
97 | }
98 | }
99 |
100 | public void close() throws IOException {
101 | client.close();
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/facebook/FacebookEmailNotVerifiedException.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.facebook;
2 |
3 | public class FacebookEmailNotVerifiedException extends Exception {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/facebook/FacebookOAuthException.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.facebook;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public class FacebookOAuthException extends Exception {
6 | FacebookOAuthException(JsonObject error) {
7 | super(error.get("message").getAsString());
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/facebook/FacebookProfileInfo.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.facebook;
2 |
3 | import com.google.gson.JsonElement;
4 | import com.google.gson.JsonObject;
5 |
6 | public class FacebookProfileInfo {
7 | public final String email;
8 | public final String pictureUrl;
9 |
10 | FacebookProfileInfo(JsonObject obj) throws NullPointerException, FacebookEmailNotVerifiedException {
11 | JsonElement email = obj.get("email");
12 | if (email == null || email.isJsonNull()) throw new FacebookEmailNotVerifiedException();
13 | else this.email = email.getAsString();
14 |
15 | JsonObject picture = obj.getAsJsonObject("picture").getAsJsonObject("data");
16 | this.pictureUrl = picture.get("url").getAsString();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/facebook/FacebookToken.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.facebook;
2 |
3 | import com.google.gson.JsonObject;
4 |
5 | public class FacebookToken {
6 | public final String appId;
7 | public final String userId;
8 | final boolean valid;
9 |
10 | FacebookToken(JsonObject obj) throws NullPointerException {
11 | appId = obj.get("app_id").getAsString();
12 | valid = obj.get("is_valid").getAsBoolean();
13 | userId = obj.get("user_id").getAsString();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/github/GithubEmails.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.github;
2 |
3 | import com.google.gson.JsonArray;
4 | import com.google.gson.JsonElement;
5 | import com.google.gson.JsonObject;
6 |
7 | import java.util.ArrayList;
8 |
9 | public class GithubEmails extends ArrayList {
10 | GithubEmails(JsonArray array) {
11 | for (JsonElement element : array) add(new Email(element.getAsJsonObject()));
12 | }
13 |
14 | public boolean isPrimaryEmailVerified() {
15 | for (Email email : this) {
16 | if (email.primary && email.verified)
17 | return true;
18 | }
19 |
20 | return false;
21 | }
22 |
23 | public static class Email {
24 | public final boolean verified;
25 | public final boolean primary;
26 | public final String email;
27 |
28 | Email(JsonObject obj) {
29 | verified = obj.get("verified").getAsBoolean();
30 | primary = obj.get("primary").getAsBoolean();
31 | email = obj.get("email").getAsString();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/github/GithubException.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.github;
2 |
3 | import com.google.gson.JsonObject;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | public class GithubException extends Exception {
7 | private GithubException(String message) {
8 | super(message);
9 | }
10 |
11 | @NotNull
12 | public static GithubException invalidScopes() {
13 | return new GithubException("Invalid scopes!");
14 | }
15 |
16 | @NotNull
17 | public static GithubException fromMessage(JsonObject obj) {
18 | return new GithubException(obj.get("message").getAsString());
19 | }
20 |
21 | @NotNull
22 | public static GithubException fromError(JsonObject obj) {
23 | return new GithubException(obj.get("error").getAsString());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/github/GithubProfileInfo.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.github;
2 |
3 | import com.google.gson.JsonObject;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | public class GithubProfileInfo {
7 | public final String id;
8 | public final String email;
9 | public final String avatarUrl;
10 | public final GithubEmails emails;
11 |
12 | GithubProfileInfo(JsonObject obj, @NotNull GithubEmails emails) {
13 | this.id = obj.get("id").getAsString();
14 | this.email = obj.get("email").getAsString();
15 | this.avatarUrl = obj.get("avatar_url").getAsString();
16 | this.emails = emails;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/google/GoogleApacheHttpRequest.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.google;
2 |
3 | import com.google.api.client.http.LowLevelHttpRequest;
4 | import com.google.api.client.http.LowLevelHttpResponse;
5 | import com.google.api.client.util.Preconditions;
6 | import com.google.api.client.util.StreamingContent;
7 | import org.apache.http.HttpEntityEnclosingRequest;
8 | import org.apache.http.client.HttpClient;
9 | import org.apache.http.client.config.RequestConfig;
10 | import org.apache.http.client.methods.HttpRequestBase;
11 | import org.apache.http.entity.AbstractHttpEntity;
12 |
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.io.OutputStream;
16 |
17 | final class GoogleApacheHttpRequest extends LowLevelHttpRequest {
18 | private final HttpClient httpClient;
19 | private final HttpRequestBase request;
20 |
21 | GoogleApacheHttpRequest(HttpClient httpClient, HttpRequestBase request) {
22 | this.httpClient = httpClient;
23 | this.request = request;
24 | }
25 |
26 | @Override
27 | public void addHeader(String name, String value) {
28 | request.addHeader(name, value);
29 | }
30 |
31 | @Override
32 | public void setTimeout(int connectTimeout, int readTimeout) {
33 | request.setConfig(RequestConfig.custom()
34 | .setConnectionRequestTimeout(connectTimeout)
35 | .setConnectTimeout(connectTimeout)
36 | .setSocketTimeout(readTimeout)
37 | .build());
38 | }
39 |
40 | @Override
41 | public LowLevelHttpResponse execute() throws IOException {
42 | if (getStreamingContent() != null) {
43 | ContentEntity entity = new ContentEntity(getContentLength(), getStreamingContent());
44 | entity.setContentEncoding(getContentEncoding());
45 | entity.setContentType(getContentType());
46 | ((HttpEntityEnclosingRequest) request).setEntity(entity);
47 | }
48 |
49 | return new GoogleApacheHttpResponse(request, httpClient.execute(request));
50 | }
51 |
52 | private static final class ContentEntity extends AbstractHttpEntity {
53 | private final long contentLength;
54 | private final StreamingContent streamingContent;
55 |
56 | ContentEntity(long contentLength, StreamingContent streamingContent) {
57 | this.contentLength = contentLength;
58 | this.streamingContent = Preconditions.checkNotNull(streamingContent);
59 | }
60 |
61 | @Override
62 | public InputStream getContent() {
63 | throw new UnsupportedOperationException();
64 | }
65 |
66 | @Override
67 | public long getContentLength() {
68 | return contentLength;
69 | }
70 |
71 | @Override
72 | public boolean isRepeatable() {
73 | return false;
74 | }
75 |
76 | @Override
77 | public boolean isStreaming() {
78 | return true;
79 | }
80 |
81 | @Override
82 | public void writeTo(OutputStream out) throws IOException {
83 | if (contentLength != 0) {
84 | streamingContent.writeTo(out);
85 | }
86 | }
87 | }
88 | }
89 |
90 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/google/GoogleApacheHttpResponse.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.google;
2 |
3 | import com.google.api.client.http.LowLevelHttpResponse;
4 | import org.apache.http.Header;
5 | import org.apache.http.HttpEntity;
6 | import org.apache.http.HttpResponse;
7 | import org.apache.http.StatusLine;
8 | import org.apache.http.client.methods.HttpRequestBase;
9 |
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 |
13 | final class GoogleApacheHttpResponse extends LowLevelHttpResponse {
14 | private final HttpRequestBase request;
15 | private final HttpResponse response;
16 | private final Header[] allHeaders;
17 |
18 | GoogleApacheHttpResponse(HttpRequestBase request, HttpResponse response) {
19 | this.request = request;
20 | this.response = response;
21 | allHeaders = response.getAllHeaders();
22 | }
23 |
24 | @Override
25 | public int getStatusCode() {
26 | StatusLine statusLine = response.getStatusLine();
27 | return statusLine == null ? 0 : statusLine.getStatusCode();
28 | }
29 |
30 | @Override
31 | public InputStream getContent() throws IOException {
32 | HttpEntity entity = response.getEntity();
33 | return entity == null ? null : entity.getContent();
34 | }
35 |
36 | @Override
37 | public String getContentEncoding() {
38 | HttpEntity entity = response.getEntity();
39 | if (entity != null) {
40 | Header contentEncodingHeader = entity.getContentEncoding();
41 | if (contentEncodingHeader != null) {
42 | return contentEncodingHeader.getValue();
43 | }
44 | }
45 |
46 | return null;
47 | }
48 |
49 | @Override
50 | public long getContentLength() {
51 | HttpEntity entity = response.getEntity();
52 | return entity == null ? -1 : entity.getContentLength();
53 | }
54 |
55 | @Override
56 | public String getContentType() {
57 | HttpEntity entity = response.getEntity();
58 | if (entity != null) {
59 | Header contentTypeHeader = entity.getContentType();
60 | if (contentTypeHeader != null) {
61 | return contentTypeHeader.getValue();
62 | }
63 | }
64 |
65 | return null;
66 | }
67 |
68 | @Override
69 | public String getReasonPhrase() {
70 | StatusLine statusLine = response.getStatusLine();
71 | return statusLine == null ? null : statusLine.getReasonPhrase();
72 | }
73 |
74 | @Override
75 | public String getStatusLine() {
76 | StatusLine statusLine = response.getStatusLine();
77 | return statusLine == null ? null : statusLine.toString();
78 | }
79 |
80 | @Override
81 | public int getHeaderCount() {
82 | return allHeaders.length;
83 | }
84 |
85 | @Override
86 | public String getHeaderName(int index) {
87 | return allHeaders[index].getName();
88 | }
89 |
90 | @Override
91 | public String getHeaderValue(int index) {
92 | return allHeaders[index].getValue();
93 | }
94 |
95 | @Override
96 | public void disconnect() {
97 | request.releaseConnection();
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/twitter/TwitterEmailNotVerifiedException.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.twitter;
2 |
3 | public class TwitterEmailNotVerifiedException extends Exception {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/socials/twitter/TwitterProfileInfo.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.socials.twitter;
2 |
3 | import com.google.gson.JsonElement;
4 | import com.google.gson.JsonObject;
5 |
6 | public class TwitterProfileInfo {
7 | public final String id;
8 | public final String avatarUrl;
9 | public final String email;
10 |
11 | TwitterProfileInfo(JsonObject obj) throws TwitterEmailNotVerifiedException {
12 | this.id = obj.get("id_str").getAsString();
13 | this.avatarUrl = obj.get("profile_image_url_https").getAsString()
14 | .replaceAll("(_(?:normal|bigger|mini))", "");
15 |
16 | JsonElement email = obj.get("email");
17 | if (email == null || email.isJsonNull()) throw new TwitterEmailNotVerifiedException();
18 | else this.email = email.getAsString();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/task/BroadcastGameListUpdateTask.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.task;
2 |
3 | import com.gianlu.pyxreloaded.Consts;
4 | import com.gianlu.pyxreloaded.data.EventWrapper;
5 | import com.gianlu.pyxreloaded.data.QueuedMessage.MessageType;
6 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
7 |
8 | public class BroadcastGameListUpdateTask extends SafeTimerTask {
9 | private final ConnectedUsers users;
10 | private volatile boolean needsUpdate = false;
11 |
12 | public BroadcastGameListUpdateTask(final ConnectedUsers users) {
13 | this.users = users;
14 | }
15 |
16 | public void needsUpdate() {
17 | needsUpdate = true;
18 | }
19 |
20 | @Override
21 | public void process() {
22 | if (needsUpdate) {
23 | users.broadcastToAll(MessageType.GAME_EVENT, new EventWrapper(Consts.Event.GAME_LIST_REFRESH));
24 | needsUpdate = false;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/task/SafeTimerTask.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.task;
2 |
3 | import org.apache.log4j.Logger;
4 |
5 |
6 | public abstract class SafeTimerTask implements Runnable {
7 | private static final Logger logger = Logger.getLogger(SafeTimerTask.class);
8 |
9 | @Override
10 | public final void run() {
11 | try {
12 | process();
13 | } catch (final Exception e) {
14 | logger.error("Exception running SafeTimerTask", e);
15 | }
16 | }
17 |
18 | public abstract void process();
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/gianlu/pyxreloaded/task/UserPingTask.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded.task;
2 |
3 | import com.gianlu.pyxreloaded.singletons.ConnectedUsers;
4 |
5 | import java.util.concurrent.ScheduledThreadPoolExecutor;
6 |
7 |
8 | public class UserPingTask extends SafeTimerTask {
9 | private final ConnectedUsers users;
10 | private final ScheduledThreadPoolExecutor globalTimer;
11 |
12 | public UserPingTask(ConnectedUsers users, ScheduledThreadPoolExecutor globalTimer) {
13 | this.users = users;
14 | this.globalTimer = globalTimer;
15 | }
16 |
17 | @Override
18 | public void process() {
19 | users.checkForPingAndIdleTimeouts();
20 | globalTimer.purge();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/com/gianlu/pyxreloaded/ConstantsTest.java:
--------------------------------------------------------------------------------
1 | package com.gianlu.pyxreloaded;
2 |
3 | import org.jetbrains.annotations.Nullable;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.lang.annotation.Annotation;
8 |
9 | public class ConstantsTest {
10 |
11 | private static void crossCheck(Class firstEnum, Class secondEnum) throws NoSuchFieldException {
12 | for (Object firstEnumConst : firstEnum.getEnumConstants()) {
13 | for (Object secondEnumConst : secondEnum.getEnumConstants()) {
14 | if (firstEnumConst == secondEnumConst || shouldIgnoreDuplicate(firstEnumConst, secondEnumConst))
15 | continue;
16 | Assertions.assertNotEquals(firstEnumConst.toString(), secondEnumConst.toString(),
17 | "Found equal value '" + firstEnumConst.toString() + "' in " + firstEnum.getSimpleName() + " and " + secondEnum.getSimpleName());
18 | }
19 | }
20 | }
21 |
22 | public static boolean shouldIgnoreDuplicate(Object firstEnumConst, Object secondEnumConst) throws NoSuchFieldException {
23 | Class firstIgnoreClass = getIgnoreDuplicateClass(firstEnumConst);
24 | Class secondIgnoreClass = getIgnoreDuplicateClass(secondEnumConst);
25 |
26 | if (firstIgnoreClass == null && secondIgnoreClass == null) return false;
27 |
28 | if (firstIgnoreClass != null) {
29 | if (secondEnumConst.getClass() == firstIgnoreClass)
30 | return true;
31 | }
32 |
33 | return secondIgnoreClass != null && firstEnumConst.getClass() == secondIgnoreClass;
34 |
35 | }
36 |
37 | @Nullable
38 | public static Class getIgnoreDuplicateClass(Object enumConst) throws NoSuchFieldException {
39 | for (Annotation annotation : enumConst.getClass().getField(((Enum>) enumConst).name()).getAnnotations()) {
40 | if (annotation.annotationType() == Consts.IgnoreDuplicateIn.class)
41 | return ((Consts.IgnoreDuplicateIn) annotation).value();
42 | }
43 |
44 | return null;
45 | }
46 |
47 | @Test
48 | public void checkConstants() throws NoSuchFieldException {
49 | Class[] classes = Consts.class.getClasses();
50 |
51 | for (Class klass : classes) {
52 | for (Class kklass : classes) {
53 | if (klass.isEnum() && kklass.isEnum()) crossCheck(klass, kklass);
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------