filestore

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package filestore reads and writes the app's file stores. The runner keeps the files; a store holds only this app's files, and no name can leave it.

The permission list declares each store as a data source named filestore:<name>:

data:
  - source: filestore:invoices
    classes: [internal]

Open returns the store as a Store, which is an fs.FS, so fs.ReadFile and fs.WalkDir work with it. Store.WriteFile and Store.Create write a file, which appears, whole, only when the write succeeds; Store.Mkdir, Store.Remove and Store.Rename change folders and names.

Rules:

  • Open each store once, in OnStart, and share it with the pages through the app's deps package.
  • Names are slash-separated paths inside the store, such as 2026/42.pdf, with no leading slash and no . or .. parts (E-FILE-001).
  • A file is at most 1 GiB (E-FILE-002).

Read more in the guide docs/guides/file-stores.md and the task docs/tasks/upload-a-file.md, which aicoded explain and the MCP tool howto print as guides/file-stores and tasks/upload-a-file.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is one file store. It is an fs.FS, so it works with fs.ReadFile, fs.WalkDir, fs.Glob and template.ParseFS.

func Open

func Open(ctx context.Context, name string) (*Store, error)

Open returns the store name. Its operations keep the values of ctx but not its cancellation, so a store opened at start-up serves every request. Open fails with E-MAN-011 when aicoded.yaml does not declare filestore:<name>.

Example

Open a store once, in OnStart, and keep it in the app's deps for every page. A store is an fs.FS.

package main

import (
	"context"
	"fmt"
	"io/fs"

	"aicoded.dev/framework/filestore"
)

var invoices *filestore.Store

func main() {
	onStart := func(ctx context.Context) error {
		var err error
		invoices, err = filestore.Open(ctx, "invoices") // filestore:invoices in the permission list
		if err != nil {
			return err
		}
		files := 0
		err = fs.WalkDir(invoices, ".", func(_ string, d fs.DirEntry, err error) error {
			if err == nil && !d.IsDir() {
				files++
			}
			return err
		})
		if err != nil {
			return err
		}
		fmt.Println(files, "invoices")
		return nil
	}
	_ = onStart
}

func (*Store) Create

func (s *Store) Create(name string) (io.WriteCloser, error)

Create starts writing the file name. The file replaces any file of that name when Close succeeds; until then, and after a failed Close, the store is unchanged. Always call Close. The folder of name must exist.

func (*Store) Mkdir

func (s *Store) Mkdir(name string) error

Mkdir creates the folder name and any missing parents.

func (*Store) Open

func (s *Store) Open(name string) (fs.File, error)

Open opens the file or folder name for reading.

func (*Store) ReadDir

func (s *Store) ReadDir(name string) ([]fs.DirEntry, error)

ReadDir returns the folder's entries sorted by name.

func (*Store) ReadFile

func (s *Store) ReadFile(name string) ([]byte, error)

ReadFile returns the whole file.

func (*Store) Remove

func (s *Store) Remove(name string) error

Remove removes the file or empty folder name.

func (*Store) Rename

func (s *Store) Rename(oldName, newName string) error

Rename moves oldName to newName, replacing a file of that name. A folder at newName is never replaced.

func (*Store) Stat

func (s *Store) Stat(name string) (fs.FileInfo, error)

Stat returns the file's information.

func (*Store) WriteFile

func (s *Store) WriteFile(name string, data []byte) error

WriteFile writes data as the file name, replacing any file of that name.

Example

WriteFile stores an uploaded file, here in a form's Process hook, under a name the app chooses. The file appears, whole, only when the write succeeds, and replaces a file of that name. Check the upload's name, size and content first, as the guide guides/forms says.

package main

import (
	"io"

	"aicoded.dev/framework/filestore"
	"aicoded.dev/framework/web/form"
)

var invoices *filestore.Store // the store Open returned in OnStart

func main() {
	process := func(upload *form.FileHeader) error {
		f, err := upload.Open()
		if err != nil {
			return err
		}
		defer f.Close()
		data, err := io.ReadAll(f)
		if err != nil {
			return err
		}
		if err := invoices.Mkdir("2026"); err != nil {
			return err
		}
		return invoices.WriteFile("2026/42.pdf", data)
	}
	_ = process
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL