Files

85 lines
2.8 KiB
Go

package webdemo
import (
"encoding/json"
"fmt"
"io"
"net/http"
"path/filepath"
"billing/internal/plugin"
)
// DatabaseInput exposes the billing management API against a standalone SQLite copy.
type DatabaseInput struct {
app *plugin.App
}
func NewDatabaseInput(databasePath string) (*DatabaseInput, error) {
absolutePath, err := filepath.Abs(databasePath)
if err != nil {
return nil, fmt.Errorf("resolve demo database path: %w", err)
}
app := plugin.NewApp()
config := fmt.Sprintf("database_path: %q\nenabled: true\ncodex_only: false\n", absolutePath)
lifecycle, err := json.Marshal(plugin.LifecycleRequest{ConfigYAML: []byte(config), SchemaVersion: plugin.SchemaVersion})
if err != nil {
return nil, fmt.Errorf("encode demo lifecycle request: %w", err)
}
if _, err := app.HandleMethod(plugin.MethodPluginRegister, lifecycle); err != nil {
app.Shutdown()
return nil, fmt.Errorf("open demo database: %w", err)
}
return &DatabaseInput{app: app}, nil
}
func (input *DatabaseInput) Close() error {
input.app.Shutdown()
return nil
}
func (input *DatabaseInput) ServeHTTP(response http.ResponseWriter, request *http.Request) {
body, err := io.ReadAll(request.Body)
if err != nil {
writeJSON(response, http.StatusBadRequest, map[string]any{"error": map[string]string{"code": "request_body_error", "message": err.Error()}})
return
}
wireRequest, err := json.Marshal(plugin.ManagementRequest{
Method: request.Method, Path: request.URL.Path, Headers: request.Header.Clone(), Query: request.URL.Query(), Body: body,
})
if err != nil {
writeJSON(response, http.StatusInternalServerError, map[string]any{"error": map[string]string{"code": "request_encode_error", "message": err.Error()}})
return
}
raw, err := input.app.HandleMethod(plugin.MethodManagementHandle, wireRequest)
if err != nil {
writeJSON(response, http.StatusInternalServerError, map[string]any{"error": map[string]string{"code": "management_error", "message": err.Error()}})
return
}
var envelope plugin.Envelope
if err := json.Unmarshal(raw, &envelope); err != nil || !envelope.OK {
message := "invalid management response"
if envelope.Error != nil {
message = envelope.Error.Message
}
writeJSON(response, http.StatusInternalServerError, map[string]any{"error": map[string]string{"code": "management_envelope_error", "message": message}})
return
}
var result plugin.ManagementResponse
if err := json.Unmarshal(envelope.Result, &result); err != nil {
writeJSON(response, http.StatusInternalServerError, map[string]any{"error": map[string]string{"code": "response_decode_error", "message": err.Error()}})
return
}
for name, values := range result.Headers {
for _, value := range values {
response.Header().Add(name, value)
}
}
status := result.StatusCode
if status == 0 {
status = http.StatusOK
}
response.WriteHeader(status)
_, _ = response.Write(result.Body)
}