small refactor, add available signals to README

This commit is contained in:
2025-08-24 10:33:39 +02:00
parent e6938a9f39
commit c0b9edbfb5
13 changed files with 64 additions and 56 deletions

View File

@@ -1,6 +1,8 @@
# miniws # miniws
miniws (minimal web server) is a very simple web server written in golang. its purpose is to be lightweight, easy to configure and easily expandable for personal use. miniws (minimal web server) is a very simple web server written in golang. its purpose is to be lightweight, easy to configure and easily expandable for personal use.
all the help you'll ever need is in this README, and in the help text (`miniws -h`). there is no other documentation you have to read.
## command line arguments ## command line arguments
``` ```
-h --help Print help information -h --help Print help information
@@ -21,6 +23,10 @@ in your config folder you will find `ipfilter.conf` and `useragentfilter.conf`
both files use the same format: specify `allow|deny` in the first line to tell miniws to treat the file as a whitelist or a blacklist, then specify one ip/user-agent per line. both files use the same format: specify `allow|deny` in the first line to tell miniws to treat the file as a whitelist or a blacklist, then specify one ip/user-agent per line.
## signals
you can pass the following signals when using -s:
- `reload`: reloads the configuration files from disk
## logging ## logging
in your logging folder you will find `access.log` and `errors.log` in your logging folder you will find `access.log` and `errors.log`

View File

@@ -3,6 +3,5 @@ go 1.24.5
use ( use (
. .
./miniws ./miniws
./miniws/sockets ./miniws/ipc
./miniws/sockets/logplus
) )

View File

@@ -2,8 +2,8 @@ package main
import ( import (
"fmt" "fmt"
"ipc"
"os" "os"
"sockets"
"miniws" "miniws"
@@ -44,7 +44,7 @@ func main() {
// signal mode // signal mode
if *signal != "" { if *signal != "" {
client := sockets.Client{} client := ipc.Client{}
client.OneShotWrite("unix", miniws.SOCKET_PATH, []byte(*signal)) client.OneShotWrite("unix", miniws.SOCKET_PATH, []byte(*signal))
return return
} }

View File

@@ -2,5 +2,5 @@ go 1.24.5
use ( use (
. .
./sockets ./ipc
) )

View File

@@ -1,4 +1,4 @@
package sockets package ipc
type buffer []byte type buffer []byte

View File

@@ -1,9 +1,8 @@
package sockets package ipc
import ( import (
"bufio" "bufio"
"log" "log"
"logplus"
"net" "net"
"os" "os"
) )
@@ -12,7 +11,7 @@ type Client struct{}
func (c *Client) Start(network, address string) { func (c *Client) Start(network, address string) {
conn, err := net.Dial(network, address) conn, err := net.Dial(network, address)
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
defer conn.Close() defer conn.Close()
buffer := make(buffer, 1<<12) buffer := make(buffer, 1<<12)
@@ -20,25 +19,25 @@ func (c *Client) Start(network, address string) {
for { for {
buffer.Zero() buffer.Zero()
scanner.Scan() scanner.Scan()
logplus.LogIfErrorFatal(scanner.Err()) LogIfErrorFatal(scanner.Err())
buffer = []byte(scanner.Text()) buffer = []byte(scanner.Text())
_, err := conn.Write(buffer) _, err := conn.Write(buffer)
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
} }
} }
func (c *Client) OneShotWrite(network, address string, content []byte) { func (c *Client) OneShotWrite(network, address string, content []byte) {
conn, err := net.Dial(network, address) conn, err := net.Dial(network, address)
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
defer conn.Close() defer conn.Close()
//will recieve a byte //will recieve a byte
buffer := make(buffer, 1) buffer := make(buffer, 1)
_, err = conn.Write(content) _, err = conn.Write(content)
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
_, err = conn.Read(buffer) _, err = conn.Read(buffer)
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
if buffer[0] == byte(0) { if buffer[0] == byte(0) {
log.Println("Signal", string(content), "doesn't exist!") log.Println("Signal", string(content), "doesn't exist!")
return return

3
miniws/ipc/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module ipc
go 1.24.5

View File

@@ -1,4 +1,4 @@
package logplus package ipc
import "log" import "log"

View File

@@ -1,8 +1,7 @@
package sockets package ipc
import ( import (
"io" "io"
"logplus"
"net" "net"
"os" "os"
"os/signal" "os/signal"
@@ -14,7 +13,7 @@ type Server struct{}
func (s *Server) Start(recvBind func(string, []string) bool, network, address string) int { func (s *Server) Start(recvBind func(string, []string) bool, network, address string) int {
socket, err := net.Listen(network, address) socket, err := net.Listen(network, address)
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
//Cleanup the socket file //Cleanup the socket file
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
@@ -29,7 +28,7 @@ func (s *Server) Start(recvBind func(string, []string) bool, network, address st
//Accept connection //Accept connection
conn, err := socket.Accept() conn, err := socket.Accept()
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
//Handle the connection //Handle the connection
//in a separate goroutine //in a separate goroutine
@@ -46,20 +45,17 @@ func (s *Server) Start(recvBind func(string, []string) bool, network, address st
conn.Close() conn.Close()
break break
} }
logplus.LogIfErrorFatal(err) LogIfErrorFatal(err)
fullstring := string(buffer) fullstring := string(buffer)
arguments := strings.Split(fullstring, " ") arguments := strings.Split(fullstring, " ")
ret := recvBind(arguments[0], arguments[1:]) ret := recvBind(arguments[0], arguments[1:])
conn.Write([]byte{bool2byte(ret)}) if ret {
conn.Write([]byte{1})
} else {
conn.Write([]byte{0})
}
buffer.Zero() buffer.Zero()
} }
}(conn) }(conn)
} }
} }
func bool2byte(b bool) byte {
if b {
return 1
}
return 0
}

View File

@@ -1,3 +0,0 @@
module sockets
go 1.24.5

View File

@@ -1,6 +0,0 @@
go 1.24.5
use (
.
./logplus
)

View File

@@ -1,3 +0,0 @@
module logplus
go 1.22.2

View File

@@ -3,13 +3,13 @@ package miniws
import ( import (
"bytes" "bytes"
"errors" "errors"
"ipc"
"log" "log"
"mime" "mime"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"slices" "slices"
"sockets"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -18,6 +18,7 @@ import (
) )
const ( const (
FILTER_MODE_INVALID FilterMode = -1
FILTER_MODE_WHITELIST FilterMode = 0 FILTER_MODE_WHITELIST FilterMode = 0
FILTER_MODE_BLACKLIST FilterMode = 1 FILTER_MODE_BLACKLIST FilterMode = 1
@@ -67,24 +68,37 @@ func (ws *WebServer) Run() {
log.Fatalln("Fatal: missing permissions to read www folder") log.Fatalln("Fatal: missing permissions to read www folder")
} }
ws.ipFilterMode, ws.ipFilter = ws.parseFilterPanics(FILENAME_IPFILTER) ipFilterMode, ipFilter, err := ws.parseFilter(FILENAME_IPFILTER)
ws.userAgentFilterMode, ws.userAgentFilter = ws.parseFilterPanics(FILENAME_USERAGENTFILTER) if err != nil {
log.Fatalln("Fatal: IP filter invalid:", err)
}
ws.ipFilterMode = ipFilterMode
ws.ipFilter = ipFilter
userAgentFilterMode, userAgentFilter, err := ws.parseFilter(FILENAME_USERAGENTFILTER)
if err != nil {
log.Fatalln("Fatal: UserAgent filter invalid:", err)
}
ws.userAgentFilter = userAgentFilter
ws.userAgentFilterMode = userAgentFilterMode
// create and start a unix socket server (to accept signal from another process using -s <cmd>) // create and start a unix socket server (to accept signal from another process using -s <cmd>)
socketserver := sockets.Server{} ipcServer := ipc.Server{}
go socketserver.Start(ws.recvBind, "unix", SOCKET_PATH) go ipcServer.Start(ws.onRecieveSignal, "unix", SOCKET_PATH)
http.HandleFunc("/", ws.get) http.HandleFunc("/", ws.get)
log.Println("Server started on port " + strconv.Itoa(ws.port)) log.Println("Server starting on port " + strconv.Itoa(ws.port) + "...")
http.ListenAndServe(":"+strconv.Itoa(ws.port), nil) httpErr := http.ListenAndServe(":"+strconv.Itoa(ws.port), nil)
if httpErr != nil {
log.Fatalln(httpErr)
}
} }
func (ws *WebServer) recvBind(command string, arguments []string) bool { func (ws *WebServer) onRecieveSignal(command string, arguments []string) bool {
command = string(bytes.Trim([]byte(command), "\x00")) command = string(bytes.Trim([]byte(command), "\x00"))
switch command { switch command {
case "reload": case "reload":
ws.parseFilterPanics(FILENAME_IPFILTER) ws.parseFilter(FILENAME_IPFILTER)
ws.parseFilterPanics(FILENAME_USERAGENTFILTER) ws.parseFilter(FILENAME_USERAGENTFILTER)
return true return true
default: default:
log.Println("Error: unknown command", command, arguments) log.Println("Error: unknown command", command, arguments)
@@ -92,7 +106,7 @@ func (ws *WebServer) recvBind(command string, arguments []string) bool {
} }
} }
func (ws *WebServer) parseFilterPanics(fileName string) (FilterMode, []string) { func (ws *WebServer) parseFilter(fileName string) (FilterMode, []string, error) {
log.Println("loaded filter: ", fileName) log.Println("loaded filter: ", fileName)
@@ -109,17 +123,19 @@ func (ws *WebServer) parseFilterPanics(fileName string) (FilterMode, []string) {
} }
if err != nil { if err != nil {
panic("Error opening " + fileName + ": " + err.Error()) return FILTER_MODE_INVALID, nil,
errors.New("Error opening " + fileName + ": " + err.Error())
} }
if fileinfo.Size() == 0 { // empty config if fileinfo.Size() == 0 { // empty config
return filterMode, filter return filterMode, filter, nil
} }
filterContent, err := os.ReadFile(fullPath) filterContent, err := os.ReadFile(fullPath)
if ws.logger.logIfError(err, fullPath) { if ws.logger.logIfError(err, fullPath) {
panic("Error reading " + fileName + ": " + err.Error()) return FILTER_MODE_INVALID, nil,
errors.New("Error reading " + fileName + ": " + err.Error())
} }
lines := strings.Split(string(filterContent), "\n") lines := strings.Split(string(filterContent), "\n")
@@ -142,10 +158,11 @@ func (ws *WebServer) parseFilterPanics(fileName string) (FilterMode, []string) {
case "deny": case "deny":
filterMode = FILTER_MODE_BLACKLIST filterMode = FILTER_MODE_BLACKLIST
default: default:
panic("invalid filter mode for " + fileName + ": use allow|deny") return FILTER_MODE_INVALID, nil,
errors.New("invalid filter mode for " + fileName + ": use allow|deny")
} }
return filterMode, filter return filterMode, filter, nil
} }