/*
* This file is part of Bitsquare.
*
* Bitsquare is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.app;
import ch.qos.logback.classic.Level;
import io.bitsquare.BitsquareException;
import io.bitsquare.btc.BitcoinNetwork;
import io.bitsquare.btc.BtcOptionKeys;
import io.bitsquare.btc.UserAgent;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.crypto.KeyStorage;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.network.NetworkOptionKeys;
import io.bitsquare.storage.Storage;
import io.bitsquare.util.spring.JOptCommandLinePropertySource;
import joptsimple.OptionSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePropertySource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Properties;
import static com.google.common.base.Preconditions.checkNotNull;
public class BitsquareEnvironment extends StandardEnvironment {
private static final Logger log = LoggerFactory.getLogger(BitsquareEnvironment.class);
private static final String BITCOIN_NETWORK_PROP = "bitcoinNetwork.properties";
public static void setDefaultAppName(String defaultAppName) {
DEFAULT_APP_NAME = defaultAppName;
}
public static String DEFAULT_APP_NAME = "Bitsquare";
public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir();
public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME);
public static final String LOG_LEVEL_DEFAULT = Level.INFO.levelStr;
static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties";
static final String BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME = "bitsquareAppDirProperties";
static final String BITSQUARE_HOME_DIR_PROPERTY_SOURCE_NAME = "bitsquareHomeDirProperties";
public static final String BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME = "bitsquareClasspathProperties";
static final String BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME = "bitsquareDefaultProperties";
private final ResourceLoader resourceLoader = new DefaultResourceLoader();
private final String appName;
private final String userDataDir;
private final String appDataDir;
private final String btcNetworkDir;
private final String logLevel, priceFeedProviders;
private BitcoinNetwork bitcoinNetwork;
private final String btcNodes, seedNodes, ignoreDevMsg, useTorForBtc,
myAddress, banList, dumpStatistics, maxMemory, socks5ProxyBtcAddress, socks5ProxyHttpAddress;
public BitsquareEnvironment(OptionSet options) {
this(new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(
options)));
}
public BitcoinNetwork getBitcoinNetwork() {
return bitcoinNetwork;
}
public void saveBitcoinNetwork(BitcoinNetwork bitcoinNetwork) {
try {
Resource resource = getAppDirPropertiesResource();
File file = resource.getFile();
Properties properties = new Properties();
if (file.exists()) {
Object propertiesObject = appDirProperties().getSource();
if (propertiesObject instanceof Properties) {
properties = (Properties) propertiesObject;
} else {
log.warn("propertiesObject not instance of Properties");
}
}
properties.setProperty(BtcOptionKeys.BTC_NETWORK, bitcoinNetwork.name());
try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
properties.store(fileOutputStream, null);
} catch (IOException e1) {
log.error(e1.getMessage());
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
public String getAppDataDir() {
return appDataDir;
}
protected BitsquareEnvironment(PropertySource commandLineProperties) {
logLevel = commandLineProperties.containsProperty(CommonOptionKeys.LOG_LEVEL_KEY) ?
(String) commandLineProperties.getProperty(CommonOptionKeys.LOG_LEVEL_KEY) :
LOG_LEVEL_DEFAULT;
userDataDir = commandLineProperties.containsProperty(AppOptionKeys.USER_DATA_DIR_KEY) ?
(String) commandLineProperties.getProperty(AppOptionKeys.USER_DATA_DIR_KEY) :
DEFAULT_USER_DATA_DIR;
appName = commandLineProperties.containsProperty(AppOptionKeys.APP_NAME_KEY) ?
(String) commandLineProperties.getProperty(AppOptionKeys.APP_NAME_KEY) :
DEFAULT_APP_NAME;
appDataDir = commandLineProperties.containsProperty(AppOptionKeys.APP_DATA_DIR_KEY) ?
(String) commandLineProperties.getProperty(AppOptionKeys.APP_DATA_DIR_KEY) :
appDataDir(userDataDir, appName);
ignoreDevMsg = commandLineProperties.containsProperty(AppOptionKeys.IGNORE_DEV_MSG_KEY) ?
(String) commandLineProperties.getProperty(AppOptionKeys.IGNORE_DEV_MSG_KEY) :
"";
dumpStatistics = commandLineProperties.containsProperty(AppOptionKeys.DUMP_STATISTICS) ?
(String) commandLineProperties.getProperty(AppOptionKeys.DUMP_STATISTICS) :
"";
maxMemory = commandLineProperties.containsProperty(AppOptionKeys.MAX_MEMORY) ?
(String) commandLineProperties.getProperty(AppOptionKeys.MAX_MEMORY) :
"";
priceFeedProviders = commandLineProperties.containsProperty(AppOptionKeys.PRICE_FEED_PROVIDERS) ?
(String) commandLineProperties.getProperty(AppOptionKeys.PRICE_FEED_PROVIDERS) :
"";
seedNodes = commandLineProperties.containsProperty(NetworkOptionKeys.SEED_NODES_KEY) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.SEED_NODES_KEY) :
"";
myAddress = commandLineProperties.containsProperty(NetworkOptionKeys.MY_ADDRESS) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.MY_ADDRESS) :
"";
banList = commandLineProperties.containsProperty(NetworkOptionKeys.BAN_LIST) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.BAN_LIST) :
"";
socks5ProxyBtcAddress = commandLineProperties.containsProperty(NetworkOptionKeys.SOCKS_5_PROXY_BTC_ADDRESS) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.SOCKS_5_PROXY_BTC_ADDRESS) :
"";
socks5ProxyHttpAddress = commandLineProperties.containsProperty(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS) ?
(String) commandLineProperties.getProperty(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS) :
"";
btcNodes = commandLineProperties.containsProperty(AppOptionKeys.BTC_NODES) ?
(String) commandLineProperties.getProperty(AppOptionKeys.BTC_NODES) :
"";
useTorForBtc = commandLineProperties.containsProperty(AppOptionKeys.USE_TOR_FOR_BTC) ?
(String) commandLineProperties.getProperty(AppOptionKeys.USE_TOR_FOR_BTC) :
"";
MutablePropertySources propertySources = this.getPropertySources();
propertySources.addFirst(commandLineProperties);
try {
propertySources.addLast(appDirProperties());
propertySources.addLast(homeDirProperties());
propertySources.addLast(classpathProperties());
bitcoinNetwork = BitcoinNetwork.valueOf(getProperty(BtcOptionKeys.BTC_NETWORK, BitcoinNetwork.DEFAULT.name()).toUpperCase());
btcNetworkDir = Paths.get(appDataDir, bitcoinNetwork.name().toLowerCase()).toString();
File btcNetworkDirFile = new File(btcNetworkDir);
if (!btcNetworkDirFile.exists())
btcNetworkDirFile.mkdir();
// btcNetworkDir used in defaultProperties
propertySources.addLast(defaultProperties());
} catch (Exception ex) {
throw new BitsquareException(ex);
}
}
private Resource getAppDirPropertiesResource() {
String location = String.format("file:%s/bitsquare.properties", appDataDir);
return resourceLoader.getResource(location);
}
PropertySource<?> appDirProperties() throws Exception {
Resource resource = getAppDirPropertiesResource();
if (!resource.exists())
return new PropertySource.StubPropertySource(BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME);
return new ResourcePropertySource(BITSQUARE_APP_DIR_PROPERTY_SOURCE_NAME, resource);
}
private PropertySource<?> homeDirProperties() throws Exception {
String location = String.format("file:%s/.bitsquare/bitsquare.properties", getProperty("user.home"));
Resource resource = resourceLoader.getResource(location);
if (!resource.exists())
return new PropertySource.StubPropertySource(BITSQUARE_HOME_DIR_PROPERTY_SOURCE_NAME);
return new ResourcePropertySource(BITSQUARE_HOME_DIR_PROPERTY_SOURCE_NAME, resource);
}
private PropertySource<?> classpathProperties() throws Exception {
Resource resource = resourceLoader.getResource("classpath:bitsquare.properties");
return new ResourcePropertySource(BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME, resource);
}
private PropertySource<?> defaultProperties() {
return new PropertiesPropertySource(BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME, new Properties() {
private static final long serialVersionUID = -8478089705207326165L;
{
setProperty(CommonOptionKeys.LOG_LEVEL_KEY, logLevel);
setProperty(NetworkOptionKeys.SEED_NODES_KEY, seedNodes);
setProperty(NetworkOptionKeys.MY_ADDRESS, myAddress);
setProperty(NetworkOptionKeys.BAN_LIST, banList);
setProperty(NetworkOptionKeys.TOR_DIR, Paths.get(btcNetworkDir, "tor").toString());
setProperty(NetworkOptionKeys.NETWORK_ID, String.valueOf(bitcoinNetwork.ordinal()));
setProperty(NetworkOptionKeys.SOCKS_5_PROXY_BTC_ADDRESS, socks5ProxyBtcAddress);
setProperty(NetworkOptionKeys.SOCKS_5_PROXY_HTTP_ADDRESS, socks5ProxyHttpAddress);
setProperty(AppOptionKeys.APP_DATA_DIR_KEY, appDataDir);
setProperty(AppOptionKeys.IGNORE_DEV_MSG_KEY, ignoreDevMsg);
setProperty(AppOptionKeys.DUMP_STATISTICS, dumpStatistics);
setProperty(AppOptionKeys.APP_NAME_KEY, appName);
setProperty(AppOptionKeys.MAX_MEMORY, maxMemory);
setProperty(AppOptionKeys.USER_DATA_DIR_KEY, userDataDir);
setProperty(AppOptionKeys.PRICE_FEED_PROVIDERS, priceFeedProviders);
setProperty(AppOptionKeys.BTC_NODES, btcNodes);
setProperty(AppOptionKeys.USE_TOR_FOR_BTC, useTorForBtc);
setProperty(UserAgent.NAME_KEY, appName);
setProperty(UserAgent.VERSION_KEY, Version.VERSION);
setProperty(BtcOptionKeys.WALLET_DIR, btcNetworkDir);
setProperty(Storage.DIR_KEY, Paths.get(btcNetworkDir, "db").toString());
setProperty(KeyStorage.DIR_KEY, Paths.get(btcNetworkDir, "keys").toString());
}
});
}
public static String defaultUserDataDir() {
if (Utilities.isWindows())
return System.getenv("APPDATA");
else if (Utilities.isOSX())
return Paths.get(System.getProperty("user.home"), "Library", "Application Support").toString();
else // *nix
return Paths.get(System.getProperty("user.home"), ".local", "share").toString();
}
private static String appDataDir(String userDataDir, String appName) {
return Paths.get(userDataDir, appName).toString();
}
}