Add npm run init-db to auto-create database and hazard_history table
Some checks failed
build-docker / Build Image (push) Has been cancelled
Some checks failed
build-docker / Build Image (push) Has been cancelled
This commit is contained in:
parent
d120c27b6e
commit
3fcf2e43cd
4 changed files with 111 additions and 32 deletions
29
README.md
29
README.md
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
`ws4kp-linhanced` is a Linux-focused fork of [`netbymatt/ws4kp`](https://github.com/netbymatt/ws4kp) by `markmental`.
|
`ws4kp-linhanced` is a Linux-focused fork of [`netbymatt/ws4kp`](https://github.com/netbymatt/ws4kp) by `markmental`.
|
||||||
|
|
||||||
Current release: `v0.2.1` (Security Update released on 7/30/2026)
|
Current release: `v0.2.2`
|
||||||
|
|
||||||
It keeps the stronger, more stable foundation of the original `ws4kp` project while selectively incorporating international weather support and global map ideas from [`mwood77/ws4kp-international`](https://github.com/mwood77/ws4kp-international). The goal is not to become a kitchen-sink weather platform. The goal is a leaner, maintainable, Linux-oriented WeatherStar fork with a clear identity.
|
It keeps the stronger, more stable foundation of the original `ws4kp` project while selectively incorporating international weather support and global map ideas from [`mwood77/ws4kp-international`](https://github.com/mwood77/ws4kp-international). The goal is not to become a kitchen-sink weather platform. The goal is a leaner, maintainable, Linux-oriented WeatherStar fork with a clear identity.
|
||||||
|
|
||||||
|
|
@ -142,31 +142,14 @@ WS4KP_MYSQL_DATABASE=ws4kp_linhanced
|
||||||
|
|
||||||
If your local MariaDB/MySQL instance is socket-only, set `WS4KP_MYSQL_SOCKET_PATH` and omit `WS4KP_MYSQL_HOST` / `WS4KP_MYSQL_PORT`.
|
If your local MariaDB/MySQL instance is socket-only, set `WS4KP_MYSQL_SOCKET_PATH` and omit `WS4KP_MYSQL_HOST` / `WS4KP_MYSQL_PORT`.
|
||||||
|
|
||||||
Create the required table:
|
The database and `hazard_history` table are created automatically when you run `npm run start`. You can also run the setup manually at any time:
|
||||||
|
|
||||||
```sql
|
```bash
|
||||||
CREATE TABLE hazard_history (
|
npm run init-db
|
||||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
location_label VARCHAR(255) NOT NULL,
|
|
||||||
location_key VARCHAR(128) NOT NULL,
|
|
||||||
hazard_type VARCHAR(128) NOT NULL,
|
|
||||||
source VARCHAR(64) NOT NULL,
|
|
||||||
severity VARCHAR(64) DEFAULT NULL,
|
|
||||||
latest_hazard_id VARCHAR(255) DEFAULT NULL,
|
|
||||||
encountered_at DATETIME NOT NULL,
|
|
||||||
last_seen_at DATETIME NOT NULL,
|
|
||||||
ongoing TINYINT(1) NOT NULL DEFAULT 1,
|
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
|
|
||||||
PRIMARY KEY (id),
|
|
||||||
UNIQUE KEY uq_logical_hazard (location_key, hazard_type, source),
|
|
||||||
KEY idx_last_seen_at (last_seen_at),
|
|
||||||
KEY idx_location_key (location_key),
|
|
||||||
KEY idx_ongoing (ongoing)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This script is idempotent, so it is safe to run repeatedly. Database initialization is skipped when running in static mode (`STATIC=1`).
|
||||||
|
|
||||||
The database retains full hazard history. The `Hazard List` UI shows only the latest 7 entries and only the most recent row per stored location. Nearby same-label locations are reconciled during updates to reduce duplicate location spam.
|
The database retains full hazard history. The `Hazard List` UI shows only the latest 7 entries and only the most recent row per stored location. Nearby same-label locations are reconciled during updates to reduce duplicate location spam.
|
||||||
|
|
||||||
In the current browser session, `Hazard List` updates immediately after new hazard history is synced.
|
In the current browser session, `Hazard List` updates immediately after new hazard history is synced.
|
||||||
|
|
|
||||||
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -3039,9 +3039,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-uri": {
|
"node_modules/fast-uri": {
|
||||||
"version": "3.1.4",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
|
||||||
"integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==",
|
"integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -4828,9 +4828,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
|
||||||
"integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
|
"integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "ws4kp-linhanced",
|
"name": "ws4kp-linhanced",
|
||||||
"version": "0.2.1",
|
"version": "0.2.2",
|
||||||
"description": "WeatherStar 4000+: Linhanced - A Linux-focused fork of the WeatherStar 4000+ project",
|
"description": "WeatherStar 4000+: Linhanced - A Linux-focused fork of the WeatherStar 4000+ project",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run build && node index.mjs",
|
"init-db": "node src/init-db.mjs",
|
||||||
|
"start": "npm run init-db && npm run build && node index.mjs",
|
||||||
"stop": "pkill -f 'node index.mjs' || echo 'No process found'",
|
"stop": "pkill -f 'node index.mjs' || echo 'No process found'",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build:travelcities": "node datagenerators/travelcities.mjs",
|
"build:travelcities": "node datagenerators/travelcities.mjs",
|
||||||
|
|
|
||||||
95
src/init-db.mjs
Normal file
95
src/init-db.mjs
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
import 'dotenv/config';
|
||||||
|
import mysql from 'mysql2/promise';
|
||||||
|
|
||||||
|
const getDbConfig = () => {
|
||||||
|
const {
|
||||||
|
WS4KP_MYSQL_HOST = '127.0.0.1',
|
||||||
|
WS4KP_MYSQL_PORT = '3306',
|
||||||
|
WS4KP_MYSQL_USER,
|
||||||
|
WS4KP_MYSQL_PASSWORD,
|
||||||
|
WS4KP_MYSQL_DATABASE,
|
||||||
|
WS4KP_MYSQL_SOCKET_PATH,
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
if (!WS4KP_MYSQL_USER || !WS4KP_MYSQL_PASSWORD || !WS4KP_MYSQL_DATABASE) {
|
||||||
|
throw new Error('Missing MySQL configuration. Set WS4KP_MYSQL_USER, WS4KP_MYSQL_PASSWORD, and WS4KP_MYSQL_DATABASE.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
user: WS4KP_MYSQL_USER,
|
||||||
|
password: WS4KP_MYSQL_PASSWORD,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (WS4KP_MYSQL_SOCKET_PATH) {
|
||||||
|
config.socketPath = WS4KP_MYSQL_SOCKET_PATH;
|
||||||
|
} else {
|
||||||
|
config.host = WS4KP_MYSQL_HOST;
|
||||||
|
config.port = Number(WS4KP_MYSQL_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ...config, database: WS4KP_MYSQL_DATABASE };
|
||||||
|
};
|
||||||
|
|
||||||
|
const createDatabase = async (connection, database) => {
|
||||||
|
await connection.execute(
|
||||||
|
`CREATE DATABASE IF NOT EXISTS \`${database}\`
|
||||||
|
CHARACTER SET utf8mb4
|
||||||
|
COLLATE utf8mb4_unicode_ci`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createHazardHistoryTable = async (connection) => {
|
||||||
|
await connection.execute(`
|
||||||
|
CREATE TABLE IF NOT EXISTS \`hazard_history\` (
|
||||||
|
\`id\` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
\`location_label\` VARCHAR(255) NOT NULL,
|
||||||
|
\`location_key\` VARCHAR(128) NOT NULL,
|
||||||
|
\`hazard_type\` VARCHAR(128) NOT NULL,
|
||||||
|
\`source\` VARCHAR(64) NOT NULL,
|
||||||
|
\`severity\` VARCHAR(64) DEFAULT NULL,
|
||||||
|
\`latest_hazard_id\` VARCHAR(255) DEFAULT NULL,
|
||||||
|
\`encountered_at\` DATETIME NOT NULL,
|
||||||
|
\`last_seen_at\` DATETIME NOT NULL,
|
||||||
|
\`ongoing\` TINYINT(1) NOT NULL DEFAULT 1,
|
||||||
|
\`created_at\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
\`updated_at\` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
PRIMARY KEY (\`id\`),
|
||||||
|
UNIQUE KEY \`uq_logical_hazard\` (\`location_key\`, \`hazard_type\`, \`source\`),
|
||||||
|
KEY \`idx_last_seen_at\` (\`last_seen_at\`),
|
||||||
|
KEY \`idx_location_key\` (\`location_key\`),
|
||||||
|
KEY \`idx_ongoing\` (\`ongoing\`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
|
`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const initDatabase = async () => {
|
||||||
|
if (process.env.STATIC) {
|
||||||
|
console.log('Skipping database initialization (STATIC mode).');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { database, ...baseConfig } = getDbConfig();
|
||||||
|
|
||||||
|
let connection;
|
||||||
|
try {
|
||||||
|
connection = await mysql.createConnection(baseConfig);
|
||||||
|
await createDatabase(connection, database);
|
||||||
|
console.log(`Database "${database}" is ready.`);
|
||||||
|
} finally {
|
||||||
|
if (connection) await connection.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connection = await mysql.createConnection({ ...baseConfig, database });
|
||||||
|
await createHazardHistoryTable(connection);
|
||||||
|
console.log('Table "hazard_history" is ready.');
|
||||||
|
} finally {
|
||||||
|
if (connection) await connection.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
initDatabase().catch((error) => {
|
||||||
|
console.error('Database initialization failed:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue