Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: define bootstrap (#22) #28

Merged
merged 1 commit into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"extendio",
"Fastward",
"fieldalignment",
"fortytw",
"goconst",
"gocritic",
"gocyclo",
Expand Down Expand Up @@ -71,6 +72,7 @@
"trimprefix",
"typecheck",
"unconvert",
"unlambda",
"unparam",
"varcheck",
"watchv",
Expand Down
1 change: 1 addition & 0 deletions core/core-defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package core
type (
// TraverseResult
TraverseResult interface {
Error() error
}

// Client is the callback invoked for each file system node found
Expand Down
7 changes: 7 additions & 0 deletions core/navigator.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
package core

type Navigator interface {
Navigate() (TraverseResult, error)
}

type NavigatorFunc func() (TraverseResult, error)

func (fn NavigatorFunc) Navigate() (TraverseResult, error) {
return fn()
}
6 changes: 3 additions & 3 deletions cycle/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ type (
Stop Event[HibernateHandler]
}

// since the Controls are only required internally as they are used
// by registry, they should be moved to an internal package. this
// since the Controls are only required internally as they are used
// by binder, they should be moved to an internal package. this
// would also necessitate moving the handler definitions to core
// so that they can be shared.

Controls struct { // --> registry
Controls struct { // --> binder
Ascend NotificationCtrl[NodeHandler]
Begin NotificationCtrl[BeginHandler]
Descend NotificationCtrl[NodeHandler]
Expand Down
4 changes: 2 additions & 2 deletions cycle/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

var _ = Describe("controls", func() {
When("bind", func() {
It("should: dispatch notification to event handler", func() {
It("🧪 should: dispatch notification to event handler", func() {
const path = "/traversal-root"

var (
Expand All @@ -20,7 +20,7 @@ var _ = Describe("controls", func() {
ended bool
)

// init(registry->options):
// init(binder->options):
//
events.Bind(&controls)

Expand Down
157 changes: 157 additions & 0 deletions director.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package traverse

import (
"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/enums"
"github.com/snivilised/traverse/pref"
)

type duffNavigatorController struct {
root string
client core.Client
from string
options []pref.Option
}

type duffResult struct{}

func (r *duffResult) Error() error {
return nil
}

func (n *duffNavigatorController) Navigate() (core.TraverseResult, error) {
return &duffResult{}, nil
}

// Prime extent
func Prime(opts ...pref.Option) OptionsBuilder {
return optionals(func() *pref.Options {
binder := pref.NewBinder()

// we probably need to mark something somehow to indicate
// Prime
//
return pref.Request(binder, opts...)
})
}

// Resume extent
func Resume(from string, _ enums.ResumeStrategy, opts ...pref.Option) OptionsBuilder {
// we need state; record the hibernation wake point, so
// using a func here is probably not optimal.
//
return optionals(func() *pref.Options {
binder := pref.NewBinder()

// we probably need to mark something somehow to indicate
// Resume so we can query the hibernation condition and
// apply.
//
load, _ := pref.Load(binder, from, opts...)

// get the resume point from the resume persistence file
// then set up hibernation with this defined as a hibernation
// filter.
//
return load.O
})
}

// Director
type Director interface {
// Extent represents the magnitude of the traversal; ie we can
// perform a full Prime run, or Resume from a previously
// cancelled run.
//
Extent(ob OptionsBuilder) core.Navigator
}

// NavigatorFactory
type NavigatorFactory interface {
// Configure is a factory function that creates a navigator.
// We don't return an error here as that would make using the factory
// awkward. Instead, if there is an error during the build process,
// we return a fake navigator that when invoked immediately returns
// a traverse error indicating the build issue.
//
Configure() Director
}

type baseFactory struct {
factory syncBuilder // the sync factory function
}

type linear struct { // NavigatorFactory
baseFactory
}

func (f *linear) Configure() Director {
// Walk
//
return direct(func(ob OptionsBuilder) core.Navigator {
// resume or prime? If resume, we need to access the hibernation
// wake condition on the retrieved options. But how do we know what
// the extent is, so we know if we need to make this query?
//
//
return &driver{
session{
o: ob.get(),
nav: &duffNavigatorController{},
},
}
})
}

type accelerator struct { // NavigatorFactory
baseFactory
}

func (f *accelerator) Configure() Director {
// Run: create the observable/worker-pool
//
return direct(func(ob OptionsBuilder) core.Navigator {
return &driver{
session{
o: ob.get(),
nav: &duffNavigatorController{},
},
}
})
}

func Walk() NavigatorFactory {
// this could just be a function, because linear doesn't carry any
// state and implements a single method interface
//
return &linear{
baseFactory{
// TODO: where to invoke this from??? (pass in extent?)
factory: sync(func(at string) error {
_ = at

// TODO: set up hibernation filter on navigator/options
//
return nil
}),
},
// extent builder (primary or resume)
// sync builder (sequential) ---> depends on extent (resume: query hibernate condition)
}
}

func Run() NavigatorFactory {
return &accelerator{
baseFactory{
factory: sync(func(at string) error {
_ = at

// TODO: set up hibernation filter on observable
//
return nil
}),
},
// extent builder (primary or resume)
// sync builder (reactive) ---> depends on extent (resume: query hibernate condition)
}
}
75 changes: 14 additions & 61 deletions driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,85 +7,38 @@ import (
"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/internal/services"
"github.com/snivilised/traverse/internal/types"
"github.com/snivilised/traverse/kernel"
"github.com/snivilised/traverse/pref"
)

const (
badge = "navigation-driver"
)

type duffNavigator struct {
root string
client core.Client
from string
options []pref.Option
}

func (n *duffNavigator) Navigate() (core.TraverseResult, error) {
return types.NavigateResult{}, nil
}

func init() {
h := bus.Handler{
services.Broker.RegisterHandler(badge, bus.Handler{
Handle: func(_ context.Context, m bus.Message) {
m.Data.(types.ContextExpiry).Expired()
},
Matcher: services.TopicContextExpired,
}

services.Broker.RegisterHandler(badge, h)
}

// replaces the runner in extendio, although it not
// entirely the same as we also need to maintain a clear
// separation between using the reactive model and the
// sequential model.
})

type Driver interface {
Primary(root string, client core.Client, options ...pref.Option) kernel.Navigator
Resume(from string) kernel.Navigator
}

func Walk() Driver {
return &driver{
session: &session{
ctx: context.Background(),
services.Broker.RegisterHandler(badge, bus.Handler{
Handle: func(_ context.Context, m bus.Message) {
_ = m.Data
// now invoke session.finish
},
}
Matcher: services.TopicTraverseResult,
})
}

func Run() Driver {
return &driver{
session: &session{},
}
}

// the driver needs to tap into the event bus via the broker
// so that it can see when the context has expired.
type driver struct {
session *session
s session
}

func (d *driver) Primary(root string,
client core.Client, options ...pref.Option,
) kernel.Navigator {
return &duffNavigator{
root: root,
client: client,
options: options,
}
}
func (d *driver) Navigate() (core.TraverseResult, error) {
d.s.start()
result, err := d.s.exec()

func (d *driver) Resume(from string) kernel.Navigator {
return &duffNavigator{
from: from,
}
}
d.s.finish(result)

func (d *driver) Expired() {
// not sure if this is right; do we also need to invoke the cancel func
// if it is defined?
//
d.session.ctx = nil
return result, err
}
2 changes: 1 addition & 1 deletion hiber/hibernation-defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ func init() {
// subscribe to options.before
func RestoreOptions() {
// called by resume to load options from json file and
// setup registry to reflect this
// setup binder to reflect this
}
Loading
Loading