-
Notifications
You must be signed in to change notification settings - Fork 0
/
hello_wiki_rest_client_customizable.opa
127 lines (115 loc) · 3.85 KB
/
hello_wiki_rest_client_customizable.opa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import stdlib.tools.markdown
uri_for_topic =
domain_parser =
{CommandLine.default_parser with
names: ["--wiki-server-domain"],
description: "The REST server for this wiki. By default, localhost.",
// FIXME, | after parser should not be needed
function on_param(x) { parser { case y=Rule.consume : {no_params: {x with domain: y}}} }
}
port_parser =
{CommandLine.default_parser with
names: ["--wiki-server-port"],
description: "The server port of the REST server for this wiki. By default, 8080.",
function on_param(x) { parser { case y=Rule.natural : {no_params: {x with port: {some: y}}}} }
}
base_uri =
CommandLine.filter(
{title : "Wiki arguments",
init : {Uri.default_absolute with domain: "localhost", schema: {some: "http"}, port: {some: 8080}},
parsers : [domain_parser, port_parser],
anonymous : []
}
)
function(topic) {
Uri.of_absolute({base_uri with path: ["_rest_", topic]});
}
exposed function load_source(topic) {
match (WebClient.Get.try_get(uri_for_topic(topic))) {
case { failure : _ }: "Error, could not connect";
case ~{ success }:
match (WebClient.Result.get_class(success)) {
case { success }: success.content;
default: "Error {success.code}";
}
}
}
function load_rendered(topic) {
source = load_source(topic);
Markdown.xhtml_of_string(Markdown.default_options, source);
}
exposed function save_source(topic, source) {
match (WebClient.Post.try_post(uri_for_topic(topic), source)) {
case { failure : _ }: {failure : "Could not reach the distant server"}
case { success : s }:
match (WebClient.Result.get_class(s)) {
case { success }: {success : load_rendered(topic)};
default: {failure : "Error {s.code}"};
}
}
}
function remove_topic(topic) {
_ = WebClient.Delete.try_delete(uri_for_topic(topic))
void
}
function edit(topic) {
#show_messages = <></>;
Dom.set_value(#edit_content, load_source(topic));
Dom.hide(#show_content);
Dom.show(#edit_content);
Dom.give_focus(#edit_content);
}
function save(topic) {
match (save_source(topic, Dom.get_value(#edit_content))) {
case ~{ success }:
#show_content = success;
Dom.hide(#edit_content);
Dom.show(#show_content);
case ~{ failure}:
#show_messages = <>{failure}</>;
}
}
function display(topic) {
Resource.styled_page("About {topic}", ["/resources/css.css"],
<div id=#header><div id=#logo></div>About {topic}</div>
<div class="show_content" id=#show_content ondblclick={function(_) { edit(topic) }}>{load_rendered(topic)}</>
<div class="show_messages" id=#show_messages />
<textarea class="edit_content" id=#edit_content style="display:none" cols="40" rows="30" onblur={function(_) { save(topic) }}></>
)
}
function rest(topic) {
match (HttpRequest.get_method()) {
case {some: method}:
match (method) {
case { post }:
_ = save_source(topic, HttpRequest.get_body()?"")
Resource.raw_status({success});
case { delete }:
remove_topic(topic);
Resource.raw_status({success});
case { get }:
Resource.source(load_source(topic), "text/plain");
default:
Resource.raw_status({method_not_allowed});
}
default: Resource.raw_status({bad_request})
}
}
function topic_of_path(path) {
String.capitalize(
String.to_lower(List.to_string_using("", "", "::", path))
);
}
function start(url) {
match (url) {
case { path : [], ... }: display("Hello");
case { path : ["rest" | path], ... }: rest(topic_of_path(path));
case ~{ path, ... }: display(topic_of_path(path));
}
}
Server.start(
Server.http,
[ {resources: @static_include_directory("resources")}
, {dispatch: start}
]
);