Last active
October 12, 2015 09:26
-
-
Save alphaKAI/0ddf2fb70240b25034f7 to your computer and use it in GitHub Desktop.
DocomoのAPIラッパーをD言語で書こうと思ってとりあえず書いてみた,対話APIと対話できるプログラム。API Keyを書き換えれば動きます。
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
import std.net.curl, | |
std.algorithm.iteration, | |
std.string, | |
std.base64, | |
std.json, | |
std.conv; | |
import std.stdio; | |
class TaiwaService{ | |
private string baseURL; | |
private string apiKey; | |
struct Parameter{ | |
string utt; | |
string context, | |
nickname, | |
nickname_y, | |
sex,//男 or 女 | |
bloodtype; | |
string birthdateY, | |
birthdateM, | |
birthdateD, | |
age; | |
string constellations; | |
string place, | |
mode,//srtr or dialog | |
t;//null: normal, 20: 関西弁, 30:赤ちゃん | |
static bool isDefault(string s){ | |
return s == null; | |
} | |
void showOptions(){ | |
mixin( | |
["utt", "context", "nickname", "nickname_y", "sex", | |
"bloodtype", "birthdateY", "birthdateD", "birthdateM", | |
"constellations", "mode", "t", "age"].map!(e => | |
"writeln(\"" ~ e ~ ":\"," ~ e ~ ");" | |
).join | |
); | |
} | |
} | |
this(bool useDocomoID = false){ | |
baseURL = useDocomoID ? | |
"https://api.apigw.smt.docomo.ne.jp/dialogue/v2/dialogue" : | |
"https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue"; | |
} | |
void setAPIKey(string _apiKey){ | |
apiKey = _apiKey; | |
} | |
string request(Parameter params, bool oauth = false, string accessToken = null){ | |
string rString; | |
auto http = HTTP(baseURL ~ "?" ~ "APIKEY=" ~ apiKey); | |
http.method = HTTP.Method.post; | |
http.setPostData(buildJsonString(params), "application/json"); | |
if(oauth) | |
http.addRequestHeader("Authorization", "Bearer " ~ accessToken); | |
http.onReceive = (ubyte[] data){ | |
rString = cast(string)data; | |
return data.length; | |
}; | |
http.perform; | |
return rString; | |
} | |
string buildElem(string key, string value){ | |
return "\"" ~ key ~ "\":\"" ~ value ~ "\""; | |
} | |
string buildJsonString(Parameter params){ | |
string rString; | |
string[] optionArray; | |
rString ~= "{"; | |
optionArray ~= buildElem("context", params.context); | |
mixin( | |
["utt", "context", "nickname", "nickname_y", "sex", | |
"bloodtype", "birthdateY", "birthdateD", "birthdateM", | |
"constellations", "mode", "t", "age"].map!(e => | |
"if(!Parameter.isDefault(params." ~ e ~ "))" | |
~ "optionArray ~= buildElem(\"" ~ e ~ "\", params." ~ e ~ ");").join | |
); | |
rString ~= optionArray.join(","); | |
rString ~= "}"; | |
//writeln(rString);//debug | |
return rString; | |
} | |
} | |
class Docomo4D{ | |
private string apiKey; | |
public TaiwaService taiwa; | |
this(string _apiKey){ | |
apiKey = _apiKey; | |
} | |
void initTaiwa(bool useDocomoID = false){ | |
taiwa = new TaiwaService(useDocomoID); | |
taiwa.setAPIKey(apiKey); | |
} | |
auto authorization(string client_id, string redirect_uri, string _scope){ | |
import std.uuid : randomUUID; | |
string baseURL = "https://api.smt.docomo.ne.jp/cgi11d/authorization"; | |
string[string] params = [ | |
"response_type":"code", | |
"client_id": client_id, | |
"redirect_uri": redirect_uri, | |
"scope" : _scope, | |
"state" : "sdabas" | |
]; | |
string path = params.keys.map!(k => k ~ "=" ~ params[k]).join("&"); | |
auto http = HTTP(); | |
return get(baseURL ~ "?" ~ path); | |
} | |
auto token(string client_id, string client_secret, | |
string code/* refresh -> refresh_token */, | |
string redirect_uri/* refresh -> scope */, bool refresh = false){ | |
string baseURL = "https://api.smt.docomo.ne.jp/cgi12/token"; | |
string[string] params = [ | |
"grant_type": refresh ? "refresh_token" : "authorization_code" | |
]; | |
if(refresh){ | |
params["refresh_token"] = code; | |
params["scope"] = redirect_uri; | |
} else { | |
params["code"] = code; | |
params["redirect_uri"] = redirect_uri; | |
} | |
auto http = HTTP(baseURL); | |
string authorize; | |
authorize = [client_id, client_secret].map!(e => urlEncode(e)).join(":"); | |
//writeln(authorize);//debug | |
authorize = Base64.encode(cast(ubyte[])authorize); | |
http.addRequestHeader("Authorization", "Basic " ~ authorize); | |
string path = params.keys.map!(k => k ~ "=" ~ params[k]).join("&"); | |
http.addRequestHeader("Content-Length", path.length.to!string); | |
http.setPostData(path, "application/x-www-form-urlencoded;charset=UTF-8"); | |
string rString; | |
http.onReceive = (ubyte[] data){ | |
rString = cast(string)data; | |
return data.length; | |
}; | |
http.perform; | |
return rString; | |
} | |
private{ | |
static string urlEncode(string urlString){ | |
import std.ascii : letters, digits; | |
import std.format, | |
std.array, | |
std.algorithm; | |
enum exChars = letters ~ digits ~ "-._~"; | |
auto result = appender!string; | |
result.reserve(urlString.length); | |
foreach(char charc; urlString){ | |
if(exChars.canFind(charc)) | |
result ~= charc; | |
else | |
formattedWrite(result, "%%%X", charc); | |
} | |
return result.data; | |
} | |
} | |
} | |
immutable apiKey = "Your API Key"; | |
void getAccessToken(){ | |
/* | |
AccessTokenを得る方法(OAuth2による認証のために必要) | |
1. DocomoIDを作る | |
2. API Keyを取得する | |
3. 下のプログラムのclient_id, client_secret, redirect_uri, scopeを自分のものに書き換える | |
(以下ではredirect_uriはhttps://localhostにしてあるものと仮定) | |
4. getAccessToken関数をmain関数に名前を変更(main関数は適当に_mainにでもしておけば良い) | |
5. そこでビルド&実行 | |
% dmd docomo4d.d -L-lcurl | |
% ./docomo4d | |
6. 正常に実行されればHTMLが吐き出される(Docomoから認証ページが降ってくる)のでそれを適当なファイルに保存してブラウザで開き | |
DocomoIDでログイン&認証をする | |
7. リダイレクト後にURLバーを開きcodeの値を取り出してコンソールに戻りそれを入力してenter | |
8. そのcodeが正常な値なのであれば多分refresh_tokenとかaccess_tokenが降ってくるのでそこからaccess_tokenを取り出せばよい | |
*/ | |
Docomo4D d4d = new Docomo4D(apiKey); | |
d4d.authorization("client_id", "redirect_uri", "scope(ex:dialogue)").writeln; | |
write("code=> "); | |
string code = readln.chomp; | |
d4d.token( | |
"client_id", | |
"client_secret", | |
code, | |
"redirect_uri").writeln; | |
} | |
void main(){ | |
Docomo4D d4d = new Docomo4D(apiKey); | |
d4d.initTaiwa;//DocomoIDによる認証をする場合はtrueを引数として渡す | |
d4d.taiwa.Parameter params; | |
while(true){ | |
writeln("normal Mode"); | |
write("> "); | |
string input = readln.chomp; | |
if(input == "exit") | |
return; | |
else if(input == "showOptions") | |
params.showOptions; | |
else if(input == "setOption"){ | |
while(true){ | |
writeln("\tsetOption mode"); | |
write("\t> "); | |
string _input = readln.chomp; | |
if(_input == "exit") | |
break; | |
else{ | |
string key = _input.split("=")[0], | |
value = _input.split("=")[1]; | |
mixin( | |
["utt", "nickname", "nickname_y", "sex", | |
"bloodtype", "birthdateY", "birthdateD", "birthdateM", | |
"constellations", "mode", "t", "age"].map!(e => | |
"if(key == \"" ~ e ~ "\")" | |
~ "params." ~ e ~ "= value;" | |
).join | |
); | |
} | |
} | |
} else { | |
//プロンプトにsetOptionと入力し、setOption modeに移行後 | |
//キー=値で年齢等を設定可能 | |
//このように直接値を代入してもよい | |
/* | |
params.nickname = "alphaKAI"; | |
params.nickname_y = "あるふぁかい"; | |
params.sex = "男"; | |
params.bloodtype = "A"; | |
params.birthdateY = "1997"; | |
params.birthdateM = "9"; | |
params.birthdateD = "1"; | |
params.age = "18"; | |
params.constellations = "乙女座"; | |
params.place = "福井"; | |
params.mode = "dialog"; | |
params.t = "0";*/ | |
if(params.context == null) | |
params.context = ""; | |
params.utt = input; | |
//writeln(params);//debug | |
string res = d4d.taiwa.request(params);//Docomo IDによる認証&OAuth2をしない場合 | |
//string res = d4d.taiwa.request(params, true, "access_token");//Docomo IDとOAuth2による認証をする場合 | |
//writeln(res);//debug | |
JSONValue parsed = parseJSON(res); | |
writeln("=>>" ~ parsed.object["utt"].str); | |
params.context = parsed.object["context"].str; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment