package com.kinancity.core;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.kinancity.core.captcha.CaptchaProvider;
import com.kinancity.core.captcha.MockCaptchaService;
import com.kinancity.core.captcha.TwoCaptchaService;
import com.kinancity.core.errors.ConfigurationException;
import com.kinancity.core.proxy.ProxyInfo;
import com.kinancity.core.proxy.ProxyManager;
import com.kinancity.core.proxy.ProxyTester;
import com.kinancity.core.proxy.impl.HttpProxy;
import com.kinancity.core.proxy.impl.NoProxy;
import com.kinancity.core.proxy.policies.NintendoTimeLimitPolicy;
import com.kinancity.core.proxy.policies.ProxyPolicy;
import lombok.Data;
@Data
public class Configuration {
private Logger logger = LoggerFactory.getLogger(getClass());
private static final String CONFIG_FILE = "config.properties";
private static Configuration instance;
private String twoCaptchaApiKey;
private int nbThreads = 5;
private CaptchaProvider captchaProvider;
private ProxyManager proxyManager;
private ProxyPolicy proxyPolicy;
private String resultLogFilename = "result.csv";
private PrintWriter resultLogWriter;
private boolean initDone = false;
private boolean skipProxyTest = false;
private int maxRetry = 3;
// If true, everything will be mocked
private boolean dryRun = false;
public static Configuration getInstance() {
if (instance == null) {
instance = new Configuration();
instance.load(CONFIG_FILE);
}
return instance;
}
public void init() throws ConfigurationException {
try {
if (captchaProvider == null) {
captchaProvider = new TwoCaptchaService(twoCaptchaApiKey, dryRun);
}
if (proxyManager == null) {
logger.info("ProxyManager using direction connection with Nintendo policy");
proxyManager = new ProxyManager();
// Add Direct connection
proxyManager.addProxy(new ProxyInfo(new NintendoTimeLimitPolicy(), new NoProxy()));
}
resultLogWriter = new PrintWriter(new FileWriter(resultLogFilename, true));
} catch (IOException e) {
throw new ConfigurationException(e);
}
initDone = true;
}
/**
* Check if all config are OK
*
* @return
*/
public boolean checkConfiguration() {
if (!initDone) {
try {
init();
} catch (ConfigurationException e) {
logger.error("Configuration Init Failed", e);
return false;
}
}
if (captchaProvider == null) {
return false;
}
if(!skipProxyTest){
logger.info("Validating given proxies");
ProxyTester proxyTester = new ProxyTester();
List<ProxyInfo> invalidProxies = new ArrayList<>();
for (ProxyInfo proxy : proxyManager.getProxies()) {
if (!proxyTester.testProxy(proxy.getProvider())) {
logger.warn("Proxy test for {} failed, remove proxy", proxy.getProvider());
invalidProxies.add(proxy);
}
}
if(invalidProxies.isEmpty()){
logger.info("All proxies are valid");
}else{
proxyManager.getProxies().removeAll(invalidProxies);
}
if (proxyManager.getProxies().isEmpty()) {
logger.error("No valid proxy given");
return false;
}
}
return true;
}
/**
* Load config from prop file
*
* @param configFilePath
*/
private void load(String configFilePath) {
try {
Properties prop = new Properties();
File configFile = new File(CONFIG_FILE);
if (!configFile.exists()) {
logger.warn("Skipping loading configuration file, you may copy config.example.properties as config.properties and edit your configuration");
return;
}
InputStream in = new FileInputStream(configFile);
prop.load(in);
in.close();
// Load Config
this.setTwoCaptchaApiKey(prop.getProperty("twoCaptcha.key"));
this.loadProxies(prop.getProperty("proxies"));
} catch (IOException e) {
logger.error("failed loading config.properties");
}
}
public void loadProxies(String proxiesConfig) {
if (proxiesConfig != null) {
proxiesConfig = proxiesConfig.replaceAll("[\\[\\]]", "");
proxyManager = new ProxyManager();
String[] proxyDefs = proxiesConfig.split("[,;]");
for (String proxyDef : proxyDefs) {
String[] parts = proxyDef.split("[:@]");
if (parts.length == 4) {
try {
// Auth Proxy
String host = parts[2];
int port = Integer.parseInt(parts[3]);
String login = parts[0];
String pass = parts[1];
proxyManager.addProxy(new ProxyInfo(getProxyPolicyInstance(), new HttpProxy(host, port, login, pass)));
} catch (NumberFormatException e) {
logger.error("Invalid proxy {}", proxyDef);
}
} else if (parts.length == 2) {
try {
// Standard HTTP Proxy
String host = parts[0];
int port = Integer.parseInt(parts[1]);
proxyManager.addProxy(new ProxyInfo(getProxyPolicyInstance(), new HttpProxy(host, port)));
} catch (NumberFormatException e) {
logger.error("Invalid proxy {}", proxyDef);
}
}
}
logger.info("ProxyManager setup with {} proxies", proxyManager.getProxies().size());
}
}
private ProxyPolicy getProxyPolicyInstance() {
if (proxyPolicy == null) {
proxyPolicy = new NintendoTimeLimitPolicy();
// proxyPolicy = new TimeLimitPolicy(3, 20);
}
return proxyPolicy.clone();
}
}