Audacity 3.2.0
UserService.cpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*!********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 UserService.cpp
7
8 Dmitry Vedenko
9
10**********************************************************************/
11
12#include "UserService.h"
13
14#include <memory>
15#include <vector>
16
17#include <wx/file.h>
18
19#include <rapidjson/document.h>
20
21#include "ServiceConfig.h"
22#include "OAuthService.h"
23
24#include "BasicUI.h"
25#include "FileNames.h"
26#include "Observer.h"
27#include "Prefs.h"
28
29#include "IResponse.h"
30#include "NetworkManager.h"
31#include "Request.h"
32
33#include "CodeConversions.h"
34
35namespace cloud::audiocom
36{
37namespace
38{
40{
41 const wxFileName avatarFileName(FileNames::ConfigDir(), "avatar");
42 return avatarFileName.GetFullPath();
43}
44
45StringSetting userName { L"/cloud/audiocom/userName", "" };
46StringSetting displayName { L"/cloud/audiocom/displayName", "" };
47StringSetting avatarEtag { L"/cloud/audiocom/avatarEtag", "" };
48
51 [](const auto& state)
52 {
53 if (state.authorised)
54 GetUserService().UpdateUserData();
55 else
57 });
58
59} // namespace
60
62{
63 auto& oauthService = GetOAuthService();
64
65 if (!oauthService.HasAccessToken())
66 return;
67
68 using namespace audacity::network_manager;
69
70 Request request(GetServiceConfig().GetAPIUrl("/me"));
71
72 request.setHeader(
74 std::string(oauthService.GetAccessToken()));
75
76 request.setHeader(
78
79 auto response = NetworkManager::GetInstance().doGet(request);
80
81 response->setRequestFinishedCallback(
82 [response, this](auto)
83 {
84 const auto httpCode = response->getHTTPCode();
85
86 if (httpCode != 200)
87 return;
88
89 const auto body = response->readAll<std::string>();
90
91 using namespace rapidjson;
92
93 Document document;
94 document.Parse(body.data(), body.size());
95
96 if (!document.IsObject())
97 return;
98
99 const auto username = document["username"].GetString();
100 const auto avatar = document["avatar"].GetString();
101 const auto profileName = document["profile"]["name"].GetString();
102
104 [this, username = std::string(username),
105 profileName = std::string(profileName),
106 avatar = std::string(avatar)]()
107 {
110
111 gPrefs->Flush();
112
113 DownloadAvatar(avatar);
114
115 Publish({});
116 });
117 });
118}
119
121{
123 [this]()
124 {
125 userName.Write({});
126 displayName.Write({});
127 avatarEtag.Write({});
128
129 gPrefs->Flush();
130
131 Publish({});
132 });
133}
134
136{
137 static UserService userService;
138 return userService;
139}
140
141void UserService::DownloadAvatar(std::string_view url)
142{
143 const auto avatarPath = MakeAvatarPath();
144 const auto avatarTempPath = avatarPath + ".tmp";
145
146 if (url.empty())
147 {
148 if (wxFileExists(avatarPath))
149 wxRemoveFile(avatarPath);
150
151 return;
152 }
153
154 std::shared_ptr<wxFile> avatarFile = std::make_shared<wxFile>();
155
156 if (!avatarFile->Create(avatarTempPath, true))
157 return;
158
159 using namespace audacity::network_manager;
160
161 auto request = Request(std::string(url));
162
163 const auto etag = audacity::ToUTF8(avatarEtag.Read());
164
165 // If ETag is present - use it to prevent re-downloading the same file
166 if (!etag.empty() && wxFileExists(avatarPath))
167 request.setHeader(common_headers::IfNoneMatch, etag);
168
169 auto response = NetworkManager::GetInstance().doGet(request);
170
171 response->setOnDataReceivedCallback(
172 [response, avatarFile](auto)
173 {
174 std::vector<char> buffer(response->getBytesAvailable());
175
176 size_t bytes = response->readData(buffer.data(), buffer.size());
177
178 avatarFile->Write(buffer.data(), buffer.size());
179 });
180
181 response->setRequestFinishedCallback(
182 [response, avatarFile, avatarPath, avatarTempPath, this](auto)
183 {
184 avatarFile->Close();
185
186 const auto httpCode = response->getHTTPCode();
187
188 if (httpCode != 200)
189 {
190 // For any response except 200 just remove the temp file
191 wxRemoveFile(avatarTempPath);
192 return;
193 }
194
195 const auto etag = response->getHeader("ETag");
196 const auto oldPath = avatarPath + ".old";
197
198 if (wxFileExists(avatarPath))
199 if (!wxRenameFile(avatarPath, oldPath))
200 return;
201
202 if (!wxRenameFile(avatarTempPath, avatarPath))
203 {
204 // Try at least to get it back...
205 wxRenameFile(oldPath, avatarPath);
206 return;
207 }
208
209 if (wxFileExists(oldPath))
210 wxRemoveFile(oldPath);
211
213 [this, etag]()
214 {
215 avatarEtag.Write(etag);
216 gPrefs->Flush();
217
218 Publish({});
219 });
220 });
221}
222
224{
225 return displayName.Read();
226}
227
229{
230 return userName.Read();
231}
232
234{
235 auto path = MakeAvatarPath();
236
237 if (!wxFileExists(path))
238 return {};
239
240 return path;
241}
242
243} // namespace cloud::audiocom
Toolkit-neutral facade for basic user interface services.
Declare functions to perform UTF-8 to std::wstring conversions.
Declare an interface for HTTP response.
Declare a class for performing HTTP requests.
FileConfig * gPrefs
Definition: Prefs.cpp:70
Declare a class for constructing HTTP requests.
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
CallbackReturn Publish(const UserDataChanged &message)
Send a message to connected callbacks.
Definition: Observer.h:207
A move-only handle representing a connection to a Publisher.
Definition: Observer.h:70
bool Write(const T &value)
Write value to config and return true if successful.
Definition: Prefs.h:252
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:200
Specialization of Setting for strings.
Definition: Prefs.h:363
Request & setHeader(const std::string &name, std::string value)
Definition: Request.cpp:46
Service for providing information about the user profile.
Definition: UserService.h:30
void DownloadAvatar(std::string_view url)
wxString GetDisplayName() const
Get the user name to display in the dialog.
wxString GetAvatarPath() const
Gets a path to the avatar.
void UpdateUserData()
Request the service to update the data.
Definition: UserService.cpp:61
wxString GetUserSlug() const
"Slug" used to construct shareable URLs
void ClearUserData()
Reset the user profile data.
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:206
FILES_API FilePath ConfigDir()
Audacity user config directory.
FrameStatistics & GetInstance() noexcept
std::string ToUTF8(const std::wstring &wstr)
wxString ToWXString(const std::string &str)
const ServiceConfig & GetServiceConfig()
Returns the instance of the ServiceConfig.
OAuthService & GetOAuthService()
Returns the instance of the OAuthService.
UserService & GetUserService()