Skip to content

Commit 9bfb760

Browse files
committed
fix lint error, implement zerolog
1 parent d374268 commit 9bfb760

23 files changed

Lines changed: 468 additions & 273 deletions

cmd/demo-app/main.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"embed"
66
"encoding/base64"
77
"encoding/json"
8+
"errors"
89
"flag"
910
"fmt"
1011
"io/fs"
@@ -15,6 +16,8 @@ import (
1516
"syscall"
1617
"time"
1718

19+
"github.com/rs/zerolog"
20+
"github.com/rs/zerolog/log"
1821
"golang.org/x/net/websocket"
1922

2023
"gosuda.org/portal/sdk"
@@ -37,6 +40,10 @@ var (
3740
)
3841

3942
func main() {
43+
zerolog.TimeFieldFormat = time.RFC3339
44+
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339})
45+
logger := log.With().Str("component", "demo-app").Logger()
46+
4047
flag.StringVar(&flagServerURL, "server-url", "https://localhost:4017", "relay API URL (https only)")
4148
flag.IntVar(&flagPort, "port", 8092, "local demo HTTP port")
4249
flag.StringVar(&flagName, "name", "demo-app", "backend display name")
@@ -47,12 +54,14 @@ func main() {
4754
flag.Parse()
4855

4956
if err := runDemo(); err != nil {
50-
fmt.Fprintf(os.Stderr, "demo command failed: %v\n", err)
57+
logger.Error().Err(err).Msg("demo command failed")
5158
os.Exit(1)
5259
}
5360
}
5461

5562
func runDemo() error {
63+
logger := log.With().Str("component", "demo-app").Logger()
64+
5665
sdkClient, err := sdk.NewClient(sdk.ClientConfig{RelayURL: flagServerURL})
5766
if err != nil {
5867
return fmt.Errorf("new client: %w", err)
@@ -79,6 +88,12 @@ func runDemo() error {
7988
}
8089
defer listener.Close()
8190

91+
logger.Info().
92+
Str("lease_id", listener.LeaseID()).
93+
Strs("public_urls", listener.PublicURLs()).
94+
Int("local_port", flagPort).
95+
Msg("demo app registered with relay")
96+
8297
mux := http.NewServeMux()
8398

8499
staticFS, err := fs.Sub(staticFiles, "static")
@@ -131,7 +146,10 @@ func runDemo() error {
131146
Handler: mux,
132147
ReadHeaderTimeout: 5 * time.Second,
133148
}
134-
_ = localSrv.ListenAndServe()
149+
logger.Info().Str("addr", localAddr).Msg("demo app listening locally")
150+
if err := localSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
151+
logger.Error().Err(err).Str("addr", localAddr).Msg("demo local server stopped")
152+
}
135153
}()
136154

137155
relaySrv := &http.Server{
@@ -149,12 +167,14 @@ func runDemo() error {
149167

150168
select {
151169
case <-sig:
170+
logger.Info().Msg("demo app shutting down")
152171
case err := <-errCh:
153-
if err != nil && err != http.ErrServerClosed {
172+
if err != nil && !errors.Is(err, http.ErrServerClosed) {
154173
return err
155174
}
156175
}
157176

177+
logger.Info().Msg("demo app shutdown complete")
158178
return nil
159179
}
160180

cmd/demo-app/static/index.html

Lines changed: 126 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,131 @@
1-
<!doctype html>
1+
<!DOCTYPE html>
22
<html lang="en">
3+
34
<head>
4-
<meta charset="utf-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1">
6-
<title>Portal Demo App</title>
7-
<link rel="stylesheet" href="/style.css">
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
7+
<meta name="apple-mobile-web-app-capable" content="yes">
8+
<meta name="mobile-web-app-capable" content="yes">
9+
<title>Portal Demo Connectivity</title>
10+
<link rel="stylesheet" href="style.css">
811
</head>
12+
913
<body>
10-
<main class="shell">
11-
<header>
12-
<p class="eyebrow">Portal Demo</p>
13-
<h1>Relay-backed demo application</h1>
14-
<p>Use this page to verify static assets, cookies, fetches, and websocket echo.</p>
15-
</header>
16-
17-
<section class="card">
18-
<h2>HTTP</h2>
19-
<button id="ping">Fetch /api/ping</button>
20-
<button id="cookies">Set cookies</button>
21-
<pre id="output">Ready.</pre>
22-
</section>
23-
24-
<section class="card">
25-
<h2>WebSocket</h2>
26-
<input id="ws-input" value="hello portal">
27-
<button id="ws-send">Send</button>
28-
<pre id="ws-output">Disconnected.</pre>
29-
</section>
30-
</main>
31-
32-
<script>
33-
const output = document.getElementById('output');
34-
const wsOutput = document.getElementById('ws-output');
35-
36-
document.getElementById('ping').addEventListener('click', async () => {
37-
const res = await fetch('/api/ping');
38-
output.textContent = JSON.stringify(await res.json(), null, 2);
39-
});
40-
41-
document.getElementById('cookies').addEventListener('click', async () => {
42-
const res = await fetch('/api/test-cookies');
43-
output.textContent = JSON.stringify(await res.json(), null, 2);
44-
});
45-
46-
const proto = location.protocol === 'https:' ? 'wss://' : 'ws://';
47-
const ws = new WebSocket(proto + location.host + '/ws');
48-
ws.onopen = () => { wsOutput.textContent = 'Connected.'; };
49-
ws.onmessage = (event) => { wsOutput.textContent = event.data; };
50-
ws.onclose = () => { wsOutput.textContent = 'Disconnected.'; };
51-
52-
document.getElementById('ws-send').addEventListener('click', () => {
53-
ws.send(document.getElementById('ws-input').value);
54-
});
55-
</script>
14+
<div class="container">
15+
<h1>Portal Demo Connectivity</h1>
16+
17+
<div class="toolbar">
18+
<button id="httpPingBtn">HTTP Ping</button>
19+
<button id="testCookiesBtn">Test Cookies</button>
20+
<button id="wsConnectBtn">WS Connect</button>
21+
<button id="wsSendBtn" disabled>WS Send "hello"</button>
22+
</div>
23+
24+
<div class="canvas-wrapper">
25+
<pre id="log" class="log"></pre>
26+
</div>
27+
28+
<div id="status" class="status">Idle</div>
29+
</div>
30+
31+
<script>
32+
const statusEl = document.getElementById('status');
33+
const logEl = document.getElementById('log');
34+
const httpPingBtn = document.getElementById('httpPingBtn');
35+
const wsConnectBtn = document.getElementById('wsConnectBtn');
36+
const wsSendBtn = document.getElementById('wsSendBtn');
37+
38+
let ws = null;
39+
40+
function log(message) {
41+
const time = new Date().toISOString();
42+
logEl.textContent += `[${time}] ${message}\n`;
43+
logEl.scrollTop = logEl.scrollHeight;
44+
}
45+
46+
httpPingBtn.addEventListener('click', async () => {
47+
statusEl.textContent = 'HTTP: Pinging...';
48+
try {
49+
const res = await fetch('/api/ping');
50+
const json = await res.json();
51+
statusEl.textContent = 'HTTP: OK';
52+
log(`HTTP /api/ping -> ${JSON.stringify(json)}`);
53+
} catch (err) {
54+
statusEl.textContent = 'HTTP: Error';
55+
log(`HTTP error: ${err}`);
56+
}
57+
});
58+
59+
document.getElementById('testCookiesBtn').addEventListener('click', async () => {
60+
statusEl.textContent = 'Cookies: Testing...';
61+
try {
62+
const res = await fetch('/api/test-cookies');
63+
const json = await res.json();
64+
statusEl.textContent = 'Cookies: OK';
65+
log(`HTTP /api/test-cookies -> ${JSON.stringify(json)}`);
66+
67+
// Log response headers
68+
log(`Response headers:`);
69+
for (const [key, value] of res.headers.entries()) {
70+
log(` ${key}: ${value}`);
71+
}
72+
73+
// Log current cookies
74+
log(`Current document.cookie: ${document.cookie || '(empty)'}`);
75+
} catch (err) {
76+
statusEl.textContent = 'Cookies: Error';
77+
log(`HTTP error: ${err}`);
78+
}
79+
});
80+
81+
wsConnectBtn.addEventListener('click', () => {
82+
if (ws && ws.readyState === WebSocket.OPEN) {
83+
ws.close();
84+
return;
85+
}
86+
87+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
88+
const basePath = location.pathname.endsWith('/') ? location.pathname : (location.pathname + '/');
89+
const url = protocol + '//' + window.location.host + basePath + 'ws';
90+
91+
statusEl.textContent = 'WS: Connecting...';
92+
log(`WS connecting to ${url}`);
93+
94+
ws = new WebSocket(url);
95+
96+
ws.onopen = () => {
97+
statusEl.textContent = 'WS: Connected';
98+
log('WS connected');
99+
wsSendBtn.disabled = false;
100+
wsConnectBtn.textContent = 'WS Disconnect';
101+
};
102+
103+
ws.onclose = () => {
104+
statusEl.textContent = 'WS: Disconnected';
105+
log('WS disconnected');
106+
wsSendBtn.disabled = true;
107+
wsConnectBtn.textContent = 'WS Connect';
108+
};
109+
110+
ws.onerror = (err) => {
111+
log(`WS error: ${err.message || err}`);
112+
};
113+
114+
ws.onmessage = (event) => {
115+
log(`WS recv: ${event.data}`);
116+
};
117+
});
118+
119+
wsSendBtn.addEventListener('click', () => {
120+
if (!ws || ws.readyState !== WebSocket.OPEN) {
121+
log('WS send skipped: not connected');
122+
return;
123+
}
124+
const msg = 'hello';
125+
ws.send(msg);
126+
log(`WS send: ${msg}`);
127+
});
128+
</script>
56129
</body>
57-
</html>
130+
131+
</html>

cmd/demo-app/static/style.css

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,85 @@
1-
:root {
2-
color-scheme: light;
3-
font-family: "Georgia", serif;
4-
background: #f6f1e8;
5-
color: #1f1a17;
1+
* {
2+
margin: 0;
3+
padding: 0;
4+
box-sizing: border-box;
65
}
76

87
body {
9-
margin: 0;
8+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
9+
background: #f5f5f5;
10+
min-height: 100vh;
11+
display: flex;
12+
align-items: center;
13+
justify-content: center;
14+
padding: 16px;
1015
}
1116

12-
.shell {
13-
max-width: 960px;
14-
margin: 0 auto;
15-
padding: 48px 20px 80px;
17+
.container {
18+
width: 100%;
19+
max-width: 520px;
20+
background: #ffffff;
21+
border-radius: 8px;
22+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
23+
padding: 16px;
24+
display: flex;
25+
flex-direction: column;
1626
}
1727

18-
.eyebrow {
19-
text-transform: uppercase;
20-
letter-spacing: 0.18em;
21-
font-size: 12px;
22-
color: #8f5e3b;
28+
h1 {
29+
font-size: 18px;
30+
margin-bottom: 12px;
31+
color: #333333;
32+
text-align: center;
33+
}
34+
35+
.toolbar {
36+
display: flex;
37+
flex-wrap: wrap;
38+
gap: 8px;
39+
margin-bottom: 12px;
40+
justify-content: center;
2341
}
2442

25-
.card {
26-
background: #fff;
27-
border: 1px solid #dccdb8;
28-
padding: 20px;
29-
margin-top: 18px;
30-
box-shadow: 0 12px 28px rgba(0, 0, 0, 0.06);
43+
.toolbar button {
44+
padding: 6px 12px;
45+
font-size: 13px;
46+
border-radius: 4px;
47+
border: 1px solid #d0d7de;
48+
background: #ffffff;
49+
cursor: pointer;
50+
transition: background 0.15s ease, border-color 0.15s ease;
3151
}
3252

33-
button,
34-
input {
35-
font: inherit;
36-
margin-right: 8px;
37-
margin-bottom: 8px;
38-
padding: 10px 12px;
53+
.toolbar button:hover {
54+
background: #f3f4f6;
55+
border-color: #c3ccd6;
3956
}
4057

41-
pre {
42-
background: #201a17;
43-
color: #f7efe4;
44-
padding: 14px;
58+
.canvas-wrapper {
59+
border-radius: 4px;
60+
border: 1px solid #e1e4e8;
61+
background: #111827;
62+
padding: 8px;
63+
height: 220px;
4564
overflow: auto;
4665
}
66+
67+
.log {
68+
width: 100%;
69+
height: 100%;
70+
border: none;
71+
background: transparent;
72+
color: #e5e7eb;
73+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
74+
"Liberation Mono", "Courier New", monospace;
75+
font-size: 12px;
76+
white-space: pre-wrap;
77+
word-break: break-all;
78+
}
79+
80+
.status {
81+
margin-top: 10px;
82+
font-size: 13px;
83+
color: #4b5563;
84+
text-align: right;
85+
}

0 commit comments

Comments
 (0)