Mercurial > hg > orthanc-gcp
comparison Plugin/GoogleUpdater.cpp @ 0:520cba9a0d42
initial commit
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 13 Jun 2019 14:57:22 +0200 |
parents | |
children | 25292488ff8f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:520cba9a0d42 |
---|---|
1 /** | |
2 * Google Cloud Platform credentials for DICOMweb and Orthanc | |
3 * Copyright (C) 2019 Osimis S.A., Belgium | |
4 * | |
5 * This program is free software: you can redistribute it and/or | |
6 * modify it under the terms of the GNU General Public License as | |
7 * published by the Free Software Foundation, either version 3 of the | |
8 * License, or (at your option) any later version. | |
9 * | |
10 * In addition, as a special exception, the copyright holders of this | |
11 * program give permission to link the code of its release with the | |
12 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
13 * that use the same license as the "OpenSSL" library), and distribute | |
14 * the linked executables. You must obey the GNU General Public License | |
15 * in all respects for all of the code used other than "OpenSSL". If you | |
16 * modify file(s) with this exception, you may extend this exception to | |
17 * your version of the file(s), but you are not obligated to do so. If | |
18 * you do not wish to do so, delete this exception statement from your | |
19 * version. If you delete this exception statement from all source files | |
20 * in the program, then also delete it here. | |
21 * | |
22 * This program is distributed in the hope that it will be useful, but | |
23 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
25 * General Public License for more details. | |
26 * | |
27 * You should have received a copy of the GNU General Public License | |
28 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
29 **/ | |
30 | |
31 | |
32 #include "GoogleUpdater.h" | |
33 | |
34 #include "GoogleConfiguration.h" | |
35 | |
36 #include <google/cloud/storage/internal/curl_handle_factory.h> | |
37 #include <google/cloud/storage/oauth2/google_credentials.h> | |
38 | |
39 | |
40 namespace | |
41 { | |
42 class CurlBuilder : public google::cloud::storage::internal::CurlRequestBuilder | |
43 { | |
44 private: | |
45 class HandleFactory : public google::cloud::storage::internal::DefaultCurlHandleFactory | |
46 { | |
47 public: | |
48 google::cloud::storage::internal::CurlPtr CreateHandle() override | |
49 { | |
50 google::cloud::storage::internal::CurlPtr handle | |
51 (google::cloud::storage::internal::DefaultCurlHandleFactory::CreateHandle()); | |
52 | |
53 const GoogleConfiguration& configuration = GoogleConfiguration::GetInstance(); | |
54 | |
55 long timeout = static_cast<long>(configuration.GetTimeoutSeconds()); | |
56 | |
57 if ((!configuration.GetCaInfo().empty() && | |
58 curl_easy_setopt(handle.get(), CURLOPT_CAINFO, configuration.GetCaInfo().c_str()) != CURLE_OK) || | |
59 curl_easy_setopt(handle.get(), CURLOPT_SSL_VERIFYHOST, 2) != CURLE_OK || | |
60 curl_easy_setopt(handle.get(), CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK || | |
61 curl_easy_setopt(handle.get(), CURLOPT_TIMEOUT, timeout) != CURLE_OK) | |
62 { | |
63 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, | |
64 "Cannot initialize a libcurl handle"); | |
65 } | |
66 | |
67 return handle; | |
68 } | |
69 | |
70 google::cloud::storage::internal::CurlMulti CreateMultiHandle() override | |
71 { | |
72 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
73 } | |
74 }; | |
75 | |
76 public: | |
77 CurlBuilder(std::string base_url, | |
78 std::shared_ptr<google::cloud::storage::internal::CurlHandleFactory> factory) : | |
79 CurlRequestBuilder(base_url, std::make_shared<HandleFactory>()) | |
80 { | |
81 } | |
82 }; | |
83 } | |
84 | |
85 | |
86 | |
87 static boost::posix_time::ptime GetNow() | |
88 { | |
89 return boost::posix_time::second_clock::local_time(); | |
90 } | |
91 | |
92 | |
93 void GoogleUpdater::Worker(const State* state, | |
94 const GoogleAccount* account, | |
95 long refreshIntervalSeconds) | |
96 { | |
97 std::shared_ptr<google::cloud::storage::oauth2::Credentials> credentials; | |
98 | |
99 switch (account->GetType()) | |
100 { | |
101 case GoogleAccount::Type_ServiceAccount: | |
102 credentials = std::make_shared<google::cloud::storage::oauth2::ServiceAccountCredentials | |
103 <CurlBuilder>>(account->GetServiceAccount()); | |
104 break; | |
105 | |
106 case GoogleAccount::Type_AuthorizedUser: | |
107 credentials = std::make_shared<google::cloud::storage::oauth2::AuthorizedUserCredentials | |
108 <CurlBuilder>>(account->GetAuthorizedUser()); | |
109 break; | |
110 | |
111 default: | |
112 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
113 } | |
114 | |
115 if (credentials.get() == NULL) | |
116 { | |
117 LOG(ERROR) << "Cannot initialize the token updater for Google Cloud Platform account: " | |
118 << account->GetName(); | |
119 return; | |
120 } | |
121 | |
122 const std::string dicomWebPluginRoot = GoogleConfiguration::GetInstance().GetDicomWebPluginRoot(); | |
123 const std::string baseGoogleUrl = GoogleConfiguration::GetInstance().GetBaseGoogleUrl(); | |
124 | |
125 std::string lastToken; | |
126 std::unique_ptr<boost::posix_time::ptime> lastUpdate; | |
127 | |
128 while (*state == State_Running) | |
129 { | |
130 if (lastUpdate.get() == NULL || | |
131 (GetNow() - *lastUpdate).total_seconds() >= refreshIntervalSeconds) | |
132 { | |
133 google::cloud::StatusOr<std::string> token = credentials->AuthorizationHeader(); | |
134 if (!token) | |
135 { | |
136 LOG(WARNING) << "Cannot generate Google Cloud Platform token for account: " << account->GetName(); | |
137 } | |
138 else if (*token != lastToken && | |
139 account->UpdateServerDefinition(dicomWebPluginRoot, baseGoogleUrl, *token)) | |
140 { | |
141 lastToken = *token; | |
142 } | |
143 | |
144 lastUpdate.reset(new boost::posix_time::ptime(GetNow())); | |
145 } | |
146 | |
147 boost::this_thread::sleep(boost::posix_time::milliseconds(100)); | |
148 } | |
149 } | |
150 | |
151 | |
152 GoogleUpdater::~GoogleUpdater() | |
153 { | |
154 if (state_ == State_Running) | |
155 { | |
156 LOG(ERROR) << "GoogleUpdater::Stop() should have been manually called"; | |
157 Stop(); | |
158 } | |
159 } | |
160 | |
161 | |
162 void GoogleUpdater::Start() | |
163 { | |
164 if (state_ != State_Setup) | |
165 { | |
166 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
167 } | |
168 | |
169 state_ = State_Running; | |
170 | |
171 const GoogleConfiguration& configuration = GoogleConfiguration::GetInstance(); | |
172 | |
173 workers_.resize(configuration.GetAccountsCount()); | |
174 | |
175 for (size_t i = 0; i < workers_.size(); i++) | |
176 { | |
177 workers_[i] = new boost::thread(Worker, &state_, &configuration.GetAccount(i), | |
178 configuration.GetRefreshIntervalSeconds()); | |
179 } | |
180 } | |
181 | |
182 | |
183 void GoogleUpdater::Stop() | |
184 { | |
185 if (state_ == State_Running) | |
186 { | |
187 state_ = State_Done; | |
188 | |
189 for (size_t i = 0; i < workers_.size(); i++) | |
190 { | |
191 if (workers_[i] != NULL) | |
192 { | |
193 if (workers_[i]->joinable()) | |
194 { | |
195 workers_[i]->join(); | |
196 } | |
197 | |
198 delete workers_[i]; | |
199 } | |
200 } | |
201 | |
202 workers_.clear(); | |
203 } | |
204 } |