Skip to content

Instantly share code, notes, and snippets.

@alphaKAI
Last active October 12, 2015 09:26
Show Gist options
  • Save alphaKAI/0ddf2fb70240b25034f7 to your computer and use it in GitHub Desktop.
Save alphaKAI/0ddf2fb70240b25034f7 to your computer and use it in GitHub Desktop.
DocomoのAPIラッパーをD言語で書こうと思ってとりあえず書いてみた,対話APIと対話できるプログラム。API Keyを書き換えれば動きます。
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