Skip to content

Instantly share code, notes, and snippets.

@cypok
Last active October 11, 2021 04:52
Show Gist options
  • Save cypok/8c1a3df1f8dc1548c855403c76356103 to your computer and use it in GitHub Desktop.
Save cypok/8c1a3df1f8dc1548c855403c76356103 to your computer and use it in GitHub Desktop.
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class HearTheTennisBackend implements HttpHandler {
private static final String COLOR_FREE = "#b1fc99";
private static final String COLOR_BUSY = "#f3d3d9";
private static final String DATA_FILE = "data.csv";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private final ArrayList<Tick> ticks = new ArrayList<>();
public static void main(String[] args) throws IOException, ParseException {
HttpHandler handler = new HearTheTennisBackend();
HttpServer server = HttpServer.create(new InetSocketAddress(8008), 0);
server.createContext("/", handler);
server.createContext("/put", handler);
server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
server.start();
}
public HearTheTennisBackend() throws IOException, ParseException {
readTicksFromDisk();
writeTicksToDisk();
}
@Override
public void handle(HttpExchange t) throws IOException {
final String responseBody;
final int responseCode;
System.out.println(t.getRequestURI().toString());
switch (t.getRequestMethod()) {
case "GET":
if (!t.getRequestURI().toString().equals("/")) {
responseCode = 404;
responseBody = "unexpected request";
} else {
responseCode = 200;
responseBody = renderMainPage();
}
break;
case "POST":
if (!t.getRequestURI().toString().startsWith("/put?")) {
responseCode = 404;
responseBody = "unexpected request";
} else {
final Map<String, String> params = queryToMap(t.getRequestURI().getQuery());
final String business = params.get("business");
final Tick tick = addNewTick(business);
responseCode = 200;
responseBody = tick.toString();
}
break;
default:
responseCode = 400;
responseBody = "unexpected method " + t.getRequestMethod();
break;
}
final OutputStream responseOS = t.getResponseBody();
final byte[] responseBytes = responseBody.getBytes(StandardCharsets.US_ASCII);
t.sendResponseHeaders(responseCode, responseBytes.length);
responseOS.write(responseBytes);
responseOS.close();
}
private Tick addNewTick(String business) throws IOException {
final State state = State.byName(business);
Tick tick = new Tick(new Date(), state);
System.out.println(tick);
ticks.add(tick);
writeTicksToDisk();
return tick;
}
private String renderMainPage() {
final StringBuilder sb = new StringBuilder();
sb.append("<html><body>Last states:<br/>");
for (int i = ticks.size() - 1; i >= 0; i--) {
Tick tick = ticks.get(i);
final String color;
switch (tick.state) {
case FREE:
color = COLOR_FREE;
break;
case BUSY:
color = COLOR_BUSY;
break;
case NODATA:
color = null;
break;
default:
throw new IllegalStateException("Unexpected value: " + tick.state);
}
if (i != ticks.size() - 1) {
sb.append("<br/>");
}
String s = DATE_FORMAT.format(tick.time);
if (color != null) {
sb.append("<span style='background-color:").append(color).append("'>").append(s).append("</span>");
} else {
sb.append(s);
}
}
sb.append("</body></html>");
return sb.toString();
}
public static Map<String, String> queryToMap(String query) {
if (query == null) {
return null;
}
Map<String, String> result = new HashMap<>();
for (String param : query.split("&")) {
String[] entry = param.split("=");
if (entry.length > 1) {
result.put(entry[0], entry[1]);
} else {
result.put(entry[0], "");
}
}
return result;
}
private void readTicksFromDisk() throws IOException, ParseException {
ticks.clear();
try (FileReader fr = new FileReader(DATA_FILE);
BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
String[] parts = line.split(",");
if (parts.length != 2) {
continue;
}
String date = parts[0];
String state = parts[1];
Tick tick = new Tick(DATE_FORMAT.parse(date), State.byName(state));
ticks.add(tick);
}
} catch (FileNotFoundException e) {
// ignore it, we will create it
}
}
private void writeTicksToDisk() throws IOException {
try (FileWriter fw = new FileWriter(DATA_FILE);
BufferedWriter bw = new BufferedWriter(fw)) {
for (Tick tick : ticks) {
bw.write(DATE_FORMAT.format(tick.time) + "," + tick.state + "\n");
}
}
}
}
class Tick {
final Date time;
final State state;
Tick(Date time, State state) {
this.time = time;
this.state = state;
}
@Override
public String toString() {
return "{" + time + ", " + state + "}";
}
}
enum State {
NODATA,
FREE,
BUSY,
;
public static State byName(String s) {
return valueOf(s.toUpperCase(Locale.ROOT));
}
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hear the Tennis</title>
<style>
.curstate {
width: 10em;
height: 2em;
line-height: 2em;
border: 1px;
text-align: center;
}
.free {
background-color: #b1fc99;
padding: 5px;
}
.busy {
background-color: #f3d3d9;
}
.last-update {
font-size: small;
}
</style>
</head>
<body>
<iframe src="https://giphy.com/embed/ECwTCTrHPVqKI" width="400" height="300" frameBorder="0" class="giphy-embed"></iframe>
<!-- <iframe src="https://giphy.com/embed/g01ZnwAUvutuK8GIQn" width="533" height="300" frameBorder="0" class="giphy-embed"></iframe>-->
<!-- <iframe src="https://giphy.com/embed/l0NwvUd7IEjn1764U" width="533" height="300" frameBorder="0" class="giphy-embed"></iframe>-->
<p>
Table tennis room is <span class="free">free</span> for the last 23 minutes.
</p>
<p>
No information for the last 48 minutes, sorry. Contact guys at 817.
</p>
<p>
<span class="last-update">Last update: 2021-10-11 11:18:02.</span>
</p>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment