summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups
diff options
context:
space:
mode:
authorNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
committerNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
commita2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5 (patch)
tree1a8769217f84bfe9d6216fafaadaf8cdd876d457 /raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups
parent34b9c34f982b2596cfa9e368a2d7f74e9a17477c (diff)
downloadRaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.tar.gz
RaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.zip
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions.go479
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go235
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go450
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go487
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go711
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager.go390
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go363
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go184
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go95
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go245
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go295
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go176
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go397
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/testing.go13
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/types.go132
15 files changed, 0 insertions, 4652 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions.go
deleted file mode 100644
index 2f9b98b..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions.go
+++ /dev/null
@@ -1,479 +0,0 @@
-package cups
-
-import (
- "errors"
- "fmt"
- "net"
- "net/url"
- "os/exec"
- "strings"
- "time"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/config"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
-)
-
-func isAuthError(err error) bool {
- if err == nil {
- return false
- }
-
- var httpErr ipp.HTTPError
- if errors.As(err, &httpErr) {
- return httpErr.Code == 401 || httpErr.Code == 403
- }
-
- var ippErr ipp.IPPError
- if errors.As(err, &ippErr) {
- return ippErr.Status == ipp.StatusErrorForbidden ||
- ippErr.Status == ipp.StatusErrorNotAuthenticated ||
- ippErr.Status == ipp.StatusErrorNotAuthorized
- }
-
- return false
-}
-
-func (m *Manager) GetPrinters() ([]Printer, error) {
- attributes := []string{
- ipp.AttributePrinterName,
- ipp.AttributePrinterUriSupported,
- ipp.AttributePrinterState,
- ipp.AttributePrinterStateReasons,
- ipp.AttributePrinterLocation,
- ipp.AttributePrinterInfo,
- ipp.AttributePrinterMakeAndModel,
- ipp.AttributePrinterIsAcceptingJobs,
- }
-
- printerAttrs, err := m.client.GetPrinters(attributes)
- if err != nil {
- if isNoPrintersError(err) {
- return []Printer{}, nil
- }
- return nil, err
- }
-
- printers := make([]Printer, 0, len(printerAttrs))
- for _, attrs := range printerAttrs {
- printer := Printer{
- Name: getStringAttr(attrs, ipp.AttributePrinterName),
- URI: getStringAttr(attrs, ipp.AttributePrinterUriSupported),
- State: parsePrinterState(attrs),
- StateReason: getStringAttr(attrs, ipp.AttributePrinterStateReasons),
- Location: getStringAttr(attrs, ipp.AttributePrinterLocation),
- Info: getStringAttr(attrs, ipp.AttributePrinterInfo),
- MakeModel: getStringAttr(attrs, ipp.AttributePrinterMakeAndModel),
- Accepting: getBoolAttr(attrs, ipp.AttributePrinterIsAcceptingJobs),
- }
-
- if printer.Name != "" {
- printers = append(printers, printer)
- }
- }
-
- return printers, nil
-}
-
-func (m *Manager) GetJobs(printerName string, whichJobs string) ([]Job, error) {
- attributes := []string{
- ipp.AttributeJobID,
- ipp.AttributeJobName,
- ipp.AttributeJobState,
- ipp.AttributeJobPrinterURI,
- ipp.AttributeJobOriginatingUserName,
- ipp.AttributeJobKilobyteOctets,
- "time-at-creation",
- }
-
- jobAttrs, err := m.client.GetJobs(printerName, "", whichJobs, false, 0, 0, attributes)
- if err != nil {
- return nil, err
- }
-
- jobs := make([]Job, 0, len(jobAttrs))
- for _, attrs := range jobAttrs {
- job := Job{
- ID: getIntAttr(attrs, ipp.AttributeJobID),
- Name: getStringAttr(attrs, ipp.AttributeJobName),
- State: parseJobState(attrs),
- User: getStringAttr(attrs, ipp.AttributeJobOriginatingUserName),
- Size: getIntAttr(attrs, ipp.AttributeJobKilobyteOctets) * 1024,
- }
-
- if uri := getStringAttr(attrs, ipp.AttributeJobPrinterURI); uri != "" {
- parts := strings.Split(uri, "/")
- if len(parts) > 0 {
- job.Printer = parts[len(parts)-1]
- }
- }
-
- if ts := getIntAttr(attrs, "time-at-creation"); ts > 0 {
- job.TimeCreated = time.Unix(int64(ts), 0)
- }
-
- if job.ID != 0 {
- jobs = append(jobs, job)
- }
- }
-
- return jobs, nil
-}
-
-func (m *Manager) CancelJob(jobID int) error {
- err := m.client.CancelJob(jobID, false)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.JobCancelPurge(jobID, false)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) PausePrinter(printerName string) error {
- err := m.client.PausePrinter(printerName)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterSetEnabled(printerName, false)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) ResumePrinter(printerName string) error {
- err := m.client.ResumePrinter(printerName)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterSetEnabled(printerName, true)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) PurgeJobs(printerName string) error {
- err := m.client.CancelAllJob(printerName, true)
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func resolveIPFromURI(uri string) string {
- parsed, err := url.Parse(uri)
- if err != nil {
- return ""
- }
- host := parsed.Hostname()
- if host == "" {
- return ""
- }
- if ip := net.ParseIP(host); ip != nil {
- return ip.String()
- }
- addrs, err := net.LookupIP(host)
- if err != nil || len(addrs) == 0 {
- return ""
- }
- for _, addr := range addrs {
- if v4 := addr.To4(); v4 != nil {
- return v4.String()
- }
- }
- return addrs[0].String()
-}
-
-func (m *Manager) GetDevices() ([]Device, error) {
- if m.pkHelper != nil {
- devices, err := m.pkHelper.DevicesGet(10, 0, nil, nil)
- if err != nil {
- return nil, err
- }
- for i := range devices {
- if devices[i].Class == "network" {
- devices[i].IP = resolveIPFromURI(devices[i].URI)
- }
- }
- return devices, nil
- }
-
- deviceAttrs, err := m.client.GetDevices()
- if err != nil {
- return nil, err
- }
-
- devices := make([]Device, 0, len(deviceAttrs))
- for uri, attrs := range deviceAttrs {
- device := Device{
- URI: uri,
- Class: getStringAttr(attrs, "device-class"),
- Info: getStringAttr(attrs, "device-info"),
- MakeModel: getStringAttr(attrs, "device-make-and-model"),
- ID: getStringAttr(attrs, "device-id"),
- Location: getStringAttr(attrs, "device-location"),
- }
- if device.Class == "network" {
- device.IP = resolveIPFromURI(uri)
- }
- devices = append(devices, device)
- }
-
- return devices, nil
-}
-
-func (m *Manager) GetPPDs() ([]PPD, error) {
- ppdAttrs, err := m.client.GetPPDs()
- if err != nil {
- return nil, err
- }
-
- ppds := make([]PPD, 0, len(ppdAttrs))
- for name, attrs := range ppdAttrs {
- ppd := PPD{
- Name: name,
- NaturalLanguage: getStringAttr(attrs, "ppd-natural-language"),
- MakeModel: getStringAttr(attrs, ipp.AttributePPDMakeAndModel),
- DeviceID: getStringAttr(attrs, "ppd-device-id"),
- Product: getStringAttr(attrs, "ppd-product"),
- PSVersion: getStringAttr(attrs, "ppd-psversion"),
- Type: getStringAttr(attrs, "ppd-type"),
- }
- ppds = append(ppds, ppd)
- }
-
- return ppds, nil
-}
-
-func (m *Manager) GetClasses() ([]PrinterClass, error) {
- attributes := []string{
- ipp.AttributePrinterName,
- ipp.AttributePrinterUriSupported,
- ipp.AttributePrinterState,
- ipp.AttributeMemberURIs,
- ipp.AttributeMemberNames,
- ipp.AttributePrinterLocation,
- ipp.AttributePrinterInfo,
- }
-
- classAttrs, err := m.client.GetClasses(attributes)
- if err != nil {
- return nil, err
- }
-
- classes := make([]PrinterClass, 0, len(classAttrs))
- for _, attrs := range classAttrs {
- class := PrinterClass{
- Name: getStringAttr(attrs, ipp.AttributePrinterName),
- URI: getStringAttr(attrs, ipp.AttributePrinterUriSupported),
- State: parsePrinterState(attrs),
- Location: getStringAttr(attrs, ipp.AttributePrinterLocation),
- Info: getStringAttr(attrs, ipp.AttributePrinterInfo),
- Members: getStringSliceAttr(attrs, ipp.AttributeMemberNames),
- }
- classes = append(classes, class)
- }
-
- return classes, nil
-}
-
-func createPrinterViaLpadmin(name, deviceURI, ppd, information, location string) error {
- args := []string{"-p", name, "-E", "-v", deviceURI, "-m", ppd}
- if information != "" {
- args = append(args, "-D", information)
- }
- if location != "" {
- args = append(args, "-L", location)
- }
- out, err := exec.Command("lpadmin", args...).CombinedOutput()
- if err != nil {
- return fmt.Errorf("lpadmin failed: %s: %w", strings.TrimSpace(string(out)), err)
- }
- return nil
-}
-
-func deletePrinterViaLpadmin(name string) error {
- out, err := exec.Command("lpadmin", "-x", name).CombinedOutput()
- if err != nil {
- return fmt.Errorf("lpadmin failed: %s: %w", strings.TrimSpace(string(out)), err)
- }
- return nil
-}
-
-func (m *Manager) CreatePrinter(name, deviceURI, ppd string, shared bool, errorPolicy, information, location string) error {
- usedPkHelper := false
-
- err := m.client.CreatePrinter(name, deviceURI, ppd, shared, errorPolicy, information, location)
- if isAuthError(err) && m.pkHelper != nil {
- if err = m.pkHelper.PrinterAdd(name, deviceURI, ppd, information, location); err != nil {
- // pkHelper failed (e.g., no polkit agent), try lpadmin as last resort.
- // lpadmin -E enables the printer, so no further setup needed.
- if lpadminErr := createPrinterViaLpadmin(name, deviceURI, ppd, information, location); lpadminErr != nil {
- return err
- }
- m.RefreshState()
- return nil
- }
- usedPkHelper = true
- } else if err != nil {
- return err
- }
-
- if usedPkHelper {
- m.pkHelper.PrinterSetEnabled(name, true) //nolint:errcheck
- m.pkHelper.PrinterSetAcceptJobs(name, true, "") //nolint:errcheck
- } else {
- if err := m.client.ResumePrinter(name); isAuthError(err) && m.pkHelper != nil {
- m.pkHelper.PrinterSetEnabled(name, true) //nolint:errcheck
- }
- if err := m.client.AcceptJobs(name); isAuthError(err) && m.pkHelper != nil {
- m.pkHelper.PrinterSetAcceptJobs(name, true, "") //nolint:errcheck
- }
- }
-
- m.RefreshState()
- return nil
-}
-
-func (m *Manager) DeletePrinter(printerName string) error {
- err := m.client.DeletePrinter(printerName)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterDelete(printerName)
- if err != nil {
- // pkHelper failed, try lpadmin as last resort
- if lpadminErr := deletePrinterViaLpadmin(printerName); lpadminErr == nil {
- err = nil
- }
- }
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) AcceptJobs(printerName string) error {
- err := m.client.AcceptJobs(printerName)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterSetAcceptJobs(printerName, true, "")
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) RejectJobs(printerName string) error {
- err := m.client.RejectJobs(printerName)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterSetAcceptJobs(printerName, false, "")
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) SetPrinterShared(printerName string, shared bool) error {
- err := m.client.SetPrinterIsShared(printerName, shared)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterSetShared(printerName, shared)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) SetPrinterLocation(printerName, location string) error {
- err := m.client.SetPrinterLocation(printerName, location)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterSetLocation(printerName, location)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) SetPrinterInfo(printerName, info string) error {
- err := m.client.SetPrinterInformation(printerName, info)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.PrinterSetInfo(printerName, info)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) MoveJob(jobID int, destPrinter string) error {
- err := m.client.MoveJob(jobID, destPrinter)
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) PrintTestPage(printerName string) (int, error) {
- jobID, err := m.client.PrintTestPage(printerName, strings.NewReader(config.TestPage), len(config.TestPage))
- if err == nil {
- m.RefreshState()
- }
- return jobID, err
-}
-
-func (m *Manager) AddPrinterToClass(className, printerName string) error {
- err := m.client.AddPrinterToClass(className, printerName)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.ClassAddPrinter(className, printerName)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) RemovePrinterFromClass(className, printerName string) error {
- err := m.client.DeletePrinterFromClass(className, printerName)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.ClassDeletePrinter(className, printerName)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) DeleteClass(className string) error {
- err := m.client.DeleteClass(className)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.ClassDelete(className)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) RestartJob(jobID int) error {
- err := m.client.RestartJob(jobID)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.JobRestart(jobID)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
-
-func (m *Manager) HoldJob(jobID int, holdUntil string) error {
- err := m.client.HoldJobUntil(jobID, holdUntil)
- if isAuthError(err) && m.pkHelper != nil {
- err = m.pkHelper.JobSetHoldUntil(jobID, holdUntil)
- }
- if err == nil {
- m.RefreshState()
- }
- return err
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go
deleted file mode 100644
index ad16a8a..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_pkhelper_test.go
+++ /dev/null
@@ -1,235 +0,0 @@
-package cups_test
-
-import (
- "testing"
-
- mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups"
- mocks_pkhelper "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups_pkhelper"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/server/cups"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
-)
-
-func authErr() error {
- return ipp.IPPError{Status: ipp.StatusErrorForbidden}
-}
-
-func TestManager_CancelJob_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelJob(1, false).Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().JobCancelPurge(1, false).Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.CancelJob(1))
-}
-
-func TestManager_CancelJob_PkHelperError(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelJob(1, false).Return(authErr())
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().JobCancelPurge(1, false).Return(assert.AnError)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.Error(t, m.CancelJob(1))
-}
-
-func TestManager_PausePrinter_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().PausePrinter("printer1").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterSetEnabled("printer1", false).Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.PausePrinter("printer1"))
-}
-
-func TestManager_ResumePrinter_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().ResumePrinter("printer1").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterSetEnabled("printer1", true).Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.ResumePrinter("printer1"))
-}
-
-func TestManager_GetDevices_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().DevicesGet(10, 0, []string(nil), []string(nil)).Return([]cups.Device{
- {URI: "usb://HP/LaserJet", Class: "direct"},
- }, nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- got, err := m.GetDevices()
- assert.NoError(t, err)
- assert.Len(t, got, 1)
- assert.Equal(t, "usb://HP/LaserJet", got[0].URI)
-}
-
-func TestManager_GetDevices_PkHelperError(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().DevicesGet(10, 0, []string(nil), []string(nil)).Return(nil, assert.AnError)
-
- m := cups.NewTestManager(mockClient, mockPk)
- _, err := m.GetDevices()
- assert.Error(t, err)
-}
-
-func TestManager_CreatePrinter_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterAdd("newprinter", "usb://HP", "generic.ppd", "info", "location").Return(nil)
- mockPk.EXPECT().PrinterSetEnabled("newprinter", true).Return(nil)
- mockPk.EXPECT().PrinterSetAcceptJobs("newprinter", true, "").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location"))
-}
-
-func TestManager_DeletePrinter_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeletePrinter("printer1").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterDelete("printer1").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.DeletePrinter("printer1"))
-}
-
-func TestManager_AcceptJobs_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().AcceptJobs("printer1").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterSetAcceptJobs("printer1", true, "").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.AcceptJobs("printer1"))
-}
-
-func TestManager_RejectJobs_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().RejectJobs("printer1").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterSetAcceptJobs("printer1", false, "").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.RejectJobs("printer1"))
-}
-
-func TestManager_SetPrinterShared_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterIsShared("printer1", true).Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterSetShared("printer1", true).Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.SetPrinterShared("printer1", true))
-}
-
-func TestManager_SetPrinterLocation_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterLocation("printer1", "Office").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterSetLocation("printer1", "Office").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.SetPrinterLocation("printer1", "Office"))
-}
-
-func TestManager_SetPrinterInfo_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterInformation("printer1", "Main Printer").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().PrinterSetInfo("printer1", "Main Printer").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.SetPrinterInfo("printer1", "Main Printer"))
-}
-
-func TestManager_AddPrinterToClass_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().AddPrinterToClass("office", "printer1").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().ClassAddPrinter("office", "printer1").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.AddPrinterToClass("office", "printer1"))
-}
-
-func TestManager_RemovePrinterFromClass_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeletePrinterFromClass("office", "printer1").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().ClassDeletePrinter("office", "printer1").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.RemovePrinterFromClass("office", "printer1"))
-}
-
-func TestManager_DeleteClass_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeleteClass("office").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().ClassDelete("office").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.DeleteClass("office"))
-}
-
-func TestManager_RestartJob_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().RestartJob(1).Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().JobRestart(1).Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.RestartJob(1))
-}
-
-func TestManager_HoldJob_WithPkHelper(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().HoldJobUntil(1, "indefinite").Return(authErr())
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- mockPk := mocks_pkhelper.NewMockPkHelper(t)
- mockPk.EXPECT().JobSetHoldUntil(1, "indefinite").Return(nil)
-
- m := cups.NewTestManager(mockClient, mockPk)
- assert.NoError(t, m.HoldJob(1, "indefinite"))
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go
deleted file mode 100644
index 70f4f21..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/actions_test.go
+++ /dev/null
@@ -1,450 +0,0 @@
-package cups
-
-import (
- "errors"
- "testing"
- "time"
-
- mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
-)
-
-func TestManager_GetPrinters(t *testing.T) {
- tests := []struct {
- name string
- mockRet map[string]ipp.Attributes
- mockErr error
- want int
- wantErr bool
- }{
- {
- name: "success",
- mockRet: map[string]ipp.Attributes{
- "printer1": {
- ipp.AttributePrinterName: []ipp.Attribute{{Value: "printer1"}},
- ipp.AttributePrinterUriSupported: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}},
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- ipp.AttributePrinterStateReasons: []ipp.Attribute{{Value: "none"}},
- ipp.AttributePrinterLocation: []ipp.Attribute{{Value: "Office"}},
- ipp.AttributePrinterInfo: []ipp.Attribute{{Value: "Test Printer"}},
- ipp.AttributePrinterMakeAndModel: []ipp.Attribute{{Value: "Generic"}},
- ipp.AttributePrinterIsAcceptingJobs: []ipp.Attribute{{Value: true}},
- },
- },
- mockErr: nil,
- want: 1,
- wantErr: false,
- },
- {
- name: "error",
- mockRet: nil,
- mockErr: errors.New("test error"),
- want: 0,
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(tt.mockRet, tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- got, err := m.GetPrinters()
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- assert.Equal(t, tt.want, len(got))
- if len(got) > 0 {
- assert.Equal(t, "printer1", got[0].Name)
- assert.Equal(t, "idle", got[0].State)
- assert.Equal(t, "Office", got[0].Location)
- assert.True(t, got[0].Accepting)
- }
- }
- })
- }
-}
-
-func TestManager_GetJobs(t *testing.T) {
- tests := []struct {
- name string
- mockRet map[int]ipp.Attributes
- mockErr error
- want int
- wantErr bool
- }{
- {
- name: "success",
- mockRet: map[int]ipp.Attributes{
- 1: {
- ipp.AttributeJobID: []ipp.Attribute{{Value: 1}},
- ipp.AttributeJobName: []ipp.Attribute{{Value: "test-job"}},
- ipp.AttributeJobState: []ipp.Attribute{{Value: 5}},
- ipp.AttributeJobPrinterURI: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}},
- ipp.AttributeJobOriginatingUserName: []ipp.Attribute{{Value: "testuser"}},
- ipp.AttributeJobKilobyteOctets: []ipp.Attribute{{Value: 10}},
- "time-at-creation": []ipp.Attribute{{Value: 1609459200}},
- },
- },
- mockErr: nil,
- want: 1,
- wantErr: false,
- },
- {
- name: "error",
- mockRet: nil,
- mockErr: errors.New("test error"),
- want: 0,
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetJobs("printer1", "", "not-completed", false, 0, 0, mock.Anything).
- Return(tt.mockRet, tt.mockErr)
-
- m := &Manager{
- client: mockClient,
- }
-
- got, err := m.GetJobs("printer1", "not-completed")
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- assert.Equal(t, tt.want, len(got))
- if len(got) > 0 {
- assert.Equal(t, 1, got[0].ID)
- assert.Equal(t, "test-job", got[0].Name)
- assert.Equal(t, "processing", got[0].State)
- assert.Equal(t, "testuser", got[0].User)
- assert.Equal(t, "printer1", got[0].Printer)
- assert.Equal(t, 10240, got[0].Size)
- assert.Equal(t, time.Unix(1609459200, 0), got[0].TimeCreated)
- }
- }
- })
- }
-}
-
-func TestManager_CancelJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelJob(1, false).Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.CancelJob(1))
-}
-
-func TestManager_PausePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().PausePrinter("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.PausePrinter("printer1"))
-}
-
-func TestManager_ResumePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().ResumePrinter("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.ResumePrinter("printer1"))
-}
-
-func TestManager_PurgeJobs(t *testing.T) {
- tests := []struct {
- name string
- mockErr error
- wantErr bool
- }{
- {
- name: "success",
- mockErr: nil,
- wantErr: false,
- },
- {
- name: "error",
- mockErr: errors.New("test error"),
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelAllJob("printer1", true).Return(tt.mockErr)
- if !tt.wantErr {
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
- }
-
- m := NewTestManager(mockClient, nil)
-
- err := m.PurgeJobs("printer1")
- if tt.wantErr {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- })
- }
-}
-
-func TestManager_GetDevices(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetDevices().Return(map[string]ipp.Attributes{
- "usb://HP/LaserJet": {
- "device-class": []ipp.Attribute{{Value: "direct"}},
- "device-info": []ipp.Attribute{{Value: "HP LaserJet"}},
- "device-make-and-model": []ipp.Attribute{{Value: "HP LaserJet 1020"}},
- },
- }, nil)
-
- m := &Manager{client: mockClient}
- got, err := m.GetDevices()
- assert.NoError(t, err)
- assert.Len(t, got, 1)
- assert.Equal(t, "usb://HP/LaserJet", got[0].URI)
- assert.Equal(t, "direct", got[0].Class)
-}
-
-func TestManager_GetPPDs(t *testing.T) {
- tests := []struct {
- name string
- mockRet map[string]ipp.Attributes
- mockErr error
- want int
- wantErr bool
- }{
- {
- name: "success",
- mockRet: map[string]ipp.Attributes{
- "drv:///sample.drv/generic.ppd": {
- "ppd-make-and-model": []ipp.Attribute{{Value: "Generic PostScript"}},
- "ppd-type": []ipp.Attribute{{Value: "ppd"}},
- },
- },
- mockErr: nil,
- want: 1,
- wantErr: false,
- },
- {
- name: "error",
- mockRet: nil,
- mockErr: errors.New("test error"),
- want: 0,
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPPDs().Return(tt.mockRet, tt.mockErr)
-
- m := &Manager{client: mockClient}
-
- got, err := m.GetPPDs()
- if tt.wantErr {
- assert.Error(t, err)
- return
- }
- assert.NoError(t, err)
- assert.Equal(t, tt.want, len(got))
- })
- }
-}
-
-func TestManager_GetClasses(t *testing.T) {
- tests := []struct {
- name string
- mockRet map[string]ipp.Attributes
- mockErr error
- want int
- wantErr bool
- }{
- {
- name: "success",
- mockRet: map[string]ipp.Attributes{
- "office": {
- ipp.AttributePrinterName: []ipp.Attribute{{Value: "office"}},
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- ipp.AttributeMemberNames: []ipp.Attribute{{Value: "printer1"}, {Value: "printer2"}},
- },
- },
- mockErr: nil,
- want: 1,
- wantErr: false,
- },
- {
- name: "error",
- mockRet: nil,
- mockErr: errors.New("test error"),
- want: 0,
- wantErr: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetClasses(mock.Anything).Return(tt.mockRet, tt.mockErr)
-
- m := &Manager{client: mockClient}
-
- got, err := m.GetClasses()
- if tt.wantErr {
- assert.Error(t, err)
- return
- }
- assert.NoError(t, err)
- assert.Equal(t, tt.want, len(got))
- if len(got) > 0 {
- assert.Equal(t, "office", got[0].Name)
- assert.Equal(t, 2, len(got[0].Members))
- }
- })
- }
-}
-
-func TestManager_CreatePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location").Return(nil)
- mockClient.EXPECT().ResumePrinter("newprinter").Return(nil)
- mockClient.EXPECT().AcceptJobs("newprinter").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.CreatePrinter("newprinter", "usb://HP", "generic.ppd", true, "stop-printer", "info", "location"))
-}
-
-func TestManager_DeletePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeletePrinter("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.DeletePrinter("printer1"))
-}
-
-func TestManager_AcceptJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().AcceptJobs("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.AcceptJobs("printer1"))
-}
-
-func TestManager_RejectJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().RejectJobs("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.RejectJobs("printer1"))
-}
-
-func TestManager_SetPrinterShared(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterIsShared("printer1", true).Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.SetPrinterShared("printer1", true))
-}
-
-func TestManager_SetPrinterLocation(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterLocation("printer1", "Office").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.SetPrinterLocation("printer1", "Office"))
-}
-
-func TestManager_SetPrinterInfo(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterInformation("printer1", "Main Printer").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.SetPrinterInfo("printer1", "Main Printer"))
-}
-
-func TestManager_MoveJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().MoveJob(1, "printer2").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- err := m.MoveJob(1, "printer2")
- assert.NoError(t, err)
-}
-
-func TestManager_PrintTestPage(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().PrintTestPage("printer1", mock.Anything, mock.Anything).Return(42, nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- jobID, err := m.PrintTestPage("printer1")
- assert.NoError(t, err)
- assert.Equal(t, 42, jobID)
-}
-
-func TestManager_AddPrinterToClass(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().AddPrinterToClass("office", "printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.AddPrinterToClass("office", "printer1"))
-}
-
-func TestManager_RemovePrinterFromClass(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeletePrinterFromClass("office", "printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.RemovePrinterFromClass("office", "printer1"))
-}
-
-func TestManager_DeleteClass(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeleteClass("office").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.DeleteClass("office"))
-}
-
-func TestManager_RestartJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().RestartJob(1).Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.RestartJob(1))
-}
-
-func TestManager_HoldJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().HoldJobUntil(1, "indefinite").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- assert.NoError(t, m.HoldJob(1, "indefinite"))
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go
deleted file mode 100644
index 57b45d5..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers.go
+++ /dev/null
@@ -1,487 +0,0 @@
-package cups
-
-import (
- "encoding/json"
- "fmt"
- "net"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/server/params"
-)
-
-type CUPSEvent struct {
- Type string `json:"type"`
- Data CUPSState `json:"data"`
-}
-
-type TestPageResult struct {
- Success bool `json:"success"`
- JobID int `json:"jobId"`
- Message string `json:"message"`
-}
-
-func HandleRequest(conn net.Conn, req models.Request, manager *Manager) {
- switch req.Method {
- case "cups.subscribe":
- handleSubscribe(conn, req, manager)
- case "cups.getPrinters":
- handleGetPrinters(conn, req, manager)
- case "cups.getJobs":
- handleGetJobs(conn, req, manager)
- case "cups.pausePrinter":
- handlePausePrinter(conn, req, manager)
- case "cups.resumePrinter":
- handleResumePrinter(conn, req, manager)
- case "cups.cancelJob":
- handleCancelJob(conn, req, manager)
- case "cups.purgeJobs":
- handlePurgeJobs(conn, req, manager)
- case "cups.getDevices":
- handleGetDevices(conn, req, manager)
- case "cups.getPPDs":
- handleGetPPDs(conn, req, manager)
- case "cups.getClasses":
- handleGetClasses(conn, req, manager)
- case "cups.createPrinter":
- handleCreatePrinter(conn, req, manager)
- case "cups.deletePrinter":
- handleDeletePrinter(conn, req, manager)
- case "cups.acceptJobs":
- handleAcceptJobs(conn, req, manager)
- case "cups.rejectJobs":
- handleRejectJobs(conn, req, manager)
- case "cups.setPrinterShared":
- handleSetPrinterShared(conn, req, manager)
- case "cups.setPrinterLocation":
- handleSetPrinterLocation(conn, req, manager)
- case "cups.setPrinterInfo":
- handleSetPrinterInfo(conn, req, manager)
- case "cups.moveJob":
- handleMoveJob(conn, req, manager)
- case "cups.printTestPage":
- handlePrintTestPage(conn, req, manager)
- case "cups.addPrinterToClass":
- handleAddPrinterToClass(conn, req, manager)
- case "cups.removePrinterFromClass":
- handleRemovePrinterFromClass(conn, req, manager)
- case "cups.deleteClass":
- handleDeleteClass(conn, req, manager)
- case "cups.restartJob":
- handleRestartJob(conn, req, manager)
- case "cups.holdJob":
- handleHoldJob(conn, req, manager)
- case "cups.testConnection":
- handleTestConnection(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetPrinters(conn net.Conn, req models.Request, manager *Manager) {
- printers, err := manager.GetPrinters()
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, printers)
-}
-
-func handleGetJobs(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.String(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- jobs, err := manager.GetJobs(printerName, "not-completed")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, jobs)
-}
-
-func handlePausePrinter(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.String(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.PausePrinter(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "paused"})
-}
-
-func handleResumePrinter(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.String(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.ResumePrinter(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "resumed"})
-}
-
-func handleCancelJob(conn net.Conn, req models.Request, manager *Manager) {
- jobID, err := params.Int(req.Params, "jobID")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.CancelJob(jobID); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job canceled"})
-}
-
-func handlePurgeJobs(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.String(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.PurgeJobs(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "jobs canceled"})
-}
-
-func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- event := CUPSEvent{
- Type: "state_changed",
- Data: initialState,
- }
-
- if err := json.NewEncoder(conn).Encode(models.Response[CUPSEvent]{
- ID: req.ID,
- Result: &event,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- event := CUPSEvent{
- Type: "state_changed",
- Data: state,
- }
- if err := json.NewEncoder(conn).Encode(models.Response[CUPSEvent]{
- Result: &event,
- }); err != nil {
- return
- }
- }
-}
-
-func handleGetDevices(conn net.Conn, req models.Request, manager *Manager) {
- devices, err := manager.GetDevices()
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, devices)
-}
-
-func handleGetPPDs(conn net.Conn, req models.Request, manager *Manager) {
- ppds, err := manager.GetPPDs()
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, ppds)
-}
-
-func handleGetClasses(conn net.Conn, req models.Request, manager *Manager) {
- classes, err := manager.GetClasses()
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, classes)
-}
-
-func handleCreatePrinter(conn net.Conn, req models.Request, manager *Manager) {
- name, err := params.StringNonEmpty(req.Params, "name")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- deviceURI, err := params.StringNonEmpty(req.Params, "deviceURI")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- ppd, err := params.StringNonEmpty(req.Params, "ppd")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- shared := params.BoolOpt(req.Params, "shared", false)
- errorPolicy := params.StringOpt(req.Params, "errorPolicy", "")
- information := params.StringOpt(req.Params, "information", "")
- location := params.StringOpt(req.Params, "location", "")
-
- if err := manager.CreatePrinter(name, deviceURI, ppd, shared, errorPolicy, information, location); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer created"})
-}
-
-func handleDeletePrinter(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.DeletePrinter(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer deleted"})
-}
-
-func handleAcceptJobs(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.AcceptJobs(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "accepting jobs"})
-}
-
-func handleRejectJobs(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.RejectJobs(printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "rejecting jobs"})
-}
-
-func handleSetPrinterShared(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- shared, err := params.Bool(req.Params, "shared")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.SetPrinterShared(printerName, shared); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "sharing updated"})
-}
-
-func handleSetPrinterLocation(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- location, err := params.String(req.Params, "location")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.SetPrinterLocation(printerName, location); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "location updated"})
-}
-
-func handleSetPrinterInfo(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- info, err := params.String(req.Params, "info")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.SetPrinterInfo(printerName, info); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "info updated"})
-}
-
-func handleMoveJob(conn net.Conn, req models.Request, manager *Manager) {
- jobID, err := params.Int(req.Params, "jobID")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- destPrinter, err := params.StringNonEmpty(req.Params, "destPrinter")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.MoveJob(jobID, destPrinter); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job moved"})
-}
-
-func handlePrintTestPage(conn net.Conn, req models.Request, manager *Manager) {
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- jobID, err := manager.PrintTestPage(printerName)
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, TestPageResult{Success: true, JobID: jobID, Message: "test page queued"})
-}
-
-func handleAddPrinterToClass(conn net.Conn, req models.Request, manager *Manager) {
- className, err := params.StringNonEmpty(req.Params, "className")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.AddPrinterToClass(className, printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer added to class"})
-}
-
-func handleRemovePrinterFromClass(conn net.Conn, req models.Request, manager *Manager) {
- className, err := params.StringNonEmpty(req.Params, "className")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- printerName, err := params.StringNonEmpty(req.Params, "printerName")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.RemovePrinterFromClass(className, printerName); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "printer removed from class"})
-}
-
-func handleDeleteClass(conn net.Conn, req models.Request, manager *Manager) {
- className, err := params.StringNonEmpty(req.Params, "className")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.DeleteClass(className); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "class deleted"})
-}
-
-func handleRestartJob(conn net.Conn, req models.Request, manager *Manager) {
- jobID, err := params.Int(req.Params, "jobID")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- if err := manager.RestartJob(jobID); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job restarted"})
-}
-
-func handleHoldJob(conn net.Conn, req models.Request, manager *Manager) {
- jobID, err := params.Int(req.Params, "jobID")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- holdUntil := params.StringOpt(req.Params, "holdUntil", "indefinite")
-
- if err := manager.HoldJob(jobID, holdUntil); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
- models.Respond(conn, req.ID, models.SuccessResult{Success: true, Message: "job held"})
-}
-
-func handleTestConnection(conn net.Conn, req models.Request, manager *Manager) {
- host, err := params.StringNonEmpty(req.Params, "host")
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- port := params.IntOpt(req.Params, "port", 631)
- protocol := params.StringOpt(req.Params, "protocol", "ipp")
-
- result, err := manager.TestRemotePrinter(host, port, protocol)
- if err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, result)
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go
deleted file mode 100644
index b73931e..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/handlers_test.go
+++ /dev/null
@@ -1,711 +0,0 @@
-package cups
-
-import (
- "bytes"
- "encoding/json"
- "errors"
- "net"
- "testing"
- "time"
-
- mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
-)
-
-type mockConn struct {
- *bytes.Buffer
-}
-
-func (m *mockConn) Close() error { return nil }
-func (m *mockConn) LocalAddr() net.Addr { return nil }
-func (m *mockConn) RemoteAddr() net.Addr { return nil }
-func (m *mockConn) SetDeadline(t time.Time) error { return nil }
-func (m *mockConn) SetReadDeadline(t time.Time) error { return nil }
-func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil }
-
-func TestHandleGetPrinters(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{
- "printer1": {
- ipp.AttributePrinterName: []ipp.Attribute{{Value: "printer1"}},
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- ipp.AttributePrinterUriSupported: []ipp.Attribute{{Value: "ipp://localhost/printers/printer1"}},
- },
- }, nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.getPrinters",
- }
-
- handleGetPrinters(conn, req, m)
-
- var resp models.Response[[]Printer]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.Equal(t, 1, len(*resp.Result))
-}
-
-func TestHandleGetPrinters_Error(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(nil, errors.New("test error"))
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.getPrinters",
- }
-
- handleGetPrinters(conn, req, m)
-
- var resp models.Response[any]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
-
-func TestHandleGetJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetJobs("printer1", "", "not-completed", false, 0, 0, mock.Anything).
- Return(map[int]ipp.Attributes{
- 1: {
- ipp.AttributeJobID: []ipp.Attribute{{Value: 1}},
- ipp.AttributeJobName: []ipp.Attribute{{Value: "job1"}},
- ipp.AttributeJobState: []ipp.Attribute{{Value: 5}},
- },
- }, nil)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.getJobs",
- Params: map[string]any{
- "printerName": "printer1",
- },
- }
-
- handleGetJobs(conn, req, m)
-
- var resp models.Response[[]Job]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.Equal(t, 1, len(*resp.Result))
-}
-
-func TestHandleGetJobs_MissingParam(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.getJobs",
- Params: map[string]any{},
- }
-
- handleGetJobs(conn, req, m)
-
- var resp models.Response[any]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
-
-func TestHandlePausePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().PausePrinter("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.pausePrinter",
- Params: map[string]any{
- "printerName": "printer1",
- },
- }
-
- handlePausePrinter(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleResumePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().ResumePrinter("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.resumePrinter",
- Params: map[string]any{
- "printerName": "printer1",
- },
- }
-
- handleResumePrinter(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleCancelJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelJob(1, false).Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.cancelJob",
- Params: map[string]any{
- "jobID": float64(1),
- },
- }
-
- handleCancelJob(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandlePurgeJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CancelAllJob("printer1", true).Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.purgeJobs",
- Params: map[string]any{
- "printerName": "printer1",
- },
- }
-
- handlePurgeJobs(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleRequest_UnknownMethod(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- client: mockClient,
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.unknownMethod",
- }
-
- HandleRequest(conn, req, m)
-
- var resp models.Response[any]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
-
-func TestHandleGetDevices(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetDevices().Return(map[string]ipp.Attributes{
- "usb://HP/LaserJet": {
- "device-class": []ipp.Attribute{{Value: "direct"}},
- "device-info": []ipp.Attribute{{Value: "HP LaserJet"}},
- },
- }, nil)
-
- m := &Manager{client: mockClient}
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{ID: 1, Method: "cups.getDevices"}
- handleGetDevices(conn, req, m)
-
- var resp models.Response[[]Device]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.Equal(t, 1, len(*resp.Result))
-}
-
-func TestHandleGetPPDs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetPPDs().Return(map[string]ipp.Attributes{
- "generic.ppd": {
- "ppd-make-and-model": []ipp.Attribute{{Value: "Generic"}},
- },
- }, nil)
-
- m := &Manager{client: mockClient}
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{ID: 1, Method: "cups.getPPDs"}
- handleGetPPDs(conn, req, m)
-
- var resp models.Response[[]PPD]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.Equal(t, 1, len(*resp.Result))
-}
-
-func TestHandleGetClasses(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().GetClasses(mock.Anything).Return(map[string]ipp.Attributes{
- "office": {
- ipp.AttributePrinterName: []ipp.Attribute{{Value: "office"}},
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- },
- }, nil)
-
- m := &Manager{client: mockClient}
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{ID: 1, Method: "cups.getClasses"}
- handleGetClasses(conn, req, m)
-
- var resp models.Response[[]PrinterClass]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.Equal(t, 1, len(*resp.Result))
-}
-
-func TestHandleCreatePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().CreatePrinter("newprinter", "usb://HP", "generic.ppd", false, "", "", "").Return(nil)
- mockClient.EXPECT().ResumePrinter("newprinter").Return(nil)
- mockClient.EXPECT().AcceptJobs("newprinter").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.createPrinter",
- Params: map[string]any{
- "name": "newprinter",
- "deviceURI": "usb://HP",
- "ppd": "generic.ppd",
- },
- }
- handleCreatePrinter(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleCreatePrinter_MissingParams(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- m := &Manager{client: mockClient}
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{ID: 1, Method: "cups.createPrinter", Params: map[string]any{}}
- handleCreatePrinter(conn, req, m)
-
- var resp models.Response[any]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
-
-func TestHandleDeletePrinter(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeletePrinter("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.deletePrinter",
- Params: map[string]any{"printerName": "printer1"},
- }
- handleDeletePrinter(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleAcceptJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().AcceptJobs("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.acceptJobs",
- Params: map[string]any{"printerName": "printer1"},
- }
- handleAcceptJobs(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleRejectJobs(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().RejectJobs("printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.rejectJobs",
- Params: map[string]any{"printerName": "printer1"},
- }
- handleRejectJobs(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleSetPrinterShared(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterIsShared("printer1", true).Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.setPrinterShared",
- Params: map[string]any{"printerName": "printer1", "shared": true},
- }
- handleSetPrinterShared(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleSetPrinterLocation(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterLocation("printer1", "Office").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.setPrinterLocation",
- Params: map[string]any{"printerName": "printer1", "location": "Office"},
- }
- handleSetPrinterLocation(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleSetPrinterInfo(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().SetPrinterInformation("printer1", "Main Printer").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.setPrinterInfo",
- Params: map[string]any{"printerName": "printer1", "info": "Main Printer"},
- }
- handleSetPrinterInfo(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleMoveJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().MoveJob(1, "printer2").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.moveJob",
- Params: map[string]any{"jobID": float64(1), "destPrinter": "printer2"},
- }
- handleMoveJob(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandlePrintTestPage(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().PrintTestPage("printer1", mock.Anything, mock.Anything).Return(42, nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.printTestPage",
- Params: map[string]any{"printerName": "printer1"},
- }
- handlePrintTestPage(conn, req, m)
-
- var resp models.Response[TestPageResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
- assert.Equal(t, 42, resp.Result.JobID)
-}
-
-func TestHandleAddPrinterToClass(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().AddPrinterToClass("office", "printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.addPrinterToClass",
- Params: map[string]any{"className": "office", "printerName": "printer1"},
- }
- handleAddPrinterToClass(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleRemovePrinterFromClass(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeletePrinterFromClass("office", "printer1").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.removePrinterFromClass",
- Params: map[string]any{"className": "office", "printerName": "printer1"},
- }
- handleRemovePrinterFromClass(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleDeleteClass(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().DeleteClass("office").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.deleteClass",
- Params: map[string]any{"className": "office"},
- }
- handleDeleteClass(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleRestartJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().RestartJob(1).Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.restartJob",
- Params: map[string]any{"jobID": float64(1)},
- }
- handleRestartJob(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleHoldJob(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().HoldJobUntil(1, "indefinite").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.holdJob",
- Params: map[string]any{"jobID": float64(1)},
- }
- handleHoldJob(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
-
-func TestHandleHoldJob_WithHoldUntil(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
- mockClient.EXPECT().HoldJobUntil(1, "no-hold").Return(nil)
- mockClient.EXPECT().GetPrinters(mock.Anything).Return(map[string]ipp.Attributes{}, nil)
-
- m := NewTestManager(mockClient, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.holdJob",
- Params: map[string]any{"jobID": float64(1), "holdUntil": "no-hold"},
- }
- handleHoldJob(conn, req, m)
-
- var resp models.Response[models.SuccessResult]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Success)
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager.go
deleted file mode 100644
index e5b7e8c..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager.go
+++ /dev/null
@@ -1,390 +0,0 @@
-package cups
-
-import (
- "errors"
- "fmt"
- "os"
- "strconv"
- "sync"
- "time"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/log"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
-)
-
-func NewManager() (*Manager, error) {
- host := os.Getenv("DMS_IPP_HOST")
- if host == "" {
- host = "localhost"
- }
-
- portStr := os.Getenv("DMS_IPP_PORT")
- port := 631
- if portStr != "" {
- if p, err := strconv.Atoi(portStr); err == nil {
- port = p
- }
- }
-
- username := os.Getenv("DMS_IPP_USERNAME")
- password := os.Getenv("DMS_IPP_PASSWORD")
-
- client := ipp.NewCUPSClient(host, port, username, password, false)
- baseURL := fmt.Sprintf("http://%s:%d", host, port)
-
- var pkHelper PkHelper
- if isLocalCUPS(host) {
- var err error
- pkHelper, err = NewPkHelper()
- if err != nil {
- log.Warnf("[CUPS] Failed to initialize pkhelper: %v", err)
- }
- }
-
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: client,
- pkHelper: pkHelper,
- baseURL: baseURL,
- stateMutex: sync.RWMutex{},
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-
- if err := m.updateState(); err != nil {
- return nil, err
- }
-
- if isLocalCUPS(host) {
- m.subscription = NewDBusSubscriptionManager(client, baseURL)
- log.Infof("[CUPS] Using D-Bus notifications for local CUPS")
- } else {
- m.subscription = NewSubscriptionManager(client, baseURL)
- log.Infof("[CUPS] Using IPPGET notifications for remote CUPS")
- }
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- return m, nil
-}
-
-func isLocalCUPS(host string) bool {
- switch host {
- case "localhost", "127.0.0.1", "::1", "":
- return true
- }
- return false
-}
-
-func (m *Manager) eventHandler() {
- defer m.eventWG.Done()
-
- if m.subscription == nil {
- return
- }
-
- for {
- select {
- case <-m.stopChan:
- return
- case event, ok := <-m.subscription.Events():
- if !ok {
- return
- }
- log.Debugf("[CUPS] Received event: %s (printer: %s, job: %d)",
- event.EventName, event.PrinterName, event.JobID)
-
- if err := m.updateState(); err != nil {
- log.Warnf("[CUPS] Failed to update state after event: %v", err)
- } else {
- m.notifySubscribers()
- }
- }
- }
-}
-
-func (m *Manager) updateState() error {
- printers, err := m.GetPrinters()
- if err != nil {
- if isNoPrintersError(err) {
- m.stateMutex.Lock()
- m.state.Printers = make(map[string]*Printer)
- m.stateMutex.Unlock()
- return nil
- }
- return err
- }
-
- printerMap := make(map[string]*Printer, len(printers))
- for _, printer := range printers {
- jobs, err := m.GetJobs(printer.Name, "not-completed")
- if err != nil {
- return err
- }
-
- printer.Jobs = jobs
- printerMap[printer.Name] = &printer
- }
-
- m.stateMutex.Lock()
- m.state.Printers = printerMap
- m.stateMutex.Unlock()
-
- return nil
-}
-
-func isNoPrintersError(err error) bool {
- if err == nil {
- return false
- }
-
- var ippErr ipp.IPPError
- if errors.As(err, &ippErr) {
- return ippErr.Status == 1030
- }
-
- return false
-}
-
-func (m *Manager) notifier() {
- defer m.notifierWg.Done()
- const minGap = 100 * time.Millisecond
- timer := time.NewTimer(minGap)
- timer.Stop()
- var pending bool
- for {
- select {
- case <-m.stopChan:
- timer.Stop()
- return
- case <-m.dirty:
- if pending {
- continue
- }
- pending = true
- timer.Reset(minGap)
- case <-timer.C:
- if !pending {
- continue
- }
-
- currentState := m.snapshotState()
-
- if m.lastNotifiedState != nil && !stateChanged(m.lastNotifiedState, &currentState) {
- pending = false
- continue
- }
-
- m.subscribers.Range(func(key string, ch chan CUPSState) bool {
- select {
- case ch <- currentState:
- default:
- }
- return true
- })
-
- stateCopy := currentState
- m.lastNotifiedState = &stateCopy
- pending = false
- }
- }
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func (m *Manager) RefreshState() {
- if err := m.updateState(); err != nil {
- log.Warnf("[CUPS] Failed to refresh state: %v", err)
- return
- }
- m.notifySubscribers()
-}
-
-func (m *Manager) GetState() CUPSState {
- return m.snapshotState()
-}
-
-func (m *Manager) snapshotState() CUPSState {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
-
- s := CUPSState{
- Printers: make(map[string]*Printer, len(m.state.Printers)),
- }
- for name, printer := range m.state.Printers {
- printerCopy := *printer
- s.Printers[name] = &printerCopy
- }
- return s
-}
-
-func (m *Manager) Subscribe(id string) chan CUPSState {
- ch := make(chan CUPSState, 64)
-
- wasEmpty := true
- m.subscribers.Range(func(key string, ch chan CUPSState) bool {
- wasEmpty = false
- return false
- })
-
- m.subscribers.Store(id, ch)
-
- if wasEmpty && m.subscription != nil {
- if err := m.subscription.Start(); err != nil {
- log.Warnf("[CUPS] Failed to start subscription manager: %v", err)
- } else {
- m.eventWG.Add(1)
- go m.eventHandler()
- }
- }
-
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- if val, ok := m.subscribers.LoadAndDelete(id); ok {
- close(val)
- }
-
- isEmpty := true
- m.subscribers.Range(func(key string, ch chan CUPSState) bool {
- isEmpty = false
- return false
- })
-
- if isEmpty && m.subscription != nil {
- m.subscription.Stop()
- m.eventWG.Wait()
- }
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
-
- if m.subscription != nil {
- m.subscription.Stop()
- }
-
- m.eventWG.Wait()
- m.notifierWg.Wait()
-
- m.subscribers.Range(func(key string, ch chan CUPSState) bool {
- close(ch)
- m.subscribers.Delete(key)
- return true
- })
-}
-
-func stateChanged(old, new *CUPSState) bool {
- if len(old.Printers) != len(new.Printers) {
- return true
- }
- for name, oldPrinter := range old.Printers {
- newPrinter, exists := new.Printers[name]
- if !exists {
- return true
- }
- if oldPrinter.State != newPrinter.State ||
- oldPrinter.StateReason != newPrinter.StateReason ||
- oldPrinter.Accepting != newPrinter.Accepting ||
- len(oldPrinter.Jobs) != len(newPrinter.Jobs) {
- return true
- }
- }
- return false
-}
-
-func parsePrinterState(attrs ipp.Attributes) string {
- if stateAttr, ok := attrs[ipp.AttributePrinterState]; ok && len(stateAttr) > 0 {
- if state, ok := stateAttr[0].Value.(int); ok {
- switch state {
- case 3:
- return "idle"
- case 4:
- return "processing"
- case 5:
- return "stopped"
- default:
- return fmt.Sprintf("%d", state)
- }
- }
- }
- return "unknown"
-}
-
-func parseJobState(attrs ipp.Attributes) string {
- if stateAttr, ok := attrs[ipp.AttributeJobState]; ok && len(stateAttr) > 0 {
- if state, ok := stateAttr[0].Value.(int); ok {
- switch state {
- case 3:
- return "pending"
- case 4:
- return "pending-held"
- case 5:
- return "processing"
- case 6:
- return "processing-stopped"
- case 7:
- return "canceled"
- case 8:
- return "aborted"
- case 9:
- return "completed"
- default:
- return fmt.Sprintf("%d", state)
- }
- }
- }
- return "unknown"
-}
-
-func getStringAttr(attrs ipp.Attributes, key string) string {
- if attr, ok := attrs[key]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(string); ok {
- return val
- }
- return fmt.Sprintf("%v", attr[0].Value)
- }
- return ""
-}
-
-func getIntAttr(attrs ipp.Attributes, key string) int {
- if attr, ok := attrs[key]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(int); ok {
- return val
- }
- }
- return 0
-}
-
-func getBoolAttr(attrs ipp.Attributes, key string) bool {
- if attr, ok := attrs[key]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(bool); ok {
- return val
- }
- }
- return false
-}
-
-func getStringSliceAttr(attrs ipp.Attributes, key string) []string {
- attr, ok := attrs[key]
- if !ok {
- return nil
- }
-
- result := make([]string, 0, len(attr))
- for _, a := range attr {
- if val, ok := a.Value.(string); ok {
- result = append(result, val)
- }
- }
- return result
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go
deleted file mode 100644
index 7f09e67..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/manager_test.go
+++ /dev/null
@@ -1,363 +0,0 @@
-package cups
-
-import (
- "testing"
-
- mocks_cups "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/cups"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
- "github.com/stretchr/testify/assert"
-)
-
-func TestNewManager(t *testing.T) {
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: nil,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-
- assert.NotNil(t, m)
- assert.NotNil(t, m.state)
-}
-
-func TestManager_GetState(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- state: &CUPSState{
- Printers: map[string]*Printer{
- "test-printer": {
- Name: "test-printer",
- State: "idle",
- },
- },
- },
- client: mockClient,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-
- state := m.GetState()
- assert.Equal(t, 1, len(state.Printers))
- assert.Equal(t, "test-printer", state.Printers["test-printer"].Name)
-}
-
-func TestManager_Subscribe(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: mockClient,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-
- ch := m.Subscribe("test-client")
- assert.NotNil(t, ch)
-
- count := 0
- m.subscribers.Range(func(key string, ch chan CUPSState) bool {
- count++
- return true
- })
- assert.Equal(t, 1, count)
-
- m.Unsubscribe("test-client")
- count = 0
- m.subscribers.Range(func(key string, ch chan CUPSState) bool {
- count++
- return true
- })
- assert.Equal(t, 0, count)
-}
-
-func TestManager_Close(t *testing.T) {
- mockClient := mocks_cups.NewMockCUPSClientInterface(t)
-
- m := &Manager{
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- client: mockClient,
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-
- m.eventWG.Add(1)
- go func() {
- defer m.eventWG.Done()
- <-m.stopChan
- }()
-
- m.notifierWg.Add(1)
- go func() {
- defer m.notifierWg.Done()
- <-m.stopChan
- }()
-
- m.Close()
- count := 0
- m.subscribers.Range(func(key string, ch chan CUPSState) bool {
- count++
- return true
- })
- assert.Equal(t, 0, count)
-}
-
-func TestStateChanged(t *testing.T) {
- tests := []struct {
- name string
- oldState *CUPSState
- newState *CUPSState
- want bool
- }{
- {
- name: "no change",
- oldState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- want: false,
- },
- {
- name: "state changed",
- oldState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "processing"},
- },
- },
- want: true,
- },
- {
- name: "printer added",
- oldState: &CUPSState{
- Printers: map[string]*Printer{},
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- want: true,
- },
- {
- name: "printer removed",
- oldState: &CUPSState{
- Printers: map[string]*Printer{
- "p1": {Name: "p1", State: "idle"},
- },
- },
- newState: &CUPSState{
- Printers: map[string]*Printer{},
- },
- want: true,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := stateChanged(tt.oldState, tt.newState)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestParsePrinterState(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- want string
- }{
- {
- name: "idle",
- attrs: ipp.Attributes{
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 3}},
- },
- want: "idle",
- },
- {
- name: "processing",
- attrs: ipp.Attributes{
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 4}},
- },
- want: "processing",
- },
- {
- name: "stopped",
- attrs: ipp.Attributes{
- ipp.AttributePrinterState: []ipp.Attribute{{Value: 5}},
- },
- want: "stopped",
- },
- {
- name: "unknown",
- attrs: ipp.Attributes{},
- want: "unknown",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := parsePrinterState(tt.attrs)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestParseJobState(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- want string
- }{
- {
- name: "pending",
- attrs: ipp.Attributes{
- ipp.AttributeJobState: []ipp.Attribute{{Value: 3}},
- },
- want: "pending",
- },
- {
- name: "processing",
- attrs: ipp.Attributes{
- ipp.AttributeJobState: []ipp.Attribute{{Value: 5}},
- },
- want: "processing",
- },
- {
- name: "completed",
- attrs: ipp.Attributes{
- ipp.AttributeJobState: []ipp.Attribute{{Value: 9}},
- },
- want: "completed",
- },
- {
- name: "unknown",
- attrs: ipp.Attributes{},
- want: "unknown",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := parseJobState(tt.attrs)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestGetStringAttr(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- key string
- want string
- }{
- {
- name: "string value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: "test-value"}},
- },
- key: "test-key",
- want: "test-value",
- },
- {
- name: "missing key",
- attrs: ipp.Attributes{},
- key: "missing",
- want: "",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := getStringAttr(tt.attrs, tt.key)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestGetIntAttr(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- key string
- want int
- }{
- {
- name: "int value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: 42}},
- },
- key: "test-key",
- want: 42,
- },
- {
- name: "missing key",
- attrs: ipp.Attributes{},
- key: "missing",
- want: 0,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := getIntAttr(tt.attrs, tt.key)
- assert.Equal(t, tt.want, got)
- })
- }
-}
-
-func TestGetBoolAttr(t *testing.T) {
- tests := []struct {
- name string
- attrs ipp.Attributes
- key string
- want bool
- }{
- {
- name: "true value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: true}},
- },
- key: "test-key",
- want: true,
- },
- {
- name: "false value",
- attrs: ipp.Attributes{
- "test-key": []ipp.Attribute{{Value: false}},
- },
- key: "test-key",
- want: false,
- },
- {
- name: "missing key",
- attrs: ipp.Attributes{},
- key: "missing",
- want: false,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := getBoolAttr(tt.attrs, tt.key)
- assert.Equal(t, tt.want, got)
- })
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go
deleted file mode 100644
index 81dd458..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper.go
+++ /dev/null
@@ -1,184 +0,0 @@
-package cups
-
-import (
- "fmt"
- "strings"
-
- "github.com/godbus/dbus/v5"
-)
-
-const (
- pkHelperDest = "org.opensuse.CupsPkHelper.Mechanism"
- pkHelperPath = "/"
- pkHelperInterface = "org.opensuse.CupsPkHelper.Mechanism"
-)
-
-type PkHelper interface {
- DevicesGet(timeout, limit int, includeSchemes, excludeSchemes []string) ([]Device, error)
- PrinterAdd(name, uri, ppd, info, location string) error
- PrinterDelete(name string) error
- PrinterSetEnabled(name string, enabled bool) error
- PrinterSetAcceptJobs(name string, enabled bool, reason string) error
- PrinterSetInfo(name, info string) error
- PrinterSetLocation(name, location string) error
- PrinterSetShared(name string, shared bool) error
- ClassAddPrinter(className, printerName string) error
- ClassDeletePrinter(className, printerName string) error
- ClassDelete(className string) error
- JobCancelPurge(jobID int, purge bool) error
- JobRestart(jobID int) error
- JobSetHoldUntil(jobID int, holdUntil string) error
-}
-
-type DBusPkHelper struct {
- conn *dbus.Conn
- obj dbus.BusObject
-}
-
-func NewPkHelper() (*DBusPkHelper, error) {
- conn, err := dbus.SystemBus()
- if err != nil {
- return nil, fmt.Errorf("failed to connect to system bus: %w", err)
- }
-
- return &DBusPkHelper{
- conn: conn,
- obj: conn.Object(pkHelperDest, pkHelperPath),
- }, nil
-}
-
-func (p *DBusPkHelper) DevicesGet(timeout, limit int, includeSchemes, excludeSchemes []string) ([]Device, error) {
- if includeSchemes == nil {
- includeSchemes = []string{}
- }
- if excludeSchemes == nil {
- excludeSchemes = []string{}
- }
-
- var errStr string
- var devicesMap map[string]string
-
- call := p.obj.Call(pkHelperInterface+".DevicesGet", 0, int32(timeout), int32(limit), includeSchemes, excludeSchemes)
- if call.Err != nil {
- return nil, call.Err
- }
- if err := call.Store(&errStr, &devicesMap); err != nil {
- return nil, err
- }
- if errStr != "" {
- return nil, fmt.Errorf("%s", errStr)
- }
-
- return parseDevicesMap(devicesMap), nil
-}
-
-func parseDevicesMap(devicesMap map[string]string) []Device {
- devicesByIndex := make(map[string]*Device)
-
- for key, value := range devicesMap {
- idx := strings.LastIndex(key, ":")
- if idx == -1 {
- continue
- }
-
- attr := key[:idx]
- index := key[idx+1:]
-
- dev, ok := devicesByIndex[index]
- if !ok {
- dev = &Device{}
- devicesByIndex[index] = dev
- }
-
- switch attr {
- case "device-uri":
- dev.URI = value
- case "device-class":
- dev.Class = value
- case "device-info":
- dev.Info = value
- case "device-make-and-model":
- dev.MakeModel = value
- case "device-id":
- dev.ID = value
- case "device-location":
- dev.Location = value
- }
- }
-
- devices := make([]Device, 0, len(devicesByIndex))
- for _, dev := range devicesByIndex {
- if dev.URI != "" {
- devices = append(devices, *dev)
- }
- }
- return devices
-}
-
-func (p *DBusPkHelper) PrinterAdd(name, uri, ppd, info, location string) error {
- return p.callSimple("PrinterAdd", name, uri, ppd, info, location)
-}
-
-func (p *DBusPkHelper) PrinterDelete(name string) error {
- return p.callSimple("PrinterDelete", name)
-}
-
-func (p *DBusPkHelper) PrinterSetEnabled(name string, enabled bool) error {
- return p.callSimple("PrinterSetEnabled", name, enabled)
-}
-
-func (p *DBusPkHelper) PrinterSetAcceptJobs(name string, enabled bool, reason string) error {
- return p.callSimple("PrinterSetAcceptJobs", name, enabled, reason)
-}
-
-func (p *DBusPkHelper) PrinterSetInfo(name, info string) error {
- return p.callSimple("PrinterSetInfo", name, info)
-}
-
-func (p *DBusPkHelper) PrinterSetLocation(name, location string) error {
- return p.callSimple("PrinterSetLocation", name, location)
-}
-
-func (p *DBusPkHelper) PrinterSetShared(name string, shared bool) error {
- return p.callSimple("PrinterSetShared", name, shared)
-}
-
-func (p *DBusPkHelper) ClassAddPrinter(className, printerName string) error {
- return p.callSimple("ClassAddPrinter", className, printerName)
-}
-
-func (p *DBusPkHelper) ClassDeletePrinter(className, printerName string) error {
- return p.callSimple("ClassDeletePrinter", className, printerName)
-}
-
-func (p *DBusPkHelper) ClassDelete(className string) error {
- return p.callSimple("ClassDelete", className)
-}
-
-func (p *DBusPkHelper) JobCancelPurge(jobID int, purge bool) error {
- return p.callSimple("JobCancelPurge", int32(jobID), purge)
-}
-
-func (p *DBusPkHelper) JobRestart(jobID int) error {
- return p.callSimple("JobRestart", int32(jobID))
-}
-
-func (p *DBusPkHelper) JobSetHoldUntil(jobID int, holdUntil string) error {
- return p.callSimple("JobSetHoldUntil", int32(jobID), holdUntil)
-}
-
-func (p *DBusPkHelper) callSimple(method string, args ...any) error {
- var errStr string
-
- call := p.obj.Call(pkHelperInterface+"."+method, 0, args...)
- if call.Err != nil {
- return call.Err
- }
- if err := call.Store(&errStr); err != nil {
- return err
- }
- if errStr != "" {
- return fmt.Errorf("%s", errStr)
- }
- return nil
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go
deleted file mode 100644
index 596f1d0..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/pkhelper_test.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package cups
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestParseDevicesMap(t *testing.T) {
- tests := []struct {
- name string
- input map[string]string
- wantLen int
- wantURIs []string
- }{
- {
- name: "empty",
- input: map[string]string{},
- wantLen: 0,
- wantURIs: nil,
- },
- {
- name: "single_device",
- input: map[string]string{
- "device-uri:0": "usb://HP/LaserJet",
- "device-class:0": "direct",
- "device-info:0": "HP LaserJet",
- "device-make-and-model:0": "HP LaserJet 1020",
- "device-id:0": "MFG:HP;MDL:LaserJet",
- },
- wantLen: 1,
- wantURIs: []string{"usb://HP/LaserJet"},
- },
- {
- name: "multiple_devices",
- input: map[string]string{
- "device-uri:0": "usb://HP/LaserJet",
- "device-class:0": "direct",
- "device-info:0": "HP LaserJet",
- "device-uri:1": "socket://192.168.1.100",
- "device-class:1": "network",
- "device-info:1": "Network Printer",
- },
- wantLen: 2,
- wantURIs: []string{"usb://HP/LaserJet", "socket://192.168.1.100"},
- },
- {
- name: "malformed_key",
- input: map[string]string{
- "no-colon-here": "value",
- },
- wantLen: 0,
- wantURIs: nil,
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := parseDevicesMap(tt.input)
- assert.Len(t, got, tt.wantLen)
-
- if tt.wantURIs != nil {
- gotURIs := make(map[string]bool)
- for _, d := range got {
- gotURIs[d.URI] = true
- }
- for _, uri := range tt.wantURIs {
- assert.True(t, gotURIs[uri], "expected URI %s not found", uri)
- }
- }
- })
- }
-}
-
-func TestParseDevicesMap_Attributes(t *testing.T) {
- input := map[string]string{
- "device-uri:0": "usb://HP/LaserJet",
- "device-class:0": "direct",
- "device-info:0": "HP LaserJet",
- "device-make-and-model:0": "HP LaserJet 1020",
- "device-id:0": "MFG:HP;MDL:LaserJet",
- "device-location:0": "USB Port",
- }
-
- got := parseDevicesMap(input)
- assert.Len(t, got, 1)
-
- dev := got[0]
- assert.Equal(t, "usb://HP/LaserJet", dev.URI)
- assert.Equal(t, "direct", dev.Class)
- assert.Equal(t, "HP LaserJet", dev.Info)
- assert.Equal(t, "HP LaserJet 1020", dev.MakeModel)
- assert.Equal(t, "MFG:HP;MDL:LaserJet", dev.ID)
- assert.Equal(t, "USB Port", dev.Location)
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go
deleted file mode 100644
index 6b369b4..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription.go
+++ /dev/null
@@ -1,245 +0,0 @@
-package cups
-
-import (
- "fmt"
- "sync"
- "time"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/log"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
-)
-
-type SubscriptionManager struct {
- client CUPSClientInterface
- subscriptionID int
- sequenceNumber int
- eventChan chan SubscriptionEvent
- stopChan chan struct{}
- wg sync.WaitGroup
- baseURL string
- running bool
- mu sync.Mutex
-}
-
-func NewSubscriptionManager(client CUPSClientInterface, baseURL string) *SubscriptionManager {
- return &SubscriptionManager{
- client: client,
- eventChan: make(chan SubscriptionEvent, 100),
- stopChan: make(chan struct{}),
- baseURL: baseURL,
- }
-}
-
-func (sm *SubscriptionManager) Start() error {
- sm.mu.Lock()
- if sm.running {
- sm.mu.Unlock()
- return fmt.Errorf("subscription manager already running")
- }
- sm.running = true
- sm.mu.Unlock()
-
- subID, err := sm.createSubscription()
- if err != nil {
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("failed to create subscription: %w", err)
- }
-
- sm.subscriptionID = subID
- log.Infof("[CUPS] Created IPP subscription with ID %d", subID)
-
- sm.wg.Add(1)
- go sm.notificationLoop()
-
- return nil
-}
-
-func (sm *SubscriptionManager) createSubscription() (int, error) {
- req := ipp.NewRequest(ipp.OperationCreatePrinterSubscriptions, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
-
- // Subscription attributes go in SubscriptionAttributes (subscription-attributes-tag in IPP)
- req.SubscriptionAttributes = map[string]any{
- "notify-events": []string{
- "printer-state-changed",
- "printer-added",
- "printer-deleted",
- "job-created",
- "job-completed",
- "job-state-changed",
- },
- "notify-pull-method": "ippget",
- "notify-lease-duration": 0,
- }
-
- // Send to root IPP endpoint
- resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- return 0, fmt.Errorf("SendRequest failed: %w", err)
- }
-
- // Check for IPP errors
- if err := resp.CheckForErrors(); err != nil {
- return 0, fmt.Errorf("IPP error: %w", err)
- }
-
- // Subscription ID comes back in SubscriptionAttributes
- if len(resp.SubscriptionAttributes) > 0 {
- if idAttr, ok := resp.SubscriptionAttributes[0]["notify-subscription-id"]; ok && len(idAttr) > 0 {
- if val, ok := idAttr[0].Value.(int); ok {
- return val, nil
- }
- }
- }
-
- return 0, fmt.Errorf("no subscription ID returned")
-}
-
-func (sm *SubscriptionManager) notificationLoop() {
- defer sm.wg.Done()
-
- backoff := 1 * time.Second
-
- for {
- select {
- case <-sm.stopChan:
- return
- default:
- }
-
- gotAny, err := sm.fetchNotificationsWithWait()
- if err != nil {
- log.Warnf("[CUPS] Error fetching notifications: %v", err)
- jitter := time.Duration(50+(time.Now().UnixNano()%200)) * time.Millisecond
- sleepTime := backoff + jitter
- if sleepTime > 30*time.Second {
- sleepTime = 30 * time.Second
- }
- select {
- case <-sm.stopChan:
- return
- case <-time.After(sleepTime):
- }
- if backoff < 30*time.Second {
- backoff *= 2
- }
- continue
- }
-
- backoff = 1 * time.Second
-
- if gotAny {
- continue
- }
-
- select {
- case <-sm.stopChan:
- return
- case <-time.After(2 * time.Second):
- }
- }
-}
-
-func (sm *SubscriptionManager) fetchNotificationsWithWait() (bool, error) {
- req := ipp.NewRequest(ipp.OperationGetNotifications, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
- req.OperationAttributes["notify-subscription-ids"] = sm.subscriptionID
- if sm.sequenceNumber > 0 {
- req.OperationAttributes["notify-sequence-numbers"] = sm.sequenceNumber
- }
-
- resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- return false, err
- }
-
- gotAny := false
- for _, eventGroup := range resp.SubscriptionAttributes {
- if seqAttr, ok := eventGroup["notify-sequence-number"]; ok && len(seqAttr) > 0 {
- if seqNum, ok := seqAttr[0].Value.(int); ok {
- sm.sequenceNumber = seqNum + 1
- }
- }
-
- event := sm.parseEvent(eventGroup)
- gotAny = true
- select {
- case sm.eventChan <- event:
- case <-sm.stopChan:
- return gotAny, nil
- default:
- log.Warn("[CUPS] Event channel full, dropping event")
- }
- }
-
- return gotAny, nil
-}
-
-func (sm *SubscriptionManager) parseEvent(attrs ipp.Attributes) SubscriptionEvent {
- event := SubscriptionEvent{
- SubscribedAt: time.Now(),
- }
-
- if attr, ok := attrs["notify-subscribed-event"]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(string); ok {
- event.EventName = val
- }
- }
-
- if attr, ok := attrs["printer-name"]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(string); ok {
- event.PrinterName = val
- }
- }
-
- if attr, ok := attrs["notify-job-id"]; ok && len(attr) > 0 {
- if val, ok := attr[0].Value.(int); ok {
- event.JobID = val
- }
- }
-
- return event
-}
-
-func (sm *SubscriptionManager) Events() <-chan SubscriptionEvent {
- return sm.eventChan
-}
-
-func (sm *SubscriptionManager) Stop() {
- sm.mu.Lock()
- if !sm.running {
- sm.mu.Unlock()
- return
- }
- sm.running = false
- sm.mu.Unlock()
-
- close(sm.stopChan)
- sm.wg.Wait()
-
- if sm.subscriptionID != 0 {
- sm.cancelSubscription()
- sm.subscriptionID = 0
- sm.sequenceNumber = 0
- }
-
- sm.stopChan = make(chan struct{})
-}
-
-func (sm *SubscriptionManager) cancelSubscription() {
- req := ipp.NewRequest(ipp.OperationCancelSubscription, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
- req.OperationAttributes["notify-subscription-id"] = sm.subscriptionID
-
- _, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- log.Warnf("[CUPS] Failed to cancel subscription %d: %v", sm.subscriptionID, err)
- } else {
- log.Infof("[CUPS] Cancelled subscription %d", sm.subscriptionID)
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go
deleted file mode 100644
index b205a6b..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/subscription_dbus.go
+++ /dev/null
@@ -1,295 +0,0 @@
-package cups
-
-import (
- "fmt"
- "strings"
- "sync"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/log"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
- "github.com/godbus/dbus/v5"
-)
-
-type DBusSubscriptionManager struct {
- client CUPSClientInterface
- subscriptionID int
- eventChan chan SubscriptionEvent
- stopChan chan struct{}
- wg sync.WaitGroup
- baseURL string
- running bool
- mu sync.Mutex
- conn *dbus.Conn
-}
-
-func NewDBusSubscriptionManager(client CUPSClientInterface, baseURL string) *DBusSubscriptionManager {
- return &DBusSubscriptionManager{
- client: client,
- eventChan: make(chan SubscriptionEvent, 100),
- stopChan: make(chan struct{}),
- baseURL: baseURL,
- }
-}
-
-func (sm *DBusSubscriptionManager) Start() error {
- sm.mu.Lock()
- if sm.running {
- sm.mu.Unlock()
- return fmt.Errorf("subscription manager already running")
- }
- sm.running = true
- sm.mu.Unlock()
-
- conn, err := dbus.ConnectSystemBus()
- if err != nil {
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("connect to system bus: %w", err)
- }
- sm.conn = conn
-
- subID, err := sm.createDBusSubscription()
- if err != nil {
- sm.conn.Close()
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("failed to create D-Bus subscription: %w", err)
- }
-
- sm.subscriptionID = subID
- log.Infof("[CUPS] Created D-Bus subscription with ID %d", subID)
-
- if err := sm.conn.AddMatchSignal(
- dbus.WithMatchInterface("org.cups.cupsd.Notifier"),
- ); err != nil {
- sm.cancelSubscription()
- sm.conn.Close()
- sm.mu.Lock()
- sm.running = false
- sm.mu.Unlock()
- return fmt.Errorf("failed to add D-Bus match: %w", err)
- }
-
- sm.wg.Add(1)
- go sm.dbusListenerLoop()
-
- return nil
-}
-
-func (sm *DBusSubscriptionManager) createDBusSubscription() (int, error) {
- req := ipp.NewRequest(ipp.OperationCreatePrinterSubscriptions, 2)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
-
- req.SubscriptionAttributes = map[string]any{
- "notify-events": []string{
- "printer-state-changed",
- "printer-added",
- "printer-deleted",
- "job-created",
- "job-completed",
- "job-state-changed",
- },
- "notify-recipient-uri": "dbus:/",
- "notify-lease-duration": 86400,
- }
-
- resp, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- return 0, fmt.Errorf("SendRequest failed: %w", err)
- }
-
- if err := resp.CheckForErrors(); err != nil {
- return 0, fmt.Errorf("IPP error: %w", err)
- }
-
- if len(resp.SubscriptionAttributes) > 0 {
- if idAttr, ok := resp.SubscriptionAttributes[0]["notify-subscription-id"]; ok && len(idAttr) > 0 {
- if val, ok := idAttr[0].Value.(int); ok {
- return val, nil
- }
- }
- }
-
- return 0, fmt.Errorf("no subscription ID returned")
-}
-
-func (sm *DBusSubscriptionManager) dbusListenerLoop() {
- defer sm.wg.Done()
-
- signalChan := make(chan *dbus.Signal, 10)
- sm.conn.Signal(signalChan)
- defer sm.conn.RemoveSignal(signalChan)
-
- for {
- select {
- case <-sm.stopChan:
- return
- case sig := <-signalChan:
- if sig == nil {
- continue
- }
-
- event := sm.parseDBusSignal(sig)
- if event.EventName == "" {
- continue
- }
-
- select {
- case sm.eventChan <- event:
- case <-sm.stopChan:
- return
- default:
- log.Warn("[CUPS] Event channel full, dropping event")
- }
- }
- }
-}
-
-func (sm *DBusSubscriptionManager) parseDBusSignal(sig *dbus.Signal) SubscriptionEvent {
- event := SubscriptionEvent{}
-
- switch sig.Name {
- case "org.cups.cupsd.Notifier.JobStateChanged":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "job-state-changed"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- if jobID, ok := sig.Body[3].(uint32); ok {
- event.JobID = int(jobID)
- }
- }
-
- case "org.cups.cupsd.Notifier.JobCreated":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "job-created"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- if jobID, ok := sig.Body[3].(uint32); ok {
- event.JobID = int(jobID)
- }
- }
-
- case "org.cups.cupsd.Notifier.JobCompleted":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "job-completed"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- if jobID, ok := sig.Body[3].(uint32); ok {
- event.JobID = int(jobID)
- }
- }
-
- case "org.cups.cupsd.Notifier.PrinterStateChanged":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "printer-state-changed"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- if printerURI, ok := sig.Body[1].(string); ok && event.PrinterName == "" {
- if idx := strings.LastIndex(printerURI, "/"); idx != -1 {
- event.PrinterName = printerURI[idx+1:]
- }
- }
- }
-
- case "org.cups.cupsd.Notifier.PrinterAdded":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "printer-added"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- }
-
- case "org.cups.cupsd.Notifier.PrinterDeleted":
- if len(sig.Body) >= 6 {
- if text, ok := sig.Body[0].(string); ok {
- event.EventName = "printer-deleted"
- parts := strings.Split(text, " ")
- if len(parts) >= 2 {
- event.PrinterName = parts[0]
- }
- }
- }
- }
-
- return event
-}
-
-func (sm *DBusSubscriptionManager) Events() <-chan SubscriptionEvent {
- return sm.eventChan
-}
-
-func (sm *DBusSubscriptionManager) Stop() {
- sm.mu.Lock()
- if !sm.running {
- sm.mu.Unlock()
- return
- }
- sm.running = false
- sm.mu.Unlock()
-
- close(sm.stopChan)
- sm.wg.Wait()
-
- if sm.subscriptionID != 0 {
- sm.cancelSubscription()
- sm.subscriptionID = 0
- }
-
- if sm.conn != nil {
- sm.conn.Close()
- sm.conn = nil
- }
-
- sm.stopChan = make(chan struct{})
-}
-
-func (sm *DBusSubscriptionManager) cancelSubscription() {
- req := ipp.NewRequest(ipp.OperationCancelSubscription, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = fmt.Sprintf("%s/", sm.baseURL)
- req.OperationAttributes[ipp.AttributeRequestingUserName] = "dms"
- req.OperationAttributes["notify-subscription-id"] = sm.subscriptionID
-
- _, err := sm.client.SendRequest(fmt.Sprintf("%s/", sm.baseURL), req, nil)
- if err != nil {
- log.Warnf("[CUPS] Failed to cancel subscription %d: %v", sm.subscriptionID, err)
- } else {
- log.Infof("[CUPS] Cancelled subscription %d", sm.subscriptionID)
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go
deleted file mode 100644
index d0203e9..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection.go
+++ /dev/null
@@ -1,176 +0,0 @@
-package cups
-
-import (
- "errors"
- "fmt"
- "net"
- "strings"
- "time"
-
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
-)
-
-var validProtocols = map[string]bool{
- "ipp": true,
- "ipps": true,
- "lpd": true,
- "socket": true,
-}
-
-func validateTestConnectionParams(host string, port int, protocol string) error {
- if host == "" {
- return errors.New("host is required")
- }
- if strings.ContainsAny(host, " \t\n\r/\\") {
- return errors.New("host contains invalid characters")
- }
- if port < 1 || port > 65535 {
- return errors.New("port must be between 1 and 65535")
- }
- if protocol != "" && !validProtocols[protocol] {
- return errors.New("protocol must be one of: ipp, ipps, lpd, socket")
- }
- return nil
-}
-
-const probeTimeout = 10 * time.Second
-
-func probeRemotePrinter(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- addr := net.JoinHostPort(host, fmt.Sprintf("%d", port))
-
- // Fast fail: TCP reachability check
- conn, err := net.DialTimeout("tcp", addr, probeTimeout)
- if err != nil {
- return &RemotePrinterInfo{
- Reachable: false,
- Error: fmt.Sprintf("cannot reach %s: %s", addr, err.Error()),
- }, nil
- }
- conn.Close()
-
- // Create a temporary IPP client pointing at the remote host.
- // The TCP dial above provides fast-fail for unreachable hosts.
- // The IPP adapter's ResponseHeaderTimeout (90s) bounds stalling servers.
- client := ipp.NewIPPClient(host, port, "", "", useTLS)
-
- // Try /ipp/print first (modern driverless printers), then / (legacy)
- info, err := probeIPPEndpoint(client, host, port, useTLS, "/ipp/print")
- if err != nil {
- // If we got an auth error, the printer exists but requires credentials.
- // Report it as reachable with the URI that triggered the auth challenge.
- if isAuthError(err) {
- proto := "ipp"
- if useTLS {
- proto = "ipps"
- }
- return &RemotePrinterInfo{
- Reachable: true,
- URI: fmt.Sprintf("%s://%s:%d/ipp/print", proto, host, port),
- Info: "authentication required",
- }, nil
- }
- info, err = probeIPPEndpoint(client, host, port, useTLS, "/")
- }
- if err != nil {
- if isAuthError(err) {
- proto := "ipp"
- if useTLS {
- proto = "ipps"
- }
- return &RemotePrinterInfo{
- Reachable: true,
- URI: fmt.Sprintf("%s://%s:%d/", proto, host, port),
- Info: "authentication required",
- }, nil
- }
- // TCP reachable but not an IPP printer
- return &RemotePrinterInfo{
- Reachable: true,
- Error: fmt.Sprintf("host is reachable but does not appear to be an IPP printer: %s", err.Error()),
- }, nil
- }
-
- return info, nil
-}
-
-func probeIPPEndpoint(client *ipp.IPPClient, host string, port int, useTLS bool, resourcePath string) (*RemotePrinterInfo, error) {
- proto := "ipp"
- if useTLS {
- proto = "ipps"
- }
- printerURI := fmt.Sprintf("%s://%s:%d%s", proto, host, port, resourcePath)
-
- httpProto := "http"
- if useTLS {
- httpProto = "https"
- }
- httpURL := fmt.Sprintf("%s://%s:%d%s", httpProto, host, port, resourcePath)
-
- req := ipp.NewRequest(ipp.OperationGetPrinterAttributes, 1)
- req.OperationAttributes[ipp.AttributePrinterURI] = printerURI
- req.OperationAttributes[ipp.AttributeRequestedAttributes] = []string{
- ipp.AttributePrinterName,
- ipp.AttributePrinterMakeAndModel,
- ipp.AttributePrinterState,
- ipp.AttributePrinterInfo,
- ipp.AttributePrinterUriSupported,
- }
-
- resp, err := client.SendRequest(httpURL, req, nil)
- if err != nil {
- return nil, err
- }
-
- if len(resp.PrinterAttributes) == 0 {
- return nil, errors.New("no printer attributes returned")
- }
-
- attrs := resp.PrinterAttributes[0]
-
- return &RemotePrinterInfo{
- Reachable: true,
- MakeModel: getStringAttr(attrs, ipp.AttributePrinterMakeAndModel),
- Name: getStringAttr(attrs, ipp.AttributePrinterName),
- Info: getStringAttr(attrs, ipp.AttributePrinterInfo),
- State: parsePrinterState(attrs),
- URI: printerURI,
- }, nil
-}
-
-// TestRemotePrinter validates inputs and probes a remote printer via IPP.
-// For lpd/socket protocols, only TCP reachability is tested.
-func (m *Manager) TestRemotePrinter(host string, port int, protocol string) (*RemotePrinterInfo, error) {
- if protocol == "" {
- protocol = "ipp"
- }
-
- if err := validateTestConnectionParams(host, port, protocol); err != nil {
- return nil, err
- }
-
- // For non-IPP protocols, only check TCP reachability
- if protocol == "lpd" || protocol == "socket" {
- addr := net.JoinHostPort(host, fmt.Sprintf("%d", port))
- conn, err := net.DialTimeout("tcp", addr, probeTimeout)
- if err != nil {
- return &RemotePrinterInfo{
- Reachable: false,
- Error: fmt.Sprintf("cannot reach %s: %s", addr, err.Error()),
- }, nil
- }
- conn.Close()
- return &RemotePrinterInfo{
- Reachable: true,
- URI: fmt.Sprintf("%s://%s:%d", protocol, host, port),
- }, nil
- }
-
- useTLS := protocol == "ipps"
-
- probeFn := m.probeRemoteFn
- if probeFn == nil {
- probeFn = probeRemotePrinter
- }
-
- return probeFn(host, port, useTLS)
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go
deleted file mode 100644
index b835028..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/test_connection_test.go
+++ /dev/null
@@ -1,397 +0,0 @@
-package cups
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "testing"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
- "github.com/stretchr/testify/assert"
-)
-
-func TestValidateTestConnectionParams(t *testing.T) {
- tests := []struct {
- name string
- host string
- port int
- protocol string
- wantErr string
- }{
- {
- name: "valid ipp",
- host: "192.168.0.5",
- port: 631,
- protocol: "ipp",
- wantErr: "",
- },
- {
- name: "valid ipps",
- host: "printer.local",
- port: 443,
- protocol: "ipps",
- wantErr: "",
- },
- {
- name: "valid lpd",
- host: "10.0.0.1",
- port: 515,
- protocol: "lpd",
- wantErr: "",
- },
- {
- name: "valid socket",
- host: "10.0.0.1",
- port: 9100,
- protocol: "socket",
- wantErr: "",
- },
- {
- name: "empty host",
- host: "",
- port: 631,
- protocol: "ipp",
- wantErr: "host is required",
- },
- {
- name: "port too low",
- host: "192.168.0.5",
- port: 0,
- protocol: "ipp",
- wantErr: "port must be between 1 and 65535",
- },
- {
- name: "port too high",
- host: "192.168.0.5",
- port: 70000,
- protocol: "ipp",
- wantErr: "port must be between 1 and 65535",
- },
- {
- name: "invalid protocol",
- host: "192.168.0.5",
- port: 631,
- protocol: "ftp",
- wantErr: "protocol must be one of: ipp, ipps, lpd, socket",
- },
- {
- name: "empty protocol treated as ipp",
- host: "192.168.0.5",
- port: 631,
- protocol: "",
- wantErr: "",
- },
- {
- name: "host with slash",
- host: "192.168.0.5/admin",
- port: 631,
- protocol: "ipp",
- wantErr: "host contains invalid characters",
- },
- {
- name: "host with space",
- host: "192.168.0.5 ",
- port: 631,
- protocol: "ipp",
- wantErr: "host contains invalid characters",
- },
- {
- name: "host with newline",
- host: "192.168.0.5\n",
- port: 631,
- protocol: "ipp",
- wantErr: "host contains invalid characters",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- err := validateTestConnectionParams(tt.host, tt.port, tt.protocol)
- if tt.wantErr == "" {
- assert.NoError(t, err)
- } else {
- assert.EqualError(t, err, tt.wantErr)
- }
- })
- }
-}
-
-func TestManager_TestRemotePrinter_Validation(t *testing.T) {
- m := NewTestManager(nil, nil)
-
- tests := []struct {
- name string
- host string
- port int
- protocol string
- wantErr string
- }{
- {
- name: "empty host returns error",
- host: "",
- port: 631,
- protocol: "ipp",
- wantErr: "host is required",
- },
- {
- name: "invalid port returns error",
- host: "192.168.0.5",
- port: 0,
- protocol: "ipp",
- wantErr: "port must be between 1 and 65535",
- },
- {
- name: "invalid protocol returns error",
- host: "192.168.0.5",
- port: 631,
- protocol: "ftp",
- wantErr: "protocol must be one of: ipp, ipps, lpd, socket",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- _, err := m.TestRemotePrinter(tt.host, tt.port, tt.protocol)
- assert.EqualError(t, err, tt.wantErr)
- })
- }
-}
-
-func TestManager_TestRemotePrinter_IPP(t *testing.T) {
- tests := []struct {
- name string
- protocol string
- probeRet *RemotePrinterInfo
- probeErr error
- wantTLS bool
- wantReach bool
- wantModel string
- }{
- {
- name: "successful ipp probe",
- protocol: "ipp",
- probeRet: &RemotePrinterInfo{
- Reachable: true,
- MakeModel: "HP OfficeJet 8010",
- Name: "OfficeJet",
- State: "idle",
- URI: "ipp://192.168.0.5:631/ipp/print",
- },
- wantTLS: false,
- wantReach: true,
- wantModel: "HP OfficeJet 8010",
- },
- {
- name: "successful ipps probe",
- protocol: "ipps",
- probeRet: &RemotePrinterInfo{
- Reachable: true,
- MakeModel: "HP OfficeJet 8010",
- URI: "ipps://192.168.0.5:631/ipp/print",
- },
- wantTLS: true,
- wantReach: true,
- wantModel: "HP OfficeJet 8010",
- },
- {
- name: "unreachable host",
- protocol: "ipp",
- probeRet: &RemotePrinterInfo{
- Reachable: false,
- Error: "cannot reach 192.168.0.5:631: connection refused",
- },
- wantReach: false,
- },
- {
- name: "empty protocol defaults to ipp",
- protocol: "",
- probeRet: &RemotePrinterInfo{
- Reachable: true,
- MakeModel: "Test Printer",
- },
- wantTLS: false,
- wantReach: true,
- wantModel: "Test Printer",
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- var capturedTLS bool
- m := NewTestManager(nil, nil)
- m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- capturedTLS = useTLS
- return tt.probeRet, tt.probeErr
- }
-
- result, err := m.TestRemotePrinter("192.168.0.5", 631, tt.protocol)
- if tt.probeErr != nil {
- assert.Error(t, err)
- return
- }
- assert.NoError(t, err)
- assert.Equal(t, tt.wantReach, result.Reachable)
- assert.Equal(t, tt.wantModel, result.MakeModel)
- assert.Equal(t, tt.wantTLS, capturedTLS)
- })
- }
-}
-
-func TestManager_TestRemotePrinter_AuthRequired(t *testing.T) {
- m := NewTestManager(nil, nil)
- m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- // Simulate what happens when the printer returns HTTP 401
- return probeRemotePrinterWithAuthError(host, port, useTLS)
- }
-
- result, err := m.TestRemotePrinter("192.168.0.107", 631, "ipp")
- assert.NoError(t, err)
- assert.True(t, result.Reachable)
- assert.Equal(t, "authentication required", result.Info)
- assert.Contains(t, result.URI, "ipp://192.168.0.107:631")
-}
-
-// probeRemotePrinterWithAuthError simulates a probe where the printer
-// returns HTTP 401 on both endpoints.
-func probeRemotePrinterWithAuthError(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- // This simulates what probeRemotePrinter does when both endpoints
- // return auth errors. We test the auth detection logic directly.
- err := ipp.HTTPError{Code: 401}
- if isAuthError(err) {
- proto := "ipp"
- if useTLS {
- proto = "ipps"
- }
- return &RemotePrinterInfo{
- Reachable: true,
- URI: fmt.Sprintf("%s://%s:%d/ipp/print", proto, host, port),
- Info: "authentication required",
- }, nil
- }
- return nil, err
-}
-
-func TestManager_TestRemotePrinter_NonIPPProtocol(t *testing.T) {
- m := NewTestManager(nil, nil)
- probeCalled := false
- m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- probeCalled = true
- return nil, nil
- }
-
- // These will fail at TCP dial (no real server), but the important
- // thing is that probeRemoteFn is NOT called for lpd/socket.
- m.TestRemotePrinter("192.168.0.5", 9100, "socket")
- assert.False(t, probeCalled, "probe function should not be called for socket protocol")
-
- m.TestRemotePrinter("192.168.0.5", 515, "lpd")
- assert.False(t, probeCalled, "probe function should not be called for lpd protocol")
-}
-
-func TestHandleTestConnection_Success(t *testing.T) {
- m := NewTestManager(nil, nil)
- m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- return &RemotePrinterInfo{
- Reachable: true,
- MakeModel: "HP OfficeJet 8010",
- Name: "OfficeJet",
- State: "idle",
- URI: "ipp://192.168.0.5:631/ipp/print",
- }, nil
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.testConnection",
- Params: map[string]any{
- "host": "192.168.0.5",
- },
- }
-
- handleTestConnection(conn, req, m)
-
- var resp models.Response[RemotePrinterInfo]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Reachable)
- assert.Equal(t, "HP OfficeJet 8010", resp.Result.MakeModel)
-}
-
-func TestHandleTestConnection_MissingHost(t *testing.T) {
- m := NewTestManager(nil, nil)
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.testConnection",
- Params: map[string]any{},
- }
-
- handleTestConnection(conn, req, m)
-
- var resp models.Response[any]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.Nil(t, resp.Result)
- assert.NotNil(t, resp.Error)
-}
-
-func TestHandleTestConnection_CustomPortAndProtocol(t *testing.T) {
- m := NewTestManager(nil, nil)
- m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- assert.Equal(t, 9631, port)
- assert.True(t, useTLS)
- return &RemotePrinterInfo{Reachable: true, URI: "ipps://192.168.0.5:9631/ipp/print"}, nil
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.testConnection",
- Params: map[string]any{
- "host": "192.168.0.5",
- "port": float64(9631),
- "protocol": "ipps",
- },
- }
-
- handleTestConnection(conn, req, m)
-
- var resp models.Response[RemotePrinterInfo]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Reachable)
-}
-
-func TestHandleRequest_TestConnection(t *testing.T) {
- m := NewTestManager(nil, nil)
- m.probeRemoteFn = func(host string, port int, useTLS bool) (*RemotePrinterInfo, error) {
- return &RemotePrinterInfo{Reachable: true}, nil
- }
-
- buf := &bytes.Buffer{}
- conn := &mockConn{Buffer: buf}
-
- req := models.Request{
- ID: 1,
- Method: "cups.testConnection",
- Params: map[string]any{"host": "192.168.0.5"},
- }
-
- HandleRequest(conn, req, m)
-
- var resp models.Response[RemotePrinterInfo]
- err := json.NewDecoder(buf).Decode(&resp)
- assert.NoError(t, err)
- assert.NotNil(t, resp.Result)
- assert.True(t, resp.Result.Reachable)
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/testing.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/testing.go
deleted file mode 100644
index 4820e34..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/testing.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package cups
-
-func NewTestManager(client CUPSClientInterface, pkHelper PkHelper) *Manager {
- return &Manager{
- client: client,
- pkHelper: pkHelper,
- state: &CUPSState{
- Printers: make(map[string]*Printer),
- },
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/types.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/types.go
deleted file mode 100644
index 52e9d2c..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/cups/types.go
+++ /dev/null
@@ -1,132 +0,0 @@
-package cups
-
-import (
- "io"
- "sync"
- "time"
-
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/ipp"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap"
-)
-
-type CUPSState struct {
- Printers map[string]*Printer `json:"printers"`
-}
-
-type Printer struct {
- Name string `json:"name"`
- URI string `json:"uri"`
- State string `json:"state"`
- StateReason string `json:"stateReason"`
- Location string `json:"location"`
- Info string `json:"info"`
- MakeModel string `json:"makeModel"`
- Accepting bool `json:"accepting"`
- Jobs []Job `json:"jobs"`
-}
-
-type Job struct {
- ID int `json:"id"`
- Name string `json:"name"`
- State string `json:"state"`
- Printer string `json:"printer"`
- User string `json:"user"`
- Size int `json:"size"`
- TimeCreated time.Time `json:"timeCreated"`
-}
-
-type Device struct {
- URI string `json:"uri"`
- Class string `json:"class"`
- Info string `json:"info"`
- MakeModel string `json:"makeModel"`
- ID string `json:"id"`
- Location string `json:"location"`
- IP string `json:"ip,omitempty"`
-}
-
-type PPD struct {
- Name string `json:"name"`
- NaturalLanguage string `json:"naturalLanguage"`
- MakeModel string `json:"makeModel"`
- DeviceID string `json:"deviceId"`
- Product string `json:"product"`
- PSVersion string `json:"psVersion"`
- Type string `json:"type"`
-}
-
-type RemotePrinterInfo struct {
- Reachable bool `json:"reachable"`
- MakeModel string `json:"makeModel"`
- Name string `json:"name"`
- Info string `json:"info"`
- State string `json:"state"`
- URI string `json:"uri"`
- Error string `json:"error,omitempty"`
-}
-
-type PrinterClass struct {
- Name string `json:"name"`
- URI string `json:"uri"`
- State string `json:"state"`
- Members []string `json:"members"`
- Location string `json:"location"`
- Info string `json:"info"`
-}
-
-type Manager struct {
- state *CUPSState
- client CUPSClientInterface
- pkHelper PkHelper
- subscription SubscriptionManagerInterface
- stateMutex sync.RWMutex
- subscribers syncmap.Map[string, chan CUPSState]
- stopChan chan struct{}
- eventWG sync.WaitGroup
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotifiedState *CUPSState
- baseURL string
- probeRemoteFn func(host string, port int, useTLS bool) (*RemotePrinterInfo, error)
-}
-
-type SubscriptionManagerInterface interface {
- Start() error
- Stop()
- Events() <-chan SubscriptionEvent
-}
-
-type CUPSClientInterface interface {
- GetPrinters(attributes []string) (map[string]ipp.Attributes, error)
- GetJobs(printer, class string, whichJobs string, myJobs bool, firstJobId, limit int, attributes []string) (map[int]ipp.Attributes, error)
- CancelJob(jobID int, purge bool) error
- PausePrinter(printer string) error
- ResumePrinter(printer string) error
- CancelAllJob(printer string, purge bool) error
- SendRequest(url string, req *ipp.Request, additionalResponseData io.Writer) (*ipp.Response, error)
-
- GetDevices() (map[string]ipp.Attributes, error)
- GetPPDs() (map[string]ipp.Attributes, error)
- GetClasses(attributes []string) (map[string]ipp.Attributes, error)
- CreatePrinter(name, deviceURI, ppd string, shared bool, errorPolicy, information, location string) error
- DeletePrinter(printer string) error
- AcceptJobs(printer string) error
- RejectJobs(printer string) error
- SetPrinterIsShared(printer string, shared bool) error
- SetPrinterLocation(printer, location string) error
- SetPrinterInformation(printer, information string) error
- MoveJob(jobID int, destPrinter string) error
- PrintTestPage(printer string, testPageData io.Reader, size int) (int, error)
- AddPrinterToClass(class, printer string) error
- DeletePrinterFromClass(class, printer string) error
- DeleteClass(class string) error
- RestartJob(jobID int) error
- HoldJobUntil(jobID int, holdUntil string) error
-}
-
-type SubscriptionEvent struct {
- EventName string
- PrinterName string
- JobID int
- SubscribedAt time.Time
-}