/* * DmitriyMX * 2017-01-04 */ package kinosearch.webapp; import com.google.gson.Gson; import kinosearch.core.Kino; import kinosearch.core.KinoPlay; import kinosearch.core.Tools; import kinosearch.core.warez.KinoWarez; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; @Controller public class WebAppController { private final Logger logger = Logger.getLogger(WebAppController.class.getName()); @Autowired private ApplicationContext coreContext; private void setDefaultModel(ModelMap model) { model.addAttribute("version", "2.0.10-SNAPSHOT"); model.addAttribute("rutext", "Поиск кино по пиратским кинотеатрам"); } @RequestMapping(value = {"/", "/index.html"}, method = RequestMethod.GET) public String index(ModelMap model) { setDefaultModel(model); return "index"; } @RequestMapping(value = {"/", "/index.html"}, method = RequestMethod.GET, params = {"search"}) public String search(@RequestParam("search") String searchText, ModelMap model) { if (searchText.trim().isEmpty()) { return "redirect:/"; } List list = Collections.synchronizedList(new LinkedList<>()); Map kinoWarezMap = coreContext.getBeansOfType(KinoWarez.class); ThreadGroup threadGroup = new ThreadGroup(""); for (KinoWarez kinoWarez : kinoWarezMap.values()) { //TODO надо ограничить количество одновременных потоков new Thread(threadGroup, () -> { List outList = kinoWarez.search(searchText, false); //FIXME "strong" нужно учитывать for (Kino kino : outList) { kino.setName("[" + kinoWarez.getName() + "] " + kino.getName()); } list.addAll(outList); }).start(); } // ждем максимум 15 секунд //FIXME надо бы убивать потоки, которые не успели найти контент for (int i = 0; i < 15 && threadGroup.activeCount() > 0; i++) { Tools.SafeSleep(1000); } model.put("searchtext", searchText); model.put("resultsearch", groupKino(list)); model.put("strong", false); //FIXME "strong" нужно учитывать setDefaultModel(model); return "index"; } private List groupKino(List list) { Map hashGroup = new HashMap<>(); List grouppedList = new ArrayList<>(); //TODO: необходима оптимизация Iterator itr1 = list.iterator(); int skip = 1; while (itr1.hasNext()) { Kino kino1 = itr1.next(); String s1 = Tools.cleanString(kino1.getName().replaceAll("^\\[.+?\\] ","")); if (hashGroup.containsKey(s1)) { skip++; continue; } KinoGroup group = new KinoGroup(s1, null, null); Iterator itr2 = list.iterator(); int val = 0; while (itr2.hasNext()) { if (val < skip) { val++; itr2.next(); continue; } Kino kino2 = itr2.next(); String s2 = Tools.cleanString(kino2.getName().replaceAll("^\\[.+?\\] ","")); int res = s1.compareTo(s2); if (res == 0) { if (!group.contains(kino2)) { group.add(kino2); } } } if (group.getKinolist().size() > 0) { group.add(kino1); hashGroup.put(s1, group); } else { grouppedList.add(kino1); } skip++; } grouppedList.addAll(0, hashGroup.values()); return grouppedList; } @RequestMapping(value = "/player/{warez}/**", method = RequestMethod.GET) public String player(@PathVariable() String warez, ModelMap model, HttpServletRequest request) throws MalformedURLException { KinoWarez kinoWarez = coreContext.getBean(warez, KinoWarez.class); if (kinoWarez == null) { return "redirect:/"; } //TODO а необходимость в URL точно оправдана? URL requestUrl = new URL(request.getRequestURL().toString()); KinoPlay kinoPlay = kinoWarez.player(requestUrl.getPath().substring(("/player/"+warez).length())); Gson gson = coreContext.getBean(Gson.class); model.put("json", gson.toJson(kinoPlay)); setDefaultModel(model); return "player"; } @RequestMapping(value = "/proxy/{warez}/**", method = RequestMethod.GET) public void proxy(@PathVariable String warez, HttpServletRequest request, HttpServletResponse response) throws IOException { //TODO а необходимость в URL точно оправдана? URL requestUrl = new URL(request.getRequestURL().toString()); String path = requestUrl.getPath().substring(("/proxy/"+warez+"/").length()); URL url = new URL("http://" + path); HttpURLConnection con =(HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); con.setDoOutput(true); con.setDoInput(true); con.setUseCaches(true); for (Enumeration names = request.getHeaderNames(); names.hasMoreElements();) { String headerName = names.nextElement().toString(); if (headerName.equalsIgnoreCase("referer")) continue; con.setRequestProperty(headerName, request.getHeader(headerName)); } boolean connected; int _try = 0; do { try { con.connect(); connected = true; } catch (IOException e) { con.disconnect(); connected = false; _try++; logger.log(Level.WARNING,String.format("Error connection to '%s': '%s'. Try again...", url.toString(), e.getMessage())); } } while (!connected && _try < 3); if (!connected) { response.sendError(524); return; } int statusCode = con.getResponseCode(); response.setStatus(statusCode); if (statusCode != 200 && statusCode != 206) { con.disconnect(); return; } for (Map.Entry> stringListEntry : con.getHeaderFields().entrySet()) { Map.Entry mapEntry = stringListEntry; if (mapEntry.getKey() != null) { response.setHeader(mapEntry.getKey().toString(), ((List) mapEntry.getValue()).get(0).toString()); } } BufferedInputStream webToProxyBuf = new BufferedInputStream(con.getInputStream()); BufferedOutputStream proxyToClientBuf = new BufferedOutputStream(response.getOutputStream()); int oneByte; try { while ((oneByte = webToProxyBuf.read()) != -1) { proxyToClientBuf.write(oneByte); } proxyToClientBuf.flush(); proxyToClientBuf.close(); } catch (Exception ignore) { // ignore } webToProxyBuf.close(); con.disconnect(); } @RequestMapping(value = {"/about", "/about.html"}, method = RequestMethod.GET) public String about(ModelMap model) { setDefaultModel(model); return "about"; } @RequestMapping(value = "/favicon.ico") public void favicon(HttpServletResponse response) { try { response.sendError(404); } catch (IOException e) { logger.log(Level.WARNING, "favicon 404", e); } } }