UserStream取得

TwitterのUserStreamを取得して、どんどんとmesしていくスクリプト。
hspextのpipeexec命令でも使って、別プロセスとして動かすことを想定して作りました。
固まることが多々あります。だからpipeを使えってことなんですけども。

TwitterのUserStreamを取得して、どんどんとmesしていくスクリプト。
hspextのpipeexec命令でも使って、別プロセスとして動かすことを想定して作りました。
固まることが多々あります。だからpipeを使えってことなんですけども。

#runtime "hsp3cl"

#packopt name "USA"





#module
#defcfunc strCnt str p1, str p2
	string = p1
	count=0 : i=-1
	repeat
		i = instr(string, i+1, p2)
		if i=-1 : break
		count++
	loop
	logmes "21"
return count

#deffunc getBlockStr str p1, int p2, int p3, var block, var other
	string = p1
	count= 0 : i=0
	sdim p2_s
	poke p2_s, 0, p2
	head=instr(string, 0, p2_s)
	if head=-1 : block="" : other=string : return block
	
	repeat ,head
		if peek(string, cnt)=$00 : return "-1"
		if peek(string, cnt)=p2 : count++
		if peek(string, cnt)=p3 : count--
		if count=0 : break
		i++
	loop
	
	block=strmid(string, head, i+1)
	other=strmid(string, head+i+1, strlen(string))
return block
#global


#include "TsubuyakiSoup.as"
#module UserStream

#uselib "crtdll.dll"
#func time "time" var

#uselib "wininet.dll"
#cfunc InternetOpen "InternetOpenA" sptr, int, sptr, sptr, int
#cfunc InternetOpenUrl "InternetOpenUrlA" int, str, sptr, int, int, int
#func InternetReadFile "InternetReadFile" int, var, int, var
#func InternetCloseHandle "InternetCloseHandle" int
#cfunc InternetConnect "InternetConnectA" int, str, int, sptr, sptr, int, int, int
#cfunc HttpOpenRequest "HttpOpenRequestA" int, sptr, str, sptr, sptr, sptr, int, int
#cfunc HttpSendRequest "HttpSendRequestA" int, sptr, int, sptr, int
#cfunc HttpQueryInfo "HttpQueryInfoA" int, int, var, var, int
#func InternetQueryDataAvailable "InternetQueryDataAvailable" int, int, int, int
#func InternetSetOption "InternetSetOptionA" int, int, int, int

#define INTERNET_FLAG_IGNORE_CERT_DATE_INVALID 0x2000
#define INTERNET_FLAG_IGNORE_CERT_CN_INVALID 0x1000

//------------------------------------------------------------
//OAuth認証を含めた、UserStreamの初期化
#deffunc UserStreamInit var p1, var p2, int p3, str p4, array p5
//  引数チェック&初期化
	sdim p1
	sdim p2
	API = p4
	if vartype(p5) != 2 : return 0
	hConnect = 0		//InternetConnectのハンドル
	hRequest = 0		//HttpOpenRequestのハンドル
	API_statcode = 0	//リクエストの結果コード
	API_p1Length = 0	//データ長
	API_rsize = 1024	//バッファ初期値
	API_hsize = 0		//取得したバイト数が代入される変数
	
	dup TS_AccessToken,TS_AccessToken@TsubuyakiSoup
	dup TS_Consumer_Key, TS_Consumer_Key@TsubuyakiSoup
	dup TS_Consumer_Secret,TS_Consumer_Secret@TsubuyakiSoup
	dup TS_AccessTokenSecret, TS_AccessTokenSecret@TsubuyakiSoup
	dup TS_RequestToken, TS_RequestToken@TsubuyakiSoup
	dup TS_RequestTokenSecret, TS_RequestTokenSecret@TsubuyakiSoup
//  メソッドの設定
	if (p3 = 1) {
		Method = "POST"
	} else {
		Method = "GET"
	}
//  ポート&フラグの設定
	UsePort = 443 : RequestFlag = -2147483648 | 0x800000 | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |INTERNET_FLAG_IGNORE_CERT_CN_INVALID : Scheme = "https"
	VersionStr = "2/"
	TokenStr = TS_AccessToken
	SigKey = TS_Consumer_Secret+" "+TS_AccessTokenSecret
	if (strmid(API,0,5) = "oauth") {
		VersionStr = ""
		if (API = "oauth/access_token") {
			repeat length(p5)
				if (p5(cnt) = "x_auth_mode=client_auth") : UsePort = 443 : RequestFlag = -2139082752 : Scheme = "https" : break
				if cnt = length(p5)-1 : TokenStr = TS_RequestToken : SigKey = TS_Consumer_Secret+" "+TS_RequestTokenSecret
			loop
		}
	}
//  シグネチャ生成
	SigArrayMax = 6 + length(p5)
	sdim SigArray, 500, SigArrayMax
	SigNonce = RandomString(8,32)
	time SigTime
	SigArray(0) = "oauth_consumer_key=" + TS_Consumer_Key
	SigArray(1) = "oauth_nonce=" + SigNonce
	SigArray(2) = "oauth_signature_method=HMAC-SHA1"
	SigArray(3) = "oauth_timestamp=" + SigTime
	SigArray(4) = "oauth_token="+ TokenStr
	SigArray(5) = "oauth_version=1.0"
	repeat SigArrayMax - 6
		SigArray(6+cnt) = p5(cnt)
	loop
	//ソート
	SortString SigArray
	//"&"で連結
	TransStr = ""+ Method +" "+ Scheme +"://userstream.twitter.com/"+ VersionStr + API +" "
	repeat SigArrayMax
		if SigArray(cnt) = "" : continue
		TransStr += SigArray(cnt) +"&"
	loop
	TransStr = strmid(TransStr, 0, strlen(TransStr)-1)
	Signature = SignatureEncode(TransStr, SigKey)
//  データ整形
	if (p3 = 1) {
		//POST
		PostStr = ""
		repeat SigArrayMax
			PostStr += SigArray(cnt) +"&"
		loop
		PostStr += "oauth_signature="+ Signature
		PostStrLen = strlen(PostStr)
		AddUrl = ""
	} else {
		//GET
		PostStr = 0
		PostStrLen = 0
		AddUrl = "?"
		repeat SigArrayMax
			AddUrl += SigArray(cnt) +"&"
		loop
		AddUrl += "oauth_signature="+ Signature
	}
	logmes TransStr
	//サーバへ接続
	hConnect = InternetConnect(TwiH_hInet@TsubuyakiSoup, "userstream.twitter.com", UsePort, 0, 0, 3, 0, 0)
	if (hConnect) {
		//リクエストの初期化
		hRequest = HttpOpenRequest(hConnect, Method, VersionStr+API+AddUrl, "HTTP/1.1", 0, 0, RequestFlag, 0)
		if (hRequest) {
			logmes VersionStr+API+AddUrl
			//サーバへリクエスト送信
			if ( HttpSendRequest(hRequest, 0, 0, PostStr, PostStrLen)) {
				API_statcode = 0
			} else {
				//サーバへリクエスト送信できなかった場合
				API_statcode = -2
			}
		} else {
			//Requestハンドルを取得できなかった場合
			API_statcode = -3
		}
		} else {
		//Connectハンドルを取得できなかった場合
		API_statcode = -4
	}
return API_statcode

//適当な部分もある、UserStreamのヘッダ取得
#deffunc getHead_US var p2
				//ヘッダを取得する変数の初期化
				p2Size = 3000
				sdim p2, p2Size
				//ヘッダの取得
				if ( HttpQueryInfo(hRequest, 22, p2, p2Size, 0) ) {
					//ヘッダの解析
					notesel p2
					repeat notemax
						noteget API_BufStr, cnt
						API_buf = instr(API_BufStr, 0, "Status: ")				//ステータスコード
						if (API_Buf != -1) : API_statcode = int(strmid(API_BufStr, API_buf+8, 3))
						API_buf = instr(API_BufStr, 0, "Content-Length: ")		//長さ
						if (API_Buf != -1) : API_p1Length = int(strmid(API_BufStr, -1, strlen(API_BufStr)-API_buf+16))
						API_buf = instr(API_BufStr, 0, "X-RateLimit-Limit: ")		//60分間にAPIを実行できる回数
						if (API_Buf != -1) : TS_RateLimit(0) = int(strmid(API_BufStr, -1, strlen(API_BufStr)-(API_buf+19)))
						API_buf = instr(API_BufStr, 0, "X-RateLimit-Remaining: ")	//APIを実行できる残り回数
						if (API_Buf != -1) : TS_RateLimit(1) = int(strmid(API_BufStr, -1, strlen(API_BufStr)-(API_buf+23)))
						API_buf = instr(API_BufStr, 0, "X-RateLimit-Reset: ")		//リセットする時間
						if (API_Buf != -1) : TS_RateLimit(2) = int(strmid(API_BufStr, -1, strlen(API_BufStr)-(API_buf+19)))
					loop
					noteunsel
				} else {
					//ヘッダの取得ができなかった場合
					API_statcode = -1
				}
return API_statcode

//適当な部分もある、UserStreamのデータ取得
#deffunc getBody_US var p1
				wait 10
				p2Size = 3000
				sdim p2, p2Size
					//入手可能なデータ量を取得
					InternetQueryDataAvailable hRequest, varptr(API_rsize), 0, 0
					//バッファの初期化
					sdim API_bufStr, API_rsize+1
					sdim p1, API_rsize+1
					repeat
						InternetReadFile hRequest, API_bufStr, API_rsize, API_hsize
						p1 += strmid(API_bufStr, 0, API_hsize)
						wait 10
						if (API_hsize = 1)||(API_hsize!API_rsize)||(API_hsize=0) : break 
					loop

return API_statcode

#global








#uselib "KERNEL32.DLL"
#cfunc OpenProcess "OpenProcess" int,int,int
#func GetExitCodeProcess "GetExitCodeProcess" int,int
#define PROCESS_QUERY_INFORMATION $400	//OpenProcess時に使う。


//コマンドライン解析用。http://lldev.jp/hsp/tips/miscellaneous.html#cmdlineprmsからDLしてください。
#include "cmdline_parser/gm_cmdline_parser.hsp"

;サンプル用設定ファイル
#include "SampleSetting.hsp"
if CONSUMER_KEY = "" : mes "「SampleSetting.hsp」でConsumerKeyとConsumerSecretを設定してください。" : end

	if getarg(0,1)="" : mes "USA: 引数が不正です。" : end		//引数が一つもない状態
	
	// 初期化
	TS_Init "TsubuyakiSoup Sample", CONSUMER_KEY, CONSUMER_SECRET, 20

	// 設定ファイルの有無確認
	xToken = ""
	xSecret = ""
	exist "Setting.txt"
	if strsize != -1 {
		notesel SFA
		noteload "Setting.txt"
		if (Decryption(SFA, "SampleKey")=0) : dialog "ファイルの復号に失敗したため、読み込むことができませんでした。終了します。" : end
		noteget xToken,0
		noteget xSecret,1
		noteunsel
		SetAccessToken xToken, xSecret
	}
	if ( (xToken ="") or (xSecret = "") ) : dialog "「Sample01_OAuth.hsp」か「Sample02_xAuth.hsp」を実行して「Setting.txt」を作成してください。" : end
	
	
	
	repeat						//コマンドラインの2~の要素を、UserStreamAPIに対しての引数とする。
		if getarg(cnt+2,1)="" : break
		Arg.cnt = getarg(cnt+2,1)
	loop
	parentpid = int(getarg(1,1))
	hParent=OpenProcess(PROCESS_QUERY_INFORMATION, 0, parentpid)	//親プロセス実行状況確認時に使う。
	if hParent=0 : mes "USA: error "+__LINE__ : wait 500 : end		//OpenProcessが実行できなかった場合。
	
	api = getarg(0,1)
	UserStreamInit body, head, 0, api, Arg	; HTTPS
	

	buf=""
*main
	;	結果待ちのためのループ
	wait 100
	
	getBody_US body
	buf+=body
	gosub *comp
	
	exitcode = 0
	GetExitCodeProcess hParent, varptr(exitcode)	//親プロセスの実行状況確認
	if exitcode!$103 : goto *exit					//親プロセスが閉じられていたら、*exitへ。
	wait 30
	goto *main

*exit
	//親プロセスが閉じられたっぽい。
	mes "USA: exit"
	wait 500
	end
	
*comp
	;	完了
	getBlockStr body, '{', '}', block, buf	//bodyの{と}の間をブロックとしてblockに格納、余ったごみをbufへ。
	mes block
	return