e-tipsmemo

ごった煮

C++ Rest SDKでtwitter②

e-tipsmemo.hatenablog.com
の続き。

requestTokenが成功すると

oauth_token=xxxxxx&oauth_token_secret=yyyyy&hoge=zzzzz

みたいな文字列が返ってくる。
Request TokenとRequest Token Secretとなんとかid(つかわない)

https://api.twitter.com/oauth/authorize?oauth_token={oauth_token}
にアクセスするとPIN codeを貰えるので、それを次のAccess Tokenを得るときに使う。

requestTokenを得るときと同じ様にパラメータを作っていく。
signatureを作るときにSecret Keyを必要とするが、ここは先程得た、””Request Token Secret(oauth_token_secret)””を使う。


あとは同じ様に ヘッダーに入れてhttprequestを投げるだけ。


成功すれば、URI_queryのような形をしたものが返ってきて、失敗したらAuthentication Failedみたいな文字列を含んだJsonが返ってくる。
例外処理とかめんどくさくなったので、基本成功したと仮定して、
oauth_tokenはaccess token
oauth_token_secretはaccess token secret
ついでにuser idとscreen nameをパースする。

それらのパースに失敗したら認証失敗したことにしている。

ここで得られた、access tokenと、access token secretを保存しておけば次からはこれをつかってツイートなどできるので
毎回の認証操作は不要になる。
なのでこれらは厳密に保管されなければならない。

Twitter API ポケットリファレンス (POCKET REFERENCE)

Twitter API ポケットリファレンス (POCKET REFERENCE)

C++ Rest SDKでtwitter①

TwitterつかうアプリケーションでC++ Rest SDKを利用した。
C++ Rest SDKはexperimentalだがoauth1 oauth2の実装もしてあったが使い方がよくわからなかったので
httprequestを直接つかった。

Twitter認証のステップをメモしておく。

最初にrequestTokenを得る。

CONSUMER_KEYはTwitterのアプリを登録したときにもらうやつで。
ATS(ACCESS_TOKEN_SECRET)は最後にもらうやつなので、この時点では空文字
これらのパラメータはkeyでソートされている必要がある。

署名

C++ REST SDKuri_builderはfalseを引き数に取らないと、appendしたときに勝手に要素をuri_encodeしてくれてしまうので
何回もやると%が%25になる関係で %252525..とかになってTwitterからAuthentication Errorが帰ってきたりする。

署名にはHMAC-SHA1が必要なので以前書いたこのライブラリを利用している。
e-tipsmemo.hatenablog.com

このライブラリはstd::stringしか受け付けないので、windowsUnicodeを設定して開発しているならば変換する必要あがあった。
e-tipsmemo.hatenablog.com


パラメータを利用してAuth文字列を得る。


Authenticationの文字列は "=" と ","でつなげるらしくこれはライブラリにはなかったので素朴に書いた


ライブラリのhttpclientを利用して、POSTで投げる。

responseの文字列は成功すればurl_queryの形で帰ってきて失敗すると、jsonで返ってくるという様なので
取りあえず url_queryだとしてパースして
パースに失敗したらREQUEST_TOKENの値がおそらく空なのでそれで判定するという雑な感じでとりあえず実装した。

Visual Studio 2017 boost xml serialization

Nuget パッケージマネージャーでboostと検索して
プロジェクトのプラットフォームツールセットのバージョンにあったBoostをインストールする

f:id:katakanan:20180630112732p:plain
今回はv140を入れた。

準備

シリアライズしたいクラスに追加する。

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/string.hpp>

class hoge
{
public:
	int a;
	std::string b;

private:
	friend class boost::serialization::access;
	template <class Archive>
	void serialize(Archive& archive, unsigned int version) 
	{
		archive& boost::serialization::make_nvp("a", a);
		archive& boost::serialization::make_nvp("b", b);
	}
};

メンバに自作の別のクラスがある場合は、そのクラスにも似たようにserialize関数を実装すると
再帰的にシリアライズされてくれる。

STLのクラスには自分で実装できないので
~~~.hppをincludeするとできる(例: boost/serialization/string.hpp )

利用

#include <boost/archive/xml_oarchive.hpp>//書き出し
#include <boost/archive/xml_iarchive.hpp>//読み込み

書き出し

hoge h;
//hに値をセットする
std::ofstream ofs(TEXT("test.xml"), std::ios::trunc);
{
	boost::archive::xml_oarchive oarchive(ofs);
	oarchive << boost::serialization::make_nvp("Root", h);
} //ファイルを閉じる前にスコープを区切る
ofs.close();

スコープを切らないと、多分oarchiveのデストラクタが呼ばれなくて(?)、xmlタグが正しく閉じられない。
間違った形のxmlをiarchiveで読もうとすると、
input stream errorでプログラムが止まる。

読み込み

std::ifstream ifs(TEXT("test.xml"));
if (ifs.fail())
{
	return false;
}
hoge h;
{
	boost::archive::xml_iarchive iarchive(ifs);
	iarchive >> boost::serialization::make_nvp("Root", h);
}
//hが読めているはず

Visual Studio 2017 C++ Rest SDK static library build

Visual Studio 2017でcpprestsdkの静的リンクライブラリを作成したときにでてきたエラーの解決方法(2018/06/19)

Cannot fimd Build/Release.Tests.settings

github.com
からリポジトリをクローンするのだが、

WSLからgitコマンドを利用したところ、一部のファイルがうまく引っ張ってこれなくて、
Visual Studioでプロジェクトファイルが開けなかった。

解決策

zipでダウンロードした。
f:id:katakanan:20180619234850p:plain

Can't find v140 in Visual Studio 2017

Nugetからcpprestsdkを利用するときも書いたが、
build set が v140でないとコンパイルが通らない。

CL.exe not found

普通はvcvarsall.batがいつの時点でかで実行されてパスが通っているはずなのだが、
通っていない。

解決策

(install dir) : ~~ \2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx86\x86
環境変数のPathに追加する。

Can not open include file: 'vcruntime.h': No such file or directory

cpprestsdk.sinはVisual Studio 2015を想定しているから見つからないのだろうか。。。

解決策

cpprestsdk.static をクリックしてプロパティから
VC++ディレクトリの
インクルードディレクトリに
D:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\include
などを
追加する。

これでビルド通った。

C++のコンパクトなハッシュライブラリ

HMAC-SHA1を計算したかった。
win32にはcrypt32とかあるけどよくわからなかったので

github.com

便利

#include "../sha1.h"
#include "../hmac.h"

#include <string>
#include <vector>
#include <iostream>

int main()
{
    std::string input= "what do ya want for nothing?";
    std::string key = "Jefe";
    std::string hash = hmac<SHA1>(&input[0], input.size(), &key[0], key.size());
    std::cout << hash << std::endl;
    return 0;
}

f:id:katakanan:20180616111719p:plain

Test Cases for HMAC-MD5 and HMAC-SHA-1

ただし出力が16進数のstringなので、一旦char arrayなどにして解釈し直さないと、間違えることがある。

バイト列でほしいなら

std::string hash = hmac<SHA1>(&input[0], input.size(), &key[0], key.size());
std::vector<unsigned char> v(hash.length() / 2, 0);

for (size_t i = 0; i < hash.length() / 2; i++)
{
	std::string b = hash.substr(i * 2, 2);
	v[i] = std::stoi(b, NULL, 16);
}

こんな感じにする必要がある。

stringとwstringとtstring

Visual Studioで文字列を扱うとき、
以下の設定の違いで

f:id:katakanan:20180616104252p:plain
f:id:katakanan:20180616104219p:plain

TCHARの定義がかわる。
f:id:katakanan:20180616104721p:plain
参考
Tchar.h における汎用テキストのマッピング

typedef std::basic_string<TCHAR> tstring;
typedef std::basic_stringstream<TCHAR> tstringstream;
typedef std::basic_ostringstream<TCHAR> tostringstream;
typedef std::basic_istringstream<TCHAR> tistringstream;

どこかのサイトで見たが、こうしておけばどちらにでも対応できる。
(本当は最初から std::wstring で良かった)

Unicode文字セットのときの、
上の定義でのtstringはstd::wstringと同じであり、
std::stringとの相互変換方法を調べた。

見つかったサイト。
kryozahiro.hateblo.jp

このサイトではwcstombsという関数を使っているが、これはもう古くてでVisual Studio 2017ではエラーがでてしまうので
微修正した。

//std::wstring -> std::string
void narrow(const std::wstring &src, std::string &dest) {
	char *mbs = new char[src.length() * MB_CUR_MAX + 1];
	size_t i;
	wcstombs_s(&i, mbs, src.length() * MB_CUR_MAX + 1, src.c_str(), src.length() * MB_CUR_MAX + 1);

	dest = mbs;
	delete[] mbs;
}
//std::string -> std::wstring
void widen(const std::string &src, std::wstring &dest) {
	wchar_t *wcs = new wchar_t[src.length() + 1];
	size_t i;
	mbstowcs_s(&i, wcs, src.length() + 1, src.c_str(), src.length() + 1);
	dest = wcs;
	delete[] wcs;
}

多分これで良いんじゃないかとおもう。

C++ Rest SDK Visual Studio 2017 E0427 Error

WindowsでWin32のアプリを作っていたとき
http requestとかするときいいライブラリないなみたいな記憶があって
わざわざC++/CLIで、C#のHttpRequestクラスみたいなものをつかてたけども、

MicrosoftのメンテしているC++ Rest SDKという物があったらしい。
(いつのまにか?)
github.com

Visual StudioだとNuget経由で簡単にパッケージの追加と削除が可能になっていてとても良いけども
なぜかメニューバーのツールメニューからNugetの項目が消える。
意味不明だ・・・

なんとかNuget経由で、cpprestsdkをインストールする

そうしたところ、以下のようなエラーがでた。
f:id:katakanan:20180614030219p:plain

調べたところプラットフォームツールセットが新しいのがいけない?

そこで、以下を追加インストールする。
f:id:katakanan:20180614030624p:plain

そしてプロジェクトのプロパティで Visual Studio 2015 (v140)を選択する。

f:id:katakanan:20180614030957p:plain

これでビルドできた。
v141とv140で何が違うんだろうか。