Compare commits
3 Commits
70d12615b8
...
b25085bcd7
| Author | SHA1 | Date | |
|---|---|---|---|
| b25085bcd7 | |||
| cf6c312e04 | |||
| da4ce37aff |
@@ -11,12 +11,30 @@ import (
|
|||||||
"tanabata/backend/internal/db"
|
"tanabata/backend/internal/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// appName tags every connection as application_name, so the backend's sessions
|
||||||
|
// are identifiable in pg_stat_activity and server logs (and distinguishable from
|
||||||
|
// e.g. goose migrations or a psql shell).
|
||||||
|
const appName = "tanabata-backend"
|
||||||
|
|
||||||
// NewPool creates and validates a *pgxpool.Pool from the given connection URL.
|
// NewPool creates and validates a *pgxpool.Pool from the given connection URL.
|
||||||
// The pool is ready to use; the caller is responsible for closing it.
|
// The pool is ready to use; the caller is responsible for closing it.
|
||||||
func NewPool(ctx context.Context, url string) (*pgxpool.Pool, error) {
|
func NewPool(ctx context.Context, url string) (*pgxpool.Pool, error) {
|
||||||
pool, err := pgxpool.New(ctx, url)
|
cfg, err := pgxpool.ParseConfig(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("pgxpool.New: %w", err)
|
return nil, fmt.Errorf("pgxpool.ParseConfig: %w", err)
|
||||||
|
}
|
||||||
|
// Set application_name unless the operator already specified one in the DSN
|
||||||
|
// (or via PGAPPNAME), so an explicit override still wins.
|
||||||
|
if cfg.ConnConfig.RuntimeParams == nil {
|
||||||
|
cfg.ConnConfig.RuntimeParams = map[string]string{}
|
||||||
|
}
|
||||||
|
if cfg.ConnConfig.RuntimeParams["application_name"] == "" {
|
||||||
|
cfg.ConnConfig.RuntimeParams["application_name"] = appName
|
||||||
|
}
|
||||||
|
|
||||||
|
pool, err := pgxpool.NewWithConfig(ctx, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("pgxpool.NewWithConfig: %w", err)
|
||||||
}
|
}
|
||||||
if err := pool.Ping(ctx); err != nil {
|
if err := pool.Ping(ctx); err != nil {
|
||||||
pool.Close()
|
pool.Close()
|
||||||
|
|||||||
@@ -128,8 +128,13 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
|||||||
|
|
||||||
invalidateSectionCache(path, (init?.method ?? 'GET').toUpperCase());
|
invalidateSectionCache(path, (init?.method ?? 'GET').toUpperCase());
|
||||||
|
|
||||||
|
// A success doesn't guarantee a JSON body: 204 never has one, and some 200/201
|
||||||
|
// responses (e.g. POST /pools/:id/files) complete with an empty body. Parsing
|
||||||
|
// those as JSON throws, so read the text first and only parse when present —
|
||||||
|
// otherwise an empty 201 would surface as a spurious "failed" error.
|
||||||
if (res.status === 204) return undefined as T;
|
if (res.status === 204) return undefined as T;
|
||||||
return res.json();
|
const text = await res.text();
|
||||||
|
return (text ? JSON.parse(text) : undefined) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Upload with XHR so we can track progress via onProgress(0–100). */
|
/** Upload with XHR so we can track progress via onProgress(0–100). */
|
||||||
|
|||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Vendored
+14
-7
@@ -35,21 +35,28 @@
|
|||||||
"type": "image/png"
|
"type": "image/png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/images/android-icon-192x192.png",
|
"src": "/images/pwa-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "any"
|
"purpose": "any"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/images/apple-icon-180x180.png",
|
"src": "/images/pwa-512x512.png",
|
||||||
"sizes": "180x180",
|
"sizes": "512x512",
|
||||||
"type": "image/png"
|
"type": "image/png",
|
||||||
|
"purpose": "any"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/images/ms-icon-310x310.png",
|
"src": "/images/pwa-maskable-192x192.png",
|
||||||
"sizes": "310x310",
|
"sizes": "192x192",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "any maskable"
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/images/pwa-maskable-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user