-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
494 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package sls; | ||
import java.sql.Connection; | ||
import java.sql.DriverManager; | ||
import java.sql.SQLException; | ||
import java.sql.Statement; | ||
|
||
public class DB_handler { | ||
|
||
private static final String DATABASE_PATH = "jdbc:sqlite:short_links.db"; | ||
|
||
public static Connection connect() { | ||
Connection cursor; | ||
try { | ||
cursor = DriverManager.getConnection(DATABASE_PATH); | ||
} catch (SQLException error) { | ||
throw new RuntimeException(error); | ||
} | ||
createTables(cursor); | ||
return cursor; | ||
} | ||
|
||
private static void createTables(Connection cursor) { | ||
String sql_links = """ | ||
CREATE TABLE links ( | ||
id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
uuid TEXT NOT NULL, | ||
link_original TEXT NOT NULL, | ||
link_short TEXT NOT NULL, | ||
following_limit INTEGER NOT NULL, | ||
time_created INTEGER NOT NULL, | ||
FOREIGN KEY (uuid) REFERENCES users (uuid) | ||
); | ||
"""; | ||
|
||
String sql_users = """ | ||
CREATE TABLE users ( | ||
id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
uuid TEXT NOT NULL DEFAULT (lower(hex(randomblob(16)))), | ||
name TEXT NOT NULL UNIQUE | ||
); | ||
"""; | ||
|
||
try (Statement stmt = cursor.createStatement()) { | ||
stmt.execute(sql_users); | ||
stmt.execute(sql_links); | ||
} catch (SQLException e) { | ||
System.out.println(e.getMessage()); | ||
} | ||
|
||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package sls; | ||
|
||
import com.sun.net.httpserver.HttpServer; | ||
import java.io.IOException; | ||
import java.net.InetSocketAddress; | ||
import java.sql.Connection; | ||
|
||
public class Main { | ||
public static void main(String[] args) throws IOException { | ||
|
||
Connection cursor = DB_handler.connect(); | ||
|
||
HttpServer server = HttpServer.create(new InetSocketAddress(10070), 0); | ||
|
||
server.createContext("/reg_short_link/", new reg_handler.GetShortLink(cursor)); | ||
server.createContext("/goto/", new follower.GoToResource(cursor)); | ||
server.createContext("/links_list/", new get_url_list.GetUrlList(cursor)); | ||
server.createContext("/delete_link/", new delete_link.DeleteLink(cursor)); | ||
|
||
server.setExecutor(null); | ||
server.start(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
Сервис работает, например, через curl или другой http клиент. Данные хранятся в СУБД sqlite. | ||
Время жизни ссылки 24 часа. Удаляется при попытке редиректа методом goto с условием, что время создания истекло относительно текущего. | ||
|
||
У сервиса есть 4 метода для взаимодействия: | ||
1) reg_short_link - регистрация пользователя и получения uuid или напоминания. | ||
Пример использования: curl http://127.0.0.1:10070/reg_short_link/artem/5?https://music.yandex.ru/home | ||
Пример ответа: "Пользователь с таким именем уже существует. uuid: **ac4afb9df4297ec9bbae3d6c10d97533**. Используйте uuid вместе с укороченной ссылкой **VDvxIBIN** в методе goto (http://127.0.0.1:10070/goto/VDvxIBIN?ac4afb9df4297ec9bbae3d6c10d97533) для редиректа на нужны ресурс: https://music.yandex.ru/home" | ||
|
||
2) goto - метод редиректа на оригинальный линк. | ||
Пример использования: curl http://127.0.0.1:10070/goto/VDvxIBIN?ac4afb9df4297ec9bbae3d6c10d97533 | ||
Пример ответа: "Переход на оригинальную ссылку https://music.yandex.ru/home успешно выполнен. Осталось 4 переходов" | ||
|
||
3) links_list - позволяет получить актуальный лист созданных пользователем ссылок, их временем создания, количеством оставшихся лимитов редиректов. | ||
Пример использования: curl http://127.0.0.1:10070/links_list/ac4afb9df4297ec9bbae3d6c10d97533 | ||
Пример ответа: | ||
Short Link: ZyK5emzk, Original Link: https://stackoverflow.com, Created time: 1733437935, Limit: 0 | ||
Short Link: VDvxIBIN, Original Link: https://music.yandex.ru/home, Created time: 1733518356, Limit: 5 | ||
|
||
4) delete_link - позволяет удалить любую ссылку пользователя, например, когда лимит редиректов исчерпан, а время истечения наступит еще не скоро. | ||
Пример использования: http://127.0.0.1:10070/delete_link/VDvxIBIN | ||
Пример ответа: "Короткая ссылка VDvxIBIN была удалена." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package sls; | ||
|
||
import com.sun.net.httpserver.HttpExchange; | ||
import com.sun.net.httpserver.HttpHandler; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
|
||
|
||
public class delete_link { | ||
static class DeleteLink implements HttpHandler { | ||
private final Connection cursor; | ||
|
||
public DeleteLink(Connection cursor) { | ||
this.cursor = cursor; | ||
} | ||
|
||
public void handle(HttpExchange exchange) throws IOException { | ||
String received_link_short = exchange.getRequestURI().getPath().split("/")[2]; | ||
String response; | ||
|
||
try { | ||
boolean check_delete = deleteLink(received_link_short); | ||
if (check_delete) { | ||
response = String.format("Короткая ссылка %s была удалена.", received_link_short); | ||
} | ||
else { | ||
response = String.format("Короткая ссылка не была найдена, удалять нечего.", received_link_short); | ||
} | ||
} catch (SQLException e) { | ||
response = String.format("Удаление ссылки %s завершилось неудачно.", received_link_short); | ||
} | ||
|
||
exchange.sendResponseHeaders(200, response.getBytes().length); | ||
OutputStream os = exchange.getResponseBody(); | ||
os.write(response.getBytes()); | ||
os.close(); | ||
} | ||
|
||
private boolean deleteLink(String link_short) throws SQLException { | ||
String deleteSQL = "DELETE FROM links WHERE link_short = ?"; | ||
|
||
try (PreparedStatement pstmt = cursor.prepareStatement(deleteSQL)) { | ||
pstmt.setString(1, link_short); | ||
int rows = pstmt.executeUpdate(); | ||
return rows > 0; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package sls; | ||
|
||
import com.sun.net.httpserver.HttpExchange; | ||
import com.sun.net.httpserver.HttpHandler; | ||
|
||
import java.awt.*; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.time.Instant; | ||
import java.util.Objects; | ||
|
||
public class follower { | ||
static class GoToResource implements HttpHandler { | ||
private final Connection cursor; | ||
|
||
public GoToResource(Connection cursor) { | ||
this.cursor = cursor; | ||
} | ||
|
||
public void handle(HttpExchange exchange) throws IOException { | ||
Instant now = Instant.now(); | ||
long current_ts = now.getEpochSecond(); | ||
|
||
String received_short_url = exchange.getRequestURI().getPath().split("/")[2]; | ||
String uuid_query = exchange.getRequestURI().getQuery(); | ||
String response; | ||
|
||
try { | ||
Object[] result = getShortLink(received_short_url); | ||
if (result != null) { | ||
String link_short = (String) result[0]; | ||
String link_original = (String) result[1]; | ||
long link_created = (long) result[2]; | ||
int following_limit = (int) result[3]; | ||
String uuid = (String) result[4]; | ||
|
||
if (Objects.equals(uuid_query, uuid)) { | ||
if (current_ts - link_created >= 86400) { | ||
deleteExpiredLink(link_short); | ||
response = String.format("Извините, но ваша ссылка %s -> %s просрочилась и была удалена (срок хранения 24 часа). Создайте новую методом reg_short_link", link_short, link_original); | ||
} else if (following_limit < 1) { | ||
response = String.format("Извините, но ваша ссылка %s -> %s исчерпала лимит переходов. Она будет удалена в течение 24 часов. Удалите текущую ссылку методом delete_link и создайте новую методом reg_short_link\nПосмотреть текущий список ссылок можно методом links_list", link_short, link_original); | ||
} else { | ||
updateCountFollowing(link_short, following_limit - 1); | ||
Desktop.getDesktop().browse(new URI(link_original)); | ||
response = String.format("Переход на оригинальную ссылку %s успешно выполнен. Осталось %d переходов", link_original, following_limit - 1); | ||
} | ||
} else { | ||
response = "Извините, но пользователя с таким uuid нет. Зарегистрируйтесь методом reg_short_link"; | ||
} | ||
} else { | ||
response = "Извините, но такой ссылки нет. Сделайте новую методом reg_short_link"; | ||
} | ||
} catch (SQLException | URISyntaxException e) { | ||
response = "Произошла ошибка обработки запроса. Попробуйте позже."; | ||
} | ||
|
||
exchange.sendResponseHeaders(200, response.getBytes().length); | ||
try (OutputStream os = exchange.getResponseBody()) { | ||
os.write(response.getBytes()); | ||
} | ||
} | ||
|
||
private Object[] getShortLink(String link_short) throws SQLException { | ||
String query = "SELECT link_short, link_original, time_created, following_limit, uuid FROM links WHERE link_short = ?"; | ||
try (PreparedStatement pstmt = cursor.prepareStatement(query)) { | ||
pstmt.setString(1, link_short); | ||
try (ResultSet rs = pstmt.executeQuery()) { | ||
if (rs.next()) { | ||
return new Object[]{rs.getString("link_short"), | ||
rs.getString("link_original"), | ||
rs.getLong("time_created"), | ||
rs.getInt("following_limit"), | ||
rs.getString("uuid")}; | ||
} | ||
else { | ||
return null; | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void deleteExpiredLink(String link_short) throws SQLException { | ||
String deleteSQL = "DELETE FROM links WHERE link_short = ?"; | ||
|
||
try (PreparedStatement pstmt = cursor.prepareStatement(deleteSQL)) { | ||
pstmt.setString(1, link_short); | ||
pstmt.executeUpdate(); | ||
} | ||
} | ||
|
||
private void updateCountFollowing(String link_short, int following_limit) throws SQLException { | ||
String updateSQL = "UPDATE links SET following_limit = ? WHERE link_short = ?"; | ||
|
||
try (PreparedStatement pstmt = cursor.prepareStatement(updateSQL)) { | ||
pstmt.setInt(1, following_limit); | ||
pstmt.setString(2, link_short); | ||
pstmt.executeUpdate(); | ||
} | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package sls; | ||
|
||
import com.sun.net.httpserver.HttpExchange; | ||
import com.sun.net.httpserver.HttpHandler; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class get_url_list { | ||
static class GetUrlList implements HttpHandler { | ||
private final Connection cursor; | ||
|
||
public GetUrlList(Connection cursor) { | ||
this.cursor = cursor; | ||
} | ||
|
||
public void handle(HttpExchange exchange) throws IOException { | ||
String received_uuid = exchange.getRequestURI().getPath().split("/")[2]; | ||
|
||
List<Object[]> results; | ||
try { | ||
results = getLinksData(received_uuid); | ||
} catch (SQLException e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
if (results != null) { | ||
StringBuilder responseBuilder = new StringBuilder(); | ||
for (Object[] result : results) { | ||
String link_short = (String) result[0]; | ||
String link_original = (String) result[1]; | ||
long link_created = (long) result[2]; | ||
int following_limit = (int) result[3]; | ||
|
||
responseBuilder.append(String.format( | ||
"Short Link: %s, Original Link: %s, Created time: %d, Limit: %d\n", | ||
link_short, link_original, link_created, following_limit | ||
)); | ||
} | ||
|
||
String response = responseBuilder.toString(); | ||
|
||
exchange.sendResponseHeaders(200, response.getBytes().length); | ||
try (OutputStream os = exchange.getResponseBody()) { | ||
os.write(response.getBytes()); | ||
} | ||
} else { | ||
String response = String.format("Извините, но для UUID: %s не было найдено ни одной ссылки. Попробуйте их создать методом reg_short_link", received_uuid); | ||
exchange.sendResponseHeaders(404, response.getBytes().length); | ||
try (OutputStream os = exchange.getResponseBody()) { | ||
os.write(response.getBytes()); | ||
} | ||
} | ||
} | ||
|
||
private List<Object[]> getLinksData(String received_uuid) throws SQLException { | ||
String query = "SELECT * FROM links WHERE uuid = ?"; | ||
List<Object[]> result = new ArrayList<>(); | ||
try (PreparedStatement pstmt = cursor.prepareStatement(query)) { | ||
pstmt.setString(1, received_uuid); | ||
try (ResultSet rs = pstmt.executeQuery()) { | ||
while (rs.next()) { | ||
result.add(new Object[]{ | ||
rs.getString("link_short"), | ||
rs.getString("link_original"), | ||
rs.getLong("time_created"), | ||
rs.getInt("following_limit")}); | ||
} | ||
} | ||
} | ||
if (!result.isEmpty()) { | ||
return result; | ||
} | ||
else { | ||
return null; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.