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) }