pike.git / lib / modules / Web.pmod / Api.pmod / Api.pike

version» Context lines:

pike.git/lib/modules/Web.pmod/Api.pmod/Api.pike:2:      //! Base class for implementing a @tt{(RESTful) WebApi@} like Facebook's   //! Graph API, Instagram's API, Twitter's API and so on.   //!   //! @b{Note:@} This class is useless in it self, and is intended to be   //! inherited by classes implementing a given @tt{Web.Api@}.   //!   //! Look at the code in @[Web.Api.Github], @[Web.Api.Instagram],   //! @[Web.Api.Linkedin] etc to see some examples of implementations.    + //#define SOCIAL_REQUEST_DEBUG +    #if defined(SOCIAL_REQUEST_DEBUG) || defined(SOCIAL_REQUEST_DATA_DEBUG)   # define TRACE(X...) werror("%s:%d: %s",basename(__FILE__),__LINE__,sprintf(X))   #else   # define TRACE(X...) 0   #endif      //! The URI to the remote API   constant API_URI = 0;      //! In some API's (LinkedIn f ex) this is named something else so it needs
pike.git/lib/modules/Web.pmod/Api.pmod/Api.pike:27:   //! is decoded.   protected constant DECODE_UTF8 = 0;      //! If @expr{1@} @[Standards.JSON.decode_utf8()] will be used when JSON data   //! is decoded.   public int(0..1) utf8_decode = DECODE_UTF8;      //! Request timeout in seconds. Only affects async queries.   public int(0..) http_request_timeout = 0;    + #if constant (Protocols.HTTP.Promise)   //! Typedef for the async callback method signature. - typedef function(mapping,Protocols.HTTP.Query:void) Callback; + typedef function(mixed,Protocols.HTTP.Query|Protocols.HTTP.Promise.Result:void) Callback; + #else + //! Typedef for the async callback method signature. + typedef function(mixed,Protocols.HTTP.Query:void) Callback; + #endif      //! Typedef for a parameter argument   typedef mapping|Web.Auth.Params ParamsArg;      //! Authorization object.   //!   //! @seealso   //! @[Web.Auth.OAuth2]   protected Web.Auth.OAuth2.Client _auth;   
pike.git/lib/modules/Web.pmod/Api.pmod/Api.pike:52:   //! The HTTP query objects when running async.   protected mapping(int:array(Protocols.HTTP.Query|Callback))    _query_objects = ([]);      protected mapping(string:string) default_headers = ([    "user-agent" : .USER_AGENT   ]);      protected int _call_id = 0;    + #define IS_BACKEND_THREAD() (this_thread() == master()->backend_thread()) +    //! Creates a new Api instance   //!   //! @param client_id   //! The application ID   //!   //! @param client_secret   //! The application secret   //!   //! @param redirect_uri   //! Where the authorization page should redirect back to. This must be
pike.git/lib/modules/Web.pmod/Api.pmod/Api.pike:261:    array(string) parts = make_multipart_message(params, data);    request_headers["content-type"] = parts[0];    data = parts[1];    params = 0;    }    }    else {    params = (mapping) p;    }    + #if constant (Protocols.HTTP.Promise) +  // If running in a handler thread (like in Roxen) we do an async call +  // but wait for the request to finish before returning. In this way we +  // can abort the request if it takes to long so that the handler thread +  // can be released. +  if (cb || !IS_BACKEND_THREAD()) { +  Thread.Queue queue; +  mixed retval; +  +  Protocols.HTTP.Promise.Arguments args; +  args = Protocols.HTTP.Promise.Arguments(([ +  "maxtime" : http_request_timeout, +  "variables" : params, +  "headers" : request_headers, +  "data" : data +  ])); +  +  Concurrent.Future fut; +  fut = Protocols.HTTP.Promise.do_method(http_method, api_method, args); +  +  fut->on_success(lambda (Protocols.HTTP.Promise.Result res) { +  mixed r = handle_response(res); +  +  if (res->status >= 200 && res->status < 400) { +  if (cb) cb(r, res); +  else retval = r; +  } +  else { +  cb && cb(0, res); +  } +  +  if (queue) { +  queue->write("@"); +  } +  }) +  ->on_failure(lambda (Protocols.HTTP.Promise.Result res) { +  cb && cb(0, res); +  if (queue) { +  queue->write("@"); +  } +  }); +  +  if (!cb) { +  queue = Thread.Queue(); +  queue->read(); +  return retval; +  } +  +  return 0; +  } +  +  TRACE("Have promises but no async call or running on backend thread\n"); +  + #endif /* Protocols.HTTP.Promise */ +     Protocols.HTTP.Query req = Protocols.HTTP.Query();       if (http_request_timeout) {    if (has_index(req, "maxtime")) {    req->maxtime = http_request_timeout;    }    else {    req->timeout = http_request_timeout;    }    }
pike.git/lib/modules/Web.pmod/Api.pmod/Api.pike:419:    m[1](0, 0);    }    }    destruct(q);    };    }       _query_objects = ([]);   }    + #if constant (Protocols.HTTP.Promise) + protected mixed handle_response(Protocols.HTTP.Query|Protocols.HTTP.Promise.Result req) + #else   protected mixed handle_response(Protocols.HTTP.Query req) -  + #endif   {    TRACE("Handle response: %O\n", req);    -  if ((< 301, 302 >)[req->status]) +  if ((< 301, 302 >)[req->status]) {    return req->headers; -  +  }    - #ifdef SOCIAL_REQUEST_DATA_DEBUG -  TRACE("Data: [%s]\n\n", req->data()||"(empty)"); +  string d; +  + #if constant (Protocols.HTTP.Promise) +  if (stringp(req->data)) { +  d = req->data; +  } +  else { +  d = req->data(); +  } + #else +  d = req->data();   #endif       if (req->status != 200) { -  string d = req->data(); -  +     TRACE("Bad resp[%d]: %s\n\n%O\n", -  req->status, req->data(), req->headers); +  req->status, d, req->headers);       if (has_value(d, "error")) {    mapping e;    mixed err = catch {    e = Standards.JSON.decode(d);    };       if (e) {    if (e->error)    error("Error %d: %s. ", e->error->code, e->error->message);
pike.git/lib/modules/Web.pmod/Api.pmod/Api.pike:456:    error("Error %d: %s. ", e->meta->code, e->meta->error_message);    }       error("Error: %s", "Unknown");    }       error("Bad status (%d) in HTTP response! ", req->status);    }       if (utf8_decode) { -  TRACE("Decode UTF8: %s\n", req->data()); -  return Standards.JSON.decode_utf8(unescape_forward_slashes(req->data())); +  TRACE("Decode UTF8: %s\n", d); +  return Standards.JSON.decode_utf8(unescape_forward_slashes(d));    }    -  return Standards.JSON.decode(unescape_forward_slashes(req->data())); +  return Standards.JSON.decode(unescape_forward_slashes(d));   }      protected string _sprintf(int t)   {    return sprintf("%O(authorized:%O)", this_program,    (_auth && !!_auth->access_token));   }      //! Convenience method for getting the URI to a specific API method   //!