Skip to content

Commit fcea377

Browse files
committed
Implement Hubic storage system - fixes rclone#200
1 parent 5023050 commit fcea377

14 files changed

+469
-8
lines changed

docs/content/about.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Rclone is a command line program to sync files and directories to and from
2020
* Google Cloud Storage
2121
* Amazon Cloud Drive
2222
* Microsoft One Drive
23+
* Hubic
2324
* The local filesystem
2425

2526
Features

docs/content/hubic.md

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
title: "Hubic"
3+
description: "Rclone docs for Hubic"
4+
date: "2015-11-08"
5+
---
6+
7+
<i class="fa fa-space-shuttle"></i> Hubic
8+
-----------------------------------------
9+
10+
Paths are specified as `remote:path`
11+
12+
Paths are specified as `remote:container` (or `remote:` for the `lsd`
13+
command.) You may put subdirectories in too, eg `remote:container/path/to/dir`.
14+
15+
The initial setup for Hubic involves getting a token from Hubic which
16+
you need to do in your browser. `rclone config` walks you through it.
17+
18+
Here is an example of how to make a remote called `remote`. First run:
19+
20+
rclone config
21+
22+
This will guide you through an interactive setup process:
23+
24+
```
25+
n) New remote
26+
d) Delete remote
27+
q) Quit config
28+
e/n/d/q> n
29+
name> remote
30+
What type of source is it?
31+
Choose a number from below
32+
1) amazon cloud drive
33+
2) drive
34+
3) dropbox
35+
4) google cloud storage
36+
5) local
37+
6) onedrive
38+
7) hubic
39+
8) s3
40+
9) swift
41+
type> 7
42+
Hubic App Client Id - leave blank normally.
43+
client_id>
44+
Hubic App Client Secret - leave blank normally.
45+
client_secret>
46+
Remote config
47+
If your browser doesn't open automatically go to the following link: http://localhost:53682/auth
48+
Log in and authorize rclone for access
49+
Waiting for code...
50+
Got code
51+
--------------------
52+
[remote]
53+
client_id =
54+
client_secret =
55+
token = {"access_token":"XXXXXX"}
56+
--------------------
57+
y) Yes this is OK
58+
e) Edit this remote
59+
d) Delete this remote
60+
y/e/d> y
61+
```
62+
63+
Note that rclone runs a webserver on your local machine to collect the
64+
token as returned from Hubic. This only runs from the moment it opens
65+
your browser to the moment you get back the verification code. This
66+
is on `http://127.0.0.1:53682/` and this it may require you to unblock
67+
it temporarily if you are running a host firewall.
68+
69+
Once configured you can then use `rclone` like this,
70+
71+
List containers in the top level of your Hubic
72+
73+
rclone lsd remote:
74+
75+
List all the files in your Hubic
76+
77+
rclone ls remote:
78+
79+
To copy a local directory to an Hubic directory called backup
80+
81+
rclone copy /home/source remote:backup
82+
83+
### Modified time ###
84+
85+
The modified time is stored as metadata on the object as
86+
`X-Object-Meta-Mtime` as floating point since the epoch accurate to 1
87+
ns.
88+
89+
This is a defacto standard (used in the official python-swiftclient
90+
amongst others) for storing the modification time for an object.
91+
92+
Note that Hubic wraps the Swift backend, so most of the properties of
93+
are the same.
94+
95+
### Limitations ###
96+
97+
Code to refresh the OpenStack token isn't done yet which may cause
98+
problems with very long transfers.

docs/content/overview.md

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Here is an overview of the major features of each cloud storage system.
2424
| Google Cloud Storage | Yes | Yes | No | No |
2525
| Amazon Cloud Drive | Yes | No | Yes | No |
2626
| Microsoft One Drive | No | Yes | Yes | No |
27+
| Hubic | Yes | Yes | No | No |
2728
| The local filesystem | Yes | Yes | Depends | No |
2829

2930
### MD5SUM ###

docs/layouts/chrome/navbar.html

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<li><a href="/googlecloudstorage/"><i class="fa fa-google"></i> Google Cloud Storage</a></li>
3939
<li><a href="/amazonclouddrive/"><i class="fa fa-amazon"></i> Amazon Cloud Drive</a></li>
4040
<li><a href="/onedrive/"><i class="fa fa-windows"></i> Microsoft One Drive</a></li>
41+
<li><a href="/hubic/"><i class="fa fa-space-shuttle"></i> Hubic</a></li>
4142
<li><a href="/local/"><i class="fa fa-file"></i> Local</a></li>
4243
</ul>
4344
</li>

fs/operations_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
_ "github.com/ncw/rclone/drive"
2525
_ "github.com/ncw/rclone/dropbox"
2626
_ "github.com/ncw/rclone/googlecloudstorage"
27+
_ "github.com/ncw/rclone/hubic"
2728
_ "github.com/ncw/rclone/local"
2829
_ "github.com/ncw/rclone/onedrive"
2930
_ "github.com/ncw/rclone/s3"

fs/test_all.sh

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ TestGoogleCloudStorage:
1010
TestDropbox:
1111
TestAmazonCloudDrive:
1212
TestOneDrive:
13+
TestHubic:
1314
"
1415

1516
function test_remote {

fstest/fstests/fstests.go

+15-2
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,14 @@ func TestObjectString(t *testing.T) {
435435
func TestObjectFs(t *testing.T) {
436436
skipIfNotOk(t)
437437
obj := findObject(t, file1.Path)
438-
if obj.Fs() != remote {
438+
equal := obj.Fs() == remote
439+
if !equal {
440+
// Check to see if this wraps something else
441+
if unwrap, ok := remote.(fs.UnWrapper); ok {
442+
equal = obj.Fs() == unwrap.UnWrap()
443+
}
444+
}
445+
if !equal {
439446
t.Errorf("Fs is wrong %v != %v", obj.Fs(), remote)
440447
}
441448
}
@@ -558,7 +565,13 @@ func TestLimitedFs(t *testing.T) {
558565
fstest.CheckListing(t, fileRemote, []fstest.Item{file2Copy})
559566
_, ok := fileRemote.(*fs.Limited)
560567
if !ok {
561-
t.Errorf("%v is not a fs.Limited", fileRemote)
568+
// Check to see if this wraps a Limited FS
569+
if unwrap, hasUnWrap := fileRemote.(fs.UnWrapper); hasUnWrap {
570+
_, ok = unwrap.UnWrap().(*fs.Limited)
571+
}
572+
if !ok {
573+
t.Errorf("%v is not a fs.Limited", fileRemote)
574+
}
562575
}
563576
}
564577

fstest/fstests/gen_tests.go

+1
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,6 @@ func main() {
132132
generateTestProgram(t, fns, "Dropbox")
133133
generateTestProgram(t, fns, "AmazonCloudDrive")
134134
generateTestProgram(t, fns, "OneDrive")
135+
generateTestProgram(t, fns, "Hubic")
135136
log.Printf("Done")
136137
}

hubic/auth.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package hubic
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/ncw/swift"
7+
)
8+
9+
// auth is an authenticator for swift
10+
type auth struct {
11+
f *Fs
12+
}
13+
14+
// newAuth creates a swift authenticator
15+
func newAuth(f *Fs) *auth {
16+
return &auth{
17+
f: f,
18+
}
19+
}
20+
21+
// Request constructs a http.Request for authentication
22+
//
23+
// returns nil for not needed
24+
func (a *auth) Request(*swift.Connection) (*http.Request, error) {
25+
err := a.f.getCredentials()
26+
if err != nil {
27+
return nil, err
28+
}
29+
return nil, nil
30+
}
31+
32+
// Response parses the result of an http request
33+
func (a *auth) Response(resp *http.Response) error {
34+
return nil
35+
}
36+
37+
// The public storage URL - set Internal to true to read
38+
// internal/service net URL
39+
func (a *auth) StorageUrl(Internal bool) string {
40+
return a.f.credentials.Endpoint
41+
}
42+
43+
// The access token
44+
func (a *auth) Token() string {
45+
return a.f.credentials.Token
46+
}
47+
48+
// The CDN url if available
49+
func (a *auth) CdnUrl() string {
50+
return ""
51+
}
52+
53+
// Check the interfaces are satisfied
54+
var _ swift.Authenticator = (*auth)(nil)

0 commit comments

Comments
 (0)