-
Notifications
You must be signed in to change notification settings - Fork 18
Onedrive #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kylemann16
wants to merge
14
commits into
connormanning:master
Choose a base branch
from
kylemann16:onedrive
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Onedrive #37
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
ec0d4e5
wip
kylemann16 ef7a194
get and tryGetSize working
kylemann16 1633160
refresh and access tokens now working correctly
kylemann16 9ebdc22
removing unnecessary logging and variables
kylemann16 fa752ca
remvong log
kylemann16 e391999
removing testing pieces from cmake file
kylemann16 23910d0
removing unnecessary logs
kylemann16 08a4318
removed resource class, added to unnamed namespace
kylemann16 5f9c03a
pull expiration time from json
kylemann16 bb77563
adding const where possible
kylemann16 25e8585
removing unnecessary consts
kylemann16 1d38db2
handle empty queries, add query util to util file
kylemann16 d719c77
removed queries from list
kylemann16 1ca4f16
more explicit query parser
kylemann16 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -78,5 +78,4 @@ class Google::Auth | |
|
|
||
| #ifdef ARBITER_CUSTOM_NAMESPACE | ||
| } | ||
| #endif | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,266 @@ | ||
| #ifndef ARBITER_IS_AMALGAMATION | ||
| #include <arbiter/drivers/onedrive.hpp> | ||
| #include <arbiter/arbiter.hpp> | ||
| #include <arbiter/drivers/fs.hpp> | ||
| #include <arbiter/util/transforms.hpp> | ||
| #include <arbiter/util/json.hpp> | ||
| #include <chrono> | ||
| #include <thread> | ||
| #endif | ||
|
|
||
| #include <vector> | ||
|
|
||
| #ifdef ARBITER_CUSTOM_NAMESPACE | ||
| namespace ARBITER_CUSTOM_NAMESPACE | ||
| { | ||
| #endif | ||
|
|
||
| namespace arbiter | ||
| { | ||
|
|
||
| using namespace internal; | ||
|
|
||
| namespace { | ||
|
|
||
|
|
||
| const std::string hostUrl = "https://graph.microsoft.com/v1.0/me/drive/root:/"; | ||
|
|
||
| std::string getBaseEndpoint(const std::string path) | ||
| { | ||
| return hostUrl + path; | ||
| } | ||
|
|
||
| std::string getBinaryEndpoint(const std::string path) | ||
| { | ||
| return path + ":/content"; | ||
| } | ||
|
|
||
| std::string getChildrenEndpoint(const std::string path) | ||
| { | ||
| return path + ":/children"; | ||
| } | ||
|
|
||
| std::string getRefreshUrl() | ||
| { | ||
| return "https://login.microsoftonline.com/common/oauth2/v2.0/token"; | ||
| } | ||
|
|
||
| std::vector<char> buildBody(const http::Query& query) | ||
| { | ||
| const std::string body(http::buildQueryString(query)); | ||
| return std::vector<char>(body.begin(), body.end()); | ||
| } | ||
|
|
||
| http::Query parseUrlQueryString(std::string url) | ||
| { | ||
| return url.find("?") != std::string::npos ? http::parseQueryString(url) : http::Query({ }); | ||
| } | ||
|
|
||
| }//unnamed | ||
|
|
||
| namespace drivers | ||
| { | ||
|
|
||
| OneDrive::OneDrive(http::Pool& pool, std::unique_ptr<Auth> auth) | ||
| : Https(pool) | ||
| , m_auth(std::move(auth)) | ||
| { } | ||
|
|
||
| std::unique_ptr<OneDrive> OneDrive::create(http::Pool& pool, const std::string s) | ||
| { | ||
| if (auto auth = Auth::create(s)) | ||
| { | ||
| return makeUnique<OneDrive>(pool, std::move(auth)); | ||
| } | ||
|
|
||
| return std::unique_ptr<OneDrive>(); | ||
| } | ||
|
|
||
| std::unique_ptr<std::size_t> OneDrive::tryGetSize(const std::string path) const | ||
| { | ||
| const std::string endpoint(getBaseEndpoint(path)); | ||
| http::Headers headers(m_auth->headers()); | ||
| headers["Content-Type"] = "application/x-www-form-urlencoded"; | ||
| drivers::Https https(m_pool); | ||
|
|
||
| const auto res(https.internalGet(endpoint, headers)); | ||
|
|
||
| if (!res.ok()) | ||
| { | ||
| std::cout << | ||
kylemann16 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "Failed get - " << res.code() << ": " << res.str() << std::endl; | ||
| return std::unique_ptr<std::size_t>(); | ||
| } | ||
|
|
||
| //parse the data into a json object and extract size key value | ||
| const auto obj = json::parse(res.data()); | ||
| if (obj.count("size")) | ||
| { | ||
| return makeUnique<std::size_t>(obj.at("size").get<std::size_t>()); | ||
| } | ||
|
|
||
| return std::unique_ptr<std::size_t>(); | ||
| } | ||
|
|
||
| std::vector<std::string> OneDrive::processList(std::string path, bool recursive) const | ||
| { | ||
| const std::string endpoint(getBaseEndpoint(path)); | ||
| std::vector<std::string> result; | ||
|
|
||
| std::string pageUrl(getChildrenEndpoint(endpoint)); | ||
|
|
||
| http::Headers headers(m_auth->headers()); | ||
| headers["Content-Type"] = "application/json"; | ||
| drivers::Https https(m_pool); | ||
|
|
||
| //iterate through files and folders located in path parent | ||
| //limit to 200 items per list, @odata.nextLink will be provided as url for | ||
| //next set of items | ||
| do | ||
| { | ||
| const http::Query queries(parseUrlQueryString(pageUrl)); | ||
|
|
||
| auto res(https.internalGet(getChildrenEndpoint(endpoint), headers, queries)); | ||
|
|
||
| const json obj(json::parse(res.data())); | ||
|
|
||
| if (!obj.contains("value") || !res.ok()) | ||
| { | ||
| std::cout << "Could not get OneDrive item " << path | ||
| << " with response code " << res.code() << ":" << res.str() << std::endl; | ||
| return std::vector<std::string>(); | ||
| } | ||
|
|
||
| //parse list | ||
| const json list(obj.at("value")); | ||
| for (auto& i: list.items()) | ||
| { | ||
| const auto data(i.value()); | ||
| const std::string fileName(data.at("name").get<std::string>()); | ||
| const std::string filePath(path + "/" + fileName); | ||
|
|
||
| result.push_back(filePath); | ||
| if (data.contains("folder") && recursive) | ||
| { | ||
| //restart process with new file head | ||
| const auto children(processList(filePath, recursive)); | ||
|
|
||
| //add result of children processes to the parent | ||
| result.insert(result.end(), children.begin(), children.end()); | ||
| } | ||
| } | ||
|
|
||
| //check for link to next set | ||
| if (obj.contains("@odata.nextLink")) | ||
| pageUrl = obj.at("@odata.nextLink"); | ||
| else | ||
| break; | ||
|
|
||
| } while (true); | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| std::vector<std::string> OneDrive::glob(std::string path, bool verbose) const | ||
| { | ||
| path.pop_back(); | ||
| bool recursive(path.back() == '*'); | ||
| if (recursive) | ||
| path.pop_back(); | ||
|
|
||
| if (path.back() == '/') | ||
| path.pop_back(); | ||
|
|
||
| return processList(path, recursive); | ||
| } | ||
|
|
||
| bool OneDrive::get( | ||
| const std::string path, | ||
| std::vector<char>& data, | ||
| const http::Headers userHeaders, | ||
| const http::Query query) const | ||
| { | ||
| const std::string endpoint(getBaseEndpoint(path)); | ||
| http::Headers headers(m_auth->headers()); | ||
| headers["Content-Type"] = "application/octet-stream"; | ||
| headers.insert(userHeaders.begin(), userHeaders.end()); | ||
|
|
||
| drivers::Https https(m_pool); | ||
| const auto res(https.internalGet(getBinaryEndpoint(endpoint), headers)); | ||
|
|
||
| if (!res.ok()) { | ||
| std::cout << | ||
kylemann16 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "Failed get - " << res.code() << ": " << res.str() << std::endl; | ||
| return false; | ||
| } | ||
|
|
||
| data = res.data(); | ||
| return true; | ||
| } | ||
|
|
||
| OneDrive::Auth::Auth(std::string s) { | ||
| const json config = json::parse(s); | ||
| m_token = config.at("access_token").get<std::string>(); | ||
| m_refresh = config.at("refresh_token").get<std::string>(); | ||
| m_redirect = config.at("redirect_uri").get<std::string>(); | ||
| m_id = config.at("client_id").get<std::string>(); | ||
| m_secret = config.at("client_secret").get<std::string>(); | ||
| } | ||
|
|
||
| std::unique_ptr<OneDrive::Auth> OneDrive::Auth::create(const std::string s) | ||
| { | ||
| return makeUnique<Auth>(s); | ||
| } | ||
|
|
||
| void OneDrive::Auth::refresh() | ||
| { | ||
| //only refresh if we get within 2 minutes of the token ending | ||
| const auto now(Time().asUnix()); | ||
| if (m_expiration - now > 120) | ||
| return; | ||
|
|
||
| http::Pool pool; | ||
| drivers::Https https(pool); | ||
| const http::Headers headers({ | ||
| { "Accept", "application/json" }, | ||
| { "Content-Type", "application/x-www-form-urlencoded" } | ||
| }); | ||
|
|
||
| const auto encoded = buildBody({ | ||
| { "access_token", m_token }, | ||
| { "refresh_token", m_refresh }, | ||
| { "client_id", m_id }, | ||
| { "client_secret", m_secret }, | ||
| { "scope", "offline_access+files.read.all+user.read.all" }, | ||
| { "grant_type", "refresh_token" } | ||
| }); | ||
|
|
||
| const auto res(https.internalPost(getRefreshUrl(), encoded, headers)); | ||
| const auto response(json::parse(res.str())); | ||
| if (res.code() != 200) | ||
| { | ||
| std::cout << res.code() << ": Failed to refresh token" << res.str() << std::endl; | ||
| throw new ArbiterError("Failed to refresh token. " + res.str()); | ||
| } | ||
|
|
||
| //reset the token, refresh, and expiration time | ||
| m_token = response.at("access_token").get<std::string>(); | ||
| m_refresh = response.at("refresh_token").get<std::string>(); | ||
| m_expiration = now + response.at("expires_in").get<int64_t>(); | ||
| } | ||
|
|
||
| http::Headers OneDrive::Auth::headers() { | ||
| std::lock_guard<std::mutex> lock(m_mutex); | ||
| refresh(); | ||
| m_headers["Accept"] = "application/json"; | ||
| m_headers["Authorization"] = "Bearer " + getToken(); | ||
| return m_headers; | ||
| } | ||
|
|
||
| }//drivers | ||
|
|
||
| }//arbiter | ||
|
|
||
| #ifdef ARBITER_CUSTOM_NAMESPACE | ||
| }; | ||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| #pragma once | ||
|
|
||
| #include <memory> | ||
| #include <mutex> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #ifndef ARBITER_IS_AMALGAMATION | ||
| #include <arbiter/drivers/http.hpp> | ||
| #endif | ||
|
|
||
| #ifdef ARBITER_CUSTOM_NAMESPACE | ||
| namespace ARBITER_CUSTOM_NAMESPACE | ||
| { | ||
| #endif | ||
|
|
||
| namespace arbiter | ||
| { | ||
|
|
||
| namespace drivers | ||
| { | ||
|
|
||
| class OneDrive : public Https | ||
| { | ||
| class Auth; | ||
|
|
||
| public: | ||
| OneDrive(http::Pool& pool, std::unique_ptr<Auth> auth); | ||
|
|
||
| static std::unique_ptr<OneDrive> create(http::Pool& pool, std::string j); | ||
|
|
||
| virtual std::string type() const override { return "od"; }; | ||
| virtual std::unique_ptr<std::size_t> tryGetSize( | ||
| std::string path) const override; | ||
| private: | ||
| virtual bool get( | ||
| std::string path, | ||
| std::vector<char>& data, | ||
| http::Headers headers, | ||
| http::Query query) const override; | ||
|
|
||
| virtual std::vector<std::string> glob( | ||
| std::string path, | ||
| bool verbose) const override; | ||
|
|
||
| std::vector<std::string> processList(std::string path, bool recursive) const; | ||
|
|
||
| std::unique_ptr<Auth> m_auth; | ||
|
|
||
| }; | ||
|
|
||
| class OneDrive::Auth | ||
| { | ||
| public: | ||
| Auth(std::string s); | ||
| static std::unique_ptr<Auth> create(std::string s); | ||
| std::string getToken() { return m_token; }; | ||
| void refresh(); | ||
| http::Headers headers(); | ||
|
|
||
| private: | ||
| //auth variables necessary for refreshing token | ||
| std::string m_refresh; | ||
| std::string m_redirect; | ||
| std::string m_id; | ||
| std::string m_secret; | ||
| std::string m_token; | ||
| int64_t m_expiration = 0; | ||
|
|
||
| mutable http::Headers m_headers; | ||
| mutable std::mutex m_mutex; | ||
| }; | ||
|
|
||
| } // namespace drivers | ||
| } // namespace arbiter | ||
|
|
||
| #ifdef ARBITER_CUSTOM_NAMESPACE | ||
| } | ||
| #endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.