Skip to content

Commit

Permalink
Add notifications and sounds to schema (#1064)
Browse files Browse the repository at this point in the history
* Add notifications and sounds to schema

Add the ability to specific app notifications and sounds in the schema.
Here is an example:

```starlark
def get_schema():
    return schema.Schema(
        version = "1",
        notifications = [
            schema.Notification(
                id = "notificationid",
                name = "Notification",
                desc = "A Notification",
                icon = "notification",
                sounds = [
                    schema.Sound(
                        title = "Ding!",
                        file = ding_mp3,
                    ),
                ],
            ),
        ],
    )
```

This change makes the `Schema` and `SchemaJSON` fields of `Applet`
public, so that embedders can inspect the schema and access the sound
files that are referenced by `schema.Sound`.

* Add Bazel build files to gitignore

Bazel files are generated as part of Tidbyt's internal development
process but are not used for the open source build.
  • Loading branch information
rohansingh authored Apr 30, 2024
1 parent 0d1fdc4 commit e09293d
Show file tree
Hide file tree
Showing 14 changed files with 549 additions and 104 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ dist/
# Dependency directories
node_modules
src/go

# build files from monorepo
BUILD.bazel
7 changes: 4 additions & 3 deletions cmd/community/validateicons.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

"github.com/spf13/cobra"

"tidbyt.dev/pixlet/icons"
"tidbyt.dev/pixlet/runtime"
"tidbyt.dev/pixlet/schema"
Expand Down Expand Up @@ -55,12 +56,12 @@ func ValidateIcons(cmd *cobra.Command, args []string) error {
}

s := schema.Schema{}
schemaStr := applet.GetSchema()
if schemaStr == "" {
js := applet.SchemaJSON
if len(js) == 0 {
return nil
}

err = json.Unmarshal([]byte(schemaStr), &s)
err = json.Unmarshal(js, &s)
if err != nil {
return fmt.Errorf("failed to load schema: %w", err)
}
Expand Down
30 changes: 13 additions & 17 deletions runtime/applet.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

"tidbyt.dev/pixlet/render"
"tidbyt.dev/pixlet/runtime/modules/animation_runtime"
"tidbyt.dev/pixlet/runtime/modules/file"
"tidbyt.dev/pixlet/runtime/modules/hmac"
"tidbyt.dev/pixlet/runtime/modules/humanize"
"tidbyt.dev/pixlet/runtime/modules/qrcode"
Expand Down Expand Up @@ -61,12 +62,12 @@ type Applet struct {

globals map[string]starlark.StringDict

mainFile string
mainFun *starlark.Function

mainFile string
mainFun *starlark.Function
schemaFile string
schema *schema.Schema
schemaJSON []byte

Schema *schema.Schema
SchemaJSON []byte
}

func WithModuleLoader(loader ModuleLoader) AppletOption {
Expand Down Expand Up @@ -189,7 +190,7 @@ func (a *Applet) RunWithConfig(ctx context.Context, config map[string]string) (r
// CallSchemaHandler calls a schema handler, passing it a single
// string parameter and returning a single string value.
func (app *Applet) CallSchemaHandler(ctx context.Context, handlerName, parameter string) (result string, err error) {
handler, found := app.schema.Handlers[handlerName]
handler, found := app.Schema.Handlers[handlerName]
if !found {
return "", fmt.Errorf("no exported handler named '%s'", handlerName)
}
Expand Down Expand Up @@ -238,11 +239,6 @@ func (app *Applet) CallSchemaHandler(ctx context.Context, handlerName, parameter
return "", fmt.Errorf("a very unexpected error happened for handler \"%s\"", handlerName)
}

// GetSchema returns the config for the applet.
func (app *Applet) GetSchema() string {
return string(app.schemaJSON)
}

// RunTests runs all test functions that are defined in the applet source.
func (app *Applet) RunTests(t *testing.T) {
app.initializers = append(app.initializers, func(thread *starlark.Thread) *starlark.Thread {
Expand Down Expand Up @@ -439,23 +435,23 @@ func (a *Applet) ensureLoaded(fsys fs.FS, pathToLoad string, currentlyLoading ..
return fmt.Errorf("calling schema function for %s: %w", a.ID, err)
}

a.schema, err = schema.FromStarlark(schemaVal, globals)
a.Schema, err = schema.FromStarlark(schemaVal, globals)
if err != nil {
return fmt.Errorf("parsing schema for %s: %w", a.ID, err)
}

a.schemaJSON, err = json.Marshal(a.schema)
a.SchemaJSON, err = json.Marshal(a.Schema)
if err != nil {
return fmt.Errorf("serializing schema to JSON for %s: %w", a.ID, err)
}
}

default:
a.globals[pathToLoad] = starlark.StringDict{
"file": File{
fsys: fsys,
path: pathToLoad,
}.Struct(),
"file": &file.File{
FS: fsys,
Path: pathToLoad,
},
}
}

Expand Down
37 changes: 34 additions & 3 deletions runtime/applet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.starlark.net/starlark"

"tidbyt.dev/pixlet/schema"
)

Expand Down Expand Up @@ -199,9 +200,8 @@ def get_schema():
require.NoError(t, err)
require.NotNil(t, app)

jsonSchema := app.GetSchema()
var s schema.Schema
json.Unmarshal([]byte(jsonSchema), &s)
json.Unmarshal(app.SchemaJSON, &s)
assert.Equal(t, "1", s.Version)

roots, err := app.Run(context.Background())
Expand Down Expand Up @@ -374,7 +374,7 @@ func TestZIPModule(t *testing.T) {
// https://go.dev/src/archive/zip/example_test.go
buf := new(bytes.Buffer)
w := zip.NewWriter(buf)
var files = []struct {
files := []struct {
Name, Body string
}{
{"readme.txt", "This archive contains some text files."},
Expand Down Expand Up @@ -422,4 +422,35 @@ def main(config):
}, printedText)
}

func TestReadFile(t *testing.T) {
src := `
load("hello.txt", hello = "file")
def assert_eq(message, actual, expected):
if not expected == actual:
fail(message, "-", "expected", expected, "actual", actual)
def test_readall():
assert_eq("readall", hello.readall(), "hello world")
def test_readall_binary():
assert_eq("readall_binary", hello.readall("rb"), b"hello world")
def main():
pass
`

helloTxt := `hello world`

vfs := &fstest.MapFS{
"main.star": {Data: []byte(src)},
"hello.txt": {Data: []byte(helloTxt)},
}

app, err := NewAppletFromFS("test_read_file", vfs)
require.NoError(t, err)
app.RunTests(t)
}

// TODO: test Screens, especially Screens.Render()
39 changes: 0 additions & 39 deletions runtime/file_test.go

This file was deleted.

48 changes: 35 additions & 13 deletions runtime/file.go → runtime/modules/file/file.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
package runtime
package file

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

"github.com/mitchellh/hashstructure/v2"
"go.starlark.net/starlark"
"go.starlark.net/starlarkstruct"
)

type File struct {
fsys fs.FS
path string
FS fs.FS
Path string
}

func (f File) Struct() *starlarkstruct.Struct {
return starlarkstruct.FromStringDict(starlark.String("File"), starlark.StringDict{
"path": starlark.String(f.path),
"readall": starlark.NewBuiltin("readall", f.readall),
})
}

func (f File) readall(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
func (f *File) readall(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var mode starlark.String
if err := starlark.UnpackArgs("readall", args, kwargs, "mode?", &mode); err != nil {
return nil, err
Expand All @@ -36,7 +30,7 @@ func (f File) readall(thread *starlark.Thread, _ *starlark.Builtin, args starlar
return r.read(thread, nil, nil, nil)
}

func (f File) reader(mode string) (*Reader, error) {
func (f *File) reader(mode string) (*Reader, error) {
var binaryMode bool
switch mode {
case "", "r", "rt":
Expand All @@ -49,13 +43,41 @@ func (f File) reader(mode string) (*Reader, error) {
return nil, fmt.Errorf("unsupported mode: %s", mode)
}

fl, err := f.fsys.Open(f.path)
fl, err := f.FS.Open(f.Path)
if err != nil {
return nil, err
}
return &Reader{fl, binaryMode}, nil
}

func (f *File) AttrNames() []string {
return []string{"path", "readall"}
}

func (f *File) Attr(name string) (starlark.Value, error) {
switch name {

case "path":
return starlark.String(f.Path), nil

case "readall":
return starlark.NewBuiltin("readall", f.readall), nil

default:
return nil, nil
}
}

func (f *File) String() string { return "File(...)" }
func (f *File) Type() string { return "File" }
func (f *File) Freeze() {}
func (f *File) Truth() starlark.Bool { return true }

func (f *File) Hash() (uint32, error) {
sum, err := hashstructure.Hash(f, hashstructure.FormatV2, nil)
return uint32(sum), err
}

type Reader struct {
io.ReadCloser
binaryMode bool
Expand Down
Loading

0 comments on commit e09293d

Please sign in to comment.