...
This commit is contained in:
8
lib/clients/rcloneclient/.heroscript
Normal file
8
lib/clients/rcloneclient/.heroscript
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
!!hero_code.generate_client
|
||||
name:'rcloneclient'
|
||||
classname:'RCloneClient'
|
||||
singleton:1
|
||||
default:1
|
||||
hasconfig:1
|
||||
reset:0
|
||||
44
lib/clients/rcloneclient/config.v
Normal file
44
lib/clients/rcloneclient/config.v
Normal file
@@ -0,0 +1,44 @@
|
||||
module rcloneclient
|
||||
|
||||
import incubaid.herolib.core.playbook
|
||||
import incubaid.herolib.core.texttools
|
||||
import os
|
||||
|
||||
// const configfile = '${os.home_dir()}/.config/rclone/rclone.conf'
|
||||
|
||||
// // will look for personal configuration file in ~/hero/config .
|
||||
// // this file is in heroscript format and will have all required info to configure rclone
|
||||
// //```
|
||||
// // !!config.s3server_define
|
||||
// // name:'tf_write_1'
|
||||
// // description:'ThreeFold Read Write Repo 1
|
||||
// // keyid:'003e2a7be6357fb0000000001'
|
||||
// // keyname:'tfrw'
|
||||
// // appkey:'K003UsdrYOZou2ulBHA8p4KLa/dL2n4'
|
||||
// // url:''
|
||||
// //```
|
||||
// pub fn configure() ! {
|
||||
// mut plbook := playbook.new(
|
||||
// path: configfile
|
||||
// // actor_filter: ['config']
|
||||
// // action_filter: [
|
||||
// // 's3server_define',
|
||||
// // ]
|
||||
// )!
|
||||
|
||||
// actions := plbook.find(filter: 'config.s3server_define')!
|
||||
// mut out := ''
|
||||
// for action in actions {
|
||||
// mut name := action.params.get_default('name', '')!
|
||||
// mut descr := action.params.get_default('descr', '')!
|
||||
// mut config := '
|
||||
// [${name}]
|
||||
// type = b2
|
||||
// account = e2a7be6357fb
|
||||
// hard_delete = true
|
||||
// key = 003b79a6ae62cd7cb04477834a24e007e7afc601ba
|
||||
// '
|
||||
// config = texttools.dedent(config)
|
||||
// out += '\n${config}\n'
|
||||
// }
|
||||
// }
|
||||
39
lib/clients/rcloneclient/rclone_test.v
Normal file
39
lib/clients/rcloneclient/rclone_test.v
Normal file
@@ -0,0 +1,39 @@
|
||||
module rcloneclient
|
||||
|
||||
fn test_rclone_new() {
|
||||
rclone := new('test_remote') or { panic(err) }
|
||||
assert rclone.name == 'test_remote'
|
||||
}
|
||||
|
||||
fn test_check_installed() {
|
||||
installed := check_installed()
|
||||
// This test will pass or fail depending on whether rclone is installed
|
||||
// on the system. It's mainly for documentation purposes.
|
||||
println('RCloneClient installed: ${installed}')
|
||||
}
|
||||
|
||||
// Note: The following tests are commented out as they require an actual rclone
|
||||
// configuration and remote to work with. They serve as examples of how to use
|
||||
// the RCloneClient module.
|
||||
|
||||
/*
|
||||
fn test_rclone_operations() ! {
|
||||
mut rclone := new('my_remote')!
|
||||
|
||||
// Test upload
|
||||
rclone.upload('./testdata', 'backup/testdata')!
|
||||
|
||||
// Test download
|
||||
rclone.download('backup/testdata', './testdata_download')!
|
||||
|
||||
// Test mount
|
||||
rclone.mount('backup', './mounted_backup')!
|
||||
|
||||
// Test list
|
||||
content := rclone.list('backup')!
|
||||
println(content)
|
||||
|
||||
// Test unmount
|
||||
rclone.unmount('./mounted_backup')!
|
||||
}
|
||||
*/
|
||||
75
lib/clients/rcloneclient/rcloneclient.v
Normal file
75
lib/clients/rcloneclient/rcloneclient.v
Normal file
@@ -0,0 +1,75 @@
|
||||
module rcloneclient
|
||||
|
||||
import os
|
||||
|
||||
// // RCloneClient represents a configured rclone instance
|
||||
// pub struct RCloneClient {
|
||||
// pub mut:
|
||||
// name string // name of the remote
|
||||
// }
|
||||
|
||||
// mount mounts a remote at the specified path
|
||||
pub fn (mut r RCloneClient) mount(remote_path string, local_path string) ! {
|
||||
if !os.exists(local_path) {
|
||||
os.mkdir_all(local_path) or { return error('Failed to create mount directory: ${err}') }
|
||||
}
|
||||
|
||||
cmd := 'rclone mount ${r.name}:${remote_path} ${local_path} --daemon'
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
return error('Failed to mount remote: ${res.output}')
|
||||
}
|
||||
}
|
||||
|
||||
// unmount unmounts a mounted remote
|
||||
pub fn (mut r RCloneClient) unmount(local_path string) ! {
|
||||
if os.user_os() == 'macos' {
|
||||
os.execute_opt('umount ${local_path}') or { return error('Failed to unmount: ${err}') }
|
||||
} else {
|
||||
os.execute_opt('fusermount -u ${local_path}') or {
|
||||
return error('Failed to unmount: ${err}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// upload uploads a file or directory to the remote
|
||||
pub fn (mut r RCloneClient) upload(local_path string, remote_path string) ! {
|
||||
if !os.exists(local_path) {
|
||||
return error('Local path does not exist: ${local_path}')
|
||||
}
|
||||
|
||||
cmd := 'rclone copy ${local_path} ${r.name}:${remote_path}'
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
return error('Failed to upload: ${res.output}')
|
||||
}
|
||||
}
|
||||
|
||||
// download downloads a file or directory from the remote
|
||||
pub fn (mut r RCloneClient) download(remote_path string, local_path string) ! {
|
||||
if !os.exists(local_path) {
|
||||
os.mkdir_all(local_path) or { return error('Failed to create local directory: ${err}') }
|
||||
}
|
||||
|
||||
cmd := 'rclone copy ${r.name}:${remote_path} ${local_path}'
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
return error('Failed to download: ${res.output}')
|
||||
}
|
||||
}
|
||||
|
||||
// list lists contents of a remote path
|
||||
pub fn (mut r RCloneClient) list(remote_path string) !string {
|
||||
cmd := 'rclone ls ${r.name}:${remote_path}'
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
return error('Failed to list remote contents: ${res.output}')
|
||||
}
|
||||
return res.output
|
||||
}
|
||||
|
||||
// check_installed checks if rclone is installed
|
||||
pub fn check_installed() bool {
|
||||
res := os.execute('which rclone')
|
||||
return res.exit_code == 0
|
||||
}
|
||||
139
lib/clients/rcloneclient/rcloneclient_factory_.v
Normal file
139
lib/clients/rcloneclient/rcloneclient_factory_.v
Normal file
@@ -0,0 +1,139 @@
|
||||
module rcloneclient
|
||||
|
||||
import incubaid.herolib.core.base
|
||||
import incubaid.herolib.core.playbook { PlayBook }
|
||||
import incubaid.herolib.ui.console
|
||||
import json
|
||||
|
||||
__global (
|
||||
rcloneclient_global map[string]&RCloneClient
|
||||
rcloneclient_default string
|
||||
)
|
||||
|
||||
/////////FACTORY
|
||||
|
||||
@[params]
|
||||
pub struct ArgsGet {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
fromdb bool // will load from filesystem
|
||||
create bool // default will not create if not exist
|
||||
}
|
||||
|
||||
pub fn new(args ArgsGet) !&RCloneClient {
|
||||
mut obj := RCloneClient{
|
||||
name: args.name
|
||||
}
|
||||
set(obj)!
|
||||
return get(name: args.name)!
|
||||
}
|
||||
|
||||
pub fn get(args ArgsGet) !&RCloneClient {
|
||||
mut context := base.context()!
|
||||
rcloneclient_default = args.name
|
||||
if args.fromdb || args.name !in rcloneclient_global {
|
||||
mut r := context.redis()!
|
||||
if r.hexists('context:rcloneclient', args.name)! {
|
||||
data := r.hget('context:rcloneclient', args.name)!
|
||||
if data.len == 0 {
|
||||
print_backtrace()
|
||||
return error('RCloneClient with name: rcloneclient does not exist, prob bug.')
|
||||
}
|
||||
mut obj := json.decode(RCloneClient, data)!
|
||||
set_in_mem(obj)!
|
||||
} else {
|
||||
if args.create {
|
||||
new(args)!
|
||||
} else {
|
||||
print_backtrace()
|
||||
return error("RCloneClient with name 'rcloneclient' does not exist")
|
||||
}
|
||||
}
|
||||
return get(name: args.name)! // no longer from db nor create
|
||||
}
|
||||
return rcloneclient_global[args.name] or {
|
||||
print_backtrace()
|
||||
return error('could not get config for rcloneclient with name:rcloneclient')
|
||||
}
|
||||
}
|
||||
|
||||
// register the config for the future
|
||||
pub fn set(o RCloneClient) ! {
|
||||
mut o2 := set_in_mem(o)!
|
||||
rcloneclient_default = o2.name
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
r.hset('context:rcloneclient', o2.name, json.encode(o2))!
|
||||
}
|
||||
|
||||
// does the config exists?
|
||||
pub fn exists(args ArgsGet) !bool {
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
return r.hexists('context:rcloneclient', args.name)!
|
||||
}
|
||||
|
||||
pub fn delete(args ArgsGet) ! {
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
r.hdel('context:rcloneclient', args.name)!
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct ArgsList {
|
||||
pub mut:
|
||||
fromdb bool // will load from filesystem
|
||||
}
|
||||
|
||||
// if fromdb set: load from filesystem, and not from mem, will also reset what is in mem
|
||||
pub fn list(args ArgsList) ![]&RCloneClient {
|
||||
mut res := []&RCloneClient{}
|
||||
mut context := base.context()!
|
||||
if args.fromdb {
|
||||
// reset what is in mem
|
||||
rcloneclient_global = map[string]&RCloneClient{}
|
||||
rcloneclient_default = ''
|
||||
}
|
||||
if args.fromdb {
|
||||
mut r := context.redis()!
|
||||
mut l := r.hkeys('context:rcloneclient')!
|
||||
|
||||
for name in l {
|
||||
res << get(name: name, fromdb: true)!
|
||||
}
|
||||
return res
|
||||
} else {
|
||||
// load from memory
|
||||
for _, client in rcloneclient_global {
|
||||
res << client
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// only sets in mem, does not set as config
|
||||
fn set_in_mem(o RCloneClient) !RCloneClient {
|
||||
mut o2 := obj_init(o)!
|
||||
rcloneclient_global[o2.name] = &o2
|
||||
rcloneclient_default = o2.name
|
||||
return o2
|
||||
}
|
||||
|
||||
pub fn play(mut plbook PlayBook) ! {
|
||||
if !plbook.exists(filter: 'rcloneclient.') {
|
||||
return
|
||||
}
|
||||
mut install_actions := plbook.find(filter: 'rcloneclient.configure')!
|
||||
if install_actions.len > 0 {
|
||||
for mut install_action in install_actions {
|
||||
heroscript := install_action.heroscript()
|
||||
mut obj2 := heroscript_loads(heroscript)!
|
||||
set(obj2)!
|
||||
install_action.done = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// switch instance to be used for rcloneclient
|
||||
pub fn switch(name string) {
|
||||
}
|
||||
74
lib/clients/rcloneclient/rcloneclient_model.v
Normal file
74
lib/clients/rcloneclient/rcloneclient_model.v
Normal file
@@ -0,0 +1,74 @@
|
||||
module rcloneclient
|
||||
|
||||
import incubaid.herolib.data.paramsparser
|
||||
import incubaid.herolib.data.encoderhero
|
||||
import os
|
||||
|
||||
pub const version = '0.0.0'
|
||||
const singleton = true
|
||||
const default = true
|
||||
|
||||
pub fn heroscript_default() !string {
|
||||
name := os.getenv_opt('RCLONE_NAME') or { 'default' }
|
||||
remote_type := os.getenv_opt('RCLONE_TYPE') or { 's3' }
|
||||
provider := os.getenv_opt('RCLONE_PROVIDER') or { 'aws' }
|
||||
access_key := os.getenv_opt('RCLONE_ACCESS_KEY') or { '' }
|
||||
secret_key := os.getenv_opt('RCLONE_SECRET_KEY') or { '' }
|
||||
region := os.getenv_opt('RCLONE_REGION') or { 'us-east-1' }
|
||||
endpoint := os.getenv_opt('RCLONE_ENDPOINT') or { '' }
|
||||
|
||||
heroscript := "
|
||||
!!rclone.configure
|
||||
name: '${name}'
|
||||
type: '${remote_type}'
|
||||
provider: '${provider}'
|
||||
access_key: '${access_key}'
|
||||
secret_key: '${secret_key}'
|
||||
region: '${region}'
|
||||
endpoint: '${endpoint}'
|
||||
"
|
||||
|
||||
return heroscript
|
||||
}
|
||||
|
||||
@[heap]
|
||||
pub struct RCloneClient {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
type_ string = 's3' // remote type (s3, sftp, etc)
|
||||
provider string = 'aws' // provider for s3 (aws, minio, etc)
|
||||
access_key string // access key for authentication
|
||||
secret_key string // secret key for authentication
|
||||
region string = 'us-east-1' // region for s3
|
||||
endpoint string // custom endpoint URL if needed
|
||||
}
|
||||
|
||||
fn cfg_play(p paramsparser.Params) ! {
|
||||
mut mycfg := RCloneClient{
|
||||
name: p.get_default('name', 'default')!
|
||||
type_: p.get_default('type', 's3')!
|
||||
provider: p.get_default('provider', 'aws')!
|
||||
access_key: p.get('access_key')!
|
||||
secret_key: p.get('secret_key')!
|
||||
region: p.get_default('region', 'us-east-1')!
|
||||
endpoint: p.get_default('endpoint', '')!
|
||||
}
|
||||
set(mycfg)!
|
||||
}
|
||||
|
||||
fn obj_init(obj_ RCloneClient) !RCloneClient {
|
||||
// never call get here, only thing we can do here is work on object itself
|
||||
mut obj := obj_
|
||||
return obj
|
||||
}
|
||||
|
||||
/////////////NORMALLY NO NEED TO TOUCH
|
||||
|
||||
pub fn heroscript_dumps(obj RCloneClient) !string {
|
||||
return encoderhero.encode[RCloneClient](obj)!
|
||||
}
|
||||
|
||||
pub fn heroscript_loads(heroscript string) !RCloneClient {
|
||||
mut obj := encoderhero.decode[RCloneClient](heroscript)!
|
||||
return obj
|
||||
}
|
||||
38
lib/clients/rcloneclient/readme.md
Normal file
38
lib/clients/rcloneclient/readme.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# a sal to work with rclone
|
||||
|
||||
Rclone is this incredible swiss army knive to deal with S3 storage servers.
|
||||
|
||||
## Example
|
||||
|
||||
```golang
|
||||
import incubaid.herolib.osal.core.rclone
|
||||
|
||||
fn main() {
|
||||
do() or { panic(err) }
|
||||
}
|
||||
|
||||
fn do() ! {
|
||||
mut z:=rclone.new()!
|
||||
|
||||
// name string @[required]
|
||||
// cmd string @[required]
|
||||
// cmd_file bool //if we wanna force to run it as a file which is given to bash -c (not just a cmd in rclone)
|
||||
// test string
|
||||
// test_file bool
|
||||
// after []string
|
||||
// env map[string]string
|
||||
// oneshot bool
|
||||
p:=z.new(
|
||||
name:"test"
|
||||
cmd:'/bin/bash'
|
||||
)!
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## protocol defined in
|
||||
|
||||
sal on top of <https://github.com/threefoldtech/rclone/tree/master>
|
||||
|
||||
<https://github.com/threefoldtech/rclone/blob/master/docs/protocol.md>
|
||||
Reference in New Issue
Block a user