DbWebServer.java 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package db;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import org.microhttp.EventLoop;
  4. import org.microhttp.Header;
  5. import org.microhttp.LogEntry;
  6. import org.microhttp.Logger;
  7. import org.microhttp.Options;
  8. import org.microhttp.Request;
  9. import org.microhttp.Response;
  10. import java.io.IOException;
  11. import java.time.Duration;
  12. import java.time.Instant;
  13. import java.time.ZoneOffset;
  14. import java.time.format.DateTimeFormatter;
  15. import java.util.List;
  16. import java.util.concurrent.Executor;
  17. import java.util.concurrent.Executors;
  18. import java.util.concurrent.ThreadLocalRandom;
  19. import java.util.function.Consumer;
  20. public class DbWebServer {
  21. static final String SERVER = "microhttp";
  22. static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC);
  23. static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  24. final int port;
  25. final DbConnectionPool connectionPool;
  26. final Executor executor;
  27. volatile String date = DATE_FORMATTER.format(Instant.now());
  28. DbWebServer(int port) {
  29. this.port = port;
  30. this.connectionPool = new DbConnectionPool(32, Duration.ofSeconds(30));
  31. this.executor = Executors.newFixedThreadPool(256);
  32. }
  33. void start() throws IOException, InterruptedException {
  34. connectionPool.start();
  35. startDateUpdater();
  36. Options options = new Options()
  37. .withHost(null) // wildcard any-address binding
  38. .withPort(port)
  39. .withReuseAddr(true)
  40. .withReusePort(true)
  41. .withAcceptLength(8_192)
  42. .withMaxRequestSize(1_024 * 1_024)
  43. .withReadBufferSize(1_024 * 64)
  44. .withResolution(Duration.ofMillis(1_000))
  45. .withRequestTimeout(Duration.ofSeconds(90));
  46. EventLoop eventLoop = new EventLoop(options, new DisabledLogger(), this::handle);
  47. eventLoop.start();
  48. eventLoop.join();
  49. }
  50. void startDateUpdater() {
  51. Thread thread = new Thread(this::runDateUpdater);
  52. thread.setDaemon(true);
  53. thread.setPriority(Thread.MIN_PRIORITY);
  54. thread.start();
  55. }
  56. void runDateUpdater() {
  57. while (true) {
  58. try {
  59. Thread.sleep(1_000);
  60. } catch (InterruptedException e) {
  61. return;
  62. }
  63. date = DATE_FORMATTER.format(Instant.now());
  64. }
  65. }
  66. void handle(Request request, Consumer<Response> callback) {
  67. if (request.uri().equals("/db")) {
  68. executor.execute(() -> handleDbQuery(callback));
  69. } else {
  70. List<Header> headers = List.of(
  71. new Header("Date", date),
  72. new Header("Server", SERVER));
  73. callback.accept(new Response(404, "Not Found", headers, new byte[0]));
  74. }
  75. }
  76. void handleDbQuery(Consumer<Response> callback) {
  77. try {
  78. WorldRow row = connectionPool.executeQuery(1 + ThreadLocalRandom.current().nextInt(10_000));
  79. List<Header> headers = List.of(
  80. new Header("Content-Type", "application/json"),
  81. new Header("Date", date),
  82. new Header("Server", SERVER));
  83. callback.accept(new Response(200, "OK", headers, jsonBody(row)));
  84. } catch (Exception e) {
  85. List<Header> headers = List.of(
  86. new Header("Date", date),
  87. new Header("Server", SERVER));
  88. callback.accept(new Response(500, "Internal Server Error", headers, new byte[0]));
  89. }
  90. }
  91. static byte[] jsonBody(WorldRow row) {
  92. try {
  93. return OBJECT_MAPPER.writeValueAsBytes(row);
  94. } catch (IOException e) {
  95. throw new RuntimeException(e);
  96. }
  97. }
  98. public static void main(String[] args) throws IOException, InterruptedException {
  99. int port = args.length > 0
  100. ? Integer.parseInt(args[0])
  101. : 8080;
  102. new DbWebServer(port).start();
  103. }
  104. static class DisabledLogger implements Logger {
  105. @Override
  106. public boolean enabled() {
  107. return false;
  108. }
  109. @Override
  110. public void log(LogEntry... logEntries) {
  111. }
  112. @Override
  113. public void log(Exception e, LogEntry... logEntries) {
  114. }
  115. }
  116. }