1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-11 07:52:50 -05:00

rename backend to core

This commit is contained in:
bbedward
2025-11-12 23:12:31 -05:00
parent 0fdc0748cf
commit db584b7897
280 changed files with 265 additions and 265 deletions

View File

@@ -0,0 +1,27 @@
package plugins
import (
"fmt"
"net"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
func HandleRequest(conn net.Conn, req models.Request) {
switch req.Method {
case "plugins.list":
HandleList(conn, req)
case "plugins.listInstalled":
HandleListInstalled(conn, req)
case "plugins.install":
HandleInstall(conn, req)
case "plugins.uninstall":
HandleUninstall(conn, req)
case "plugins.update":
HandleUpdate(conn, req)
case "plugins.search":
HandleSearch(conn, req)
default:
models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
}
}

View File

@@ -0,0 +1,196 @@
package plugins
import (
"encoding/json"
"testing"
"github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/net"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
func TestHandleList(t *testing.T) {
conn := net.NewMockConn(t)
conn.EXPECT().Write(mock.Anything).Return(0, nil).Maybe()
req := models.Request{
ID: 123,
Method: "plugins.list",
Params: map[string]interface{}{},
}
HandleList(conn, req)
}
func TestHandleListInstalled(t *testing.T) {
conn := net.NewMockConn(t)
conn.EXPECT().Write(mock.Anything).Return(0, nil).Maybe()
req := models.Request{
ID: 123,
Method: "plugins.listInstalled",
Params: map[string]interface{}{},
}
HandleListInstalled(conn, req)
}
func TestHandleInstallMissingName(t *testing.T) {
conn := net.NewMockConn(t)
var written []byte
conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
written = b
return len(b), nil
}).Maybe()
req := models.Request{
ID: 123,
Method: "plugins.install",
Params: map[string]interface{}{},
}
HandleInstall(conn, req)
var resp models.Response[SuccessResult]
err := json.Unmarshal(written, &resp)
assert.NoError(t, err)
assert.NotEmpty(t, resp.Error)
assert.Contains(t, resp.Error, "missing or invalid 'name' parameter")
}
func TestHandleInstallInvalidName(t *testing.T) {
conn := net.NewMockConn(t)
var written []byte
conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
written = b
return len(b), nil
}).Maybe()
req := models.Request{
ID: 123,
Method: "plugins.install",
Params: map[string]interface{}{
"name": 123,
},
}
HandleInstall(conn, req)
var resp models.Response[SuccessResult]
err := json.Unmarshal(written, &resp)
assert.NoError(t, err)
assert.NotEmpty(t, resp.Error)
}
func TestHandleUninstallMissingName(t *testing.T) {
conn := net.NewMockConn(t)
var written []byte
conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
written = b
return len(b), nil
}).Maybe()
req := models.Request{
ID: 123,
Method: "plugins.uninstall",
Params: map[string]interface{}{},
}
HandleUninstall(conn, req)
var resp models.Response[SuccessResult]
err := json.Unmarshal(written, &resp)
assert.NoError(t, err)
assert.NotEmpty(t, resp.Error)
}
func TestHandleUpdateMissingName(t *testing.T) {
conn := net.NewMockConn(t)
var written []byte
conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
written = b
return len(b), nil
}).Maybe()
req := models.Request{
ID: 123,
Method: "plugins.update",
Params: map[string]interface{}{},
}
HandleUpdate(conn, req)
var resp models.Response[SuccessResult]
err := json.Unmarshal(written, &resp)
assert.NoError(t, err)
assert.NotEmpty(t, resp.Error)
}
func TestHandleSearchMissingQuery(t *testing.T) {
conn := net.NewMockConn(t)
var written []byte
conn.EXPECT().Write(mock.Anything).RunAndReturn(func(b []byte) (int, error) {
written = b
return len(b), nil
}).Maybe()
req := models.Request{
ID: 123,
Method: "plugins.search",
Params: map[string]interface{}{},
}
HandleSearch(conn, req)
var resp models.Response[[]PluginInfo]
err := json.Unmarshal(written, &resp)
assert.NoError(t, err)
assert.NotEmpty(t, resp.Error)
}
func TestSortPluginInfoByFirstParty(t *testing.T) {
plugins := []PluginInfo{
{Name: "third-party", Repo: "https://github.com/other/test"},
{Name: "first-party", Repo: "https://github.com/AvengeMedia/test"},
}
SortPluginInfoByFirstParty(plugins)
assert.Equal(t, "first-party", plugins[0].Name)
assert.Equal(t, "third-party", plugins[1].Name)
}
func TestPluginInfoJSON(t *testing.T) {
info := PluginInfo{
Name: "test",
Description: "test description",
Installed: true,
FirstParty: true,
}
data, err := json.Marshal(info)
assert.NoError(t, err)
var unmarshaled PluginInfo
err = json.Unmarshal(data, &unmarshaled)
assert.NoError(t, err)
assert.Equal(t, info.Name, unmarshaled.Name)
assert.Equal(t, info.Installed, unmarshaled.Installed)
}
func TestSuccessResult(t *testing.T) {
result := SuccessResult{
Success: true,
Message: "test message",
}
data, err := json.Marshal(result)
assert.NoError(t, err)
var unmarshaled SuccessResult
err = json.Unmarshal(data, &unmarshaled)
assert.NoError(t, err)
assert.True(t, unmarshaled.Success)
assert.Equal(t, "test message", unmarshaled.Message)
}

View File

@@ -0,0 +1,69 @@
package plugins
import (
"fmt"
"net"
"github.com/AvengeMedia/DankMaterialShell/core/internal/plugins"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
func HandleInstall(conn net.Conn, req models.Request) {
idOrName, ok := req.Params["name"].(string)
if !ok {
models.RespondError(conn, req.ID, "missing or invalid 'name' parameter")
return
}
registry, err := plugins.NewRegistry()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
return
}
pluginList, err := registry.List()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
return
}
// First, try to find by ID (preferred method)
var plugin *plugins.Plugin
for _, p := range pluginList {
if p.ID == idOrName {
plugin = &p
break
}
}
// Fallback to name for backward compatibility
if plugin == nil {
for _, p := range pluginList {
if p.Name == idOrName {
plugin = &p
break
}
}
}
if plugin == nil {
models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", idOrName))
return
}
manager, err := plugins.NewManager()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
return
}
if err := manager.Install(*plugin); err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to install plugin: %v", err))
return
}
models.Respond(conn, req.ID, SuccessResult{
Success: true,
Message: fmt.Sprintf("plugin installed: %s", plugin.Name),
})
}

View File

@@ -0,0 +1,51 @@
package plugins
import (
"fmt"
"net"
"strings"
"github.com/AvengeMedia/DankMaterialShell/core/internal/plugins"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
func HandleList(conn net.Conn, req models.Request) {
registry, err := plugins.NewRegistry()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
return
}
pluginList, err := registry.List()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
return
}
manager, err := plugins.NewManager()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
return
}
result := make([]PluginInfo, len(pluginList))
for i, p := range pluginList {
installed, _ := manager.IsInstalled(p)
result[i] = PluginInfo{
ID: p.ID,
Name: p.Name,
Category: p.Category,
Author: p.Author,
Description: p.Description,
Repo: p.Repo,
Path: p.Path,
Capabilities: p.Capabilities,
Compositors: p.Compositors,
Dependencies: p.Dependencies,
Installed: installed,
FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
}
}
models.Respond(conn, req.ID, result)
}

View File

@@ -0,0 +1,76 @@
package plugins
import (
"fmt"
"net"
"strings"
"github.com/AvengeMedia/DankMaterialShell/core/internal/plugins"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
func HandleListInstalled(conn net.Conn, req models.Request) {
manager, err := plugins.NewManager()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
return
}
installedNames, err := manager.ListInstalled()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to list installed plugins: %v", err))
return
}
registry, err := plugins.NewRegistry()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
return
}
allPlugins, err := registry.List()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
return
}
pluginMap := make(map[string]plugins.Plugin)
for _, p := range allPlugins {
pluginMap[p.ID] = p
}
result := make([]PluginInfo, 0, len(installedNames))
for _, id := range installedNames {
if plugin, ok := pluginMap[id]; ok {
hasUpdate := false
if hasUpdates, err := manager.HasUpdates(id, plugin); err == nil {
hasUpdate = hasUpdates
}
result = append(result, PluginInfo{
ID: plugin.ID,
Name: plugin.Name,
Category: plugin.Category,
Author: plugin.Author,
Description: plugin.Description,
Repo: plugin.Repo,
Path: plugin.Path,
Capabilities: plugin.Capabilities,
Compositors: plugin.Compositors,
Dependencies: plugin.Dependencies,
FirstParty: strings.HasPrefix(plugin.Repo, "https://github.com/AvengeMedia"),
HasUpdate: hasUpdate,
})
} else {
result = append(result, PluginInfo{
ID: id,
Name: id,
Note: "not in registry",
})
}
}
SortPluginInfoByFirstParty(result)
models.Respond(conn, req.ID, result)
}

View File

@@ -0,0 +1,73 @@
package plugins
import (
"fmt"
"net"
"strings"
"github.com/AvengeMedia/DankMaterialShell/core/internal/plugins"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
func HandleSearch(conn net.Conn, req models.Request) {
query, ok := req.Params["query"].(string)
if !ok {
models.RespondError(conn, req.ID, "missing or invalid 'query' parameter")
return
}
registry, err := plugins.NewRegistry()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
return
}
pluginList, err := registry.List()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
return
}
searchResults := plugins.FuzzySearch(query, pluginList)
if category, ok := req.Params["category"].(string); ok && category != "" {
searchResults = plugins.FilterByCategory(category, searchResults)
}
if compositor, ok := req.Params["compositor"].(string); ok && compositor != "" {
searchResults = plugins.FilterByCompositor(compositor, searchResults)
}
if capability, ok := req.Params["capability"].(string); ok && capability != "" {
searchResults = plugins.FilterByCapability(capability, searchResults)
}
searchResults = plugins.SortByFirstParty(searchResults)
manager, err := plugins.NewManager()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
return
}
result := make([]PluginInfo, len(searchResults))
for i, p := range searchResults {
installed, _ := manager.IsInstalled(p)
result[i] = PluginInfo{
ID: p.ID,
Name: p.Name,
Category: p.Category,
Author: p.Author,
Description: p.Description,
Repo: p.Repo,
Path: p.Path,
Capabilities: p.Capabilities,
Compositors: p.Compositors,
Dependencies: p.Dependencies,
Installed: installed,
FirstParty: strings.HasPrefix(p.Repo, "https://github.com/AvengeMedia"),
}
}
models.Respond(conn, req.ID, result)
}

View File

@@ -0,0 +1,23 @@
package plugins
type PluginInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Category string `json:"category,omitempty"`
Author string `json:"author,omitempty"`
Description string `json:"description,omitempty"`
Repo string `json:"repo,omitempty"`
Path string `json:"path,omitempty"`
Capabilities []string `json:"capabilities,omitempty"`
Compositors []string `json:"compositors,omitempty"`
Dependencies []string `json:"dependencies,omitempty"`
Installed bool `json:"installed,omitempty"`
FirstParty bool `json:"firstParty,omitempty"`
Note string `json:"note,omitempty"`
HasUpdate bool `json:"hasUpdate,omitempty"`
}
type SuccessResult struct {
Success bool `json:"success"`
Message string `json:"message"`
}

View File

@@ -0,0 +1,69 @@
package plugins
import (
"fmt"
"net"
"github.com/AvengeMedia/DankMaterialShell/core/internal/plugins"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
func HandleUninstall(conn net.Conn, req models.Request) {
name, ok := req.Params["name"].(string)
if !ok {
models.RespondError(conn, req.ID, "missing or invalid 'name' parameter")
return
}
registry, err := plugins.NewRegistry()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
return
}
pluginList, err := registry.List()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
return
}
var plugin *plugins.Plugin
for _, p := range pluginList {
if p.Name == name {
plugin = &p
break
}
}
if plugin == nil {
models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", name))
return
}
manager, err := plugins.NewManager()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
return
}
installed, err := manager.IsInstalled(*plugin)
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if plugin is installed: %v", err))
return
}
if !installed {
models.RespondError(conn, req.ID, fmt.Sprintf("plugin not installed: %s", name))
return
}
if err := manager.Uninstall(*plugin); err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to uninstall plugin: %v", err))
return
}
models.Respond(conn, req.ID, SuccessResult{
Success: true,
Message: fmt.Sprintf("plugin uninstalled: %s", name),
})
}

View File

@@ -0,0 +1,69 @@
package plugins
import (
"fmt"
"net"
"github.com/AvengeMedia/DankMaterialShell/core/internal/plugins"
"github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
)
func HandleUpdate(conn net.Conn, req models.Request) {
name, ok := req.Params["name"].(string)
if !ok {
models.RespondError(conn, req.ID, "missing or invalid 'name' parameter")
return
}
registry, err := plugins.NewRegistry()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create registry: %v", err))
return
}
pluginList, err := registry.List()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to list plugins: %v", err))
return
}
var plugin *plugins.Plugin
for _, p := range pluginList {
if p.Name == name {
plugin = &p
break
}
}
if plugin == nil {
models.RespondError(conn, req.ID, fmt.Sprintf("plugin not found: %s", name))
return
}
manager, err := plugins.NewManager()
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to create manager: %v", err))
return
}
installed, err := manager.IsInstalled(*plugin)
if err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to check if plugin is installed: %v", err))
return
}
if !installed {
models.RespondError(conn, req.ID, fmt.Sprintf("plugin not installed: %s", name))
return
}
if err := manager.Update(*plugin); err != nil {
models.RespondError(conn, req.ID, fmt.Sprintf("failed to update plugin: %v", err))
return
}
models.Respond(conn, req.ID, SuccessResult{
Success: true,
Message: fmt.Sprintf("plugin updated: %s", name),
})
}

View File

@@ -0,0 +1,17 @@
package plugins
import (
"sort"
"strings"
)
func SortPluginInfoByFirstParty(pluginInfos []PluginInfo) {
sort.SliceStable(pluginInfos, func(i, j int) bool {
isFirstPartyI := strings.HasPrefix(pluginInfos[i].Repo, "https://github.com/AvengeMedia")
isFirstPartyJ := strings.HasPrefix(pluginInfos[j].Repo, "https://github.com/AvengeMedia")
if isFirstPartyI != isFirstPartyJ {
return isFirstPartyI
}
return false
})
}