1 | package ru.exlmoto.code.controller;
|
2 |
|
3 | import com.fasterxml.jackson.core.JsonProcessingException;
|
4 | import com.fasterxml.jackson.databind.ObjectMapper;
|
5 | import com.fasterxml.jackson.databind.node.ObjectNode;
|
6 |
|
7 | import org.slf4j.Logger;
|
8 | import org.slf4j.LoggerFactory;
|
9 |
|
10 | import org.springframework.util.StringUtils;
|
11 | import org.springframework.web.bind.annotation.GetMapping;
|
12 | import org.springframework.web.bind.annotation.PathVariable;
|
13 | import org.springframework.web.bind.annotation.PostMapping;
|
14 | import org.springframework.web.bind.annotation.RestController;
|
15 | import org.springframework.web.bind.annotation.RequestParam;
|
16 |
|
17 | import ru.exlmoto.code.configuration.CodeConfiguration;
|
18 | import ru.exlmoto.code.controller.enumeration.Skin;
|
19 | import ru.exlmoto.code.entity.CodeEntity;
|
20 | import ru.exlmoto.code.helper.ResourceHelper;
|
21 | import ru.exlmoto.code.helper.UtilityHelper;
|
22 | import ru.exlmoto.code.highlight.HighlightService;
|
23 | import ru.exlmoto.code.highlight.enumeration.Mode;
|
24 | import ru.exlmoto.code.service.DatabaseService;
|
25 |
|
26 | import java.io.InputStream;
|
27 | import java.io.UncheckedIOException;
|
28 |
|
29 | import java.util.Scanner;
|
30 |
|
31 | @RestController
|
32 | public class ApiController {
|
33 | private final Logger log = LoggerFactory.getLogger(ApiController.class);
|
34 |
|
35 | private final CodeConfiguration config;
|
36 | private final DatabaseService database;
|
37 | private final HighlightService highlight;
|
38 | private final ResourceHelper resource;
|
39 | private final UtilityHelper util;
|
40 |
|
41 | public ApiController(CodeConfiguration config,
|
42 | DatabaseService database,
|
43 | HighlightService highlight,
|
44 | ResourceHelper resource,
|
45 | UtilityHelper util) {
|
46 | this.config = config;
|
47 | this.database = database;
|
48 | this.highlight = highlight;
|
49 | this.resource = resource;
|
50 | this.util = util;
|
51 | }
|
52 |
|
53 | @GetMapping(path = "/api/raw/{id}", produces = "text/plain;charset=UTF-8")
|
54 | public String raw(@PathVariable(name = "id") String id) {
|
55 | return util.getLong(id).flatMap(database::getCodeSnippet).map(CodeEntity::getCodeRaw).orElse(
|
56 | "Error: Cannot get code snippet with '" + id + "' id."
|
57 | );
|
58 | }
|
59 |
|
60 | /*
|
61 | * Highlight API usage examples:
|
62 | * $ cat file.txt | curl --data-binary @- "https://code.exlmoto.ru/api/"
|
63 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml"
|
64 | * $ cat src.java | curl --data-binary @- "https://code.exlmoto.ru/api/?o=java"
|
65 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml;nolines"
|
66 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml;nolines;15"
|
67 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml;nolines;15,20"
|
68 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml;nolines;15,20&h=HighlightJs"
|
69 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml;nolines;15,20&h=HighlightRouge"
|
70 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml;nolines;15,20&h=HighlightPygments"
|
71 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml;nolines;15&h=HighlightPygmentsJython"
|
72 | *
|
73 | * Create simple HTML page:
|
74 | * $ cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml" > page.html
|
75 | * Another way:
|
76 | * $ CONTENT=`cat file.xml | curl --data-binary @- "https://code.exlmoto.ru/api/?o=xml"`
|
77 | * $ echo "<code class="hljs highlight"><pre>$CONTENT</pre></code>" > page.html
|
78 | */
|
79 | @PostMapping(path = "/api", produces = "text/plain;charset=UTF-8")
|
80 | public String highlight(InputStream inputDataStream,
|
81 | @RequestParam(name = "o", required = false, defaultValue = "") String options,
|
82 | @RequestParam(name = "h", required = false, defaultValue = "HighlightJs") String mode) {
|
83 | Scanner scanner = new Scanner(inputDataStream).useDelimiter("\\A"); // https://stackoverflow.com/a/5445161
|
84 | if (scanner.hasNext()) {
|
85 | String code = scanner.next();
|
86 | if (StringUtils.hasText(code) && code.length() < config.getSnippetMaxLength()) {
|
87 | return highlight.highlightCode(Mode.getMode(mode), util.getCorrectOptions(options), code);
|
88 | }
|
89 | }
|
90 | scanner.close();
|
91 | return "Error: Cannot highlight code snippet.";
|
92 | }
|
93 |
|
94 | /*
|
95 | * Highlight CSS usage examples:
|
96 | * $ curl "https://code.exlmoto.ru/api/css"
|
97 | * $ curl "https://code.exlmoto.ru/api/css?skin=pastorg"
|
98 | * $ curl "https://code.exlmoto.ru/api/css?skin=pastorg&mode=HighlightRouge"
|
99 | * $ curl "https://code.exlmoto.ru/api/css?skin=techno&mode=HighlightPygments"
|
100 | */
|
101 | @GetMapping(path = "/api/css", produces = "text/css;charset=UTF-8")
|
102 | public String css(@RequestParam(name = "skin", required = false, defaultValue = "techno") String skin,
|
103 | @RequestParam(name = "mode", required = false, defaultValue = "HighlightJs") String mode) {
|
104 | try {
|
105 | return resource.readFileToString("classpath:" + Mode.getCss(Mode.valueOf(mode), Skin.valueOf(skin)));
|
106 | } catch (IllegalArgumentException | UncheckedIOException ignored) { }
|
107 | return "Error: Cannot get CSS from resources.";
|
108 | }
|
109 |
|
110 | @GetMapping(path = "/api/versions", produces = "application/json;charset=UTF-8")
|
111 | public String versions() {
|
112 | final ObjectMapper mapper = new ObjectMapper();
|
113 | final ObjectNode root = mapper.createObjectNode();
|
114 | highlight.getLibraryVersions().forEach((k, v) -> {
|
115 | final ObjectNode child = mapper.createObjectNode();
|
116 | child.put("language", v.getFirst());
|
117 | child.put("library", v.getSecond());
|
118 | root.set(k.name(), child);
|
119 | });
|
120 | root.put("GraalVM", highlight.getApplicationVersions().getFirst());
|
121 | root.put("CodePolyglot", highlight.getApplicationVersions().getSecond());
|
122 |
|
123 | try {
|
124 | return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root);
|
125 | } catch (JsonProcessingException jpe) {
|
126 | final String error = String.format("Cannot generate JSON version information: '%s'.", jpe.getMessage());
|
127 | log.error(error, jpe);
|
128 | return "{ \"error\" : \"" + error + "\" }";
|
129 | }
|
130 | }
|
131 | }
|