mega

package module
v0.0.0-...-f163f49 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 26, 2021 License: MIT Imports: 24 Imported by: 0

README

go-mega

A client library in go for mega.co.nz storage service.

An implementation of command-line utility can be found at https://github.com/t3rm1n4l/megacmd

Build Status

What can i do with this library?

This is an API client library for MEGA storage service. Currently, the library supports the basic APIs and operations as follows:

  • User login
  • Fetch filesystem tree
  • Upload file
  • Download file
  • Create directory
  • Move file or directory
  • Rename file or directory
  • Delete file or directory
  • Parallel split download and upload
  • Filesystem events auto sync
  • Unit tests
API methods

Please find full doc at https://pkg.go.dev/github.com/t3rm1n4l/go-mega

Testing
export MEGA_USER=<user_email>
export MEGA_PASSWD=<user_passwd>
$ make test
go test -v
=== RUN TestLogin
--- PASS: TestLogin (1.90 seconds)
=== RUN TestGetUser
--- PASS: TestGetUser (1.65 seconds)
=== RUN TestUploadDownload
--- PASS: TestUploadDownload (12.28 seconds)
=== RUN TestMove
--- PASS: TestMove (9.31 seconds)
=== RUN TestRename
--- PASS: TestRename (9.16 seconds)
=== RUN TestDelete
--- PASS: TestDelete (3.87 seconds)
=== RUN TestCreateDir
--- PASS: TestCreateDir (2.34 seconds)
=== RUN TestConfig
--- PASS: TestConfig (0.01 seconds)
=== RUN TestPathLookup
--- PASS: TestPathLookup (8.54 seconds)
=== RUN TestEventNotify
--- PASS: TestEventNotify (19.65 seconds)
PASS
ok  github.com/t3rm1n4l/go-mega68.745s
TODO
  • Implement APIs for public download url generation
  • Implement download from public url
  • Add shared user content management APIs
  • Add contact list management APIs
License

MIT

Documentation

Index

Constants

View Source
const (
	API_URL              = "https://g.api.mega.co.nz"
	BASE_DOWNLOAD_URL    = "https://mega.co.nz"
	RETRIES              = 10
	DOWNLOAD_WORKERS     = 3
	MAX_DOWNLOAD_WORKERS = 30
	UPLOAD_WORKERS       = 1
	MAX_UPLOAD_WORKERS   = 30
	TIMEOUT              = time.Second * 10
)

Default settings

View Source
const (
	FILE   = 0
	FOLDER = 1
	ROOT   = 2
	INBOX  = 3
	TRASH  = 4
)

Filesystem node types

Variables

View Source
var (
	// General errors
	EINTERNAL  = errors.New("Internal error occured")
	EARGS      = errors.New("Invalid arguments")
	EAGAIN     = errors.New("Try again")
	ERATELIMIT = errors.New("Rate limit reached")
	EBADRESP   = errors.New("Bad response from server")

	// Upload errors
	EFAILED  = errors.New("The upload failed. Please restart it from scratch")
	ETOOMANY = errors.New("Too many concurrent IP addresses are accessing this upload target URL")
	ERANGE   = errors.New("The upload file packet is out of range or not starting and ending on a chunk boundary")
	EEXPIRED = errors.New("The upload target URL you are trying to access has expired. Please request a fresh one")

	// Filesystem/Account errors
	ENOENT              = errors.New("Object (typically, node or user) not found")
	ECIRCULAR           = errors.New("Circular linkage attempted")
	EACCESS             = errors.New("Access violation")
	EEXIST              = errors.New("Trying to create an object that already exists")
	EINCOMPLETE         = errors.New("Trying to access an incomplete resource")
	EKEY                = errors.New("A decryption operation failed")
	ESID                = errors.New("Invalid or expired user session, please relogin")
	EBLOCKED            = errors.New("User blocked")
	EOVERQUOTA          = errors.New("Request over quota")
	ETEMPUNAVAIL        = errors.New("Resource temporarily not available, please try again later")
	EMACMISMATCH        = errors.New("MAC verification failed")
	EBADATTR            = errors.New("Bad node attribute")
	ETOOMANYCONNECTIONS = errors.New("Too many connections on this resource.")
	EWRITE              = errors.New("File could not be written to (or failed post-write integrity check).")
	EREAD               = errors.New("File could not be read from (or changed unexpectedly during reading).")
	EAPPKEY             = errors.New("Invalid or missing application key.")
	ESSL                = errors.New("SSL verification failed")
	EGOINGOVERQUOTA     = errors.New("Not enough quota")
	EMFAREQUIRED        = errors.New("Multi-factor authentication required")

	// Config errors
	EWORKER_LIMIT_EXCEEDED = errors.New("Maximum worker limit exceeded")
)

Functions

This section is empty.

Types

type Download

type Download struct {
	// contains filtered or unexported fields
}

Download contains the internal state of a download

func (*Download) ChunkLocation

func (d *Download) ChunkLocation(id int) (position int64, size int, err error)

ChunkLocation returns the position in the file and the size of the chunk

func (*Download) Chunks

func (d *Download) Chunks() int

Chunks returns The number of chunks in the download.

func (*Download) DownloadChunk

func (d *Download) DownloadChunk(id int) (chunk []byte, err error)

DownloadChunk gets a chunk with the given number and update the mac, returning the position in the file of the chunk

func (*Download) Finish

func (d *Download) Finish() (err error)

Finish checks the accumulated MAC for each block.

If all the chunks weren't downloaded then it will just return nil

type DownloadMsg

type DownloadMsg struct {
	Cmd string `json:"a"`
	G   int    `json:"g"`
	P   string `json:"p,omitempty"`
	N   string `json:"n,omitempty"`
}

type DownloadResp

type DownloadResp struct {
	G    string   `json:"g"`
	Size uint64   `json:"s"`
	Attr string   `json:"at"`
	Err  ErrorMsg `json:"e"`
}

type ErrorMsg

type ErrorMsg int

type Events

type Events struct {
	W  string            `json:"w"`
	Sn string            `json:"sn"`
	E  []json.RawMessage `json:"a"`
}

Events is received from a poll of the server to read the events

Each event can be an error message or a different field so we delay decoding

type FSEvent

type FSEvent struct {
	Cmd string `json:"a"`

	T struct {
		Files []FSNode `json:"f"`
	} `json:"t"`
	Owner string `json:"ou"`

	N    string `json:"n"`
	User string `json:"u"`
	Attr string `json:"at"`
	Key  string `json:"k"`
	Ts   int64  `json:"ts"`
	I    string `json:"i"`
}

FSEvent - event for various file system events

Delete (a=d) Update attr (a=u) New nodes (a=t)

type FSNode

type FSNode struct {
	Hash   string `json:"h"`
	Parent string `json:"p"`
	User   string `json:"u"`
	T      int    `json:"t"`
	Attr   string `json:"a"`
	Key    string `json:"k"`
	Ts     int64  `json:"ts"`
	SUser  string `json:"su"`
	SKey   string `json:"sk"`
	Sz     int64  `json:"s"`
}

type FileAttr

type FileAttr struct {
	Name string `json:"n"`
}

type FileAttrMsg

type FileAttrMsg struct {
	Cmd  string `json:"a"`
	Attr string `json:"attr"`
	Key  string `json:"key"`
	N    string `json:"n"`
	I    string `json:"i"`
}

type FileDeleteMsg

type FileDeleteMsg struct {
	Cmd string `json:"a"`
	N   string `json:"n"`
	I   string `json:"i"`
}

type FileInfoMsg

type FileInfoMsg struct {
	Cmd string `json:"a"`
	F   int    `json:"f"`
	P   string `json:"p"`
}

type FilesMsg

type FilesMsg struct {
	Cmd string `json:"a"`
	C   int    `json:"c"`
}

type FilesResp

type FilesResp struct {
	F []FSNode `json:"f"`

	Ok []struct {
		Hash string `json:"h"`
		Key  string `json:"k"`
	} `json:"ok"`

	S []struct {
		Hash string `json:"h"`
		User string `json:"u"`
	} `json:"s"`
	User []struct {
		User  string `json:"u"`
		C     int    `json:"c"`
		Email string `json:"m"`
	} `json:"u"`
	Sn string `json:"sn"`
}

type GenericEvent

type GenericEvent struct {
	Cmd string `json:"a"`
}

GenericEvent is a generic event for parsing the Cmd type before decoding more specifically

type GetLinkMsg

type GetLinkMsg struct {
	Cmd string `json:"a"`
	N   string `json:"n"`
}

type LoginMsg

type LoginMsg struct {
	Cmd        string `json:"a"`
	User       string `json:"user"`
	Handle     string `json:"uh"`
	SessionKey string `json:"sek,omitempty"`
	Si         string `json:"si,omitempty"`
	Mfa        string `json:"mfa,omitempty"`
}

type LoginResp

type LoginResp struct {
	Csid       string `json:"csid"`
	Privk      string `json:"privk"`
	Key        string `json:"k"`
	Ach        int    `json:"ach"`
	SessionKey string `json:"sek"`
	U          string `json:"u"`
}

type Mega

type Mega struct {

	// Filesystem object
	FS *MegaFS
	// contains filtered or unexported fields
}

func New

func New() *Mega

func (*Mega) CreateDir

func (m *Mega) CreateDir(name string, parent *Node) (*Node, error)

Create a directory in the filesystem

func (*Mega) Delete

func (m *Mega) Delete(node *Node, destroy bool) error

Delete a file or directory from filesystem

func (*Mega) DownloadFile

func (m *Mega) DownloadFile(src *Node, dstpath string, progress *chan int) error

Download file from filesystem reporting progress if not nil

func (*Mega) GetQuota

func (m *Mega) GetQuota() (QuotaResp, error)

Get quota information

func (*Mega) GetUser

func (m *Mega) GetUser() (UserResp, error)

Get user information

func (m *Mega) Link(n *Node, includeKey bool) (string, error)

Exports public link for node, with or without decryption key included

func (*Mega) Login

func (m *Mega) Login(email string, passwd string, multiFactor string) error

Authenticate and start a session

func (*Mega) Move

func (m *Mega) Move(src *Node, parent *Node) error

Move a file from one location to another

func (*Mega) NewDownload

func (m *Mega) NewDownload(src *Node) (*Download, error)

Create a new Download from the src Node

Call Chunks to find out how many chunks there are, then for id = 0..chunks-1 call DownloadChunk. Finally call Finish() to receive the error status.

func (*Mega) NewUpload

func (m *Mega) NewUpload(parent *Node, name string, fileSize int64) (*Upload, error)

Create a new Upload of name into parent of fileSize

Call Chunks to find out how many chunks there are, then for id = 0..chunks-1 Call ChunkLocation then UploadChunk. Finally call Finish() to receive the error status and the *Node.

func (*Mega) Rename

func (m *Mega) Rename(src *Node, name string) error

Rename a file or folder

func (*Mega) SetAPIUrl

func (c *Mega) SetAPIUrl(u string)

Set mega service base url

func (*Mega) SetClient

func (m *Mega) SetClient(client *http.Client) *Mega

SetClient sets the HTTP client in use

func (*Mega) SetDebugger

func (m *Mega) SetDebugger(debugf func(format string, v ...interface{})) *Mega

SetDebugger sets the logger for debug messages. By default these messages are not output.

func (*Mega) SetDownloadWorkers

func (c *Mega) SetDownloadWorkers(w int) error

Set concurrent download workers

func (*Mega) SetLogger

func (m *Mega) SetLogger(logf func(format string, v ...interface{})) *Mega

SetLogger sets the logger for important messages. By default this is log.Printf. Use nil to discard the messages.

func (*Mega) SetRetries

func (c *Mega) SetRetries(r int)

Set number of retries for api calls

func (*Mega) SetTimeOut

func (c *Mega) SetTimeOut(t time.Duration)

Set connection timeout

func (*Mega) SetUploadWorkers

func (c *Mega) SetUploadWorkers(w int) error

Set concurrent upload workers

func (*Mega) UploadFile

func (m *Mega) UploadFile(srcpath string, parent *Node, name string, progress *chan int) (node *Node, err error)

Upload a file to the filesystem

func (*Mega) WaitEvents

func (m *Mega) WaitEvents(eventChan <-chan struct{}, duration time.Duration) (timedout bool)

WaitEvents waits for all outstanding events to be received for a maximum of duration. eventChan should be a channel as returned from WaitEventStart.

If the timeout elapsed then it returns true otherwise false.

func (*Mega) WaitEventsStart

func (m *Mega) WaitEventsStart() <-chan struct{}

WaitEventsStart - call this before you do the action which might generate events then use the returned channel as a parameter to WaitEvents to wait for the event(s) to be received.

type MegaFS

type MegaFS struct {
	// contains filtered or unexported fields
}

Mega filesystem object

func (*MegaFS) GetChildren

func (fs *MegaFS) GetChildren(n *Node) ([]*Node, error)

Get the list of child nodes for a given node

func (*MegaFS) GetInbox

func (fs *MegaFS) GetInbox() *Node

Get inbox node

func (*MegaFS) GetRoot

func (fs *MegaFS) GetRoot() *Node

Get filesystem root node

func (*MegaFS) GetSharedRoots

func (fs *MegaFS) GetSharedRoots() []*Node

Get top level directory nodes shared by other users

func (*MegaFS) GetTrash

func (fs *MegaFS) GetTrash() *Node

Get filesystem trash node

func (*MegaFS) HashLookup

func (fs *MegaFS) HashLookup(h string) *Node

Get a node pointer from its hash

func (*MegaFS) PathLookup

func (fs *MegaFS) PathLookup(root *Node, ns []string) ([]*Node, error)

Retreive all the nodes in the given node tree path by name This method returns array of nodes upto the matched subpath (in same order as input names array) even if the target node is not located.

type MoveFileMsg

type MoveFileMsg struct {
	Cmd string `json:"a"`
	N   string `json:"n"`
	T   string `json:"t"`
	I   string `json:"i"`
}

type Node

type Node struct {
	// contains filtered or unexported fields
}

Filesystem node

func (*Node) GetHash

func (n *Node) GetHash() string

func (*Node) GetName

func (n *Node) GetName() string

func (*Node) GetSize

func (n *Node) GetSize() int64

func (*Node) GetTimeStamp

func (n *Node) GetTimeStamp() time.Time

func (*Node) GetType

func (n *Node) GetType() int

type NodeMeta

type NodeMeta struct {
	// contains filtered or unexported fields
}

type PreloginMsg

type PreloginMsg struct {
	Cmd  string `json:"a"`
	User string `json:"user"`
}

type PreloginResp

type PreloginResp struct {
	Version int    `json:"v"`
	Salt    string `json:"s"`
}

type QuotaMsg

type QuotaMsg struct {
	// Action, should be "uq" for quota request
	Cmd string `json:"a"`
	// xfer should be 1
	Xfer int `json:"xfer"`
	// Without strg=1 only reports total capacity for account
	Strg int `json:"strg,omitempty"`
}

type QuotaResp

type QuotaResp struct {
	// Mstrg is total capacity in bytes
	Mstrg uint64 `json:"mstrg"`
	// Cstrg is used capacity in bytes
	Cstrg uint64 `json:"cstrg"`
	// Per folder usage in bytes?
	Cstrgn map[string][]int64 `json:"cstrgn"`
}

type Upload

type Upload struct {
	// contains filtered or unexported fields
}

Upload contains the internal state of a upload

func (*Upload) ChunkLocation

func (u *Upload) ChunkLocation(id int) (position int64, size int, err error)

ChunkLocation returns the position in the file and the size of the chunk

func (*Upload) Chunks

func (u *Upload) Chunks() int

Chunks returns The number of chunks in the upload.

func (*Upload) Finish

func (u *Upload) Finish() (node *Node, err error)

Finish completes the upload and returns the created node

func (*Upload) UploadChunk

func (u *Upload) UploadChunk(id int, chunk []byte) (err error)

UploadChunk uploads the chunk of id

type UploadCompleteMsg

type UploadCompleteMsg struct {
	Cmd string `json:"a"`
	T   string `json:"t"`
	N   [1]struct {
		H string `json:"h"`
		T int    `json:"t"`
		A string `json:"a"`
		K string `json:"k"`
	} `json:"n"`
	I string `json:"i,omitempty"`
}

type UploadCompleteResp

type UploadCompleteResp struct {
	F []FSNode `json:"f"`
}

type UploadMsg

type UploadMsg struct {
	Cmd string `json:"a"`
	S   int64  `json:"s"`
}

type UploadResp

type UploadResp struct {
	P string `json:"p"`
}

type UserMsg

type UserMsg struct {
	Cmd string `json:"a"`
}

type UserResp

type UserResp struct {
	U     string `json:"u"`
	S     int    `json:"s"`
	Email string `json:"email"`
	Name  string `json:"name"`
	Key   string `json:"k"`
	C     int    `json:"c"`
	Pubk  string `json:"pubk"`
	Privk string `json:"privk"`
	Terms string `json:"terms"`
	TS    string `json:"ts"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL