Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/compute/cloud/common/dns.tsx
1503 views
1
import { DNS_COST_PER_HOUR, checkValidDomain } from "@cocalc/util/compute/dns";
2
import { useTypedRedux } from "@cocalc/frontend/app-framework";
3
import { useEffect, useMemo, useState } from "react";
4
import { Alert, Button, Checkbox, Flex, Input, Spin, Switch } from "antd";
5
import { A, Icon } from "@cocalc/frontend/components";
6
import { currency } from "@cocalc/util/misc";
7
import { debounce } from "lodash";
8
import { isDnsAvailable } from "@cocalc/frontend/compute/api";
9
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
10
import ShowError from "@cocalc/frontend/components/error";
11
12
async function checkDns(dns, setDnsError, setChecking) {
13
try {
14
checkValidDomain(dns);
15
} catch (err) {
16
setDnsError(`${err}.
17
Please enter a valid subdomain name. Subdomains can consist of
18
letters (a-z, A-Z), numbers (0-9), and hyphens (-). They
19
cannot start or end with a hyphen.`);
20
return false;
21
}
22
try {
23
setChecking(true);
24
if (!(await isDnsAvailable(dns))) {
25
setDnsError(
26
`${dns} is not available -- in use by another compute server`,
27
);
28
return false;
29
}
30
setDnsError("");
31
return true;
32
} catch (err) {
33
setDnsError(`${err}`);
34
} finally {
35
setChecking(false);
36
}
37
}
38
39
export default function DNS({ setConfig, configuration, loading }) {
40
const compute_servers_dns = useTypedRedux("customize", "compute_servers_dns");
41
const [help, setHelp] = useState<boolean>(false);
42
const [showDns, setShowDns] = useState<boolean>(!!configuration.dns);
43
const [dnsError, setDnsError] = useState<string>("");
44
const [dns, setDns] = useState<string | undefined>(configuration.dns);
45
const [checking, setChecking] = useState<boolean>(false);
46
const checkValid = useMemo(() => {
47
const f = reuseInFlight(async (dns) => {
48
await checkDns(dns, setDnsError, setChecking);
49
});
50
return debounce(f, 1000);
51
}, [setDnsError]);
52
53
useEffect(() => {
54
if (dns) {
55
checkValid(dns);
56
}
57
}, [dns]);
58
59
if (!compute_servers_dns) {
60
return null;
61
}
62
63
return (
64
<div>
65
<Flex style={{ alignItems: "center" }}>
66
<Checkbox
67
style={{ flex: 1 }}
68
disabled={loading}
69
checked={showDns}
70
onChange={() => {
71
setShowDns(!showDns);
72
if (showDns) {
73
// disable on backend.
74
setConfig({ dns: "" });
75
}
76
}}
77
>
78
DNS: Custom Subdomain with SSL ({currency(DNS_COST_PER_HOUR)}/hour
79
when running or stopped)
80
</Checkbox>{" "}
81
{showDns && (
82
<Switch
83
size="small"
84
checkedChildren={"Help"}
85
unCheckedChildren={"Help"}
86
style={{ float: "right" }}
87
checked={help}
88
onChange={(val) => setHelp(val)}
89
/>
90
)}
91
</Flex>
92
93
{showDns && (
94
<div style={{ marginTop: "5px" }}>
95
<Flex style={{ alignItems: "center" }}>
96
<Input
97
disabled={loading}
98
style={{ margin: "15px 50px 15px 0", flex: 0.5 }}
99
maxLength={63}
100
showCount
101
allowClear
102
value={dns}
103
onChange={(e) => {
104
const dns = e.target.value.trim();
105
setDns(dns);
106
if (!dns) {
107
setConfig({ dns: "" });
108
}
109
}}
110
/>
111
{showDns && (
112
<A
113
style={{ flex: 0.5 }}
114
href={`https://${configuration.dns}.${compute_servers_dns}`}
115
>
116
<Icon name="external-link" /> https://{dns ?? "*"}.
117
{compute_servers_dns}
118
</A>
119
)}
120
</Flex>
121
<Button
122
disabled={
123
configuration.dns == dns || dnsError || loading || checking
124
}
125
onClick={async () => {
126
if (await checkDns(dns, setDnsError, setChecking)) {
127
const s = (dns ?? "").toLowerCase();
128
setConfig({ dns: s });
129
setDns(s);
130
}
131
}}
132
>
133
{!dns || configuration.dns != dns
134
? "Enable Custom Domain"
135
: "Custom Domain Enabled"}
136
{checking && <Spin style={{ marginLeft: "15px" }} delay={500} />}
137
</Button>
138
{dns && dnsError && (
139
<ShowError
140
error={dnsError}
141
setError={setDnsError}
142
style={{ margin: "10px 0" }}
143
/>
144
)}
145
{help && (
146
<Alert
147
type="info"
148
style={{ margin: "10px 0" }}
149
showIcon
150
message={"Custom DNS Subdomain"}
151
description={
152
<>
153
<p>
154
A custom DNS A record with{" "}
155
<A href="https://developers.cloudflare.com/dns/manage-dns-records/reference/proxied-dns-records/">
156
https and http proxying will be created at CloudFlare
157
</A>{" "}
158
as long as your VM is not deprovisioned. Whenever your VM
159
starts running it is allocated an external ip address, and
160
CoCalc updates the DNS entry to point at that ip address. An
161
https web server that you run on your compute server
162
listening on port 443 with a self-signed certificate will
163
appear to have a valid certificate to browsers visiting the
164
above URL.
165
</p>
166
<ul>
167
<li> You can enable or disable custom DNS at any time.</li>
168
<li>
169
<b>NOTE:</b> Depending on your browser, JupyterLab and VS
170
Code may fail in random ways due to security restrictions
171
if you do not enable DNS.
172
</li>
173
<li>
174
<A href="https://youtu.be/Il6rkXaDfUA">
175
<Icon
176
name="youtube"
177
style={{
178
color: "white",
179
background: "#ff0100",
180
padding: "0 3px",
181
borderRadius: "5px",
182
marginRight: "5px",
183
}}
184
/>
185
Web Server Demo
186
</A>
187
</li>
188
</ul>
189
</>
190
}
191
/>
192
)}
193
</div>
194
)}
195
</div>
196
);
197
}
198
199