package com.torrenttunes.server.tools;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.HttpGet;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
import org.javalite.activejdbc.DB;
import org.javalite.activejdbc.DBException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spark.Request;
import spark.Response;
import spark.utils.GzipUtils;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.frostwire.jlibtorrent.TorrentInfo;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.torrenttunes.client.tools.WriteMultilingualHTMLFiles;
import com.torrenttunes.server.DataSources;
import com.torrenttunes.server.db.Actions;
import de.javakaffee.kryoserializers.KryoReflectionFactorySupport;
public class Tools {
static final Logger log = LoggerFactory.getLogger(Tools.class);
public static final Kryo KRYO = new KryoReflectionFactorySupport();
public static final Gson GSON = new Gson();
public static final Gson GSON2 = new GsonBuilder().setPrettyPrinting().create();
public static final ObjectMapper MAPPER = new ObjectMapper();
public static final SimpleDateFormat RESPONSE_HEADER_DATE_FORMAT =
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
public static void allowOnlyLocalHeaders(Request req, Response res) {
log.debug("req ip = " + req.ip());
// res.header("Access-Control-Allow-Origin", "http://mozilla.com");
// res.header("Access-Control-Allow-Origin", "null");
// res.header("Access-Control-Allow-Origin", "*");
// res.header("Access-Control-Allow-Credentials", "true");
if (!isLocalIP(req.ip())) {
throw new NoSuchElementException("Not a local ip, can't access");
}
}
public static Boolean isLocalIP(String ip) {
Boolean isLocalIP = (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1"));
return isLocalIP;
}
public static void allowAllHeaders(Request req, Response res) {
String origin = req.headers("Origin");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Origin", origin);
res.header("Content-Encoding", "gzip");
}
public static void set15MinuteCache(Request req, Response res) {
res.header("Cache-Control", "private,max-age=300,s-maxage=900");
res.header("Last-Modified", RESPONSE_HEADER_DATE_FORMAT.format(DataSources.APP_START_DATE));
}
public static void logRequestInfo(Request req) {
String origin = req.headers("Origin");
String origin2 = req.headers("origin");
String host = req.headers("Host");
log.debug("request host: " + host);
log.debug("request origin: " + origin);
log.debug("request origin2: " + origin2);
// System.out.println("origin = " + origin);
// if (DataSources.ALLOW_ACCESS_ADDRESSES.contains(req.headers("Origin"))) {
// res.header("Access-Control-Allow-Origin", origin);
// }
for (String header : req.headers()) {
log.debug("request header | " + header + " : " + req.headers(header));
}
log.debug("request ip = " + req.ip());
log.debug("request pathInfo = " + req.pathInfo());
log.debug("request host = " + req.host());
log.debug("request url = " + req.url());
}
public static final Map<String, String> createMapFromAjaxPost(String reqBody) {
log.debug(reqBody);
Map<String, String> postMap = new HashMap<String, String>();
String[] split = reqBody.split("&");
for (int i = 0; i < split.length; i++) {
String[] keyValue = split[i].split("=");
try {
if (keyValue.length > 1) {
postMap.put(URLDecoder.decode(keyValue[0], "UTF-8"),URLDecoder.decode(keyValue[1], "UTF-8"));
}
} catch (UnsupportedEncodingException |ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
throw new NoSuchElementException(e.getMessage());
}
}
log.debug(GSON2.toJson(postMap));
return postMap;
}
public static FilenameFilter TORRENT_FILE_FILTER = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".torrent");
}
};
public static void setupDirectories() {
if (!new File(DataSources.HOME_DIR()).exists()) {
log.info("Setting up ~/." + DataSources.APP_NAME + " dirs");
new File(DataSources.HOME_DIR()).mkdirs();
new File(DataSources.TORRENTS_DIR()).mkdirs();
com.torrenttunes.client.tools.DataSources.APP_NAME = DataSources.APP_NAME;
com.torrenttunes.client.tools.DataSources.MUSIC_STORAGE_PATH =
DataSources.HOME_DIR() + "/music";
new File(com.torrenttunes.client.tools.DataSources.MUSIC_STORAGE_PATH).mkdirs();
new File(com.torrenttunes.client.tools.DataSources.TORRENTS_DIR()).mkdirs();
} else {
log.info("Home directory already exists");
}
}
public static String encodeURL(String s) {
try {
return URLEncoder.encode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void copyResourcesToHomeDir(Boolean copyAnyway) {
String zipFile = null;
if (copyAnyway || !new File(DataSources.SOURCE_CODE_HOME()).exists()) {
log.info("Copying resources to ~/." + DataSources.APP_NAME + " dirs");
try {
if (new File(DataSources.SHADED_JAR_FILE).exists()) {
java.nio.file.Files.copy(Paths.get(DataSources.SHADED_JAR_FILE), Paths.get(DataSources.ZIP_FILE()),
StandardCopyOption.REPLACE_EXISTING);
zipFile = DataSources.SHADED_JAR_FILE;
} else if (new File(DataSources.SHADED_JAR_FILE_2).exists()) {
java.nio.file.Files.copy(Paths.get(DataSources.SHADED_JAR_FILE_2), Paths.get(DataSources.ZIP_FILE()),
StandardCopyOption.REPLACE_EXISTING);
zipFile = DataSources.SHADED_JAR_FILE_2;
} else {
log.info("you need to build the project first");
}
} catch (IOException e) {
e.printStackTrace();
}
Tools.unzip(new File(zipFile), new File(DataSources.SOURCE_CODE_HOME()));
// new Tools().copyJarResourcesRecursively("src", configHome);
WriteMultilingualHTMLFiles.write();
} else {
log.info("The source directory already exists");
}
}
public static void unzip(File zipfile, File directory) {
try {
ZipFile zfile = new ZipFile(zipfile);
Enumeration<? extends ZipEntry> entries = zfile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
File file = new File(directory, entry.getName());
if (entry.isDirectory()) {
file.mkdirs();
} else {
file.getParentFile().mkdirs();
InputStream in = zfile.getInputStream(entry);
try {
copy(in, file);
} finally {
in.close();
}
}
}
zfile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void copy(InputStream in, File file) throws IOException {
OutputStream out = new FileOutputStream(file);
try {
copy(in, out);
} finally {
out.close();
}
}
private static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
while (true) {
int readCount = in.read(buffer);
if (readCount < 0) {
break;
}
out.write(buffer, 0, readCount);
}
}
private static void copy(File file, OutputStream out) throws IOException {
InputStream in = new FileInputStream(file);
try {
copy(in, out);
} finally {
in.close();
}
}
public static void runSQLFile(Connection c,File sqlFile) {
try {
Statement stmt = null;
stmt = c.createStatement();
String sql;
sql = Files.toString(sqlFile, Charset.defaultCharset());
log.info(sql);
stmt.executeUpdate(sql);
stmt.close();
} catch (IOException | SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static final void dbInit() {
Properties prop = DataSources.DB_PROP;
try {
new DB("default").open("com.mysql.jdbc.Driver",
prop.getProperty("dburl") + "?useUnicode=true&characterEncoding=UTF-8",
prop.getProperty("dbuser"),
prop.getProperty("dbpassword"));
} catch (DBException e) {
e.printStackTrace();
dbClose();
dbInit();
}
}
public static final void dbClose() {
new DB("default").close();
}
public static String extractInfoHashFromMagnetLink(String magnetLink) {
// magnet:?xt=urn:btih:09c17295ccc24af400a2a91495af440b27766b5e&dn=Fugazi+-+Studio+Discography+1989-2001+%5BFLAC%5D
return magnetLink.split("btih:")[1].split("&dn")[0].toLowerCase();
}
public static String extractNameFromMagnetLink(String magnetLink) {
String encoded = magnetLink.split("&dn=")[1];
String name = null;
try {
name = URLDecoder.decode(encoded, "UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return name;
}
public static JsonNode jsonToNode(String json) {
try {
JsonNode root = MAPPER.readTree(json);
return root;
} catch (Exception e) {
log.error("json: " + json);
e.printStackTrace();
}
return null;
}
public static String nodeToJson(ObjectNode a) {
try {
return Tools.MAPPER.writeValueAsString(a);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static String nodeToJsonPretty(JsonNode a) {
try {
return Tools.MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(a);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void uninstall() {
try {
FileUtils.deleteDirectory(new File(DataSources.HOME_DIR()));
log.info("Torrenttunes-tracker uninstalled successfully.");
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String convertWikimediaCommonsURLToImageUrl(String wmLink) {
String fileName = wmLink.split("File:")[1];
String md5 = Hashing.md5().hashString(fileName, Charsets.UTF_8).toString();
String weirdPathString = md5.substring(0, 1) + "/" + md5.substring(0, 2) + "/";
String imageURL = "https://upload.wikimedia.org/wikipedia/commons/" + weirdPathString +
fileName;
return imageURL;
}
public static Boolean writeFileToResponse(File file, Request req, Response res) {
return writeFileToResponse(file.getAbsolutePath(), req, res);
}
public static Boolean writeFileToResponse(String path, Request req, Response res) {
try {
OutputStream wrappedOutputStream = GzipUtils.checkAndWrap(req.raw(),
res.raw());
IOUtils.copy(new FileInputStream(new File(path)), wrappedOutputStream);
wrappedOutputStream.flush();
wrappedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
public static HttpServletResponse writeFileToResponse2(String path, Response res) {
byte[] encoded;
try {
encoded = java.nio.file.Files.readAllBytes(Paths.get(path));
ServletOutputStream os = res.raw().getOutputStream();
os.write(encoded);
os.close();
return res.raw();
} catch (IOException e) {
throw new NoSuchElementException("Couldn't write response from path: " + path);
}
}
public static void addExternalWebServiceVarToTools() {
log.info("tools.js = " + DataSources.TOOLS_JS());
try {
List<String> lines = java.nio.file.Files.readAllLines(Paths.get(DataSources.TOOLS_JS()));
String interalServiceLine = "var localSparkService = '" +
DataSources.WEB_SERVICE_URL + "';";
String torrentTunesServiceLine = "var torrentTunesSparkService ='" +
DataSources.TORRENTTUNES_URL() + "';";
String externalServiceLine = "var externalSparkService ='" +
DataSources.EXTERNAL_URL + "';";
lines.set(0, interalServiceLine);
lines.set(1, torrentTunesServiceLine);
lines.set(2, externalServiceLine);
java.nio.file.Files.write(Paths.get(DataSources.TOOLS_JS()), lines);
Files.touch(new File(DataSources.TOOLS_JS()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String getImageFromWikipedia(String wikipedia) {
// First extract the title
String[] wikiUrlSplit = wikipedia.split("/wiki/");
String title = wikiUrlSplit[1];
String wikiQuery = "https://en.wikipedia.org/w/api.php?action=query&titles=" + title +
"&prop=pageimages&pithumbsize=300&format=json&piprop=original";
log.info("image query = " + wikiQuery);
String wikiJson = httpGetString(wikiQuery);
JsonNode node = jsonToNode(wikiJson);
JsonNode pages = node.get("query").get("pages");
String pageId = pages.getFieldNames().next();
String image = pages.get(pageId).get("thumbnail").get("original").asText();
return image;
}
public static final String httpGetString(String url) {
String res = "";
try {
URL externalURL = new URL(url);
URLConnection yc = externalURL.openConnection();
// yc.setRequestProperty("User-Agent", USER_AGENT);
BufferedReader in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
res+="\n" + inputLine;
in.close();
return res;
} catch(IOException e) {}
return res;
}
public static void setContentTypeFromFileName(String pageName, Response res) {
if (pageName.endsWith(".css")) {
res.type("text/css");
} else if (pageName.endsWith(".js")) {
res.type("application/javascript");
} else if (pageName.endsWith(".png")) {
res.type("image/png");
res.header("Content-Disposition", "attachment;");
} else if (pageName.endsWith(".svg")) {
res.type("image/svg+xml");
}
}
public static Properties loadProperties(String propertiesFileLocation) {
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream(propertiesFileLocation);
// load a properties file
prop.load(input);
} catch (IOException e) {
e.printStackTrace();
}
return prop;
}
public static void setJsonContentType(Response res) {
res.type("application/json; charset=utf-8");
}
}