Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / xwalk / extensions / xesh / xesh_main.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 //
3 // Copyright (c) 2013 Intel Corporation. All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6
7
8 // This is the XWalk Extensions Shell. It implements a simple javascript shell,
9 // based on V8, that can load XWalk Extensions for testing purposes.
10 // It is a single process application which runs with three threads (main, IO
11 // and v8).
12 // The overall implementation started upon v8/samples/shell.cc .
13
14 #include <unistd.h>
15 #include <string>
16 #include "base/at_exit.h"
17 #include "base/command_line.h"
18 #include "base/file_util.h"
19 #include "base/files/file_path.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "base/message_loop/message_loop.h"
22 #include "base/message_loop/message_pump_libevent.h"
23 #include "base/run_loop.h"
24 #include "base/synchronization/waitable_event.h"
25 #include "base/task_runner_util.h"
26 #include "base/threading/thread.h"
27 #include "ipc/ipc_sync_channel.h"
28 #include "xwalk/extensions/common/xwalk_extension_server.h"
29 #include "xwalk/extensions/common/xwalk_extension_switches.h"
30 #include "xwalk/extensions/xesh/xesh_v8_runner.h"
31
32
33 using xwalk::extensions::XWalkExtensionServer;
34
35 // Specifies which file XESh will use as input.
36 const char kInputFilePath[] = "input-file";
37
38 namespace {
39
40 inline void PrintInitialInfo() {
41   fprintf(stderr, "\n---- XESh: XWalk Extensions Shell ----");
42   fprintf(stderr, "\nCrosswalk Version: %s\nv8 Version: %s\n", XWALK_VERSION,
43       XEShV8Runner::GetV8Version());
44 }
45
46 inline void PrintPromptLine() {
47   fprintf(stderr, "xesh> ");
48 }
49
50 std::string ReadLine() {
51   std::string result;
52   static const size_t kBufferSize = 256;
53   char buffer[kBufferSize];
54
55   while (fgets(buffer, kBufferSize - 1, stdin) != NULL) {
56     result += buffer;
57     size_t len = result.length();
58     if (len == 0)
59       break;
60     char end = result[len - 1];
61     if (end == '\n' || end == '\0')
62       break;
63   }
64
65   // Handle ^D (EOF).
66   if (feof(stdin))
67     exit(0);
68
69   return result;
70 }
71
72 // This class will watch the stdin file descriptor (i.e. stdin) so we know
73 // when we can read without blocking its thread. It will live on the IO Thread.
74 // In case where XESh got executed with the parameter --input-file=
75 // this class will first read this input file, get its content executed by v8
76 // and then it will start listening to stdin again.
77 class InputWatcher : public base::MessagePumpLibevent::Watcher {
78  public:
79   InputWatcher(XEShV8Runner* v8_runner, base::MessageLoop* v8_loop)
80     : is_waiting_v8_runner_(false),
81       v8_runner_(v8_runner),
82       v8_message_loop_(v8_loop) {}
83
84   virtual ~InputWatcher() {}
85
86   // base::MessagePumpLibevent::Watcher implementation.
87   void virtual OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
88     if (is_waiting_v8_runner_)
89       return;
90
91     CallV8ExecuteString(ReadLine());
92   }
93
94   void virtual OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
95
96   void StartWatching() {
97     CommandLine* cmd_line = CommandLine::ForCurrentProcess();
98
99     if (cmd_line->HasSwitch(kInputFilePath)) {
100       std::string file_contents;
101       ReadFileToString(cmd_line->GetSwitchValuePath(kInputFilePath),
102           &file_contents);
103
104       CallV8ExecuteString(file_contents);
105     }
106
107     // base::MessageLoop::current() will return the IO thread message loop.
108     base::MessageLoopForIO* io_loop =
109         static_cast<base::MessageLoopForIO*>(base::MessageLoop::current());
110     io_loop->WatchFileDescriptor(STDIN_FILENO, true,
111         base::MessageLoopForIO::WATCH_READ, &fd_watcher_, this);
112   }
113
114  private:
115   void CallV8ExecuteString(std::string statement) {
116     is_waiting_v8_runner_ = true;
117
118     PostTaskAndReplyWithResult(v8_message_loop_->message_loop_proxy(),
119         FROM_HERE,
120         base::Bind(&XEShV8Runner::ExecuteString, base::Unretained(v8_runner_),
121             statement),
122         base::Bind(&InputWatcher::OnFinishedV8Execution,
123             base::Unretained(this)));
124   }
125
126   void OnFinishedV8Execution(const std::string& result) {
127     is_waiting_v8_runner_ = false;
128
129     fprintf(stderr, "%s\n", result.c_str());
130     PrintPromptLine();
131   }
132
133   bool is_waiting_v8_runner_;
134   XEShV8Runner* v8_runner_;
135   base::MessageLoop* v8_message_loop_;
136   base::MessagePumpLibevent::FileDescriptorWatcher fd_watcher_;
137
138   DISALLOW_COPY_AND_ASSIGN(InputWatcher);
139 };
140
141 // Creates and manages the lifetime of the native side of XWalkExtension's
142 // Framework. That means managing XWalkExtensionServer and its IPC-related
143 // objects.
144 class ExtensionManager {
145  public:
146   ExtensionManager()
147     : shutdown_event_(false, false) {
148   }
149
150   ~ExtensionManager() {
151     shutdown_event_.Signal();
152   }
153
154   void LoadExtensions() {
155     base::FilePath extensions_dir =
156         CommandLine::ForCurrentProcess()->GetSwitchValuePath(
157             switches::kXWalkExternalExtensionsPath);
158
159     scoped_ptr<base::ValueMap> runtime_variables(new base::ValueMap);
160     (*runtime_variables)["app_id"] = new base::StringValue("xesh");
161
162     std::vector<std::string> extensions =
163         RegisterExternalExtensionsInDirectory(&server_, extensions_dir,
164             runtime_variables.Pass());
165
166     fprintf(stderr, "\nExtensions Loaded:\n");
167     std::vector<std::string>::const_iterator it = extensions.begin();
168     for (; it != extensions.end(); ++it)
169       fprintf(stderr, "- %s\n", it->c_str());
170   }
171
172   void Initialize(base::MessageLoopProxy* io_message_loop_proxy) {
173     handle_ = IPC::Channel::GenerateVerifiedChannelID(std::string());
174
175     server_channel_ = IPC::SyncChannel::Create(handle_,
176         IPC::Channel::MODE_SERVER, &server_, io_message_loop_proxy, true,
177         &shutdown_event_);
178
179     server_.Initialize(server_channel_.get());
180   }
181
182   const IPC::ChannelHandle& ipc_channel_handle() { return handle_; }
183
184  private:
185   IPC::ChannelHandle handle_;
186   base::WaitableEvent shutdown_event_;
187   XWalkExtensionServer server_;
188   scoped_ptr<IPC::SyncChannel> server_channel_;
189 };
190 }  // namespace
191
192 int main(int argc, char* argv[]) {
193   base::AtExitManager exit_manager;
194   CommandLine::Init(argc, argv);
195
196   PrintInitialInfo();
197
198   base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI);
199   main_message_loop.set_thread_name("XESh_Main");
200
201   base::Thread io_thread("XESh_IOThread");
202   io_thread.StartWithOptions(base::Thread::Options(base::MessageLoop::TYPE_IO,
203       0));
204
205   base::Thread v8_thread("XESh_V8Thread");
206   v8_thread.StartWithOptions(base::Thread::Options(
207       base::MessageLoop::TYPE_DEFAULT, 0));
208
209   ExtensionManager extension_manager;
210   extension_manager.LoadExtensions();
211   extension_manager.Initialize(io_thread.message_loop_proxy());
212
213   XEShV8Runner v8_runner;
214   static_cast<base::MessageLoopForIO*>(v8_thread.message_loop())->PostTask(
215       FROM_HERE, base::Bind(&XEShV8Runner::Initialize,
216       base::Unretained(&v8_runner), argc, argv, io_thread.message_loop_proxy(),
217       extension_manager.ipc_channel_handle()));
218
219   InputWatcher input_watcher(&v8_runner, v8_thread.message_loop());
220
221   static_cast<base::MessageLoopForIO*>(io_thread.message_loop())->PostTask(
222       FROM_HERE, base::Bind(&InputWatcher::StartWatching,
223       base::Unretained(&input_watcher)));
224
225   PrintPromptLine();
226   base::RunLoop run_loop;
227   run_loop.Run();
228
229   static_cast<base::MessageLoopForIO*>(v8_thread.message_loop())->PostTask(
230       FROM_HERE, base::Bind(&XEShV8Runner::Shutdown,
231       base::Unretained(&v8_runner)));
232
233   io_thread.Stop();
234   v8_thread.Stop();
235   return 0;
236 }