Error org.freedesktop.DBus.Error.UnknownMethod: Unknown / invalid method 'Notify'

I am trying to make a notification server with godbus but i cant properly export my server object to dbus and dbus only recognizes my introspect xml. I am following https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html to implement it. I have also used _example/server.go in godbus repo as you might notice in my server code provided below. Here is the server code:

package main

import (
    "fmt"
    "os"

    "github.com/godbus/dbus/v5"
    "github.com/godbus/dbus/v5/introspect"
)

const xml = `
<node>
    <interface name="org.freedesktop.Notifications">
        <method name="Notify">
            <arg direction="in" type="s"/>
            <arg direction="in" type="u"/>
            <arg direction="in" type="s"/>
            <arg direction="in" type="s"/>
            <arg direction="in" type="s"/>
            <arg direction="in" type="as"/>
            <arg direction="in" type="a{sv}"/>
            <arg direction="in" type="i"/>
            <arg direction="out" type="u"/>
        </method>

        <method name="GetCapabilities">
            <arg direction="out" type="as"/>
        </method>

        <method name="GetServerInformation">
            <arg direction="out" type="s"/>
            <arg direction="out" type="s"/>
            <arg direction="out" type="s"/>
            <arg direction="out" type="s"/>
        </method>

        <method name="CloseNotification">
            <arg direction="in" type="u"/>
        </method>

        <signal name="NotificationClosed">
            <arg type="u" name="id"/>
            <arg type="u" name="reason"/>
        </signal>
    </interface>` + introspect.IntrospectDataString + `</node> `

type NotificationServer struct {
}

func (s *NotificationServer) Notify(appName string, replacesID uint32, appIcon string, summary string, body string, actions []string, hints map[string]dbus.Variant, expireTimeout int32) (uint32, *dbus.Error) {
    fmt.Printf("New notification: %s\n", body)
    return 0, nil
}

func (s *NotificationServer) GetCapabilities() ([]string, *dbus.Error) {
    return []string{"action-icons", "actions", "body", "body-hyperlinks", "body-images", "body-markup", "icon-multi", "icon-static", "persistence", "sound"}, nil
}

func (s *NotificationServer) GetServerInformation() (string, string, string, string, *dbus.Error) {
    return "antarctica", "antarctica.com", "1.0", "1.2", nil
}

func (s *NotificationServer) CloseNotification(id uint32) *dbus.Error {
    s.NotificationClosed(id, 0)
    return nil
}
func (s *NotificationServer) NotificationClosed(id, reason uint32) {

}

func main() {
    conn, err := dbus.ConnectSessionBus()
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    reply, err := conn.RequestName("com.antarctica.notification",
        dbus.NameFlagDoNotQueue)
    if err != nil {
        panic(err)
    }

    if reply != dbus.RequestNameReplyPrimaryOwner {
        fmt.Fprintln(os.Stderr, "name already taken")
        os.Exit(1)
    }
    server := NotificationServer{}
    err = conn.Export(server,"/org/freedesktop/Notifications","org.freedesktop.Notifications")
    if err != nil {
        panic(err)
    }
    conn.Export(introspect.Introspectable(xml), "/org/freedesktop/Notifications", "org.freedesktop.DBus.Introspectable")
    fmt.Println("Listening on com.antarctica.notification / /com/antarctica/notification ...")
    select {}
}

Now the problem is that eventho the introspect xml is accessible to client:

$ gdbus introspect --session --dest com.antarctica.notification --object-path /org/freedesktop/Notifications --xml

> returns xml

I cant use org.freedesktop.Notifications methods that i wrote in my server code. for example Notify is Unknown/Invalid and this is the same for each method:

$ dbus-send --session --print-reply=literal --dest=com.antarctica.notification /org/freedesktop/Notifications org.freedesktop.Notifications.Notify

> Error org.freedesktop.DBus.Error.UnknownMethod: Unknown / invalid method 'Notify'

Also in qdbusviewer when I try to execute any method it says "Unable to find method x on path /org/freedesktop/Notifications in interface org.freedesktop.Notifications"

What I have tried:

  1. checked if dbus is running
  2. checked if my server is running
  3. I tried restarting dbus service and my computer as well
  4. I think NotificationServer instance (server) isnt being exported at all but i have no idea why

Upvotes: 3

Views: 1290

Answers (1)

Dom
Dom

Reputation: 136

This works. You made two mistakes:

  1. com.antarctica.notification
  2. func (s *NotificationServer)

You have to request 'org.freedesktop.Notifications' as name and you can not use a pointer in the func.

  1. org.freedesktop.Notifications
  2. func (s NotificationServer)
  3. (you don't need introspection either)
package main

import (
    "fmt"
    "os"

    "github.com/godbus/dbus/v5"
)

type notificationServer struct{}

func (s notificationServer) Notify(appName string, replacesID uint32, appIcon string, summary string, body string, actions []string, hints map[string]dbus.Variant, expireTimeout int32) (uint32, *dbus.Error) {
    fmt.Printf("New notification: %s\n", body)
    return 0, nil
}

func (s notificationServer) GetCapabilities() ([]string, *dbus.Error) {
    return []string{"action-icons", "actions", "body", "body-hyperlinks", "body-images", "body-markup", "icon-multi", "icon-static", "persistence", "sound"}, nil
}

func (s notificationServer) GetServerInformation() (string, string, string, string, *dbus.Error) {
    return "antarctica", "antarctica.com", "1.0", "1.2", nil
}

func main() {
    conn, err := dbus.ConnectSessionBus()
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    f := notificationServer{}
    conn.Export(f, "/org/freedesktop/Notifications", "org.freedesktop.Notifications")

    reply, err := conn.RequestName("org.freedesktop.Notifications", dbus.NameFlagDoNotQueue)
    if err != nil {
        panic(err)
    }
    if reply != dbus.RequestNameReplyPrimaryOwner {
        fmt.Fprintln(os.Stderr, "name already taken")
        os.Exit(1)
    }
    fmt.Println("Listening...")
    select {}
}

Upvotes: 2

Related Questions