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 }