diff --git a/src/main/java/cz/kamma/tvcom/HttpServerApp.java b/src/main/java/cz/kamma/tvcom/HttpServerApp.java index be40765..b11d845 100644 --- a/src/main/java/cz/kamma/tvcom/HttpServerApp.java +++ b/src/main/java/cz/kamma/tvcom/HttpServerApp.java @@ -13,219 +13,257 @@ import java.util.List; public class HttpServerApp { - // ✅ Statický API klíč - private static final String API_KEY = "6666-1234"; + // ✅ Statický API klíč + private static final String API_KEY = "6666-1234"; - public static void main(String[] args) throws Exception { - TransmissionService service = new TransmissionService(); + public static void main(String[] args) throws Exception { + TransmissionService service = new TransmissionService(); - HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); - ObjectMapper mapper = new ObjectMapper(); + HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); + ObjectMapper mapper = new ObjectMapper(); - // /transmissions -> all data nebo jen pro konkrétní datum - server.createContext("/transmissions", exchange -> { - try { - setCors(exchange); - if (!checkApiKey(exchange)) return; + // /transmissions -> all data nebo jen pro konkrétní datum + server.createContext("/transmissions", exchange -> { + try { + setCors(exchange); + if (!checkApiKey(exchange)) + return; - URI uri = exchange.getRequestURI(); - String query = uri.getQuery(); - String date = null; + URI uri = exchange.getRequestURI(); + String query = uri.getQuery(); + String date = null; - if (query != null) { - for (String part : query.split("&")) { - if (part.startsWith("date=")) { - date = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8); - } - } - } + if (query != null) { + for (String part : query.split("&")) { + if (part.startsWith("date=")) { + date = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8); + } + } + } - List result; - if (date != null && !date.isBlank()) { - result = service.getByDateLazy(date); - } else { - result = service.getAll(); - } + List result; + if (date != null && !date.isBlank()) { + result = service.getByDateLazy(date); + } else { + result = service.getAll(); + } - respondJson(exchange, mapper.writeValueAsString(result)); - } catch (Exception e) { - e.printStackTrace(); - sendError(exchange, 500, e.getMessage()); - } - }); + respondJson(exchange, mapper.writeValueAsString(result)); + } catch (Exception e) { + e.printStackTrace(); + sendError(exchange, 500, e.getMessage()); + } + }); - // /search?q=... - server.createContext("/search", exchange -> { - try { - setCors(exchange); - if (!checkApiKey(exchange)) return; + // /search?q=... + server.createContext("/search", exchange -> { + try { + setCors(exchange); + if (!checkApiKey(exchange)) + return; - URI uri = exchange.getRequestURI(); - String query = null; - if (uri.getQuery() != null) { - String fullq = uri.getQuery(); - for (String part : fullq.split("&")) { - if (part.startsWith("q=")) { - query = java.net.URLDecoder.decode(part.substring(2), StandardCharsets.UTF_8.name()); - } - } - } - List results = service.search(query); - respondJson(exchange, mapper.writeValueAsString(results)); - } catch (Exception e) { - e.printStackTrace(); - sendError(exchange, 500, e.getMessage()); - } - }); + URI uri = exchange.getRequestURI(); + String query = null; + if (uri.getQuery() != null) { + String fullq = uri.getQuery(); + for (String part : fullq.split("&")) { + if (part.startsWith("q=")) { + query = java.net.URLDecoder.decode(part.substring(2), StandardCharsets.UTF_8.name()); + } + } + } + List results = service.search(query); + respondJson(exchange, mapper.writeValueAsString(results)); + } catch (Exception e) { + e.printStackTrace(); + sendError(exchange, 500, e.getMessage()); + } + }); - // /refresh endpoint - server.createContext("/refresh", exchange -> { - try { - setCors(exchange); - if (!checkApiKey(exchange)) return; + // /refresh endpoint + server.createContext("/refresh", exchange -> { + try { + setCors(exchange); + if (!checkApiKey(exchange)) + return; - if ("GET".equalsIgnoreCase(exchange.getRequestMethod())) { - // přečti volitelné datum z query stringu - String dateParam = null; - String query = exchange.getRequestURI().getQuery(); - if (query != null) { - for (String part : query.split("&")) { - if (part.startsWith("date=")) { - dateParam = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8); - break; - } - } - } + if ("GET".equalsIgnoreCase(exchange.getRequestMethod())) { + // přečti volitelné datum z query stringu + String dateParam = null; + String query = exchange.getRequestURI().getQuery(); + if (query != null) { + for (String part : query.split("&")) { + if (part.startsWith("date=")) { + dateParam = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8); + break; + } + } + } - // pokud není zadané, použij dnešní den - String dateStr = (dateParam != null && !dateParam.isBlank()) - ? dateParam - : java.time.LocalDate.now().toString(); + // pokud není zadané, použij dnešní den + String dateStr = (dateParam != null && !dateParam.isBlank()) ? dateParam + : java.time.LocalDate.now().toString(); - // načti data pro konkrétní den - System.out.println("🔄 Obnovuji data pro den: " + dateStr); - service.reloadDayAsync(dateStr); + // načti data pro konkrétní den + System.out.println("🔄 Obnovuji data pro den: " + dateStr); + service.reloadDayAsync(dateStr); - respondJson(exchange, "{\"status\":\"ok\",\"message\":\"Data pro den " + dateStr + " se obnovují.\"}"); - } else { - exchange.sendResponseHeaders(405, -1); - } - } catch (Exception e) { - sendError(exchange, 500, e.getMessage()); - } - }); + respondJson(exchange, + "{\"status\":\"ok\",\"message\":\"Data pro den " + dateStr + " se obnovují.\"}"); + } else { + exchange.sendResponseHeaders(405, -1); + } + } catch (Exception e) { + sendError(exchange, 500, e.getMessage()); + } + }); - // serve /index.html - server.createContext("/", exchange -> { - try { - setCors(exchange); - if (!checkApiKey(exchange)) return; - String path = exchange.getRequestURI().getPath(); - if ("/".equals(path) || path.isEmpty() || path.equals("/index.html")) { - String html = readResource("/index.html"); - if (html == null) { - sendError(exchange, 404, "index.html not found in resources"); - return; - } - exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8"); - byte[] bytes = html.getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(200, bytes.length); - try (OutputStream os = exchange.getResponseBody()) { - os.write(bytes); - } - } else { - sendError(exchange, 404, "Not found"); - } - } catch (Exception e) { - e.printStackTrace(); - sendError(exchange, 500, e.getMessage()); - } - }); + // serve /index.html + server.createContext("/", exchange -> { + try { + setCors(exchange); + String path = exchange.getRequestURI().getPath(); + if (path.equals("/icon.png")) { + byte[] data = readResourceAsBytes("/icon.png"); + if (data == null) { + sendError(exchange, 404, "index.html not found in resources"); + return; + } + exchange.getResponseHeaders().set("Content-Type", "image/png"); + exchange.sendResponseHeaders(200, data.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(data); + os.flush(); + } + return; + } - server.start(); - System.out.println("🚀 HTTP server běží na http://localhost:8080"); - System.out.println(" ➜ /transmissions (všechny přenosy JSON, vyžaduje X-API-KEY)"); - System.out.println(" ➜ /search?q=Brno (vyhledávání JSON, vyžaduje X-API-KEY)"); - System.out.println(" ➜ /refresh (spustí opětovné načtení dat, vyžaduje X-API-KEY)"); - System.out.println(" ➜ / (web UI)"); - } + if (!checkApiKey(exchange)) + return; + if ("/".equals(path) || path.isEmpty() || path.equals("/index.html")) { + String html = readResource("/index.html"); + if (html == null) { + sendError(exchange, 404, "index.html not found in resources"); + return; + } + exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8"); + byte[] bytes = html.getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + os.flush(); + } + } else { + sendError(exchange, 404, "Not found"); + } + } catch (Exception e) { + e.printStackTrace(); + sendError(exchange, 500, e.getMessage()); + } + }); - // ======= API Key ochrana ======= - private static boolean checkApiKey(HttpExchange exchange) throws IOException { - String query = exchange.getRequestURI().getQuery(); // např. apiKey=xxxx - String key = null; + server.start(); + System.out.println("🚀 HTTP server běží na http://localhost:8080"); + System.out.println(" ➜ /transmissions (všechny přenosy JSON, vyžaduje X-API-KEY)"); + System.out.println(" ➜ /search?q=Brno (vyhledávání JSON, vyžaduje X-API-KEY)"); + System.out.println(" ➜ /refresh (spustí opětovné načtení dat, vyžaduje X-API-KEY)"); + System.out.println(" ➜ / (web UI)"); + } - if (query != null) { - for (String part : query.split("&")) { - if (part.startsWith("apiKey=")) { - key = java.net.URLDecoder.decode(part.substring(7), StandardCharsets.UTF_8); - break; - } - } - } + private static byte[] readResourceAsBytes(String string) { + try (InputStream is = HttpServerApp.class.getResourceAsStream(string)) { + if (is == null) + return null; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + byte[] data = new byte[16384]; + int nRead; + while ((nRead = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + return buffer.toByteArray(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } - if (!API_KEY.equals(key)) { - exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8"); - byte[] bytes = "{\"error\":\"Unauthorized\"}".getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(401, bytes.length); - try (OutputStream os = exchange.getResponseBody()) { - os.write(bytes); - } - return false; - } - return true; - } + // ======= API Key ochrana ======= + private static boolean checkApiKey(HttpExchange exchange) throws IOException { + String query = exchange.getRequestURI().getQuery(); // např. apiKey=xxxx + String key = null; - // ======= CORS ======= - private static void setCors(HttpExchange exchange) { - Headers h = exchange.getResponseHeaders(); - h.set("Access-Control-Allow-Origin", "*"); - h.set("Access-Control-Allow-Methods", "GET, OPTIONS"); - h.set("Access-Control-Allow-Headers", "Content-Type, X-API-KEY"); - if ("OPTIONS".equalsIgnoreCase(exchange.getRequestMethod())) { - try { - exchange.sendResponseHeaders(204, -1); - } catch (IOException e) { - e.printStackTrace(); - } - } - } + if (query != null) { + for (String part : query.split("&")) { + if (part.startsWith("apiKey=")) { + key = java.net.URLDecoder.decode(part.substring(7), StandardCharsets.UTF_8); + break; + } + } + } - // ======= JSON odpověď ======= - private static void respondJson(HttpExchange exchange, String json) throws IOException { - exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8"); - byte[] bytes = json.getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(200, bytes.length); - try (OutputStream os = exchange.getResponseBody()) { - os.write(bytes); - } - } + if (!API_KEY.equals(key)) { + exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8"); + byte[] bytes = "{\"error\":\"Unauthorized\"}".getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(401, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + } + return false; + } + return true; + } - // ======= Chyba ======= - private static void sendError(HttpExchange exchange, int code, String message) throws IOException { - exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8"); - byte[] bytes = message.getBytes(StandardCharsets.UTF_8); - exchange.sendResponseHeaders(code, bytes.length); - try (OutputStream os = exchange.getResponseBody()) { - os.write(bytes); - } - } + // ======= CORS ======= + private static void setCors(HttpExchange exchange) { + Headers h = exchange.getResponseHeaders(); + h.set("Access-Control-Allow-Origin", "*"); + h.set("Access-Control-Allow-Methods", "GET, OPTIONS"); + h.set("Access-Control-Allow-Headers", "Content-Type, X-API-KEY"); + if ("OPTIONS".equalsIgnoreCase(exchange.getRequestMethod())) { + try { + exchange.sendResponseHeaders(204, -1); + } catch (IOException e) { + e.printStackTrace(); + } + } + } - // ======= Načtení resource ======= - private static String readResource(String resourcePath) { - try (InputStream is = HttpServerApp.class.getResourceAsStream(resourcePath)) { - if (is == null) return null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { - StringBuilder sb = new StringBuilder(); - String line; - while ((line = br.readLine()) != null) { - sb.append(line).append("\n"); - } - return sb.toString(); - } - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } + // ======= JSON odpověď ======= + private static void respondJson(HttpExchange exchange, String json) throws IOException { + exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8"); + byte[] bytes = json.getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + } + } + + // ======= Chyba ======= + private static void sendError(HttpExchange exchange, int code, String message) throws IOException { + exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8"); + byte[] bytes = message.getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(code, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + } + } + + // ======= Načtení resource ======= + private static String readResource(String resourcePath) { + try (InputStream is = HttpServerApp.class.getResourceAsStream(resourcePath)) { + if (is == null) + return null; + try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append("\n"); + } + return sb.toString(); + } + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } } diff --git a/src/main/resources/icon.png b/src/main/resources/icon.png new file mode 100644 index 0000000..554c802 Binary files /dev/null and b/src/main/resources/icon.png differ diff --git a/src/main/resources/index.html b/src/main/resources/index.html index 4961220..0c33753 100644 --- a/src/main/resources/index.html +++ b/src/main/resources/index.html @@ -2,6 +2,7 @@ + TVCOM Přenosy -

📺 TVCOM Přenosy

+

📺 TVCOM Přenosy

-
- - - - -
+
+ + +
-
Načítám data...
- +
Načítám data...
+ -