1

Michael Lauer博士的“Vala 简介”一书中,他提到 lib Soup 异步 api 已损坏。我正在努力使用来自radio-browsersession.queue_message的服务使用该查询广播电台编写一个简单的示例。这是我的代码。我将不胜感激来自像“Al Thomas”这样有经验的程序员的任何帮助。谢谢你。

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;
    }
4

1 回答 1

1

虽然我不是 Al Thomas,但我仍然可以提供帮助。;)

要使异步调用在其中工作,需要运行一个主循环,并且通常来自主程序线程。因此,您希望从您的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();
}

此外,如果您想等待异步调用完成,您通常需要使用yield来自另一个异步函数的关键字进行调用,例如:

    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;
    }

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();
}

作为进一步阅读,我会推荐Vala 教程的async 部分,以及 wiki 上的asyc 示例

于 2020-04-26T03:14:25.450 回答