content: /*
   * Copyright 1999-2018 Alibaba Group Holding Ltd.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.alibaba.nacos.client.config.impl;
  
  import com.alibaba.nacos.api.common.Constants;
  import com.alibaba.nacos.api.utils.StringUtils;
  import com.alibaba.nacos.client.utils.ConcurrentDiskUtil;
  import com.alibaba.nacos.client.config.utils.JvmUtil;
  import com.alibaba.nacos.client.config.utils.SnapShotSwitch;
  import com.alibaba.nacos.client.utils.LogUtils;
  import com.alibaba.nacos.common.utils.IoUtils;
  import org.slf4j.Logger;
  
  import java.io.File;
  import java.io.IOException;
  
  import static com.alibaba.nacos.client.utils.ParamUtil.simplyEnvNameIfOverLimit;
  
  /**
   * Encrypted data key (EncryptedDataKey) local snapshot, disaster recovery directory related.
   *
   * @author luyanbo(RobberPhex)
   */
  public class LocalEncryptedDataKeyProcessor extends LocalConfigInfoProcessor {
      
      private static final Logger LOGGER = LogUtils.logger(LocalEncryptedDataKeyProcessor.class);
      
      private static final String FAILOVER_CHILD_1 = "encrypted-data-key";
      
      private static final String FAILOVER_CHILD_2 = "failover";
      
      private static final String FAILOVER_CHILD_3 = "failover-tenant";
      
      private static final String SNAPSHOT_CHILD_1 = "encrypted-data-key";
      
      private static final String SNAPSHOT_CHILD_2 = "snapshot";
      
      private static final String SNAPSHOT_CHILD_3 = "snapshot-tenant";
      
      private static final String SUFFIX = "_nacos";
      
      /**
       * Obtain the EncryptedDataKey of the disaster recovery configuration. NULL means there is no local file or an
       * exception is thrown.
       */
      public static String getEncryptDataKeyFailover(String envName, String dataId, String group, String tenant) {
          envName = simplyEnvNameIfOverLimit(envName);
          File file = getEncryptDataKeyFailoverFile(envName, dataId, group, tenant);
          if (!file.exists() || !file.isFile()) {
              return null;
          }
          
          try {
              return readFile(file);
          } catch (IOException ioe) {
              LOGGER.error("[" + envName + "] get failover error, " + file, ioe);
              return null;
          }
      }
      
      /**
       * Get the EncryptedDataKey of the locally cached file. NULL means there is no local file or an exception is
       * thrown.
       */
      public static String getEncryptDataKeySnapshot(String envName, String dataId, String group, String tenant) {
          
          if (!SnapShotSwitch.getIsSnapShot()) {
              return null;
          }
          File file = getEncryptDataKeySnapshotFile(envName, dataId, group, tenant);
          if (!file.exists() || !file.isFile()) {
              return null;
          }
          
          try {
              return readFile(file);
          } catch (IOException ioe) {
              LOGGER.error("[" + envName + "] get snapshot error, " + file, ioe);
              return null;
          }
      }
      
      /**
       * Save the snapshot of encryptDataKey. If the content is NULL, delete the snapshot.
       */
      public static void saveEncryptDataKeySnapshot(String envName, String dataId, String group, String tenant,
              String encryptDataKey) {
          if (!SnapShotSwitch.getIsSnapShot()) {
              return;
          }
          File file = getEncryptDataKeySnapshotFile(envName, dataId, group, tenant);
          try {
              if (null == encryptDataKey) {
                  try {
                      IoUtils.delete(file);
                  } catch (IOException ioe) {
                      LOGGER.error("[" + envName + "] delete snapshot error, " + file, ioe);
                  }
              } else {
                  File parentFile = file.getParentFile();
                  if (!parentFile.exists()) {
                      boolean isMdOk = parentFile.mkdirs();
                      if (!isMdOk) {
                          LOGGER.error("[{}] save snapshot error", envName);
                      }
                  }
                  if (JvmUtil.isMultiInstance()) {
                      ConcurrentDiskUtil.writeFileContent(file, encryptDataKey, Constants.ENCODE);
                  } else {
                      IoUtils.writeStringToFile(file, encryptDataKey, Constants.ENCODE);
                  }
              }
          } catch (IOException ioe) {
              LOGGER.error("[" + envName + "] save snapshot error, " + file, ioe);
          }
      }
      
      private static File getEncryptDataKeyFailoverFile(String envName, String dataId, String group, String tenant) {
          envName = simplyEnvNameIfOverLimit(envName);
          
          File tmp = new File(LOCAL_SNAPSHOT_PATH, envName + SUFFIX);
          tmp = new File(tmp, FAILOVER_CHILD_1);
          
          if (StringUtils.isBlank(tenant)) {
              tmp = new File(tmp, FAILOVER_CHILD_2);
          } else {
              tmp = new File(tmp, FAILOVER_CHILD_3);
              tmp = new File(tmp, tenant);
          }
          
          return new File(new File(tmp, group), dataId);
      }
      
      private static File getEncryptDataKeySnapshotFile(String envName, String dataId, String group, String tenant) {
          envName = simplyEnvNameIfOverLimit(envName);
          
          File tmp = new File(LOCAL_SNAPSHOT_PATH, envName + SUFFIX);
          tmp = new File(tmp, SNAPSHOT_CHILD_1);
          
          if (StringUtils.isBlank(tenant)) {
              tmp = new File(tmp, SNAPSHOT_CHILD_2);
          } else {
              tmp = new File(tmp, SNAPSHOT_CHILD_3);
              tmp = new File(tmp, tenant);
          }
          
          return new File(new File(tmp, group), dataId);
      }
      
  }
  