Почему accountservice всегда возвращает пустой список пользователей?

Я пытаюсь получить список пользователей системы в Vala, но все, что я получаю, это пустой список. Поскольку документация Vala довольно проста, я не знаю, как это решить. Вот что я пытаюсь:

var users_list = Act.UserManager.get_default ().list_users ();

person dvilela    schedule 19.06.2017    source источник
comment
В исходном архиве есть дополнительная документация для библиотеки accountservice. Нажмите «Загрузить версии» на главной странице: freedesktop.org/wiki/Software/AccountsService   -  person Jens Mühlenhoff    schedule 19.06.2017
comment
Пакет accountservice содержит двоичный файл, который вы можете запустить с вашего терминала. Вы можете сначала запустить его, чтобы увидеть, действительно ли интерфейс DBus работает в вашей системе.   -  person Jens Mühlenhoff    schedule 19.06.2017
comment
Я просмотрел эту документацию в источнике, но она выглядит примерно так же. Кажется, это код, который я должен использовать. Как я могу проверить имя этого двоичного файла?   -  person dvilela    schedule 19.06.2017
comment
Извините, нет двоичного файла пользователя. Я был под впечатлением, потому что есть бинарные пакеты, но не содержащие пользовательский бинарник.   -  person Jens Mühlenhoff    schedule 19.06.2017
comment
Однако следует отметить одну вещь: возвращает экземпляр одноэлементного менеджера пользователей. Вызов этой функции автоматически загружает список пользователей, если он еще не загружен. Свойство is-loaded будет установлено в TRUE, когда пользователи закончат загрузку, и тогда можно будет вызвать act_user_manager_list_users().   -  person Jens Mühlenhoff    schedule 19.06.2017
comment
Может быть, вам нужно подождать, пока свойство is-loaded не будет установлено в TRUE?   -  person Jens Mühlenhoff    schedule 19.06.2017
comment
Я так и думал, и безуспешно установил цикл while, ожидающий is_loaded. Я подождал секунд 20 или около того, но свойства, похоже, не изменились.   -  person dvilela    schedule 19.06.2017
comment
Может быть, использовать GLib.Timeout вместо узкой петли?   -  person Jens Mühlenhoff    schedule 20.06.2017


Ответы (1)


Похоже, что UserManager не имеет доступных данных при его создании. Данные доступны, только если свойство is_loaded истинно.

В GLib сигнал notify может выдаваться при изменении свойства. Поэтому мы воспользуемся этим в следующем рабочем примере:

int main () {
    var loop = new EventLoop ();
    var manager = new UserManager (loop);
    if (!manager.is_running) {
        print ("AccountsService is not running\n");
        return 1;
    }
    loop.run ();
    return 0;
}

class UserManager {

    private Act.UserManager manager;
    private EventLoop loop;

    public bool is_running {
        get { return !manager.no_service (); }
    }

    public UserManager (EventLoop event_loop) {
        loop = event_loop;
        manager = Act.UserManager.get_default ();
        manager.notify["is-loaded"].connect( this.loaded );
    }

    void loaded (ParamSpec property) {
        print (@"Property \"$(property.name)\" has changed\n");
        this.print_users ();
        this.loop.quit ();
    }

    void print_users () {
        if (!manager.is_loaded) { return; }
        print ("%-20s | %-20s\n", "User name", "Logged In Time");
        foreach (var user in manager.list_users ()) {
            print ("%-20s | %-20s\n",
                   user.user_name,
                   new DateTime.from_unix_local(user.login_time).to_string()
                   );
            }
    }
}

class EventLoop {

    private MainLoop loop;

    public EventLoop () {
        loop = new MainLoop ();
    }

    public void run() {
        this.loop.run ();
    }

    public void quit() {
        Idle.add (()=> { 
            this.loop.quit ();
            return Source.REMOVE;
        });
    }
}

В примере создается класс UserManager для оболочки UserManager AccountsService. Предполагается, что менеджер пользователей никогда не загружается, когда он впервые возвращается Act.UserManager.get_default (), поэтому как часть конструктора устанавливается обратный вызов при изменении свойства is_loaded. Это строка:

manager.notify["is-loaded"].connect( this.loaded );

manager имеет сигнал уведомления, который выдается при изменении любого свойства. В примере используется деталь сигнала, которая срабатывает только при изменении свойства is-loaded. По какой-то причине в его имени используется тире, а не подчеркивание. Я не мог найти никакой документации о том, почему это так. С сигналом notify обратный вызов может принимать ParamSpec в качестве аргумента. Это использовалось для поиска сведений об изменившемся свойстве, но в примере больше не требуется, поскольку используется подробность сигнала "is-loaded".

В примере также создается класс EventLoop, который действует как оболочка вокруг класса MainLoop GLib. UserManager имеет зависимость EventLoop, поэтому цикл обработки событий может завершиться и программа завершится.

Другим подходом может быть использование службы org.freedesktop.Accounts D-Bus непосредственно из Vala.

person AlThomas    schedule 20.06.2017
comment
Это прекрасно работает, но почему не работает цикл while, пока is_loaded не изменится? - person dvilela; 20.06.2017
comment
AccountsService — это клиент для службы org.freedesktop.Accounts D-Bus. Реализация D-Bus в GLib использует MainLoop GLib. для программирования на основе событий. Поэтому я думаю, вам нужно разрешить программе вернуться в основной цикл, чтобы она могла получать сообщения от службы D-Bus. Использование цикла while этого не делает. - person AlThomas; 20.06.2017
comment
Вот почему я предложил использовать GLib.Timeout вместо узкого цикла while. Это решение, конечно, еще лучше :). - person Jens Mühlenhoff; 21.06.2017