initial commit

This commit is contained in:
2025-12-23 12:15:28 +11:00
commit 09a2bcdf3a
10 changed files with 1528 additions and 0 deletions

59
watcher/caddyfile_test.go Normal file
View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Suyono
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package watcher
import (
"bytes"
"encoding/json"
"os"
"path/filepath"
"testing"
_ "gitea.suyono.dev/suyono/caddy-autoreload/autoreload"
caddycmd "github.com/caddyserver/caddy/v2/cmd"
_ "github.com/caddyserver/caddy/v2/modules/standard"
)
func prettyJSON(t *testing.T, b []byte) string {
t.Helper()
buf := new(bytes.Buffer)
if err := json.Indent(buf, b, "", " "); err != nil {
return string(b)
}
return buf.String()
}
func TestParseModule(t *testing.T) {
cfgdir, ok := os.LookupEnv("CADDY_CONFIG_DIR")
if !ok {
t.Fatal("CADDY_CONFIG_DIR env variable is not set")
}
var (
b []byte
str string
err error
)
if b, str, err = caddycmd.LoadConfig(filepath.Join(cfgdir, "Caddyfile"), "caddyfile"); err != nil {
t.Fatal("failed to load config:", err)
}
t.Log("loaded config file:", str)
t.Log("json data:", prettyJSON(t, b))
}

90
watcher/watcher.go Normal file
View File

@@ -0,0 +1,90 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Suyono
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package watcher
import (
"net/http"
"gitea.suyono.dev/suyono/caddy-autoreload/autoreload"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"go.uber.org/zap"
)
type AutoReloadWatcher struct {
Cert string `json:"cert,omitempty"`
app *autoreload.AutoReload
logger *zap.Logger
}
func init() {
caddy.RegisterModule(AutoReloadWatcher{})
httpcaddyfile.RegisterHandlerDirective("auto_reload", parseCaddyWatcher)
}
func (AutoReloadWatcher) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers.auto_reload_watcher",
New: func() caddy.Module {
return &AutoReloadWatcher{
app: autoreload.GetAutoReload(),
}
},
}
}
func (w *AutoReloadWatcher) Provision(ctx caddy.Context) error {
w.logger = ctx.Logger(w)
// useful for debugging
w.logger = w.logger.WithOptions(zap.AddCaller())
if w.app == nil {
w.app = autoreload.GetAutoReload()
}
w.app.AddCertPath(w.Cert)
w.logger.Debug("added cert into main reloader", zap.String("cert file", w.Cert))
return nil
}
func (w *AutoReloadWatcher) ServeHTTP(wr http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
return next.ServeHTTP(wr, r)
}
func parseCaddyWatcher(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
w := new(AutoReloadWatcher)
for h.Next() {
for h.NextBlock(0) {
switch h.Val() {
case "cert":
if !h.NextArg() {
return nil, h.Err("cert require cert file path as parameter")
}
w.Cert = h.Val()
default:
return nil, h.Errf("unrecognized subdirective %q", h.Val())
}
}
}
return w, nil
}