예제 #1
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;
    }
  }
예제 #2
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;
    }
  }