Last active
June 13, 2018 19:53
-
-
Save alphaKAI/48bf34e9802aeceec8771acd0d8a8a3a to your computer and use it in GitHub Desktop.
Twitter API Client in OCaml (Nocrypto, base64, OCurl, ocaml-uri)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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