Beispiel #1
0
  /** Profile info operation. */
  private long profInfoOp(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final PersistenceManager pm,
      final ApiAccount apiAccount)
      throws IOException {
    LOGGER.fine("API account: " + apiAccount.getUser().getEmail());

    final Integer bnetId;
    final Integer bnetSubId;
    final String gatewayString;
    final String playerName;
    final Gateway gateway;

    final String bnetProfileUrlParam = request.getParameter(PARAM_BNET_PROFILE_URL);
    if (bnetProfileUrlParam == null || bnetProfileUrlParam.isEmpty()) {
      // Player id is provided explicitly
      bnetId = getIntParam(request, PARAM_BNET_ID);
      bnetSubId = getIntParam(request, PARAM_BNET_SUBID);
      gatewayString = request.getParameter(PARAM_GATEWAY);
      playerName = request.getParameter(PARAM_PLAYER_NAME);
      if (bnetId == null
          || bnetSubId == null
          || gatewayString == null
          || gatewayString.isEmpty()
          || playerName == null
          || playerName.isEmpty()) {
        LOGGER.warning("Missing parameters!");
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing parameters!");
        return 0;
      }
      gateway = Gateway.fromBinaryValue(gatewayString);
      if (gateway == Gateway.UNKNOWN || gateway == Gateway.PUBLIC_TEST) {
        LOGGER.warning("Invalid gateway parameter: " + gatewayString);
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid gateway parameter!");
        return 0;
      }
    } else {
      // Player id is provided through his/her Battle.net profile URL
      try {
        Gateway foundGateway = null;
        for (final Gateway gateway_ : EnumCache.GATEWAYS)
          if (bnetProfileUrlParam.startsWith(gateway_.bnetUrl)) {
            foundGateway = gateway_;
            break;
          }
        if (foundGateway == null
            || foundGateway == Gateway.UNKNOWN
            || foundGateway == Gateway.PUBLIC_TEST) throw new Exception("No matching gateway!");
        gateway = foundGateway;

        final String[] urlParts = bnetProfileUrlParam.split("/");
        if (urlParts.length < 3) throw new Exception("Not enough parts in URL!");

        playerName = URLDecoder.decode(urlParts[urlParts.length - 1], "UTF-8");
        bnetSubId = Integer.valueOf(urlParts[urlParts.length - 2]);
        bnetId = Integer.valueOf(urlParts[urlParts.length - 3]);

      } catch (final Exception e) {
        LOGGER.log(Level.SEVERE, "Invalid Battle.net profile URL: " + bnetProfileUrlParam, e);
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid Battle.net profile URL!");
        return 0;
      }
    }

    long opsCharged = 1;

    final Boolean retrieveExtInfoParam = getBooleanParam(request, PARAM_RETRIEVE_EXT_INFO);
    // Default or requested values:
    final boolean retrieveExtInfo = retrieveExtInfoParam == null ? false : retrieveExtInfoParam;

    try {
      final PlayerId playerId = new PlayerId();
      playerId.battleNetId = bnetId;
      playerId.battleNetSubId = bnetSubId;
      playerId.gateway = gateway;
      playerId.name = playerName;

      final String bnetProfileUrl = playerId.getBattleNetProfileUrl(BnetLanguage.ENGLISH);

      LOGGER.fine("Bnet profile URL: " + bnetProfileUrl);

      final URLFetchService urlFetchService = URLFetchServiceFactory.getURLFetchService();

      // Default deadline: 5 seconds... increase it!
      final HTTPRequest profileRequest = new HTTPRequest(new URL(bnetProfileUrl));
      profileRequest
          .getFetchOptions()
          .setDeadline(50.0); // 50-sec deadline (leaving 10 seconds to process...
      final Future<HTTPResponse> profileFetchAsync = urlFetchService.fetchAsync(profileRequest);

      final Future<HTTPResponse> extProfileFetchAsync;
      if (retrieveExtInfo) {
        opsCharged++;
        // Start retrieving extended profile info in parallel
        final HTTPRequest extProfileRequest =
            new HTTPRequest(new URL(bnetProfileUrl + "ladder/leagues"));
        extProfileRequest
            .getFetchOptions()
            .setDeadline(50.0); // 50-sec deadline (leaving 10 seconds to process...
        extProfileFetchAsync = urlFetchService.fetchAsync(extProfileRequest);
      } else extProfileFetchAsync = null;

      final XmlBuilder xb = new XmlBuilder("1.1");

      HTTPResponse profileResponse = null;
      Profile profile = null;
      Element profInfoElement = null;
      try {
        profileResponse = profileFetchAsync.get();

        switch (profileResponse.getResponseCode()) {
          case HttpServletResponse.SC_OK:
            {
              final byte[] content = profileResponse.getContent();
              if (content.length == 0) throw new Exception("Content length = 0!");
              profile = BnetUtils.retrieveProfile(null, new ByteArrayInputStream(content));
              if (profile != null) {
                LOGGER.fine("Parse OK");

                xb.createResultElement(ProfInfoResult.OK);
                opsCharged += 2;

                profInfoElement = xb.setParentElement(xb.createElement(XTAG_PROFILE_INFO));
                // Re-include player id
                final Element playerElement =
                    xb.createElement(XTAG_PLAYER_ID, XATTR_NAME, playerName);
                playerElement.setAttribute(XATTR_BNET_ID, bnetId.toString());
                playerElement.setAttribute(XATTR_BNET_SUBID, bnetSubId.toString());
                playerElement.setAttribute(XATTR_GATEWAY, gateway.toString());
                playerElement.setAttribute(XATTR_GW_CODE, gateway.binaryValue);
                playerElement.setAttribute(XATTR_REGION, playerId.getRegion().toString());
                playerElement.setAttribute(XATTR_PROFILE_URL, bnetProfileUrl);
                final Element portraitElement =
                    xb.createElement(XTAG_PORTRAIT, XATTR_GROUP, profile.portraitGroup);
                portraitElement.setAttribute(XATTR_ROW, Integer.toString(profile.portraitRow));
                portraitElement.setAttribute(
                    XATTR_COLUMN, Integer.toString(profile.portraitColumn));
                xb.createElement(XTAG_ACHIEVEMENT_POINTS, profile.achievementPoints);
                xb.createElement(XTAG_TOTAL_CAREER_GAMES, profile.totalCareerGames);
                xb.createElement(XTAG_GAMES_THIS_SEASON, profile.gamesThisSeason);
                xb.createElement(XTAG_TERRAN_WINS, profile.terranWins);
                xb.createElement(XTAG_ZERG_WINS, profile.zergWins);
                xb.createElement(XTAG_PROTOSS_WINS, profile.protossWins);
                final Element highestSoloFlElement =
                    xb.createElement(XTAG_HIGHEST_SOLO_FL, profile.highestSoloFinishLeague);
                if (profile.highestSoloFinishTimes > 0)
                  highestSoloFlElement.setAttribute(
                      XATTR_TIMES_ACHIEVED, Integer.toString(profile.highestSoloFinishTimes));
                final Element highestTeamFlElement =
                    xb.createElement(XTAG_HIGHEST_TEAM_FL, profile.highestTeamFinishLeague);
                if (profile.highestTeamFinishTimes > 0)
                  highestTeamFlElement.setAttribute(
                      XATTR_TIMES_ACHIEVED, Integer.toString(profile.highestTeamFinishTimes));

                break;
              } else {
                LOGGER.fine("Parse error!");
                xb.createResultElement(ProfInfoResult.PARSING_ERROR); // Parse fails
              }
            }
          case HttpServletResponse.SC_NOT_FOUND:
            LOGGER.fine("Invalid player!");
            xb.createResultElement(ProfInfoResult.INVALID_PLAYER);
            break;
          default:
            // Treat other response HTTP status codes as BNET_ERROR
            throw new Exception("Response code: " + profileResponse.getResponseCode());
        }

      } catch (final Exception e) {
        LOGGER.log(Level.SEVERE, "", e);
        xb.createResultElement(ProfInfoResult.BNET_ERROR);
      } finally {
        if (retrieveExtInfo && profile == null) extProfileFetchAsync.cancel(true);
      }

      if (retrieveExtInfo && profile != null) {
        try {
          profileResponse = extProfileFetchAsync.get();

          final byte[] content;
          if (profileResponse.getResponseCode() == HttpServletResponse.SC_OK
              && (content = profileResponse.getContent()).length > 0) {
            profile =
                BnetUtils.retrieveExtProfile(null, new ByteArrayInputStream(content), profile);
            if (profile != null) {
              LOGGER.fine("Parse extended OK");

              opsCharged += 2;
              xb.setParentElement(profInfoElement);
              final Element allRankGroupsElement =
                  xb.setParentElement(xb.createElement(XTAG_ALL_RANK_GROUPS));
              int allRankGroupsCount = 0;
              for (int bracket = 0; bracket < profile.allRankss.length; bracket++) {
                final TeamRank[] allRanks = profile.allRankss[bracket];
                if (allRanks != null && allRanks.length > 0) {
                  allRankGroupsCount++;
                  xb.setParentElement(allRankGroupsElement);
                  final Element allRankGroupElement =
                      xb.createElement(XTAG_ALL_RANK_GROUP, XATTR_COUNT, allRanks.length);
                  allRankGroupElement.setAttribute(
                      XATTR_FORMAT, (bracket + 1) + "v" + (bracket + 1));

                  for (int i = 0; i < allRanks.length; i++) {
                    xb.setParentElement(allRankGroupElement);
                    final Element teamRankElement =
                        xb.setParentElement(
                            xb.createElement(
                                XTAG_TEAM_RANK, XATTR_LEAGUE, allRanks[i].league.stringValue));
                    teamRankElement.setAttribute(
                        XATTR_DIVISION_RANK, Integer.toString(allRanks[i].divisionRank));
                    // Team members
                    xb.setParentElement(
                        xb.createElement(
                            XTAG_TEAM_MEMBERS, XATTR_COUNT, allRanks[i].teamMembers.length));
                    for (final String memberName : allRanks[i].teamMembers)
                      xb.createElement(XTAG_TEAM_MEMBER, XATTR_NAME, memberName);
                  }
                }
              }
              allRankGroupsElement.setAttribute(XATTR_COUNT, Integer.toString(allRankGroupsCount));
            } else LOGGER.fine("Parse extended error!");
          }
        } catch (final Exception e) {
          LOGGER.log(
              Level.SEVERE,
              "Failed to get extended profile info, we return the basic profile info silently.",
              e);
          // Failed to get extended profile info, we return the basic profile info silently
        }
      }

      xb.printDocument(response);

      return opsCharged;

    } catch (final Exception e) {
      LOGGER.log(Level.SEVERE, "", e);
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      return 0;
    }
  }
Beispiel #2
0
  /** Parse replay operation. */
  private long parseRepOp(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final PersistenceManager pm,
      final ApiAccount apiAccount)
      throws IOException {
    final String fileContent = request.getParameter(PARAM_FILE_CONTENT);
    final Integer fileLength = getIntParam(request, PARAM_FILE_LENGTH);
    LOGGER.fine("API account: " + apiAccount.getUser().getEmail() + ", file length: " + fileLength);
    if (fileContent == null || fileContent.isEmpty() || fileLength == null) {
      LOGGER.warning("Missing parameters!");
      response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing parameters!");
      return 0;
    }

    final byte[] decodedFileContent = ServerUtils.decodeBase64String(fileContent);
    if (decodedFileContent == null) {
      LOGGER.warning("Invalid Base64 encoded file content!");
      response.sendError(
          HttpServletResponse.SC_BAD_REQUEST, "Invalid Base64 encoded file content!");
      return 0;
    }
    if (decodedFileContent.length != fileLength) {
      LOGGER.warning(
          "Supplied file length does not match decoded file content length: "
              + fileLength
              + " != "
              + decodedFileContent.length);
      response.sendError(
          HttpServletResponse.SC_BAD_REQUEST,
          "Supplied file length does not match decoded file content length!");
      return 0;
    }

    try {
      long opsCharged = 1;

      final Boolean parseMessagesParam = getBooleanParam(request, PARAM_PARSE_MESSAGES);
      final Boolean parseActionsParam = getBooleanParam(request, PARAM_PARSE_ACTIONS);

      // Default or requested values:
      final boolean parseMessages = parseMessagesParam == null ? true : parseMessagesParam;
      final boolean parseActions = parseActionsParam == null ? true : parseActionsParam;

      final Set<ReplayContent> contentToExtractSet =
          EnumSet.copyOf(ReplayFactory.GENERAL_INFO_CONTENT);
      if (parseMessages) contentToExtractSet.add(ReplayContent.MESSAGE_EVENTS);
      if (parseActions) {
        contentToExtractSet.add(ReplayContent.GAME_EVENTS);
        opsCharged++;
      }

      final Replay replay =
          ReplayFactory.parseReplay(
              "attachedFile.SC2Replay",
              new MpqParser(new ByteArrayMpqDataInput(decodedFileContent)),
              contentToExtractSet);

      final XmlBuilder xb = new XmlBuilder("1.0");
      xb.createResultElement(replay == null ? ParseRepResult.PARSING_ERROR : ParseRepResult.OK);
      xb.createElement(XTAG_ENGINE_VER, ReplayFactory.getVersion());
      if (replay == null) {
        LOGGER.fine("Replay parsing error!");
        xb.printDocument(response);
        return opsCharged;
      }

      final Element repInfoElement = xb.setParentElement(xb.createElement(XTAG_REP_INFO));
      xb.createElement(XTAG_VERSION, replay.version);
      xb.createElement(XTAG_EXPANSION, replay.details.expansion);
      final Element gameLengthSecElement =
          xb.createElement(
              XTAG_GAME_LENGTH, replay.converterGameSpeed.convertToRealTime(replay.gameLengthSec));
      gameLengthSecElement.setAttribute(XATTR_UNIT, "sec");
      gameLengthSecElement.setAttribute(
          XATTR_GAME_TIME_VALUE, Integer.toString(replay.gameLengthSec));
      xb.createElement(XTAG_GAME_LENGTH, replay.frames).setAttribute(XATTR_UNIT, "frame");
      xb.createElement(XTAG_GAME_TYPE, replay.initData.gameType);
      if (replay.initData.competitive != null)
        xb.createElement(XTAG_IS_COMPETITIVE, replay.initData.competitive);
      xb.createElement(XTAG_GAME_SPEED, replay.initData.gameSpeed);
      xb.createElement(XTAG_FORMAT, replay.initData.format);
      xb.createElement(XTAG_GATEWAY, replay.initData.gateway);
      xb.createElement(XTAG_MAP_FILE_NAME, replay.initData.mapFileName);
      xb.setParentElement(xb.createElement(XTAG_CLIENTS));
      final Player[] players = replay.details.players;
      final String[] arrangedClientNames = replay.initData.getArrangedClientNames(players);
      xb.getParentElement().setAttribute(XATTR_COUNT, Integer.toString(arrangedClientNames.length));
      for (int i = 0; i < arrangedClientNames.length; i++)
        xb.createElement(XTAG_CLIENT, arrangedClientNames[i])
            .setAttribute(XATTR_INDEX, Integer.toString(i));
      xb.setParentElement(repInfoElement);
      xb.createElement(XTAG_MAP_NAME, replay.details.originalMapName);
      xb.createDateTimeElement(XTAG_SAVE_TIME, new Date(replay.details.saveTime));
      xb.createElement(
          XTAG_SAVE_TIME_ZONE, String.format(Locale.US, "%+.2f", replay.details.saveTimeZone));
      final Element playersElement = xb.createElement(XTAG_PLAYERS);
      xb.setParentElement(playersElement);
      playersElement.setAttribute(XATTR_COUNT, Integer.toString(players.length));
      for (int i = 0; i < players.length; i++) {
        final Player player = players[i];
        xb.setParentElement(playersElement);
        xb.setParentElement(xb.createElement(XTAG_PLAYER, XATTR_INDEX, Integer.toString(i)));
        final Element playerElement =
            xb.createElement(XTAG_PLAYER_ID, XATTR_NAME, player.playerId.name);
        playerElement.setAttribute(XATTR_BNET_ID, Integer.toString(player.playerId.battleNetId));
        playerElement.setAttribute(
            XATTR_BNET_SUBID, Integer.toString(player.playerId.battleNetSubId));
        playerElement.setAttribute(XATTR_GATEWAY, player.playerId.gateway.toString());
        playerElement.setAttribute(XATTR_GW_CODE, player.playerId.gateway.binaryValue);
        playerElement.setAttribute(XATTR_REGION, player.playerId.getRegion().toString());
        playerElement.setAttribute(
            XATTR_PROFILE_URL,
            player.playerId.getBattleNetProfileUrl(player.playerId.gateway.defaultLanguage));
        xb.createElement(
            XTAG_TEAM, player.team == Player.TEAM_UNKNOWN ? TEXT_UNKNOWN : player.team);
        xb.createElement(XTAG_RACE, player.race);
        xb.createElement(XTAG_FINAL_RACE, player.finalRace);
        xb.createElement(XTAG_LEAGUE, player.getLeague());
        xb.createElement(XTAG_SWARM_LEVELS, player.getSwarmLevels());
        final Element colorElement = xb.createElement(XTAG_COLOR, XATTR_NAME, player.playerColor);
        colorElement.setAttribute(XATTR_RED, Integer.toString(player.argbColor[1]));
        colorElement.setAttribute(XATTR_GREEN, Integer.toString(player.argbColor[2]));
        colorElement.setAttribute(XATTR_BLUE, Integer.toString(player.argbColor[3]));
        xb.createElement(XTAG_TYPE, player.type);
        xb.createElement(XTAG_DIFFICULTY, player.difficulty);
        xb.createElement(XTAG_HANDICAP, player.handicap);
        xb.createElement(XTAG_IS_WINNER, player.isWinner == null ? TEXT_UNKNOWN : player.isWinner);

        if (parseActions) {
          xb.createElement(XTAG_ACTIONS_COUNT, player.actionsCount);
          xb.createElement(XTAG_EFFECTIVE_ACTIONS_COUNT, player.effectiveActionsCount);
          xb.createElement(XTAG_LAST_ACTION_FRAME, player.lastActionFrame);
          xb.createElement(XTAG_APM, ReplayUtils.calculatePlayerApm(replay, player))
              .setAttribute(
                  XATTR_EXCLUDED_ACTIONS_COUNT, Integer.toString(player.excludedActionsCount));
          xb.createElement(XTAG_EAPM, ReplayUtils.calculatePlayerEapm(replay, player))
              .setAttribute(
                  XATTR_EXCLUDED_ACTIONS_COUNT,
                  Integer.toString(player.excludedEffectiveActionsCount));
          Float fvalue;
          xb.createElement(
                  XTAG_AVG_SPAWNING_RATIO,
                  (fvalue = player.getAverageSpawningRatio()) == null
                      ? TEXT_UNKNOWN
                      : (int) (fvalue * 100))
              .setAttribute(XATTR_UNIT, "%");
          xb.createElement(
                  XTAG_AVG_INJECTION_GAP,
                  (fvalue = player.getAverageInjectionGap()) == null
                      ? TEXT_UNKNOWN
                      : ReplayUtils.formatFramesDecimal(
                          fvalue.intValue(), replay.converterGameSpeed))
              .setAttribute(XATTR_UNIT, "sec");
        }
      }

      if (parseMessages) {
        xb.setParentElement(null); // Root element
        final Element inGameChatElement =
            xb.createElement(XTAG_IN_GAME_CHAT, XATTR_COUNT, replay.messageEvents.messages.length);
        inGameChatElement.setAttribute(XATTR_PATTERN, "HH:mm:ss");
        xb.setParentElement(inGameChatElement);
        int ms = 0;
        for (final Message message : replay.messageEvents.messages) {
          ms += message.time;
          final Element messageElement =
              xb.createElement(
                  message instanceof Text ? XTAG_TEXT : XTAG_PING,
                  XATTR_CLIENT_INDEX,
                  message.client);
          messageElement.setAttribute(XATTR_CLIENT, arrangedClientNames[message.client]);
          messageElement.setAttribute(
              XATTR_TIME, ReplayUtils.formatMs(ms, replay.converterGameSpeed));
          if (message instanceof Text) {
            messageElement.setAttribute(XATTR_VALUE, ((Text) message).text);
            final byte opCode = ((Text) message).opCode;
            messageElement.setAttribute(
                XATTR_TARGET,
                opCode == MessageEvents.OP_CODE_CHAT_TO_ALL
                    ? "all"
                    : opCode == MessageEvents.OP_CODE_CHAT_TO_ALLIES
                        ? "allies"
                        : opCode == MessageEvents.OP_CODE_CHAT_TO_OBSERVERS
                            ? "observers"
                            : "unknown");
          } else if (message instanceof Blink) {
            messageElement.setAttribute(XATTR_X, ReplayUtils.formatCoordinate(((Blink) message).x));
            messageElement.setAttribute(XATTR_Y, ReplayUtils.formatCoordinate(((Blink) message).y));
          }
        }
      }

      if (parseActions) {
        final Boolean sendActionsSelectParam = getBooleanParam(request, PARAM_SEND_ACTIONS_SELECT);
        final Boolean sendActionsBuildParam = getBooleanParam(request, PARAM_SEND_ACTIONS_BUILD);
        final Boolean sendActionsTrainParam = getBooleanParam(request, PARAM_SEND_ACTIONS_TRAIN);
        final Boolean sendActionsResearchParam =
            getBooleanParam(request, PARAM_SEND_ACTIONS_RESEARCH);
        final Boolean sendActionsUpgradeParam =
            getBooleanParam(request, PARAM_SEND_ACTIONS_UPGRADE);
        final Boolean sendActionsOtherParam = getBooleanParam(request, PARAM_SEND_ACTIONS_OTHER);
        final Boolean sendActionsInactionParam =
            getBooleanParam(request, PARAM_SEND_ACTIONS_INACTION);

        // Default or requested values:
        final boolean sendActionsSelect =
            sendActionsSelectParam == null ? false : sendActionsSelectParam;
        final boolean sendActionsBuild =
            sendActionsBuildParam == null ? true : sendActionsBuildParam;
        final boolean sendActionsTrain =
            sendActionsTrainParam == null ? true : sendActionsTrainParam;
        final boolean sendActionsResearch =
            sendActionsResearchParam == null ? true : sendActionsResearchParam;
        final boolean sendActionsUpgrade =
            sendActionsUpgradeParam == null ? true : sendActionsUpgradeParam;
        final boolean sendActionsOther =
            sendActionsOtherParam == null ? false : sendActionsOtherParam;
        final boolean sendActionsInaction =
            sendActionsInactionParam == null ? false : sendActionsInactionParam;

        final Set<ActionType> sendActionTypeSet = EnumSet.noneOf(ActionType.class);
        if (sendActionsSelect) sendActionTypeSet.add(ActionType.SELECT);
        if (sendActionsBuild) sendActionTypeSet.add(ActionType.BUILD);
        if (sendActionsTrain) sendActionTypeSet.add(ActionType.TRAIN);
        if (sendActionsResearch) sendActionTypeSet.add(ActionType.RESEARCH);
        if (sendActionsUpgrade) sendActionTypeSet.add(ActionType.UPGRADE);
        if (sendActionsOther) sendActionTypeSet.add(ActionType.OTHER);
        if (sendActionsInaction) sendActionTypeSet.add(ActionType.INACTION);

        if (sendActionsSelect || sendActionsOther) opsCharged++;
        if (sendActionsInaction) opsCharged++;

        xb.setParentElement(null); // Root element
        final Element actionsElement =
            xb.createElement(
                XTAG_ACTIONS, XATTR_ALL_ACTIONS_COUNT, replay.gameEvents.actions.length);
        actionsElement.setAttribute(
            XATTR_ERROR_PARSING, Boolean.toString(replay.gameEvents.errorParsing));
        xb.setParentElement(actionsElement);

        int count = 0; // Sent actions count
        if (!sendActionTypeSet.isEmpty()) {
          final StringBuilder actionStringBuilder = new StringBuilder();
          for (final Action action : replay.gameEvents.actions)
            if (sendActionTypeSet.contains(action.type)) {
              count++;
              final Element actionElement =
                  xb.createElement(XTAG_ACTION_, XATTR_PLAYER_, action.player);
              actionElement.setAttribute(XATTR_TYPE_, ACTION_TYPE_STRINGS[action.type.ordinal()]);
              actionElement.setAttribute(XATTR_FRAME_, Integer.toString(action.frame));
              actionStringBuilder.setLength(0);
              action.customToString(actionStringBuilder);
              actionElement.setAttribute(XATTR_STRING_, actionStringBuilder.toString());
            }
        }
        actionsElement.setAttribute(XATTR_COUNT, Integer.toString(count));
      }

      xb.printDocument(response);

      return opsCharged;
    } catch (final InvalidMpqArchiveException imae) {
      LOGGER.log(Level.WARNING, "", imae);
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Invalid SC2Replay file!");
      return 0;
    } catch (final Exception e) {
      LOGGER.log(Level.SEVERE, "", e);
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      return 0;
    }
  }
Beispiel #3
0
  /** Info operation. */
  private long infoOp(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final PersistenceManager pm,
      final ApiAccount apiAccount)
      throws IOException {
    Integer daysCount = getIntParam(request, PARAM_DAYS_COUNT);
    LOGGER.fine("API account: " + apiAccount.getUser().getEmail() + ", days count: " + daysCount);

    if (daysCount != null) {
      if (daysCount < 0 || daysCount > 14) {
        LOGGER.warning("Invalid days count, must be between 0 and 14!");
        response.sendError(
            HttpServletResponse.SC_BAD_REQUEST, "Invalid days count, must be between 0 and 14!");
        return 0;
      }
    } else daysCount = 2;

    try {
      // Total + days count (last days count)
      final List<ApiCallStat> apiCallStatList =
          new JQBuilder<>(pm, ApiCallStat.class)
              .filter("ownerKey==p1 && day==p2", "KEY p1")
              .range(0, daysCount + 1)
              .desc("day")
              .get(apiAccount.getKey());

      final XmlBuilder xb = new XmlBuilder("1.0");

      xb.createResultElement(InfoResult.OK);
      xb.createElement(
          XTAG_ENGINE_VER,
          ReplayFactory
              .getVersion()); // DO NOT USE ReplayFactory.VERSION because the compiler replaces the
                              // actual ReplayFactory.VERSION and in live environment not the value
                              // from sc2gears-parsing-engine.jar will be used!
      xb.createDateTimeElement(XTAG_SERVER_TIME, new Date());

      xb.createElement(XTAG_PAID_OPS, apiAccount.getPaidOps());
      xb.createElement(
          XTAG_AVAIL_OPS,
          apiCallStatList.isEmpty()
              ? apiAccount.getPaidOps()
              : apiAccount.getPaidOps() - apiCallStatList.get(0).getUsedOps());

      final Element callStatsElement =
          xb.createElement(XTAG_CALL_STATS, XATTR_COUNT, apiCallStatList.size());
      callStatsElement.setAttribute(XATTR_PATTERN, ApiCallStat.DAY_PATTERN);
      for (final ApiCallStat apiCallStat : apiCallStatList) {
        xb.setParentElement(callStatsElement);
        xb.setParentElement(xb.createElement(XTAG_CALL_STAT, XATTR_DAY, apiCallStat.getDay()));
        xb.createElement(XTAG_API_CALLS, apiCallStat.getCalls());
        xb.createElement(XTAG_USED_OPS, apiCallStat.getUsedOps());
        xb.createElement(XTAG_AVG_EXEC_TIME, apiCallStat.getAvgExecTime())
            .setAttribute(XATTR_UNIT, "ms");
        xb.createElement(XTAG_DENIED_CALLS, apiCallStat.getDeniedCalls());
        xb.createElement(XTAG_ERRORS, apiCallStat.getErrors());

        xb.createElement(XTAG_INFO_CALLS, apiCallStat.getInfoCalls());
        xb.createElement(XTAG_AVG_INFO_EXEC_TIME, apiCallStat.getAvgInfoExecTime())
            .setAttribute(XATTR_UNIT, "ms");
        xb.createElement(XTAG_MAP_INFO_CALLS, apiCallStat.getMapInfoCalls());
        xb.createElement(XTAG_AVG_MAP_INFO_EXEC_TIME, apiCallStat.getAvgMapInfoExecTime())
            .setAttribute(XATTR_UNIT, "ms");
        xb.createElement(XTAG_PARSE_REP_CALLS, apiCallStat.getParseRepCalls());
        xb.createElement(XTAG_AVG_PARSE_REP_EXEC_TIME, apiCallStat.getAvgParseRepExecTime())
            .setAttribute(XATTR_UNIT, "ms");
        xb.createElement(XTAG_PROF_INFO_CALLS, apiCallStat.getProfInfoCalls());
        xb.createElement(XTAG_AVG_PROF_INFO_EXEC_TIME, apiCallStat.getAvgProfInfoExecTime())
            .setAttribute(XATTR_UNIT, "ms");
      }

      xb.printDocument(response);

      return 0;
    } catch (final Exception e) {
      LOGGER.log(Level.SEVERE, "", e);
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      return 0;
    }
  }
Beispiel #4
0
  /** Get map info operation. */
  private long mapInfoOp(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final PersistenceManager pm,
      final ApiAccount apiAccount)
      throws IOException {
    String mapFileName = request.getParameter(PARAM_MAP_FILE_NAME);

    LOGGER.fine(
        "API account: " + apiAccount.getUser().getEmail() + ", map file name: " + mapFileName);

    if (mapFileName == null || mapFileName.isEmpty()) {
      LOGGER.warning("Missing map file name!");
      response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing map file name!");
      return 0;
    }

    if ((mapFileName = ServerUtils.checkMapFileName(mapFileName)) == null) {
      LOGGER.warning("Invalid map file name: " + mapFileName);
      response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid map file name!");
      return 0;
    }

    try {
      final XmlBuilder xb = new XmlBuilder("1.0");

      long opsCharged = 0;

      final List<Map> mapList =
          new JQBuilder<>(pm, Map.class).filter("fname==p1", "String p1").get(mapFileName);
      if (mapList.isEmpty()) {
        // Register a task to process the map
        TaskServlet.register_processMapTask(mapFileName);
        xb.createResultElement(MapInfoResult.PROCESSING);
      } else {
        final Map map = mapList.get(0);
        switch (map.getStatus()) {
          case Map.STATUS_PROCESSING:
            xb.createResultElement(MapInfoResult.PROCESSING);
            break;
          case Map.STATUS_PARSING_ERROR:
            xb.createResultElement(MapInfoResult.PARSING_ERROR);
            break;
          case Map.STATUS_DL_ERROR:
            xb.createResultElement(MapInfoResult.DOWNLOAD_ERROR);
            break;
          case Map.STATUS_READY:
            {
              opsCharged = 1;
              xb.createResultElement(MapInfoResult.OK);
              Element element = xb.createElement(XTAG_MAP);
              element.setAttribute(XATTR_NAME, map.getName());
              element.setAttribute(XATTR_WIDTH, Integer.toString(map.getMwidth()));
              element.setAttribute(XATTR_HEIGHT, Integer.toString(map.getMheight()));
              element = xb.createElement(XTAG_MAP_IMAGE);
              element.setAttribute(XATTR_FORMAT, "JPEG");
              element.setAttribute(XATTR_SIZE, Integer.toString(map.getSize()));
              element.setAttribute(XATTR_WIDTH, Integer.toString(map.getWidth()));
              element.setAttribute(XATTR_HEIGHT, Integer.toString(map.getHeight()));
              element.setTextContent(
                  javax.xml.bind.DatatypeConverter.printBase64Binary(map.getImage().getBytes()));
              break;
            }
        }
      }

      xb.printDocument(response);

      return opsCharged;
    } catch (final Exception e) {
      LOGGER.log(Level.SEVERE, "", e);
      response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      return 0;
    }
  }
Beispiel #5
0
  @Override
  protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
      throws ServletException, IOException {
    final long startNanoTime = System.nanoTime();

    final String operation = checkProtVerAndGetOperation(PROTOCOL_VERSION_1, request, response);
    if (operation == null) return;

    final String apiKey = request.getParameter(PARAM_API_KEY);
    if (apiKey == null || apiKey.isEmpty()) {
      LOGGER.warning("Missing API key!");
      response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing API key!");
      return;
    }

    long opsCharged = 0;
    ApiAccount apiAccount = null;
    PersistenceManager pm = null;
    ResponseWrapper responseWrapper = null;
    boolean denied = false;

    try {
      pm = PMF.get().getPersistenceManager();

      // Check API key
      final List<ApiAccount> apiAccountList =
          new JQBuilder<>(pm, ApiAccount.class).filter("apiKey==p1", "String p1").get(apiKey);
      if (apiAccountList.isEmpty()) {
        LOGGER.warning("Unauthorized access, invalid API Key: " + apiKey);
        response.sendError(
            HttpServletResponse.SC_FORBIDDEN, "Unauthorized access, invalid API Key!");
        return;
      }
      apiAccount = apiAccountList.get(0);

      responseWrapper = new ResponseWrapper(response);

      // Check Ops quota
      final List<ApiCallStat> totalApiCallStatList =
          new JQBuilder<>(pm, ApiCallStat.class)
              .filter("ownerKey==p1 && day==p2", "KEY p1, String p2")
              .get(apiAccount.getKey(), ApiCallStat.DAY_TOTAL);
      final long totalUsedOps =
          totalApiCallStatList.isEmpty() ? 0 : totalApiCallStatList.get(0).getUsedOps();
      if (!OPERATION_INFO.equals(operation) && totalUsedOps >= apiAccount.getPaidOps()) {
        denied = true;
        LOGGER.warning(
            "Ops quota have been exceeded, serving denied! (API account: "
                + apiAccount.getUser().getEmail()
                + ")");
        responseWrapper.sendError(
            HttpServletResponse.SC_PAYMENT_REQUIRED,
            "Ops quota have been exceeded, serving denied!");
        return;
      }

      switch (operation) {
        case OPERATION_INFO:
          opsCharged = infoOp(request, responseWrapper, pm, apiAccount);
          break;
        case OPERATION_MAP_INFO:
          opsCharged = mapInfoOp(request, responseWrapper, pm, apiAccount);
          break;
        case OPERATION_PARSE_REPLAY:
          opsCharged = parseRepOp(request, responseWrapper, pm, apiAccount);
          break;
        case OPERATION_PROFILE_INFO:
          opsCharged = profInfoOp(request, responseWrapper, pm, apiAccount);
          break;
        default:
          LOGGER.warning(
              "Invalid Operation! (API account: " + apiAccount.getUser().getEmail() + ")");
          responseWrapper.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid Operation!");
          return;
      }

      // Notification available Ops will be checked in the task servlet, update API call stat task

    } finally {
      if (apiAccount != null)
        TaskServlet.register_updateApiCallStat(
            apiAccount.getKey(),
            apiAccount.getPaidOps(),
            apiAccount.getNotificationAvailOps(),
            opsCharged,
            (System.nanoTime() - startNanoTime) / 1000000l,
            denied,
            responseWrapper == null ? true : responseWrapper.isError(),
            operation);
      if (pm != null) pm.close();
    }
  }