MVP
This commit is contained in:
92
main.go
92
main.go
@@ -1,27 +1,103 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
type PDAlert struct {
|
||||||
// http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
RoutingKey string `json:"routing_key"`
|
||||||
// fmt.Fprintf(w, "Hello! you've requested %s\n", r.URL.Path)
|
EventAction string `json:"event_action"`
|
||||||
// })
|
Payload PDPayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
http.Handle("/", http.FileServer(http.Dir("./static")))
|
type PDPayload struct {
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
Severity string `json:"severity"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PHandler struct {
|
||||||
|
next http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPHandler(next http.Handler) *PHandler {
|
||||||
|
return &PHandler{
|
||||||
|
next: next,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ph *PHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
err := r.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("invalid form: %s\n", err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := r.Form.Get("msg")
|
||||||
|
if msg == "" {
|
||||||
|
ph.next.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
err = json.NewEncoder(buf).Encode(PDAlert{
|
||||||
|
RoutingKey: "63e451a6e5f84309d08d439bfe5efab5",
|
||||||
|
EventAction: "trigger",
|
||||||
|
Payload: PDPayload{
|
||||||
|
Summary: msg,
|
||||||
|
Source: "urlparam",
|
||||||
|
Severity: "critical",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("failed to create PD request: %s\n", err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", "https://events.pagerduty.com/v2/enqueue", buf)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("failed to create HTTP request: %s\n", err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &http.Client{}
|
||||||
|
res, err := c.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("error from PD: %s\n", err), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(res.Body)
|
||||||
|
res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode != 202 {
|
||||||
|
http.Error(w, fmt.Sprintf("error from PD: %s", string(body)), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte("page sent\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.Handle("/", NewPHandler(http.FileServer(http.Dir("./static"))))
|
||||||
|
|
||||||
port := os.Getenv("PORT")
|
port := os.Getenv("PORT")
|
||||||
if port == "" {
|
if port == "" {
|
||||||
port = "80"
|
port = "80"
|
||||||
}
|
}
|
||||||
|
|
||||||
bindAddr := fmt.Sprintf(":%s", port)
|
bind := fmt.Sprintf(":%s", port)
|
||||||
fmt.Printf("==> Server listening at %s 🚀\n", bindAddr)
|
log.Printf("listening on %s", bind)
|
||||||
|
|
||||||
if err := http.ListenAndServe(bindAddr, nil); err != nil {
|
if err := http.ListenAndServe(bind, nil); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,89 @@
|
|||||||
<html>
|
<!doctype html>
|
||||||
<head>
|
<html class="sl-theme-dark">
|
||||||
<link
|
<head>
|
||||||
rel="stylesheet"
|
<style>
|
||||||
media="(prefers-color-scheme:light)"
|
:not(:defined) {
|
||||||
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.18.0/cdn/themes/light.css"
|
visibility: hidden;
|
||||||
/>
|
}
|
||||||
<link
|
body {
|
||||||
rel="stylesheet"
|
margin: 30px;
|
||||||
media="(prefers-color-scheme:dark)"
|
font: 12px var(--sl-font-sans);
|
||||||
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.18.0/cdn/themes/dark.css"
|
display: flex;
|
||||||
onload="document.documentElement.classList.add('sl-theme-dark');"
|
flex-direction: column;
|
||||||
/>
|
align-items: center;
|
||||||
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.18.0/cdn/shoelace.js" ></script>
|
}
|
||||||
</head>
|
</style>
|
||||||
<body>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
</body>
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.18.0/cdn/themes/dark.css" />
|
||||||
|
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.18.0/cdn/shoelace-autoloader.js"></script>
|
||||||
|
<script>
|
||||||
|
function clearAlerts() {
|
||||||
|
document.getElementById('sent').hide();
|
||||||
|
document.getElementById('err').hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(err1, err2) {
|
||||||
|
clearAlerts();
|
||||||
|
|
||||||
|
document.getElementById('err1').innerText = err1;
|
||||||
|
document.getElementById('err2').innerText = err2;
|
||||||
|
document.getElementById('err').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function pageIan() {
|
||||||
|
const msg = document.getElementById('message').value;
|
||||||
|
|
||||||
|
if (msg == '') {
|
||||||
|
error('Please fill in Message', '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearAlerts();
|
||||||
|
|
||||||
|
const resp = await fetch(
|
||||||
|
'https://events.pagerduty.com/v2/enqueue',
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
payload: {
|
||||||
|
severity: 'critical',
|
||||||
|
source: 'jsapp',
|
||||||
|
summary: msg,
|
||||||
|
},
|
||||||
|
routing_key: '63e451a6e5f84309d08d439bfe5efab5',
|
||||||
|
event_action: 'trigger',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!resp.ok) {
|
||||||
|
error('Failed to send page', (await resp.json()).message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('sent').show();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<title>Page Ian</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="width: min(500px, 100vw)">
|
||||||
|
<sl-alert id="err" variant="danger">
|
||||||
|
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
|
||||||
|
<strong id="err1"></strong><br />
|
||||||
|
<span id="err2"></span>
|
||||||
|
</sl-alert>
|
||||||
|
<sl-alert id="sent" variant="success">
|
||||||
|
<sl-icon slot="icon" name="check2-circle"></sl-icon>
|
||||||
|
<strong>Page sent</strong>
|
||||||
|
</sl-alert>
|
||||||
|
<br />
|
||||||
|
<sl-textarea id="message" placeholder="Message" oninput="clearAlerts()"></sl-textarea>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<div style="text-align: center">
|
||||||
|
<sl-button type="submit" variant="primary" onclick="pageIan()">Page Ian</sl-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user