{"action":"created","comment":{"url":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/comments/165242376","pull_request_review_id":93148058,"id":165242376,"diff_hunk":"@@ -0,0 +1,190 @@\n+//\n+// Storage module for Wasabi (https://www.wasabi.com)\n+//\n+\n+// Wasabi is nominally compatible with AWS S3, but the copy-and-delete\n+// method used for renaming objects creates additional expense under\n+// Wasabi's billing system.  This module is a pass-through to the\n+// existing S3 module for everything other than that one operation.\n+//\n+// This module copyright 2017 Mark Feit (https://github.com/markfeit)\n+// and may be distributed under the same terms as Duplicacy.\n+\n+package duplicacy\n+\n+import (\n+\t\"crypto/hmac\"\n+\t\"crypto/sha1\"\n+\t\"encoding/base64\"\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"net/http\"\n+\t\"time\"\n+)\n+\n+type WasabiStorage struct {\n+\tStorageBase\n+\n+\ts3         *S3Storage\n+\tregion     string\n+\tendpoint   string\n+\tbucket     string\n+\tstorageDir string\n+\tkey        string\n+\tsecret     string\n+\tclient     *http.Client\n+}\n+\n+// See the Storage interface in duplicacy_storage.go for function\n+// descriptions.\n+\n+func CreateWasabiStorage(\n+\tregionName string, endpoint string,\n+\tbucketName string, storageDir string,\n+\taccessKey string, secretKey string,\n+\tthreads int,\n+) (storage *WasabiStorage, err error) {\n+\n+\ts3storage, error := CreateS3Storage(regionName, endpoint, bucketName,\n+\t\tstorageDir, accessKey, secretKey, threads,\n+\t\ttrue,  // isSSLSupported\n+\t\tfalse, // isMinioCompatible\n+\t)\n+\n+\tif err != nil {\n+\t\treturn nil, error\n+\t}\n+\n+\twasabi := &WasabiStorage{\n+\n+\t\t// Pass-through to existing S3 module\n+\t\ts3: s3storage,\n+\n+\t\t// Local copies required for renaming\n+\t\tregion:     regionName,\n+\t\tendpoint:   endpoint,\n+\t\tbucket:     bucketName,\n+\t\tstorageDir: storageDir,\n+\t\tkey:        accessKey,\n+\t\tsecret:     secretKey,\n+\t\tclient:     &http.Client{},\n+\t}\n+\n+\twasabi.DerivedStorage = wasabi\n+\twasabi.SetDefaultNestingLevels([]int{0}, 0)\n+\n+\treturn wasabi, nil\n+}\n+\n+func (storage *WasabiStorage) ListFiles(\n+\tthreadIndex int, dir string,\n+) (files []string, sizes []int64, err error) {\n+\treturn storage.s3.ListFiles(threadIndex, dir)\n+}\n+\n+func (storage *WasabiStorage) DeleteFile(\n+\tthreadIndex int, filePath string,\n+) (err error) {\n+\treturn storage.s3.DeleteFile(threadIndex, filePath)\n+\n+}\n+\n+// This is a lightweight implementation of a call to Wasabi for a\n+// rename.  It's designed to get the job done with as few dependencies\n+// on other packages as possible rather than being somethng\n+// general-purpose and reusable.\n+func (storage *WasabiStorage) MoveFile(\n+\tthreadIndex int, from string, to string,\n+) (err error) {\n+\n+\t// The from path includes the bucket\n+\tfrom_path := fmt.Sprintf(\"/%s/%s/%s\", storage.bucket, storage.storageDir, from)\n+\n+\t// The to path does not.\n+\t// to_path := fmt.Sprintf(\"%s/%s\", storage.storageDir, from)","path":"src/duplicacy_wasabistorage.go","position":104,"original_position":104,"commit_id":"b52d6b3f7f65d8bed577b0660e1a4ac701cfbcce","original_commit_id":"b52d6b3f7f65d8bed577b0660e1a4ac701cfbcce","user":{"login":"gilbertchen","id":10550069,"avatar_url":"https://avatars0.githubusercontent.com/u/10550069?v=4","gravatar_id":"","url":"https://api.github.com/users/gilbertchen","html_url":"https://github.com/gilbertchen","followers_url":"https://api.github.com/users/gilbertchen/followers","following_url":"https://api.github.com/users/gilbertchen/following{/other_user}","gists_url":"https://api.github.com/users/gilbertchen/gists{/gist_id}","starred_url":"https://api.github.com/users/gilbertchen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gilbertchen/subscriptions","organizations_url":"https://api.github.com/users/gilbertchen/orgs","repos_url":"https://api.github.com/users/gilbertchen/repos","events_url":"https://api.github.com/users/gilbertchen/events{/privacy}","received_events_url":"https://api.github.com/users/gilbertchen/received_events","type":"User","site_admin":false},"body":"Please delete this line.","created_at":"2018-02-01T02:02:39Z","updated_at":"2018-02-01T02:11:16Z","html_url":"https://github.com/gilbertchen/duplicacy/pull/331#discussion_r165242376","pull_request_url":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/comments/165242376"},"html":{"href":"https://github.com/gilbertchen/duplicacy/pull/331#discussion_r165242376"},"pull_request":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331"}}},"pull_request":{"url":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331","id":163341453,"html_url":"https://github.com/gilbertchen/duplicacy/pull/331","diff_url":"https://github.com/gilbertchen/duplicacy/pull/331.diff","patch_url":"https://github.com/gilbertchen/duplicacy/pull/331.patch","issue_url":"https://api.github.com/repos/gilbertchen/duplicacy/issues/331","number":331,"state":"open","locked":false,"title":"Added semi-dedicated Wasabi storage module.  #322","user":{"login":"markfeit","id":12251320,"avatar_url":"https://avatars0.githubusercontent.com/u/12251320?v=4","gravatar_id":"","url":"https://api.github.com/users/markfeit","html_url":"https://github.com/markfeit","followers_url":"https://api.github.com/users/markfeit/followers","following_url":"https://api.github.com/users/markfeit/following{/other_user}","gists_url":"https://api.github.com/users/markfeit/gists{/gist_id}","starred_url":"https://api.github.com/users/markfeit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markfeit/subscriptions","organizations_url":"https://api.github.com/users/markfeit/orgs","repos_url":"https://api.github.com/users/markfeit/repos","events_url":"https://api.github.com/users/markfeit/events{/privacy}","received_events_url":"https://api.github.com/users/markfeit/received_events","type":"User","site_admin":false},"body":"Adds a storage module for Wasabi that uses the existing S3 code for everything except renaming objects.  See #322.\r\n","created_at":"2018-01-17T03:12:13Z","updated_at":"2018-02-01T02:11:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"12422b4b2d4e0fdea9f4c8cd50db60dd9139aa25","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"milestone":null,"commits_url":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331/commits","review_comments_url":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331/comments","review_comment_url":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/comments{/number}","comments_url":"https://api.github.com/repos/gilbertchen/duplicacy/issues/331/comments","statuses_url":"https://api.github.com/repos/gilbertchen/duplicacy/statuses/b52d6b3f7f65d8bed577b0660e1a4ac701cfbcce","head":{"label":"markfeit:master","ref":"master","sha":"b52d6b3f7f65d8bed577b0660e1a4ac701cfbcce","user":{"login":"markfeit","id":12251320,"avatar_url":"https://avatars0.githubusercontent.com/u/12251320?v=4","gravatar_id":"","url":"https://api.github.com/users/markfeit","html_url":"https://github.com/markfeit","followers_url":"https://api.github.com/users/markfeit/followers","following_url":"https://api.github.com/users/markfeit/following{/other_user}","gists_url":"https://api.github.com/users/markfeit/gists{/gist_id}","starred_url":"https://api.github.com/users/markfeit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markfeit/subscriptions","organizations_url":"https://api.github.com/users/markfeit/orgs","repos_url":"https://api.github.com/users/markfeit/repos","events_url":"https://api.github.com/users/markfeit/events{/privacy}","received_events_url":"https://api.github.com/users/markfeit/received_events","type":"User","site_admin":false},"repo":{"id":116488728,"name":"duplicacy","full_name":"markfeit/duplicacy","owner":{"login":"markfeit","id":12251320,"avatar_url":"https://avatars0.githubusercontent.com/u/12251320?v=4","gravatar_id":"","url":"https://api.github.com/users/markfeit","html_url":"https://github.com/markfeit","followers_url":"https://api.github.com/users/markfeit/followers","following_url":"https://api.github.com/users/markfeit/following{/other_user}","gists_url":"https://api.github.com/users/markfeit/gists{/gist_id}","starred_url":"https://api.github.com/users/markfeit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/markfeit/subscriptions","organizations_url":"https://api.github.com/users/markfeit/orgs","repos_url":"https://api.github.com/users/markfeit/repos","events_url":"https://api.github.com/users/markfeit/events{/privacy}","received_events_url":"https://api.github.com/users/markfeit/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/markfeit/duplicacy","description":"A new generation cloud backup tool ","fork":true,"url":"https://api.github.com/repos/markfeit/duplicacy","forks_url":"https://api.github.com/repos/markfeit/duplicacy/forks","keys_url":"https://api.github.com/repos/markfeit/duplicacy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/markfeit/duplicacy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/markfeit/duplicacy/teams","hooks_url":"https://api.github.com/repos/markfeit/duplicacy/hooks","issue_events_url":"https://api.github.com/repos/markfeit/duplicacy/issues/events{/number}","events_url":"https://api.github.com/repos/markfeit/duplicacy/events","assignees_url":"https://api.github.com/repos/markfeit/duplicacy/assignees{/user}","branches_url":"https://api.github.com/repos/markfeit/duplicacy/branches{/branch}","tags_url":"https://api.github.com/repos/markfeit/duplicacy/tags","blobs_url":"https://api.github.com/repos/markfeit/duplicacy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/markfeit/duplicacy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/markfeit/duplicacy/git/refs{/sha}","trees_url":"https://api.github.com/repos/markfeit/duplicacy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/markfeit/duplicacy/statuses/{sha}","languages_url":"https://api.github.com/repos/markfeit/duplicacy/languages","stargazers_url":"https://api.github.com/repos/markfeit/duplicacy/stargazers","contributors_url":"https://api.github.com/repos/markfeit/duplicacy/contributors","subscribers_url":"https://api.github.com/repos/markfeit/duplicacy/subscribers","subscription_url":"https://api.github.com/repos/markfeit/duplicacy/subscription","commits_url":"https://api.github.com/repos/markfeit/duplicacy/commits{/sha}","git_commits_url":"https://api.github.com/repos/markfeit/duplicacy/git/commits{/sha}","comments_url":"https://api.github.com/repos/markfeit/duplicacy/comments{/number}","issue_comment_url":"https://api.github.com/repos/markfeit/duplicacy/issues/comments{/number}","contents_url":"https://api.github.com/repos/markfeit/duplicacy/contents/{+path}","compare_url":"https://api.github.com/repos/markfeit/duplicacy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/markfeit/duplicacy/merges","archive_url":"https://api.github.com/repos/markfeit/duplicacy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/markfeit/duplicacy/downloads","issues_url":"https://api.github.com/repos/markfeit/duplicacy/issues{/number}","pulls_url":"https://api.github.com/repos/markfeit/duplicacy/pulls{/number}","milestones_url":"https://api.github.com/repos/markfeit/duplicacy/milestones{/number}","notifications_url":"https://api.github.com/repos/markfeit/duplicacy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/markfeit/duplicacy/labels{/name}","releases_url":"https://api.github.com/repos/markfeit/duplicacy/releases{/id}","deployments_url":"https://api.github.com/repos/markfeit/duplicacy/deployments","created_at":"2018-01-06T14:20:26Z","updated_at":"2018-01-06T14:20:28Z","pushed_at":"2018-01-20T17:07:25Z","git_url":"git://github.com/markfeit/duplicacy.git","ssh_url":"git@github.com:markfeit/duplicacy.git","clone_url":"https://github.com/markfeit/duplicacy.git","svn_url":"https://github.com/markfeit/duplicacy","homepage":"https://duplicacy.com","size":754,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":null,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"gilbertchen:master","ref":"master","sha":"91f02768f9ab122b31498e3829e20437c3b309f7","user":{"login":"gilbertchen","id":10550069,"avatar_url":"https://avatars0.githubusercontent.com/u/10550069?v=4","gravatar_id":"","url":"https://api.github.com/users/gilbertchen","html_url":"https://github.com/gilbertchen","followers_url":"https://api.github.com/users/gilbertchen/followers","following_url":"https://api.github.com/users/gilbertchen/following{/other_user}","gists_url":"https://api.github.com/users/gilbertchen/gists{/gist_id}","starred_url":"https://api.github.com/users/gilbertchen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gilbertchen/subscriptions","organizations_url":"https://api.github.com/users/gilbertchen/orgs","repos_url":"https://api.github.com/users/gilbertchen/repos","events_url":"https://api.github.com/users/gilbertchen/events{/privacy}","received_events_url":"https://api.github.com/users/gilbertchen/received_events","type":"User","site_admin":false},"repo":{"id":52319759,"name":"duplicacy","full_name":"gilbertchen/duplicacy","owner":{"login":"gilbertchen","id":10550069,"avatar_url":"https://avatars0.githubusercontent.com/u/10550069?v=4","gravatar_id":"","url":"https://api.github.com/users/gilbertchen","html_url":"https://github.com/gilbertchen","followers_url":"https://api.github.com/users/gilbertchen/followers","following_url":"https://api.github.com/users/gilbertchen/following{/other_user}","gists_url":"https://api.github.com/users/gilbertchen/gists{/gist_id}","starred_url":"https://api.github.com/users/gilbertchen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gilbertchen/subscriptions","organizations_url":"https://api.github.com/users/gilbertchen/orgs","repos_url":"https://api.github.com/users/gilbertchen/repos","events_url":"https://api.github.com/users/gilbertchen/events{/privacy}","received_events_url":"https://api.github.com/users/gilbertchen/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/gilbertchen/duplicacy","description":"A new generation cloud backup tool ","fork":false,"url":"https://api.github.com/repos/gilbertchen/duplicacy","forks_url":"https://api.github.com/repos/gilbertchen/duplicacy/forks","keys_url":"https://api.github.com/repos/gilbertchen/duplicacy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gilbertchen/duplicacy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gilbertchen/duplicacy/teams","hooks_url":"https://api.github.com/repos/gilbertchen/duplicacy/hooks","issue_events_url":"https://api.github.com/repos/gilbertchen/duplicacy/issues/events{/number}","events_url":"https://api.github.com/repos/gilbertchen/duplicacy/events","assignees_url":"https://api.github.com/repos/gilbertchen/duplicacy/assignees{/user}","branches_url":"https://api.github.com/repos/gilbertchen/duplicacy/branches{/branch}","tags_url":"https://api.github.com/repos/gilbertchen/duplicacy/tags","blobs_url":"https://api.github.com/repos/gilbertchen/duplicacy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gilbertchen/duplicacy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gilbertchen/duplicacy/git/refs{/sha}","trees_url":"https://api.github.com/repos/gilbertchen/duplicacy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gilbertchen/duplicacy/statuses/{sha}","languages_url":"https://api.github.com/repos/gilbertchen/duplicacy/languages","stargazers_url":"https://api.github.com/repos/gilbertchen/duplicacy/stargazers","contributors_url":"https://api.github.com/repos/gilbertchen/duplicacy/contributors","subscribers_url":"https://api.github.com/repos/gilbertchen/duplicacy/subscribers","subscription_url":"https://api.github.com/repos/gilbertchen/duplicacy/subscription","commits_url":"https://api.github.com/repos/gilbertchen/duplicacy/commits{/sha}","git_commits_url":"https://api.github.com/repos/gilbertchen/duplicacy/git/commits{/sha}","comments_url":"https://api.github.com/repos/gilbertchen/duplicacy/comments{/number}","issue_comment_url":"https://api.github.com/repos/gilbertchen/duplicacy/issues/comments{/number}","contents_url":"https://api.github.com/repos/gilbertchen/duplicacy/contents/{+path}","compare_url":"https://api.github.com/repos/gilbertchen/duplicacy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gilbertchen/duplicacy/merges","archive_url":"https://api.github.com/repos/gilbertchen/duplicacy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gilbertchen/duplicacy/downloads","issues_url":"https://api.github.com/repos/gilbertchen/duplicacy/issues{/number}","pulls_url":"https://api.github.com/repos/gilbertchen/duplicacy/pulls{/number}","milestones_url":"https://api.github.com/repos/gilbertchen/duplicacy/milestones{/number}","notifications_url":"https://api.github.com/repos/gilbertchen/duplicacy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gilbertchen/duplicacy/labels{/name}","releases_url":"https://api.github.com/repos/gilbertchen/duplicacy/releases{/id}","deployments_url":"https://api.github.com/repos/gilbertchen/duplicacy/deployments","created_at":"2016-02-23T01:28:10Z","updated_at":"2018-01-31T09:31:46Z","pushed_at":"2018-02-01T01:45:09Z","git_url":"git://github.com/gilbertchen/duplicacy.git","ssh_url":"git@github.com:gilbertchen/duplicacy.git","clone_url":"https://github.com/gilbertchen/duplicacy.git","svn_url":"https://github.com/gilbertchen/duplicacy","homepage":"https://duplicacy.com","size":773,"stargazers_count":1546,"watchers_count":1546,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":110,"mirror_url":null,"archived":false,"open_issues_count":174,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":110,"open_issues":174,"watchers":1546,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331"},"html":{"href":"https://github.com/gilbertchen/duplicacy/pull/331"},"issue":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/issues/331"},"comments":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/issues/331/comments"},"review_comments":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331/comments"},"review_comment":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/pulls/331/commits"},"statuses":{"href":"https://api.github.com/repos/gilbertchen/duplicacy/statuses/b52d6b3f7f65d8bed577b0660e1a4ac701cfbcce"}},"author_association":"NONE"}}
{"actor":{"display_login":"gilbertchen"}}