Skip to content

Commit 078035e

Browse files
fadymondyclaude
andcommitted
refactor(kernel)!: feature providers are opt-in packages, not kernel defaults
Only 'log' is a core default. cache/queue/storage/realtime/i18n move to togo/providers/* and self-register when blank-imported. A project enables features by importing the packages (chosen at `togo new`); the kernel core hard-codes no features. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 9a4f97d commit 078035e

6 files changed

Lines changed: 87 additions & 37 deletions

File tree

provider.go

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
package togo
22

3-
import (
4-
"sort"
5-
6-
"github.com/togo-framework/togo/cache"
7-
"github.com/togo-framework/togo/i18n"
8-
"github.com/togo-framework/togo/queue"
9-
"github.com/togo-framework/togo/realtime"
10-
"github.com/togo-framework/togo/storage"
11-
)
3+
import "sort"
124

135
// Provider contributes a service to the kernel. The kernel core is tiny (config,
14-
// router, hooks, plugin lifecycle); EVERY other capability — including the
15-
// built-in log/cache/queue/storage/realtime/i18n — is registered as a Provider.
16-
// Nothing is hard-coded in the core: providers run in ascending Priority, and a
17-
// later provider for the same capability overrides an earlier one, so any plugin
18-
// can inject or replace anything by calling RegisterProvider in its init().
6+
// router, hooks, log, plugin lifecycle). Every OTHER capability — cache, queue,
7+
// storage, realtime, i18n, db drivers — lives in its own provider package under
8+
// togo/providers/* and self-registers in init(). A project opts into features by
9+
// blank-importing those packages (chosen at `togo new`), so the core hard-codes
10+
// nothing and any plugin can inject/override a provider globally.
1911
type Provider interface {
2012
ProviderName() string
2113
ProviderPriority() int
@@ -25,49 +17,37 @@ type Provider interface {
2517
// providerRegistry is the global, append-only provider list (defaults + plugins).
2618
var providerRegistry []Provider
2719

28-
// RegisterProvider registers a service provider globally. Call it from a
29-
// package init() (the built-in defaults do exactly this). Higher Priority runs
30-
// later and wins.
20+
// RegisterProvider registers a service provider globally (call from init()).
21+
// Higher Priority runs later and wins.
3122
func RegisterProvider(p Provider) { providerRegistry = append(providerRegistry, p) }
3223

33-
// providerFunc adapts a func to a Provider.
3424
type providerFunc struct {
3525
name string
3626
priority int
3727
fn func(*Kernel) error
3828
}
3929

40-
func (p providerFunc) ProviderName() string { return p.name }
41-
func (p providerFunc) ProviderPriority() int { return p.priority }
30+
func (p providerFunc) ProviderName() string { return p.name }
31+
func (p providerFunc) ProviderPriority() int { return p.priority }
4232
func (p providerFunc) Provide(k *Kernel) error { return p.fn(k) }
4333

44-
// RegisterProviderFunc is a convenience for registering a provider from a func.
34+
// RegisterProviderFunc registers a provider from a func.
4535
func RegisterProviderFunc(name string, priority int, fn func(*Kernel) error) {
4636
RegisterProvider(providerFunc{name: name, priority: priority, fn: fn})
4737
}
4838

49-
// Priority bands for built-in providers (plugins pick their own).
39+
// Priority bands (providers pick their own; built-in feature packages use these).
5040
const (
51-
PriorityCore = 0 // log, config-derived
41+
PriorityCore = 0 // log
5242
PriorityService = 50 // cache, storage, realtime, i18n
5343
PriorityLate = 90 // queue (depends on log)
5444
)
5545

56-
// The built-in capabilities register themselves here — exactly like a plugin
57-
// would. Remove/override any of them with RegisterProvider.
46+
// Only the logger is a core default — it's foundational and always present.
47+
// All feature providers live in togo/providers/* and register themselves when
48+
// the project imports them.
5849
func init() {
5950
RegisterProviderFunc("log", PriorityCore, func(k *Kernel) error { k.Log = newLogger(); return nil })
60-
RegisterProviderFunc("i18n", PriorityService, func(k *Kernel) error {
61-
k.I18n = i18n.Load(k.Config.LocaleDir, k.Config.Locale)
62-
return nil
63-
})
64-
RegisterProviderFunc("cache", PriorityService, func(k *Kernel) error { k.Cache = cache.NewMemory(); return nil })
65-
RegisterProviderFunc("storage", PriorityService, func(k *Kernel) error { k.Storage = storage.NewFS(k.Config.StorageDir); return nil })
66-
RegisterProviderFunc("realtime", PriorityService, func(k *Kernel) error { k.Realtime = realtime.NewBroker(); return nil })
67-
RegisterProviderFunc("queue", PriorityLate, func(k *Kernel) error {
68-
k.Queue = queue.NewMemory(func(err error) { k.Log.Error("queue job failed", "err", err) })
69-
return nil
70-
})
7151
}
7252

7353
// applyProviders runs every registered provider in ascending priority order.
@@ -81,7 +61,7 @@ func (k *Kernel) applyProviders() {
8161
}
8262
}
8363

84-
// Providers returns the names of registered providers in run order (for debugging).
64+
// Providers returns the names of registered providers in run order.
8565
func Providers() []string {
8666
ps := append([]Provider(nil), providerRegistry...)
8767
sort.SliceStable(ps, func(i, j int) bool { return ps[i].ProviderPriority() < ps[j].ProviderPriority() })
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Package cacheprovider registers the default in-memory cache. Blank-import to enable.
2+
package cacheprovider
3+
4+
import (
5+
"github.com/togo-framework/togo"
6+
"github.com/togo-framework/togo/cache"
7+
)
8+
9+
func init() {
10+
togo.RegisterProviderFunc("cache", togo.PriorityService, func(k *togo.Kernel) error {
11+
k.Cache = cache.NewMemory()
12+
return nil
13+
})
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Package i18nprovider registers JSON-keyed translations. Blank-import to enable.
2+
package i18nprovider
3+
4+
import (
5+
"github.com/togo-framework/togo"
6+
"github.com/togo-framework/togo/i18n"
7+
)
8+
9+
func init() {
10+
togo.RegisterProviderFunc("i18n", togo.PriorityService, func(k *togo.Kernel) error {
11+
k.I18n = i18n.Load(k.Config.LocaleDir, k.Config.Locale)
12+
return nil
13+
})
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Package queueprovider registers the in-process job queue. Blank-import to enable.
2+
package queueprovider
3+
4+
import (
5+
"github.com/togo-framework/togo"
6+
"github.com/togo-framework/togo/queue"
7+
)
8+
9+
func init() {
10+
togo.RegisterProviderFunc("queue", togo.PriorityLate, func(k *togo.Kernel) error {
11+
k.Queue = queue.NewMemory(func(err error) { k.Log.Error("queue job failed", "err", err) })
12+
return nil
13+
})
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Package realtimeprovider registers the SSE realtime broker. Blank-import to enable.
2+
package realtimeprovider
3+
4+
import (
5+
"github.com/togo-framework/togo"
6+
"github.com/togo-framework/togo/realtime"
7+
)
8+
9+
func init() {
10+
togo.RegisterProviderFunc("realtime", togo.PriorityService, func(k *togo.Kernel) error {
11+
k.Realtime = realtime.NewBroker()
12+
return nil
13+
})
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Package storageprovider registers filesystem storage. Blank-import to enable.
2+
package storageprovider
3+
4+
import (
5+
"github.com/togo-framework/togo"
6+
"github.com/togo-framework/togo/storage"
7+
)
8+
9+
func init() {
10+
togo.RegisterProviderFunc("storage", togo.PriorityService, func(k *togo.Kernel) error {
11+
k.Storage = storage.NewFS(k.Config.StorageDir)
12+
return nil
13+
})
14+
}

0 commit comments

Comments
 (0)