fix(pkg/api): emit installed change events
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
fe8c7e5982
commit
25667064ca
4 changed files with 99 additions and 3 deletions
2
go.mod
2
go.mod
|
|
@ -15,6 +15,7 @@ require (
|
||||||
forge.lthn.ai/core/config v0.1.8
|
forge.lthn.ai/core/config v0.1.8
|
||||||
github.com/gin-gonic/gin v1.12.0
|
github.com/gin-gonic/gin v1.12.0
|
||||||
github.com/goccy/go-json v0.10.6
|
github.com/goccy/go-json v0.10.6
|
||||||
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
golang.org/x/net v0.52.0
|
golang.org/x/net v0.52.0
|
||||||
golang.org/x/sys v0.42.0
|
golang.org/x/sys v0.42.0
|
||||||
|
|
@ -93,7 +94,6 @@ require (
|
||||||
github.com/gorilla/context v1.1.2 // indirect
|
github.com/gorilla/context v1.1.2 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/gorilla/sessions v1.4.0 // indirect
|
github.com/gorilla/sessions v1.4.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
|
||||||
github.com/hashicorp/go-version v1.8.0 // indirect
|
github.com/hashicorp/go-version v1.8.0 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,19 @@ import (
|
||||||
// and Renderable.
|
// and Renderable.
|
||||||
type ScmProvider struct {
|
type ScmProvider struct {
|
||||||
index *marketplace.Index
|
index *marketplace.Index
|
||||||
installer *marketplace.Installer
|
installer marketplaceInstaller
|
||||||
registry *repos.Registry
|
registry *repos.Registry
|
||||||
hub *ws.Hub
|
hub *ws.Hub
|
||||||
medium io.Medium
|
medium io.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type marketplaceInstaller interface {
|
||||||
|
Install(context.Context, marketplace.Module) error
|
||||||
|
Remove(string) error
|
||||||
|
Update(context.Context, string) error
|
||||||
|
Installed() ([]marketplace.InstalledModule, error)
|
||||||
|
}
|
||||||
|
|
||||||
// compile-time interface checks
|
// compile-time interface checks
|
||||||
var (
|
var (
|
||||||
_ provider.Provider = (*ScmProvider)(nil)
|
_ provider.Provider = (*ScmProvider)(nil)
|
||||||
|
|
@ -47,7 +54,7 @@ var (
|
||||||
// installer, and registry. The WS hub is used to emit real-time events.
|
// installer, and registry. The WS hub is used to emit real-time events.
|
||||||
// Pass nil for any dependency that is not available.
|
// Pass nil for any dependency that is not available.
|
||||||
// Usage: NewProvider(...)
|
// Usage: NewProvider(...)
|
||||||
func NewProvider(idx *marketplace.Index, inst *marketplace.Installer, reg *repos.Registry, hub *ws.Hub) *ScmProvider {
|
func NewProvider(idx *marketplace.Index, inst marketplaceInstaller, reg *repos.Registry, hub *ws.Hub) *ScmProvider {
|
||||||
return &ScmProvider{
|
return &ScmProvider{
|
||||||
index: idx,
|
index: idx,
|
||||||
installer: inst,
|
installer: inst,
|
||||||
|
|
@ -81,6 +88,7 @@ func (p *ScmProvider) Channels() []string {
|
||||||
"scm.marketplace.refreshed",
|
"scm.marketplace.refreshed",
|
||||||
"scm.marketplace.installed",
|
"scm.marketplace.installed",
|
||||||
"scm.marketplace.removed",
|
"scm.marketplace.removed",
|
||||||
|
"scm.installed.changed",
|
||||||
"scm.manifest.verified",
|
"scm.manifest.verified",
|
||||||
"scm.registry.changed",
|
"scm.registry.changed",
|
||||||
}
|
}
|
||||||
|
|
@ -293,6 +301,11 @@ func (p *ScmProvider) installItem(c *gin.Context) {
|
||||||
"code": mod.Code,
|
"code": mod.Code,
|
||||||
"name": mod.Name,
|
"name": mod.Name,
|
||||||
})
|
})
|
||||||
|
p.emitEvent("scm.installed.changed", map[string]any{
|
||||||
|
"action": "installed",
|
||||||
|
"code": mod.Code,
|
||||||
|
"name": mod.Name,
|
||||||
|
})
|
||||||
|
|
||||||
c.JSON(http.StatusOK, api.OK(map[string]any{"installed": true, "code": mod.Code}))
|
c.JSON(http.StatusOK, api.OK(map[string]any{"installed": true, "code": mod.Code}))
|
||||||
}
|
}
|
||||||
|
|
@ -313,6 +326,10 @@ func (p *ScmProvider) removeItem(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.emitEvent("scm.marketplace.removed", map[string]any{"code": code})
|
p.emitEvent("scm.marketplace.removed", map[string]any{"code": code})
|
||||||
|
p.emitEvent("scm.installed.changed", map[string]any{
|
||||||
|
"action": "removed",
|
||||||
|
"code": code,
|
||||||
|
})
|
||||||
|
|
||||||
c.JSON(http.StatusOK, api.OK(map[string]any{"removed": true, "code": code}))
|
c.JSON(http.StatusOK, api.OK(map[string]any{"removed": true, "code": code}))
|
||||||
}
|
}
|
||||||
|
|
@ -474,6 +491,11 @@ func (p *ScmProvider) updateInstalled(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.emitEvent("scm.installed.changed", map[string]any{
|
||||||
|
"action": "updated",
|
||||||
|
"code": code,
|
||||||
|
})
|
||||||
|
|
||||||
c.JSON(http.StatusOK, api.OK(map[string]any{"updated": true, "code": code}))
|
c.JSON(http.StatusOK, api.OK(map[string]any{"updated": true, "code": code}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
73
pkg/api/provider_events_test.go
Normal file
73
pkg/api/provider_events_test.go
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
// SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
package api_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"dappco.re/go/core/scm/marketplace"
|
||||||
|
scmapi "dappco.re/go/core/scm/pkg/api"
|
||||||
|
"dappco.re/go/core/ws"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeInstaller struct {
|
||||||
|
updateCalls []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeInstaller) Install(context.Context, marketplace.Module) error { return nil }
|
||||||
|
|
||||||
|
func (f *fakeInstaller) Remove(string) error { return nil }
|
||||||
|
|
||||||
|
func (f *fakeInstaller) Update(_ context.Context, code string) error {
|
||||||
|
f.updateCalls = append(f.updateCalls, code)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeInstaller) Installed() ([]marketplace.InstalledModule, error) { return nil, nil }
|
||||||
|
|
||||||
|
func TestScmProvider_UpdateInstalled_EmitsInstalledChangedEvent_Good(t *testing.T) {
|
||||||
|
hub := ws.NewHub()
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
t.Cleanup(cancel)
|
||||||
|
go hub.Run(ctx)
|
||||||
|
|
||||||
|
server := httptest.NewServer(hub.Handler())
|
||||||
|
t.Cleanup(server.Close)
|
||||||
|
|
||||||
|
wsURL := "ws" + strings.TrimPrefix(server.URL, "http")
|
||||||
|
conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() { _ = conn.Close() })
|
||||||
|
|
||||||
|
require.NoError(t, conn.WriteJSON(ws.Message{Type: ws.TypeSubscribe, Data: "scm.installed.changed"}))
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
|
||||||
|
installer := &fakeInstaller{}
|
||||||
|
p := scmapi.NewProvider(nil, installer, nil, hub)
|
||||||
|
r := setupRouter(p)
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest("POST", "/api/v1/scm/installed/demo/update", nil)
|
||||||
|
r.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
require.Equal(t, http.StatusOK, w.Code)
|
||||||
|
require.Equal(t, []string{"demo"}, installer.updateCalls)
|
||||||
|
|
||||||
|
var msg ws.Message
|
||||||
|
require.NoError(t, conn.ReadJSON(&msg))
|
||||||
|
assert.Equal(t, ws.TypeEvent, msg.Type)
|
||||||
|
assert.Equal(t, "scm.installed.changed", msg.Channel)
|
||||||
|
|
||||||
|
data, ok := msg.Data.(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.Equal(t, "updated", data["action"])
|
||||||
|
assert.Equal(t, "demo", data["code"])
|
||||||
|
}
|
||||||
|
|
@ -42,6 +42,7 @@ func TestScmProvider_Channels_Good(t *testing.T) {
|
||||||
assert.Contains(t, channels, "scm.marketplace.refreshed")
|
assert.Contains(t, channels, "scm.marketplace.refreshed")
|
||||||
assert.Contains(t, channels, "scm.marketplace.installed")
|
assert.Contains(t, channels, "scm.marketplace.installed")
|
||||||
assert.Contains(t, channels, "scm.marketplace.removed")
|
assert.Contains(t, channels, "scm.marketplace.removed")
|
||||||
|
assert.Contains(t, channels, "scm.installed.changed")
|
||||||
assert.Contains(t, channels, "scm.manifest.verified")
|
assert.Contains(t, channels, "scm.manifest.verified")
|
||||||
assert.Contains(t, channels, "scm.registry.changed")
|
assert.Contains(t, channels, "scm.registry.changed")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue