Asynchronous 异步Vala示例

Asynchronous 异步Vala示例,asynchronous,vala,libsoup,Asynchronous,Vala,Libsoup,在Michael Lauer博士的《Vala简介》一书中,他提到lib-Soup异步api已被破坏。我正在努力使用session.queue\u message编写一个简单的示例,该示例用于查询使用该服务的无线电台。这是我的密码。我非常感谢像“Al Thomas”这样有经验的程序员提供的任何帮助。多谢各位 public class Station : Object { // A globally unique identifier for the change of the stati

在Michael Lauer博士的《Vala简介》一书中,他提到lib-Soup异步api已被破坏。我正在努力使用
session.queue\u 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;
    }
公共类站:对象{
//用于更改站点信息的全局唯一标识符
公共字符串changeuuid{get;set;default=”“;}
//站点的全局唯一标识符
公共字符串StationUID{get;set;default=”“;}
//车站的名称
公共字符串名称{get;set;default=”“;}
//用户提供的流URL
公共字符串url{get;set;default=”“;}
//等等…许多属性
公共字符串到_字符串(){
var builder=newstringbuilder();
builder.append\u printf(“\nchangeuuid=%s\n”,changeuuid);
builder.append\u printf(“stationuid=%s\n”,stationuid);
builder.append\u printf(“name=%s\n”,name);
builder.append\u printf(“url=%s\n”,url);
返回(拥有)builder.str;
}
}
公共类RadioBrowser:对象{
私有静态会话;
//专用静态主回路主回路;
公共常量字符串API_URL=”https://de1.api.radio-browser.info/json/stations";
public const string USER_AGENT=“github.aeldemery.radiolibrary”;
公共无线浏览器(字符串user\u agent=user\u agent,uint timeout=50)
需要(超时>0)
{
Intl.setlocale();
session=newsoup.session();
session.timeout=超时;
session.user\u agent=user\u agent;
session.use\u thread\u context=true;
//main_loop=新的MainLoop();
}
私有无效检查\响应\状态(Soup.Message msg){
如果(msg.status_code!=200){
var str=“Error:状态消息错误%s.”。printf(msg.reason\u短语);
错误(str);
}
}
公共Gee.ArrayList列表站(){
var stations=new Gee.ArrayList();
var data_list=Datalist();
数据列表。设置数据(“限制”、“100”);
var parser=newjson.parser();
parser.array_element.connect((PAR、数组、索引)=>{
var station=Json.gobject_反序列化(typeof(station)、array.get_元素(index))作为station;
断言非空(站);
stations.add(station);
});
var msg=Soup.Form.request\u new\u from\u datalist(
“职位”,
API_URL,
数据表
);
//发送消息有效,但队列消息无效
//session.send_消息(msg);
session.queue_消息(msg,(sess,mess)=>{
检查\u响应\u状态(msg);
试一试{
parser.load_from_data((string)msg.response_body.flatte().data);
}捕获(错误e){
错误(“分析数据失败,错误:+e.message”);
}
});
返回站;
}
}
int main(字符串[]args){
var radio_browser=新的RadioBrowser();
var stations=radio_browser.listStations();
断言非空(站);
foreach(变电站中的var站){
打印(station.to_字符串());
}
返回0;
}

虽然我不是艾尔·托马斯,但我还是可以帮上忙的

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

作为进一步阅读,我建议您阅读Vala教程的部分,以及wiki上的。

非常感谢。虽然我注意到lamda外的站点不可见,因此所有循环站点必须位于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();
}