1 //
2 // Copyright RIME Developers
3 // Distributed under the BSD License
4 //
5 // 2011-12-01 GONG Chen <chen.sst@gmail.com>
6 //
7 #include <chrono>
8 #include <utility>
9 #include <boost/date_time/posix_time/posix_time_types.hpp>
10 #include <boost/filesystem.hpp>
11 #include <rime/deployer.h>
12 
13 namespace rime {
14 
Deployer()15 Deployer::Deployer() : shared_data_dir("."),
16                        user_data_dir("."),
17                        prebuilt_data_dir("build"),
18                        staging_dir("build"),
19                        sync_dir("sync"),
20                        user_id("unknown") {
21 }
22 
~Deployer()23 Deployer::~Deployer() {
24   JoinWorkThread();
25 }
26 
RunTask(const string & task_name,TaskInitializer arg)27 bool Deployer::RunTask(const string& task_name, TaskInitializer arg) {
28   auto c = DeploymentTask::Require(task_name);
29   if (!c) {
30     LOG(ERROR) << "unknown deployment task: " << task_name;
31     return false;
32   }
33   the<DeploymentTask> t(c->Create(arg));
34   if (!t) {
35     LOG(ERROR) << "error creating deployment task: " << task_name;
36     return false;
37   }
38   return t->Run(this);
39 }
40 
ScheduleTask(const string & task_name,TaskInitializer arg)41 bool Deployer::ScheduleTask(const string& task_name, TaskInitializer arg) {
42   auto c = DeploymentTask::Require(task_name);
43   if (!c) {
44     LOG(ERROR) << "unknown deployment task: " << task_name;
45     return false;
46   }
47   an<DeploymentTask> t(c->Create(arg));
48   if (!t) {
49     LOG(ERROR) << "error creating deployment task: " << task_name;
50     return false;
51   }
52   ScheduleTask(t);
53   return true;
54 }
55 
ScheduleTask(an<DeploymentTask> task)56 void Deployer::ScheduleTask(an<DeploymentTask> task) {
57   std::lock_guard<std::mutex> lock(mutex_);
58   pending_tasks_.push(task);
59 }
60 
NextTask()61 an<DeploymentTask> Deployer::NextTask() {
62   std::lock_guard<std::mutex> lock(mutex_);
63   if (!pending_tasks_.empty()) {
64     auto result = pending_tasks_.front();
65     pending_tasks_.pop();
66     return result;
67   }
68   // there is still chance that a task is added by another thread
69   // right after this call... careful.
70   return nullptr;
71 }
72 
HasPendingTasks()73 bool Deployer::HasPendingTasks() {
74   std::lock_guard<std::mutex> lock(mutex_);
75   return !pending_tasks_.empty();
76 }
77 
Run()78 bool Deployer::Run() {
79   LOG(INFO) << "running deployment tasks:";
80   message_sink_("deploy", "start");
81   int success = 0;
82   int failure = 0;
83   do {
84     while (auto task = NextTask()) {
85       if (task->Run(this))
86         ++success;
87       else
88         ++failure;
89       //boost::this_thread::interruption_point();
90     }
91     LOG(INFO) << success + failure << " tasks ran: "
92               << success << " success, " << failure << " failure.";
93     message_sink_("deploy", !failure ? "success" : "failure");
94     // new tasks could have been enqueued while we were sending the message.
95     // before quitting, double check if there is nothing left to do.
96   }
97   while (HasPendingTasks());
98   return !failure;
99 }
100 
StartWork(bool maintenance_mode)101 bool Deployer::StartWork(bool maintenance_mode) {
102   if (IsWorking()) {
103     LOG(WARNING) << "a work thread is already running.";
104     return false;
105   }
106   maintenance_mode_ = maintenance_mode;
107   if (pending_tasks_.empty()) {
108     return false;
109   }
110   LOG(INFO) << "starting work thread for "
111             << pending_tasks_.size() << " tasks.";
112   work_ = std::async(std::launch::async, [this] { Run(); });
113   return work_.valid();
114 }
115 
StartMaintenance()116 bool Deployer::StartMaintenance() {
117   return StartWork(true);
118 }
119 
IsWorking()120 bool Deployer::IsWorking() {
121   if (!work_.valid())
122     return false;
123   auto status = work_.wait_for(std::chrono::milliseconds(0));
124   return status != std::future_status::ready;
125 }
126 
IsMaintenanceMode()127 bool Deployer::IsMaintenanceMode() {
128   return maintenance_mode_ && IsWorking();
129 }
130 
JoinWorkThread()131 void Deployer::JoinWorkThread() {
132   if (work_.valid())
133     work_.get();
134 }
135 
JoinMaintenanceThread()136 void Deployer::JoinMaintenanceThread() {
137   JoinWorkThread();
138 }
139 
user_data_sync_dir() const140 string Deployer::user_data_sync_dir() const {
141   return (boost::filesystem::path(sync_dir) / user_id).string();
142 }
143 
144 }  // namespace rime
145