Compare commits

...

4 Commits

4 changed files with 44 additions and 13 deletions

View File

@@ -33,6 +33,7 @@ local function loadConfig()
if cfg.serverUrl then SERVER_URL = cfg.serverUrl end
if cfg.pollInterval then POLL_INTERVAL = cfg.pollInterval end
if cfg.stateInterval then STATE_INTERVAL = cfg.stateInterval end
if cfg.apiKey then API_KEY = cfg.apiKey end
print("[CONFIG] Loaded from " .. CONFIG_FILE)
end
end
@@ -46,6 +47,7 @@ local latestState = nil -- last broadcast from master
local modem = nil
local modemName = nil
local running = true
local API_KEY = nil -- optional API key for server auth
-------------------------------------------------
-- Find modem
@@ -71,6 +73,7 @@ local function httpPost(path, body)
local url = SERVER_URL .. path
local data = textutils.serialiseJSON(body)
local headers = { ["Content-Type"] = "application/json" }
if API_KEY then headers["Authorization"] = "Bearer " .. API_KEY end
local ok, err = pcall(function()
local response = http.post(url, data, headers)
@@ -89,8 +92,10 @@ end
local function httpGet(path)
local url = SERVER_URL .. path
local headers = nil
if API_KEY then headers = { ["Authorization"] = "Bearer " .. API_KEY } end
local ok, result = pcall(function()
local response = http.get(url)
local response = http.get(url, headers)
if response then
local data = response.readAll()
response.close()
@@ -274,6 +279,11 @@ local function main()
print("[OK] Server URL: " .. SERVER_URL)
print("[OK] Poll interval: " .. POLL_INTERVAL .. "s")
print("[OK] State interval: " .. STATE_INTERVAL .. "s")
if API_KEY then
print("[OK] API key configured")
else
print("[WARN] No API key set (open access)")
end
print("")
print("Bridge is running. Press Ctrl+T to stop.")
print("Listening for master broadcasts on ch " .. BROADCAST_CHANNEL)

View File

@@ -9,6 +9,10 @@ RUN npm install
COPY . .
# Accept API key at build time so Vite can inline it
ARG VITE_API_KEY=""
ENV VITE_API_KEY=${VITE_API_KEY}
RUN npm run build
# Stage 2: Serve with nginx

View File

@@ -1,12 +1,24 @@
import { create } from 'zustand';
const WS_URL = import.meta.env.VITE_WS_URL ||
const _baseWsUrl = import.meta.env.VITE_WS_URL ||
`${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`;
const API_URL = import.meta.env.VITE_API_URL ||
`${window.location.protocol}//${window.location.host}/api`;
const API_KEY = import.meta.env.VITE_API_KEY || '';
console.log('🔌 WebSocket URL:', WS_URL);
// Append API key to WebSocket URL as query param
const WS_URL = API_KEY ? `${_baseWsUrl}?key=${encodeURIComponent(API_KEY)}` : _baseWsUrl;
// Build common headers for authenticated requests
function authHeaders(extra = {}) {
const headers = { 'Content-Type': 'application/json', ...extra };
if (API_KEY) headers['Authorization'] = `Bearer ${API_KEY}`;
return headers;
}
console.log('🔌 WebSocket URL:', _baseWsUrl);
console.log('📡 API URL:', API_URL);
if (API_KEY) console.log('🔒 API key configured');
// Generate a unique command ID for idempotent requests
function newCommandId() {
@@ -187,7 +199,7 @@ export const useInventoryStore = create((set, get) => ({
try {
const response = await fetch(`${API_URL}/order`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ itemName, amount, dropperName, commandId: newCommandId() }),
});
return await response.json();
@@ -201,7 +213,7 @@ export const useInventoryStore = create((set, get) => ({
try {
const response = await fetch(`${API_URL}/scan`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ commandId: newCommandId() }),
});
return await response.json();
@@ -215,7 +227,7 @@ export const useInventoryStore = create((set, get) => ({
try {
const response = await fetch(`${API_URL}/smelting/toggle`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ commandId: newCommandId() }),
});
return await response.json();
@@ -229,7 +241,7 @@ export const useInventoryStore = create((set, get) => ({
try {
const response = await fetch(`${API_URL}/recipes/toggle`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ recipe, commandId: newCommandId() }),
});
return await response.json();
@@ -243,7 +255,7 @@ export const useInventoryStore = create((set, get) => ({
try {
await fetch(`${API_URL}/recipes/enable-all`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ commandId: newCommandId() }),
});
} catch (error) {
@@ -255,7 +267,7 @@ export const useInventoryStore = create((set, get) => ({
try {
await fetch(`${API_URL}/recipes/disable-all`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ commandId: newCommandId() }),
});
} catch (error) {
@@ -267,7 +279,7 @@ export const useInventoryStore = create((set, get) => ({
try {
const response = await fetch(`${API_URL}/craft`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ recipeIdx, commandId: newCommandId() }),
});
return await response.json();
@@ -281,7 +293,7 @@ export const useInventoryStore = create((set, get) => ({
try {
const response = await fetch(`${API_URL}/sort-barrel`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ barrelName, commandId: newCommandId() }),
});
return await response.json();
@@ -296,7 +308,7 @@ export const useInventoryStore = create((set, get) => ({
try {
const response = await fetch(`${API_URL}/dropper-nicknames`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: authHeaders(),
body: JSON.stringify({ dropperName, nickname }),
});
const result = await response.json();

View File

@@ -5,6 +5,8 @@ services:
- inventory-network
volumes:
- server-data:/data
environment:
- API_KEY=${API_KEY:-}
restart: unless-stopped
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001/api/health',r=>{process.exit(r.statusCode===200?0:1)}).on('error',()=>process.exit(1))"]
@@ -14,7 +16,10 @@ services:
retries: 3
client:
build: ./client
build:
context: ./client
args:
VITE_API_KEY: ${API_KEY:-}
ports:
- "80:80"
networks: