v8にはunevalが無かったのでdankogaiさん作のuneval.jsを使わせて頂いた。
実行画面はblosxom.rhinoの書き換えなので、パクリ気味ですが...
fcgi-v8でファイル日付の取得が実装出来ていないので、今は日付は表示されていません。![]()
blosxom.v8よかったら遊んでみて下さい。
fcgi-v8でファイル日付の取得が実装出来ていないので、今は日付は表示されていません。![]()
blosxom.v8よかったら遊んでみて下さい。
FILE* fp = fopen(...);
v8::Local<v8::Object> obj = v8::Object::New();
obj->Set(v8::String::New("value"), v8::External::New((void*)fp));
という様に、v8::Externalでメンバを追加してやれば良い。
v8::Handle<v8::Value> Print(const v8::Arguments& args) {
bool first = true;
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope;
if (first) {
first = false;
} else {
printf(" ");
}
v8::String::AsciiValue str(args[i]);
printf("%s", *str);
}
printf("\n");
return v8::Undefined();
}
となってて、何でも文字列化してくれる様に思えてた。で実際
var obj = test();
print(obj.value); // ここでクラッシュ
こんな事やると落ちてしまうんだけど、良く考えたらExternalって言ってるんだから値の出しようもない。確かに以下の様なコードをshell.ccに含ませ
global->Set(v8::String::New("hoge"), v8::External::New(NULL));
javascriptから"print(hoge)"で例外を発生させた際のデバッグ出力で確かめたら
==== Stack trace ============================================
(No security context)
1: DefaultString(this=00C104BD <JS Object>#0#,x=00E0068D <Proxy>#1#)
(No security context)
2: ToString(this=00C104BD <JS Object>#0#,x=00E0068D <Proxy>#1#)
6: arguments adaptor frame: 1->0
Security context: 00E006A1 <FixedArray[41]>#2#
7: /* anonymous */(this=00C10361 <JS Global Object>#3#)
==== Details ================================================
(No security context)
[1]: DefaultString(this=00C104BD <JS Object>#0#,x=00E0068D <Proxy>#1#) {
// stack-allocated locals
var v = 01000135 <undefined>
var s = 01000135 <undefined>
// expression stack (top to bottom)
[04] : 01000361 <String[8]: toString>
[03] : 00E0068D <Proxy>#1#
[02] : 00E0068D <Proxy>#1#
--------- s o u r c e c o d e ---------
function DefaultString(x) {? if ((typeof(x.toString) === 'function')) {? var s = x.toString();? if (%IsPrimitive(s)) return s;? }? if ((typeof(x.valueOf) === 'function')) {? var v = x.valueOf();? if (%IsPrimitive(v)) return v;? }? throw %MakeTypeError('cannot_convert_to_primitive', []);?}
-----------------------------------------
}
(No security context)
[2]: ToString(this=00C104BD <JS Object>#0#,x=00E0068D <Proxy>#1#) {
// expression stack (top to bottom)
[02] : 01002845 <String[13]: DefaultString>
[01] : 00C104BD <JS Object>#0#
[00] : 0100232D <String[8]: ToString>
--------- s o u r c e c o d e ---------
function ToString(x) {? if ((typeof(x) === 'string')) return x;? if ((typeof(x) === 'number')) return %NumberToString(x);? if ((typeof(x) === 'boolean')) return x ? 'true' : 'false';? if ((typeof(x) === 'undefined')) return 'undefined';? return ((x === null)) ? 'null' : %ToString(%DefaultString(x));?}
-----------------------------------------
とNULL参照している事が分かる。v8からすると"訳分かんない物をToStringして表示しようとしただけさ。"と言ったところか。
if (argv[0]->IsExternal()) {
printf("[native code]");
continue;
}
よくブラウザなんかで見かける"[native code]"という表示になる様にしました。
typedef enum _OBJECT_TYPE {
OBJECT_TYPE_FILE_POINTER, // FILE*
OBJECT_TYPE_WINDOW_HANDLE // ウィンドウハンドル
} OBJECT_TYPE;
typedef struct _OBJECT_VALUE {
OBJECT_TYPE type;
void* object;
} OBJECT_VALUE;
// 設定
OBJECT_VALUE* val = new OBJECT_VALUE;
val->type = OBJECT_TYPE_FILE_POINTER;
val->object = fopen("test.dat", "rb");
obj->Set(v8::String::New("value"), v8::External::New((void*)val));
// 取得
v8::Local<v8::Value> valueobj = obj->Get(v8::String::New("value"));
if (!valueobj->IsExternal()) return v8::ThrowException(v8::String::New("Exception: invalid object"));
OBJECT_VALUE* val = static_cast< OBJECT_VALUE* >(v8::Handle<v8::External>::Cast(valueobj)->Value());
if (val->type == OBJECT_TYPE_FILE_POINTER) {
// FILE*な処理
} else
if (val->type == OBJECT_TYPE_WINDOW_HANDLE) {
// ウィンドウハンドルな処理
}
こんな構造と設定および取得をすべき、という事になる。ここまで気付くのに結構時間を使ってしまった。
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
v8::Local<v8::Template> p = t->PrototypeTemplate();
p->Set("friendsTimeline", v8::FunctionTemplate::New(TwitterFriendsTimeline));
p->Set("updateStatus", v8::FunctionTemplate::New(TwitterUpdateStatus));
v8::Local<v8::ObjectTemplate> i = t->InstanceTemplate();
i->Set(v8::String::New("username"), v8::String::New(""));
i->Set(v8::String::New("password"), v8::String::New(""));
global->Set(v8::String::New("Twitter"), t);
このTwitterFriendsTimelineには以下の様なコードを...
v8::Handle<v8::Value> TwitterFriendsTimeline(const v8::Arguments& args) {
v8::Handle<v8::Value> ret = v8::Undefined();
v8::Local<v8::Object> This = args.This();
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
v8::String::AsciiValue username(This->Get(v8::String::New("username")));
v8::String::AsciiValue password(This->Get(v8::String::New("password")));
CURL* curl = NULL;
CURLcode res = CURLE_OK;
char *auth;
response_data = NULL;
response_size = 0;
curl = curl_easy_init();
if (!curl) return v8::ThrowException(v8::String::New("Error: unknown"));
int n = strlen(*username) + strlen(*password);
auth = (char*) malloc(n + 2);
memset(auth, 0, n + 2);
strcpy(auth, *username);
strcat(auth, ":");
strcat(auth, *password);
curl_easy_setopt(curl, CURLOPT_URL, "http://twitter.com/statuses/friends_timeline.json");
curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
free(auth);
if (res == CURLE_OK) {
char* json = NULL;
json = (char*) malloc(response_size+1);
memset(json, 0, response_size+1);
memcpy(json, (char*) response_data, response_size);
v8::Handle<v8::String> source = v8::String::New(json);
free(json);
v8::Handle<v8::Script> script = v8::Script::Compile(source);
if (script.IsEmpty()) {
ret = v8::ThrowException(v8::String::New("Error: unknown"));
goto leave;
}
v8::Handle<v8::Value> result = script->Run();
if (script.IsEmpty()) {
ret = v8::ThrowException(v8::String::New("Error: unknown"));
goto leave;
}
if (!result->IsArray()) {
ret = v8::ThrowException(v8::String::New("Error: unknown"));
goto leave;
}
ret = result;
}
leave:
if (response_data) free(response_data);
response_data = NULL;
return ret;
}
さらにTwitterUpdateStatusには
v8::Handle<v8::Value> TwitterUpdateStatus(const v8::Arguments& args) {
v8::Handle<v8::Value> ret = v8::Undefined();
v8::Local<v8::Object> This = args.This();
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
if (args.Length() != 1) return v8::ThrowException(v8::String::New("Error: usage(message)"));
v8::String::AsciiValue username(This->Get(v8::String::New("username")));
v8::String::AsciiValue password(This->Get(v8::String::New("password")));
v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
v8::Local<v8::Function> func = v8::Function::Cast(*global->Get(v8::String::New("encodeURIComponent")));
v8::Local<v8::Value> funcargs[1];
funcargs[0] = args[0]->ToString();
v8::Local<v8::Value> result_val = func->Call(global, 1, funcargs);
v8::String::AsciiValue escaped(result_val->ToString());
char* status = url_encode_alloc(*escaped);
CURL* curl = NULL;
CURLcode res = CURLE_OK;
char *auth;
char url[2048];
response_data = NULL;
response_size = 0;
curl = curl_easy_init();
if (!curl) return v8::ThrowException(v8::String::New("Error: unknown"));
memset(url, 0, sizeof(url));
strncpy(url, "http://twitter.com/statuses/update.xml", sizeof(url)-1);
strncat(url, "?status=", sizeof(url)-1);;
strncat(url, status, sizeof(url)-1);
free(status);
int n = strlen(*username) + strlen(*password);
auth = (char*) malloc(n + 2);
memset(auth, 0, n + 2);
strcpy(auth, *username);
strcat(auth, ":");
strcat(auth, *password);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
free(auth);
if (res != CURLE_OK) {
ret = v8::ThrowException(v8::String::New("Error: unknown"));
}
if (response_data) free(response_data);
response_data = NULL;
return ret;
}
これだけ準備出来れば、あとは
var twitter = new Twitter()
twitter.username = "my-username"
twitter.password = "my-password"
var statuses = twitter.friendsTimeline();
for (var n = 0; n < statuses.length; n++) {
print(statuses[n].user.screen_name, ":", statuses[n].text);
}
twitter.updateStatus("v8エンジン12気筒");
こんなスクリプト書いて
# shell twitter.js
とかやればfollowerのステータスが出た後でメッセージがポストされます。このブログを応援する