Skip to content

Instantly share code, notes, and snippets.

@alphaKAI
Last active June 13, 2018 19:53
Show Gist options
  • Save alphaKAI/48bf34e9802aeceec8771acd0d8a8a3a to your computer and use it in GitHub Desktop.
Save alphaKAI/48bf34e9802aeceec8771acd0d8a8a3a to your computer and use it in GitHub Desktop.
Twitter API Client in OCaml (Nocrypto, base64, OCurl, ocaml-uri)
#use "topfind";;
#require "nocrypto";;
#require "base64";;
#require "curl";;
#require "uri";;
let debug = true;;
let baseUrl = "https://api.twitter.com/1.1/";;
type request_method =
| POST
| GET;;
let rm_to_string = function
| POST -> "POST"
| GET -> "GET";;
let url_encode x = Uri.pct_encode ~component:`Userinfo x;;
let getUnixtime = Unix.time () |> int_of_float |> string_of_int;;
let starts_with s1 s2 =
let len1 = String.length s1
and len2 = String.length s2 in
if len1 < len2 then false else
let sub = String.sub s1 0 len2 in
(sub = s2);;
let buildParams consumerKey accessToken aparams = [
("oauth_consumer_key", consumerKey);
("oauth_nonce", "abcdef");
("oauth_signature_method", "HMAC-SHA1");
("oauth_timestamp", getUnixtime);
("oauth_token", accessToken);
("oauth_version", "1.0")
] @ aparams |> List.map (fun (x, y) -> (x, url_encode y));;
let signature _method url consumerSecret accessTokenSecret params =
let query = params |> List.map (fun (x, y) -> x ^ "=" ^ y) |> String.concat "&" in
(if debug then Printf.printf "query : %s\n" query);
let key = [consumerSecret; accessTokenSecret] |> List.map (fun x -> url_encode x) |> String.concat "&" in
(if debug then Printf.printf "key : %s\n" key);
let base = [_method; url; query] |> List.map (fun x -> url_encode x) |> String.concat "&" in
(if debug then Printf.printf "base : %s\n" base);
let oauthSignature = Nocrypto.Hash.SHA1.hmac ~key:(Cstruct.of_string key) (Cstruct.of_string base)
|> Cstruct.to_string |> B64.encode |> url_encode in
(if debug then Printf.printf "oauthSignature : %s\n" oauthSignature);
oauthSignature;;
let writeFunc s =
begin
Printf.printf "RECIVED!!!\n";
Printf.printf "[writeFunc] %s\n" s;
flush stdout;
String.length s
end;;
(* REST API *)
let request _method endpoint consumerKey consumerSecret accessToken accessTokenSecret aparams =
let method_str = rm_to_string _method in
let params = buildParams consumerKey accessToken aparams in
let url = baseUrl ^ endpoint in
let oauth_signature = signature method_str url consumerSecret accessTokenSecret params in
let xparams = [("oauth_signature", oauth_signature)] @ params in
let authorizeKeys = xparams |> List.filter (fun (x, _) -> starts_with x "oauth_") in
let authorize = "Authorization: OAuth " ^ (authorizeKeys |> List.map (fun (x, y) -> x ^ "=" ^ y) |> String.concat ",") in
let path = xparams |> List.map (fun (x, y) -> x ^ "=" ^ y) |> String.concat "&" in
if debug then
begin
Printf.printf "method: %s\n" @@ rm_to_string _method;
Printf.printf "path: %s\n" path;
Printf.printf "authorize: %s\n" authorize;
end;
let connection = Curl.init () in
if _method == POST then
begin
Curl.setopt connection (Curl.CURLOPT_POST true);
Curl.setopt connection (Curl.CURLOPT_POSTFIELDS path);
Curl.setopt connection (Curl.CURLOPT_POSTFIELDSIZE (String.length path));
Curl.set_url connection url
end
else
begin
let reqURL = url ^ "?" ^ path in
Curl.set_url connection reqURL
end;
Curl.set_writefunction connection writeFunc;
Curl.set_httpheader connection [authorize];
Curl.perform connection;
Curl.cleanup connection;;
(* STREAMING API *)
let stream url consumerKey consumerSecret accessToken accessTokenSecret aparams =
let params = buildParams consumerKey accessToken aparams in
let oauth_signature = signature (rm_to_string GET) url consumerSecret accessTokenSecret params in
let xparams = [("oauth_signature", oauth_signature)] @ params in
let authorizeKeys = xparams |> List.filter (fun (x, _) -> starts_with x "oauth_") in
let authorize = "Authorization: OAuth " ^ (authorizeKeys |> List.map (fun (x, y) -> x ^ "=" ^ y) |> String.concat ",") in
let path = xparams |> List.map (fun (x, y) -> x ^ "=" ^ y) |> String.concat "&" in
if debug then
begin
Printf.printf "path: %s\n" path;
Printf.printf "authorize: %s\n" authorize;
end;
let connection = Curl.init ()
and reqURL = url ^ "?" ^ path in
Curl.set_url connection reqURL;
Curl.set_writefunction connection writeFunc;
Curl.set_httpheader connection [authorize];
Curl.setopt connection (Curl.CURLOPT_SSLVERIFYPEER false);
Curl.set_timeout connection 0;
Curl.perform connection;
Curl.cleanup connection;;
let () =
Curl.global_init Curl.CURLINIT_GLOBALALL;
begin
let consumerKey = "Your Consumer Key"
and consumerSecret = "Your Consumer Secret"
and accessToken = "Your Access Token"
and accessTokenSecret = "Your Access Token Secret"
and _method = POST
and endpoint = "statuses/update.json"
and params = [("status", "Tweeting via OCaml!!!")] in
(* REST API *)
request _method endpoint consumerKey consumerSecret accessToken accessTokenSecret params ;
(* STREAMING API *)
stream "https://userstream.twitter.com/1.1/user.json" consumerKey consumerSecret accessToken accessTokenSecret []
end;
Curl.global_cleanup ()
;;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment