/* This code is PUBLIC DOMAIN, and is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. See the accompanying * LICENSE file. */ #include <v8.h> #include <node.h> #include <node_object_wrap.h> #include <uv.h> #include <p4/clientapi.h> #include "basicuser.h" namespace p4node { using v8::Persistent; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionCallback; using v8::FunctionTemplate; using v8::HandleScope; using v8::Handle; using v8::Object; using v8::Value; using v8::Local; using v8::Isolate; using v8::String; using v8::Number; using v8::Array; using v8::Exception; using v8::TryCatch; using v8::Context; class Api : public node::ObjectWrap { private: int m_count; BasicUser ui; ClientApi client; public: static Persistent<Function> constructor; static void Init(Handle<Object> exports) { Isolate* isolate = exports->GetIsolate(); Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, Api::New); auto module_name = String::NewFromUtf8(isolate, "p4nodeapi"); tpl->SetClassName(module_name); tpl->InstanceTemplate()->SetInternalFieldCount(1); NODE_SET_PROTOTYPE_METHOD(tpl, "run", Api::Run); NODE_SET_PROTOTYPE_METHOD(tpl, "close", Api::Close); constructor.Reset(isolate, tpl->GetFunction()); exports->Set(module_name, tpl->GetFunction()); } Api() : m_count(0) { } ~Api() { } static void New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); Api* api = new Api(); int usetags = 1; api->Wrap(args.This()); Local<Object> params; if (args.Length() > 0) { if (!args[0]->IsObject()) { auto msg = String::NewFromUtf8(isolate, "Argument 0 must be an Object"); isolate->ThrowException(Exception::TypeError(msg)); } else { params = Local<Object>::Cast(args[0]); } auto port_key = String::NewFromUtf8(isolate, "port"); auto user_key = String::NewFromUtf8(isolate, "user"); auto password_key = String::NewFromUtf8(isolate, "password"); auto client_key = String::NewFromUtf8(isolate, "client"); auto json_key = String::NewFromUtf8(isolate, "json"); //* Override the environment P4 settings if parameters are set if (params->HasOwnProperty(port_key)) { auto value = *String::Utf8Value( params->Get(port_key)->ToString() ); api->client.SetPort(value); } if (params->HasOwnProperty(user_key)) { auto value = *String::Utf8Value( params->Get(user_key)->ToString() ); api->client.SetUser(value); } if (params->HasOwnProperty(password_key)) { auto value = *String::Utf8Value( params->Get(password_key)->ToString() ); api->client.SetPassword(value); } if (params->HasOwnProperty(client_key)) { auto value = *String::Utf8Value( params->Get(client_key)->ToString() ); api->client.SetClient(value); } if (params->HasOwnProperty(json_key)) { char *json = *String::Utf8Value( params->Get(json_key)->ToString() ); if (!strcmp("false",json) || !strcmp("False",json) || !strcmp("FALSE",json)) { usetags = 0; } } } if (usetags) { api->client.SetProtocol("tag", ""); } Error e; // TODO We *might* need to put this on a work queue api->client.Init(&e ); if( e.Test() ) { // e.Fmt( &msg ); // fprintf( stderr, "client.Init %s\n", msg.Text() ); api->ui.OutputError("connection refused."); api->client.Final(&e ); } //return args.This(); } struct p4_baton_t { Api *api; int increment_by; int sleep_for; Persistent<Function> cb; char** myargv; int myargc; char *command; char *inputData; }; static void Run(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); Local<Array> cmd; Local<String> inputString = String::NewFromUtf8(isolate, "", String::kNormalString, 0); Local<Function> cb; Api *api = node::ObjectWrap::Unwrap<Api>(args.Holder()); if (args.Length() <=1) { auto msg = String::NewFromUtf8( isolate, "Not enough arguments. [expected: (cmd, cb) || (cmd, input, cb)]" ); auto err = Exception::SyntaxError(msg); isolate->ThrowException(err); } if (!args[0]->IsArray()) { auto msg = String::NewFromUtf8( isolate, "Usage is (cmd, [options, input], fxn) - did not see a string cmd" ); auto err = Exception::TypeError(msg); isolate->ThrowException(err); } else { cmd = Local<Array>::Cast(args[0]); } if (args[1]->IsFunction()) { cb = Local<Function>::Cast(args[1]); } else if (args[1]->IsObject()) { Local<Object> params = Local<Object>::Cast(args[1]); auto user_key = String::NewFromUtf8(isolate, "user"); auto password_key = String::NewFromUtf8(isolate, "password"); auto client_key = String::NewFromUtf8(isolate, "client"); if (params->HasOwnProperty(user_key)) { auto value = *String::Utf8Value(params->Get(user_key)->ToString()); //std::cout << "Set user to: " << value << std::endl; api->client.SetUser(value); } if (params->HasOwnProperty(password_key)) { auto value = *String::Utf8Value(params->Get(password_key)->ToString()); //std::cout << "Set password to: " << value << std::endl; api->client.SetPassword(value); } if (params->HasOwnProperty(client_key)) { auto value = *String::Utf8Value(params->Get(client_key)->ToString()); //std::cout << "Set client to: " << value << std::endl; api->client.SetClient(value); } if (args[2]->IsString()) { inputString = Local<String>::Cast(args[2]); if (args[3]->IsFunction()) { cb = Local<Function>::Cast(args[3]); } else { auto msg = String::NewFromUtf8(isolate, "Usage is (cmd, opts, input, fxn)"); auto err = Exception::TypeError(msg); isolate->ThrowException(err); } } else if (args[2]->IsFunction()) { cb = Local<Function>::Cast(args[2]); } else { auto msg = String::NewFromUtf8(isolate, "Usage is (cmd, opts, fxn)"); auto err = Exception::TypeError(msg); isolate->ThrowException(err); } } else if (args[1]->IsString()) { inputString = Local<String>::Cast(args[1]); if (args[2]->IsFunction()) { cb = Local<Function>::Cast(args[2]); } else { auto msg = String::NewFromUtf8(isolate, "Usage is (cmd, [options, input,] fxn)"); auto err = Exception::TypeError(msg); isolate->ThrowException(err); } } else { auto msg = String::NewFromUtf8(isolate, "Usage is (cmd, [input], fxn) did not see a callback method"); auto err = Exception::TypeError(msg); isolate->ThrowException(err); } int parmCount = cmd->Length(); char** argv; int argc; char *command; char *inputData; argv = new char*[parmCount-1]; argc = parmCount-1; //std::cout<< "Run() cmd IsArray? " <<cmd->IsArray() << " length=" << cmd->Length()<<std::endl; for (int i = 0 ; i < parmCount; i++) { String::Utf8Value p(cmd->Get(v8::Number::New(isolate, i))); //std::cout << i << " p: " << *p << " len: " << strlen(*p) << std::endl; char* ap; if ( i == 0) { command = (char*)malloc(strlen(*p) + 1); strcpy(command,*p); } else { ap = (char*)malloc(strlen(*p) + 1); strcpy(ap,*p); argv[i-1] = ap; //std::cout << i << " argv : " << argv[i-1] << " len: " << strlen(argv[i-1]) << std::endl; } } String::Utf8Value cmdstr(cmd); //std::cout << "Run .. cmd string " << *cmdstr << std::endl; p4_baton_t *baton = new p4_baton_t(); baton->api = api; baton->increment_by = 2; baton->sleep_for = 1; baton->cb.Reset(isolate, cb); baton->myargv = argv; baton->myargc = argc; baton->command = command; String::Utf8Value s(inputString); inputData = (char*)malloc(strlen(*s)+1); strcpy(inputData,*s); baton->inputData = inputData; api->Ref(); uv_work_t *work_req = (uv_work_t *) (calloc(1, sizeof(uv_work_t))); work_req->data = baton; uv_queue_work(uv_default_loop(), work_req, EIO_P4, (uv_after_work_cb)EIO_AfterP4); } static void Close(const FunctionCallbackInfo<Value>& args) { Error e; // TODO we probably need to place this on the work queue Api *api = node::ObjectWrap::Unwrap<Api>(args.This()); api->client.Final(&e); } static void EIO_P4(uv_work_t *req) { Error e; StrBuf msg; char** argv; int argc = 0; p4_baton_t *baton = static_cast<p4_baton_t *>(req->data); baton->api->m_count += baton->increment_by; Api *api = baton->api; argv = baton->myargv; argc = baton->myargc; char *command = baton->command; if (sizeof(baton->inputData)>0) // ?? expression is always true? { (&api->ui)->SetInputData(baton->inputData); } api->client.SetArgv(argc, argv); api->client.Run(command, &api->ui); return; } static void EIO_AfterP4(uv_work_t *req) { auto isolate = Isolate::GetCurrent(); p4_baton_t *baton = static_cast<p4_baton_t *>(req->data); baton->api->Unref(); Local<Value> argv[2]; // GetErr & GetInfo return the p4 command's err and/or data response(s) */ argv[0] = String::NewFromUtf8(isolate, baton->api->ui.GetErr()); argv[1] = String::NewFromUtf8(isolate, baton->api->ui.GetInfo()); TryCatch try_catch; //baton->cb.Call(isolate, 2, argv); //baton->cb.Get(isolate)->Call(isolate->GetCurrentContext(), 2, argv); Local<Function> cb = baton->cb.Get(isolate); Local<Value> result; cb->Call(result, 2, argv); if (try_catch.HasCaught()) { node::FatalException(isolate, try_catch); } baton->cb.Reset(); delete baton; return; } }; Persistent<Function> Api::constructor; } // namespace p4node extern "C" { static void init (v8::Local<v8::Object> exports) { p4node::Api::Init(exports); } NODE_MODULE(p4nodeapi, init) }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#2 | 16512 | photex |
p4nodeapi build and implementation updates - CMake - Node 5.0.0 - p4 api 15.2 |
||
#1 | 16495 | photex | branched p4nodeapi | ||
//guest/matt_attaway/p4nodeapi/src/cpp/p4nodeapi.cc | |||||
#1 | 8517 | Matt Attaway |
Add a node.js language binding for Perforce This is fairly simple extension for node to make it easier to run Perforce commands from your node.js application. We've used this a fair amount internally, but it hasn't seen the same level of love as the other Perforce APIs. This API is not supported by Perforce support, but you are welcome to post on the forums if you have questions. |