/* * mod_v8 for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * Copyright (C) 2013-2014, Peter Olsson * * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mod_v8 for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application * * The Initial Developer of the Original Code is * Peter Olsson * Portions created by the Initial Developer are Copyright (C) * the Initial Developer. All Rights Reserved. * * Contributor(s): * Peter Olsson * * jsmain.cpp -- JavaScript Main V8 script runner * */ #include "javascript.hpp" #if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >=5 #include "mod_v8.h" #endif #ifdef V8_ENABLE_DEBUGGING #include #endif #include #include #include #include #include #include #include #if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >=5 #include #endif using namespace std; using namespace v8; #ifdef V8_ENABLE_DEBUGGING void V8DispatchDebugMessages() { Isolate* isolate = Isolate::GetCurrent(); Persistent *persistent_contect = (Persistent *)isolate->GetData(1); HandleScope handle_scope(isolate); Local context = Local::New(isolate, *persistent_contect); Context::Scope scope(context); Debug::ProcessDebugMessages(); } #endif bool JSMain::FileExists(const char *file) { ifstream fh(file); bool file_exists = false; if (fh) { fh.close(); file_exists = true; } return file_exists; } const string JSMain::LoadFileToString(const string& filename) { if (filename.length() == 0) { return ""; } ifstream in(filename.c_str(), std::ios::in | std::ios::binary); if (in) { string contents; in.seekg(0, std::ios::end); contents.resize((size_t)in.tellg()); in.seekg(0, std::ios::beg); in.read(&contents[0], contents.size()); in.close(); return contents; } return ""; } JSMain::JSMain(void) { #if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >=5 Isolate::CreateParams params; params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); isolate = Isolate::New(params); #else isolate = Isolate::New(); #endif extenderClasses = new vector(); extenderFunctions = new vector(); extenderInstances = new vector(); activeInstances = new set(); forcedTermination = false; forcedTerminationMessage = NULL; forcedTerminationLineNumber = 0; forcedTerminationScriptFile = NULL; } JSMain::~JSMain(void) { bool enteredIsolate = false; for (size_t i = 0; i < extenderInstances->size(); i++) { registered_instance_t *inst = (*extenderInstances)[i]; if (inst) { if (inst->name) free(inst->name); free(inst); } } for (size_t i = 0; i < extenderFunctions->size(); i++) { js_function_t *proc = (*extenderFunctions)[i]; if (proc) { if (proc->name) free((char *)proc->name); free(proc); } } extenderInstances->clear(); extenderClasses->clear(); extenderFunctions->clear(); #if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >=5 if (isolate) { #else if (!Isolate::GetCurrent()) { #endif enteredIsolate = true; isolate->Enter(); } /* It's probably not totally safe to call this here, but it whould always be empty by now anyway */ DisposeActiveInstances(); if (enteredIsolate) { isolate->Exit(); } delete extenderClasses; delete extenderFunctions; delete extenderInstances; delete activeInstances; if (forcedTerminationMessage) free(forcedTerminationMessage); if (forcedTerminationScriptFile) free(forcedTerminationScriptFile); isolate->Dispose(); } const string JSMain::GetExceptionInfo(Isolate* isolate, TryCatch* try_catch) { HandleScope handle_scope(isolate); String::Utf8Value exception(try_catch->Exception()); const char *exception_string = js_safe_str(*exception); Handle message = try_catch->Message(); string res; if (message.IsEmpty()) { // V8 didn't provide any extra information about this error; just return the exception. res = exception_string; } else { String::Utf8Value filename(message->GetScriptResourceName()); const char *filename_string = js_safe_str(*filename); int linenum = message->GetLineNumber(); ostringstream ss; ss << filename_string << ":" << linenum << ": " << exception_string << "\r\n"; // Print line of source code. String::Utf8Value sourceline(message->GetSourceLine()); const char *sourceline_string = js_safe_str(*sourceline); ss << sourceline_string << "\r\n"; // Print wavy underline. int start = message->GetStartColumn(); for (int i = 0; i < start; i++) { ss << " "; } int32_t end = message->GetEndColumn(isolate->GetCurrentContext()).FromMaybe(0); for (int i = start; i < end; i++) { ss << "^"; } res = ss.str(); } return res; } void JSMain::Include(const v8::FunctionCallbackInfo& args) { for (int i = 0; i < args.Length(); i++) { HandleScope handle_scope(args.GetIsolate()); String::Utf8Value str(args[i]); // load_file loads the file with this name into a string string js_file = LoadFileToString(js_safe_str(*str)); if (js_file.length() > 0) { #if defined(V8_MAJOR_VERSION) && V8_MAJOR_VERSION >=5 MaybeLocal script; LoadScript(&script, args.GetIsolate(), js_file.c_str(), js_safe_str(*str)); if (script.IsEmpty()) { args.GetReturnValue().Set(false); } else { args.GetReturnValue().Set(script.ToLocalChecked()->Run()); } #else Handle source = String::NewFromUtf8(args.GetIsolate(), js_file.c_str()); Handle