Asyn c Vala Пример - PullRequest
       40

Asyn c Vala Пример

1 голос
/ 25 апреля 2020

В книге «Введение в Вала» доктора Михаэля Лауэра он упомянул, что api lib Soup c api нарушен. Я изо всех сил пытаюсь написать простой пример, используя session.queue_message, который запрашивает радиостанции, используя службу из radio-browser . Вот мой код Я был бы признателен за любую помощь от опытных программистов, таких как «Аль Томас». Спасибо.

public class Station : Object {

    // A globally unique identifier for the change of the station information
    public string changeuuid { get; set; default = ""; }

    // A globally unique identifier for the station
    public string stationuuid { get; set; default = ""; }

    // The name of the station
    public string name { get; set; default = ""; }

    // The stream URL provided by the user
    public string url { get; set; default = ""; }
    // and so on ... many properties
    public string to_string () {
        var builder = new StringBuilder ();
        builder.append_printf ("\nchangeuuid = %s\n", changeuuid);
        builder.append_printf ("stationuuid  = %s\n", stationuuid);
        builder.append_printf ("name = %s\n", name);
        builder.append_printf ("url = %s\n", url);
        return (owned) builder.str;
    }
}

public class RadioBrowser : Object {
    private static Soup.Session session;
    // private static MainLoop main_loop;
    public const string API_URL = "https://de1.api.radio-browser.info/json/stations";
    public const string USER_AGENT = "github.aeldemery.radiolibrary";

    public RadioBrowser (string user_agent = USER_AGENT, uint timeout = 50)
    requires (timeout > 0)
    {
        Intl.setlocale ();
        session = new Soup.Session ();
        session.timeout = timeout;
        session.user_agent = user_agent;
        session.use_thread_context = true;

        // main_loop = new MainLoop ();
    }

    private void check_response_status (Soup.Message msg) {
        if (msg.status_code != 200) {
            var str = "Error: Status message error %s.".printf (msg.reason_phrase);
            error (str);
        }
    }

    public Gee.ArrayList<Station> listStations () {
        var stations = new Gee.ArrayList<Station> ();
        var data_list = Datalist<string> ();
        data_list.set_data ("limit", "100");

        var parser = new Json.Parser ();
        parser.array_element.connect ((pars, array, index) => {
            var station = Json.gobject_deserialize (typeof (Station), array.get_element (index)) as Station;
            assert_nonnull (station);
            stations.add (station);
        });

        var msg = Soup.Form.request_new_from_datalist (
            "POST",
            API_URL,
            data_list
        );
        // send_message works but not queue_message
        // session.send_message (msg);

        session.queue_message (msg, (sess, mess) => {
            check_response_status (msg);
            try {
                parser.load_from_data ((string) msg.response_body.flatten ().data);
            } catch (Error e) {
                error ("Failed to parse data, error:" + e.message);
            }
        });

        return stations;
       }
    }

    int main (string[] args) {
        var radio_browser = new RadioBrowser ();
        var stations = radio_browser.listStations ();
        assert_nonnull (stations);

       foreach (var station in stations) {
           print (station.to_string ());
       }
       return 0;
    }

1 Ответ

1 голос
/ 26 апреля 2020

Хотя я не Аль Томас, я все еще могу помочь. ;)

Для работы асинхронных вызовов c должен быть запущен основной l oop, обычно из основного потока программы. Таким образом, вы хотите создать и выполнить основную l oop из вашей функции main(), а не из кода вашего приложения:

int main (string[] args) {
    var loop = new GLib.MainLoop ();
    var radio_browser = new RadioBrowser ();

    // set up async calls here

    // then set the main loop running as the last thing
    loop.run();
}

Также, если вы хотите ждать асинхронного вызова c для завершения обычно требуется выполнить вызов с использованием ключевого слова yield из другой функции asyn c Например:

    public async Gee.ArrayList<Station> listStations () {
        …

        // When this call is made, execution of listStations() will be
        // suspended until the soup response is received
        yield session.send_async(msg);

        // Execution then resumes normally
        check_response_status (msg);
        parser.load_from_data ((string) msg.response_body.flatten ().data);

        …

        return stations;
    }

Затем вы можете вызвать его из (non-asyn c) main функция с использованием записи listStations.begin(…):

int main (string[] args) {
    var loop = new GLib.MainLoop ();
    var radio_browser = new RadioBrowser ();
    radio_browser.listStations.begin((obj, res) => {
        var stations = radio_browser.listStations.end(res);
        …
        loop.quit();
    });
    loop.run();
}

В качестве дальнейшего чтения я бы порекомендовал раздел asyn c Учебного пособия по Vala и asy c примеры также в вики.

...