Как определить, работает ли текущий процесс Go в автономной (не GUI) среде? - PullRequest
0 голосов
/ 24 октября 2018

У меня есть программа Go, которая хочет установить Traicicon.В случае, если процесс выполняется без заголовка, то есть он не сможет создать графический интерфейс пользователя, программа Go по-прежнему имеет смысл и должна запускаться, но, очевидно, она не будет устанавливать traicicon.

Что такоепуть в Go, как определить, является ли текущий процесс Go безголовым?

В настоящее время я использую следующий код:

func isHeadless() bool {
    _, display := os.LookupEnv("DISPLAY")
    return !(runtime.GOOS == "windows" || display)
}

Этот код прекрасно работает на «нормальной» Windows, Linuxили Mac OS X, и я уверен, что он также отлично работает на FreeBSD, NetBSD, Dragonfly и многих других.

Тем не менее, у этого кода, очевидно, много проблем:

  • Предполагается, что Windows никогда не бывает без головы (неправильно, что, если процесс был запущен без входа пользователя в систему, а также есть Windows 10 IoT Core, которую можно настроить на работу без головы https://docs.microsoft.com/en-us/windows/iot-core/learn-about-hardware/headlessmode)
  • Это неподдержка Android (для которой также существует безголовая версия IoT).
  • Предполагается, что все, кроме Windows, имеет X-сервер и, следовательно, переменную среды DISPLAY (например, неправильно).Android)

Итак, как правильно в Go определить, является ли текущий процесс безголовым / работает в безголовой среде?

Я не ищу обходных путей, напримердобавив в мою программу ключ командной строки --headless.Потому что у меня уже есть , что в любом случае для пользователей, у которых есть головы, но которые хотят, чтобы программа работала так, как если бы она была безголовой.

В некоторых других средах программирования такие возможности существуют.Например, Java имеет java.awt.GraphicsEnvironment.isHeadless(), и я ищу аналогичную возможность в Go.

Некоторые люди предложили просто попробовать создать пользовательский интерфейс и отловить ошибку.Это не работает, по крайней мере, не с библиотекой, которую я использую.Я использую github.com/getlantern/systray.Когда systray.Run() не может создать пользовательский интерфейс, процесс умирает.Мой код для настройки системного трея выглядит следующим образом:

func setupSystray() { // called from main()
    go func() {
        systray.Run(onReady, nil)
    }()
}

func onReady() {
    systray.SetTitle("foo")
    // ...
}

Когда я запускаю этот код в Linux с DISPLAY unset, вывод будет следующим:

$ ./myapp-linux-amd64
Unable to init server: Could not connect: Connection refused

(myapp-linux-amd64:5783): Gtk-WARNING **: 19:42:37.914: cannot open display: 
$ echo $?
1

Это можетможно утверждать, что это ошибка в библиотеке (и я создал билет для библиотеки https://github.com/getlantern/systray/issues/71),, но, тем не менее, некоторые другие API и среды предоставляют функцию isHeadless(), и я ищу эквивалент в Golang.

Ответы [ 3 ]

0 голосов
/ 25 октября 2018

В связи с отсутствием библиотеки / решения для этого я создал ее сам.https://github.com/christianhujer/isheadless

Пример использования:

package main

import (
    . "fmt"
    . "github.com/christianhujer/isheadless"
    . "os"
)

func main() {
    headless := IsHeadless()
    Fprintf(Stderr, "%s: info: headless: %v\n", Args[0], headless)
    Exit(map[bool]int{true: 0, false: 1}[headless])
}

Пример выполнения:

$ ./isheadless ; echo $?
./isheadless: info: headless: false
1
$ DISPLAY= ./isheadless ; echo $?
./isheadless: info: headless: true
0
0 голосов
/ 25 октября 2018

Что ж, ответ на вопрос точно так, как было сказано , заключается в том, чтобы просто посмотреть, что делает Java в своих isHeadless().

Здесь - это то, чтоOpenJDK 10 делает.

Я не могу скопировать код, поскольку он предположительно нарушил бы его лицензию, но в сущности, разбивка выглядит следующим образом:

  1. Получить системное свойство "java.awt.без головы";используйте его, если он найден.
  2. Получить системное свойство "javaplugin.version";если он существует, сеанс не безголовый.Используйте это значение.
  3. Получите системное свойство "os.name".Если он буквально содержит подстроку «OS X», а системное свойство «awt.toolkit» равно строке «sun.awt.HToolkit», сеанс не является безголовым.Используйте это значение.
  4. Проверьте, равно ли системное свойство "os.name" одному из "Linux", "SunOS", "FreeBSD", "NetBSD", "OpenBSD" или "AIX", и если да,попробуйте найти переменную окружения "DISPLAY";если он отсутствует, сеанс безголовый.

Как вы можете видеть, на самом деле проверка довольно слабая, и я не вижу какой-либо специальной обработки Windows.

Тем не менее, этоточно отвечает на ваш вопрос.

0 голосов
/ 24 октября 2018

Я думаю, что вы, возможно, атакуете эту проблему с неправильной точки зрения.

Обнаружение надежно того, что ваша программа действительно видит безголовый компьютер, IMO, довольно бесполезно по ряду причин.

Следовательно, я думаю, что я бы принял подход, обычно используемый, например, в работе с файловыми системами:

  1. Попытка выполнить операцию.
  2. В случае неудачи,Соберите ошибку.
  3. Анализируйте ошибку и действуйте соответствующим образом.

То есть просто попробуйте явно инициализировать клиентскую (вашу) сторону всего, что работает со стеком GUI в вашем кодеотловить любую возможную ошибку и проанализировать ее.Если говорится, что не удалось инициализировать подсистему, просто поднимите соответствующий флаг и продолжайте.

...