golang-udm-0.1+14.10.20140721/0000755000015301777760000000000012363157605016007 5ustar pbusernogroup00000000000000golang-udm-0.1+14.10.20140721/uploader_test.go0000644000015301777760000001464212363157415021216 0ustar pbusernogroup00000000000000/* * Copyright 2014 Canonical Ltd. * * Authors: * Manuel de la Pena: manuel.delapena@canonical.com * * This file is part of ubuntu-download-manager. * * ubuntu-download-manager is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * ubuntu-download-manager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package udm import ( "errors" "reflect" "launchpad.net/go-dbus/v1" . "launchpad.net/gocheck" ) type UploadSuite struct { proxy *fakeProxy upload *FileUpload msg_args []interface{} msg_args_err error started_ch chan bool started_w watch canceled_ch chan bool canceled_w watch finished_ch chan string finished_w watch errors_ch chan error errors_w watch progress_ch chan Progress progress_w watch } var _ = Suite(&UploadSuite{}) func (s *UploadSuite) SetUpTest(c *C) { s.proxy = &fakeProxy{} s.started_ch = make(chan bool) s.started_w = newFakeWatch() s.canceled_ch = make(chan bool) s.canceled_w = newFakeWatch() s.finished_ch = make(chan string) s.finished_w = newFakeWatch() s.errors_ch = make(chan error) s.errors_w = newFakeWatch() s.progress_ch = make(chan Progress) s.progress_w = newFakeWatch() s.upload = &FileUpload{nil, s.proxy, "", s.started_ch, s.started_w, s.canceled_ch, s.canceled_w, s.finished_ch, s.finished_w, s.errors_ch, s.errors_w, s.progress_ch, s.progress_w} readArgs = func(msg *dbus.Message, args ...interface{}) error { for i, arg := range args { v := reflect.ValueOf(arg) e := v.Elem() switch s.msg_args[i].(type) { default: return errors.New("unexpected type") case bool: e.SetBool(s.msg_args[i].(bool)) case uint64: e.SetUint(s.msg_args[i].(uint64)) } } return s.msg_args_err } } func (s *UploadSuite) TestProgressError(c *C) { s.proxy.Result = newDBusError() progress, err := s.upload.Progress() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "progress") c.Assert(progress, Equals, uint64(0)) c.Assert(err, NotNil) } func (s *UploadSuite) TestProgress(c *C) { expected_progress := uint64(98) s.proxy.Result = newDBusReturn() s.msg_args = make([]interface{}, 1) s.msg_args[0] = expected_progress s.msg_args_err = nil progress, err := s.upload.Progress() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "progress") c.Assert(err, IsNil) c.Assert(progress, Equals, expected_progress) } func (s *UploadSuite) TestMetadataError(c *C) { s.proxy.Result = newDBusError() metadata, err := s.upload.Metadata() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "metadata") c.Assert(metadata, IsNil) c.Assert(err, NotNil) } func (s *UploadSuite) TestSetThrotthleError(c *C) { throttle := uint64(9) s.proxy.Result = newDBusError() err := s.upload.SetThrottle(throttle) c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "setThrottle") c.Assert(err, NotNil) c.Assert(s.proxy.Args[0], Equals, throttle) } func (s *UploadSuite) TestSetThrottle(c *C) { s.proxy.Result = newDBusReturn() err := s.upload.SetThrottle(uint64(9)) c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "setThrottle") c.Assert(err, IsNil) } func (s *UploadSuite) TestThrottle(c *C) { expected_throttle := uint64(98) s.proxy.Result = newDBusReturn() s.msg_args = make([]interface{}, 1) s.msg_args[0] = expected_throttle s.msg_args_err = nil throttle, err := s.upload.Throttle() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "throttle") c.Assert(err, IsNil) c.Assert(throttle, Equals, expected_throttle) } func (s *UploadSuite) TestAllowMobileUploadError(c *C) { s.proxy.Result = newDBusError() err := s.upload.AllowMobileUpload(true) c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "allowMobileUpload") c.Assert(err, NotNil) } func (s *UploadSuite) TestAllowMobileUpload(c *C) { expected_allowed := true s.proxy.Result = newDBusReturn() err := s.upload.AllowMobileUpload(expected_allowed) c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "allowMobileUpload") c.Assert(err, IsNil) c.Assert(s.proxy.Args[0], Equals, expected_allowed) } func (s *UploadSuite) TestIsMobileUploadError(c *C) { s.proxy.Result = newDBusError() allowed, err := s.upload.IsMobileUpload() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "isMobileUploadAllowed") c.Assert(allowed, Equals, false) c.Assert(err, NotNil) } func (s *UploadSuite) TestIsMobileUpload(c *C) { expected_allowed := true s.proxy.Result = newDBusReturn() s.msg_args = make([]interface{}, 1) s.msg_args[0] = expected_allowed s.msg_args_err = nil allowed, err := s.upload.IsMobileUpload() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "isMobileUploadAllowed") c.Assert(err, IsNil) c.Assert(allowed, Equals, expected_allowed) } func (s *UploadSuite) TestStartDBusError(c *C) { s.proxy.Result = newDBusError() err := s.upload.Start() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "start") c.Assert(err, NotNil) } func (s *UploadSuite) TestStartError(c *C) { s.proxy.Result = newDBusReturn() s.proxy.Err = errors.New("Fake error") err := s.upload.Start() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "start") c.Assert(err, NotNil) } func (s *UploadSuite) TestCancelDBusError(c *C) { s.proxy.Result = newDBusError() err := s.upload.Cancel() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "cancel") c.Assert(err, NotNil) } func (s *UploadSuite) TestCancelError(c *C) { s.proxy.Result = newDBusReturn() s.proxy.Err = errors.New("Fake error") err := s.upload.Cancel() c.Assert(s.proxy.Interface, Equals, UPLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "cancel") c.Assert(err, NotNil) } golang-udm-0.1+14.10.20140721/downloader_test.go0000644000015301777760000002260512363157415021537 0ustar pbusernogroup00000000000000/* * Copyright 2014 Canonical Ltd. * * Authors: * Manuel de la Pena: manuel.delapena@canonical.com * * This file is part of ubuntu-download-manager. * * ubuntu-download-manager is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * ubuntu-download-manager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package udm import ( "errors" "launchpad.net/go-dbus/v1" . "launchpad.net/gocheck" "reflect" ) type DownloadSuite struct { proxy *fakeProxy download *FileDownload msg_args []interface{} msg_args_err error started_ch chan bool started_w watch paused_ch chan bool paused_w watch resumed_ch chan bool resumed_w watch canceled_ch chan bool canceled_w watch finished_ch chan string finished_w watch errors_ch chan error errors_w watch progress_ch chan Progress progress_w watch } var _ = Suite(&DownloadSuite{}) func (s *DownloadSuite) SetUpTest(c *C) { s.proxy = &fakeProxy{} s.started_ch = make(chan bool) s.started_w = newFakeWatch() s.paused_ch = make(chan bool) s.paused_w = newFakeWatch() s.resumed_ch = make(chan bool) s.resumed_w = newFakeWatch() s.canceled_ch = make(chan bool) s.canceled_w = newFakeWatch() s.finished_ch = make(chan string) s.finished_w = newFakeWatch() s.errors_ch = make(chan error) s.errors_w = newFakeWatch() s.progress_ch = make(chan Progress) s.progress_w = newFakeWatch() s.download = &FileDownload{nil, s.proxy, "", s.started_ch, s.started_w, s.paused_ch, s.paused_w, s.resumed_ch, s.resumed_w, s.canceled_ch, s.canceled_w, s.finished_ch, s.finished_w, s.errors_ch, s.errors_w, s.progress_ch, s.progress_w} readArgs = func(msg *dbus.Message, args ...interface{}) error { for i, arg := range args { v := reflect.ValueOf(arg) e := v.Elem() switch s.msg_args[i].(type) { default: return errors.New("unexpected type") case bool: e.SetBool(s.msg_args[i].(bool)) case uint64: e.SetUint(s.msg_args[i].(uint64)) } } return s.msg_args_err } } func (s *DownloadSuite) TestTotalSizeError(c *C) { s.proxy.Result = newDBusError() size, err := s.download.TotalSize() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "totalSize") c.Assert(size, Equals, uint64(0)) c.Assert(err, NotNil) } func (s *DownloadSuite) TestTotalSize(c *C) { expected_size := uint64(98) s.proxy.Result = newDBusReturn() s.msg_args = make([]interface{}, 1) s.msg_args[0] = expected_size s.msg_args_err = nil size, err := s.download.TotalSize() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "totalSize") c.Assert(err, IsNil) c.Assert(size, Equals, expected_size) } func (s *DownloadSuite) TestProgressError(c *C) { s.proxy.Result = newDBusError() progress, err := s.download.Progress() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "progress") c.Assert(progress, Equals, uint64(0)) c.Assert(err, NotNil) } func (s *DownloadSuite) TestProgress(c *C) { expected_progress := uint64(98) s.proxy.Result = newDBusReturn() s.msg_args = make([]interface{}, 1) s.msg_args[0] = expected_progress s.msg_args_err = nil progress, err := s.download.Progress() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "progress") c.Assert(err, IsNil) c.Assert(progress, Equals, expected_progress) } func (s *DownloadSuite) TestMetadataError(c *C) { s.proxy.Result = newDBusError() metadata, err := s.download.Metadata() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "metadata") c.Assert(metadata, IsNil) c.Assert(err, NotNil) } func (s *DownloadSuite) TestSetThrotthleError(c *C) { throttle := uint64(9) s.proxy.Result = newDBusError() err := s.download.SetThrottle(throttle) c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "setThrottle") c.Assert(err, NotNil) c.Assert(s.proxy.Args[0], Equals, throttle) } func (s *DownloadSuite) TestSetThrottle(c *C) { s.proxy.Result = newDBusReturn() err := s.download.SetThrottle(uint64(9)) c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "setThrottle") c.Assert(err, IsNil) } func (s *DownloadSuite) TestThrottleError(c *C) { s.proxy.Result = newDBusError() size, err := s.download.Throttle() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "throttle") c.Assert(size, Equals, uint64(0)) c.Assert(err, NotNil) } func (s *DownloadSuite) TestThrottle(c *C) { expected_throttle := uint64(98) s.proxy.Result = newDBusReturn() s.msg_args = make([]interface{}, 1) s.msg_args[0] = expected_throttle s.msg_args_err = nil throttle, err := s.download.Throttle() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "throttle") c.Assert(err, IsNil) c.Assert(throttle, Equals, expected_throttle) } func (s *DownloadSuite) TestAllowMobileDownloadError(c *C) { s.proxy.Result = newDBusError() err := s.download.AllowMobileDownload(true) c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "allowGSMDownload") c.Assert(err, NotNil) } func (s *DownloadSuite) TestAllowMobileDownload(c *C) { expected_allowed := true s.proxy.Result = newDBusReturn() err := s.download.AllowMobileDownload(expected_allowed) c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "allowGSMDownload") c.Assert(err, IsNil) c.Assert(s.proxy.Args[0], Equals, expected_allowed) } func (s *DownloadSuite) TestSetDestinationDirError(c *C) { s.proxy.Result = newDBusError() err := s.download.SetDestinationDir("/new/path") c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "setDestinationDir") c.Assert(err, NotNil) } func (s *DownloadSuite) TestSetDestinationDir(c *C) { expected_dir := "/path/to/use" s.proxy.Result = newDBusReturn() err := s.download.SetDestinationDir(expected_dir) c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "setDestinationDir") c.Assert(err, IsNil) c.Assert(s.proxy.Args[0], Equals, expected_dir) } func (s *DownloadSuite) TestIsMobileDownloadError(c *C) { s.proxy.Result = newDBusError() allowed, err := s.download.IsMobileDownload() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "isGSMDownloadAllowed") c.Assert(allowed, Equals, false) c.Assert(err, NotNil) } func (s *DownloadSuite) TestIsMobileDownload(c *C) { expected_allowed := true s.proxy.Result = newDBusReturn() s.msg_args = make([]interface{}, 1) s.msg_args[0] = expected_allowed s.msg_args_err = nil allowed, err := s.download.IsMobileDownload() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "isGSMDownloadAllowed") c.Assert(err, IsNil) c.Assert(allowed, Equals, expected_allowed) } func (s *DownloadSuite) TestStartDBusError(c *C) { s.proxy.Result = newDBusError() err := s.download.Start() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "start") c.Assert(err, NotNil) } func (s *DownloadSuite) TestStartError(c *C) { s.proxy.Result = newDBusReturn() s.proxy.Err = errors.New("Fake error") err := s.download.Start() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "start") c.Assert(err, NotNil) } func (s *DownloadSuite) TestPauseDBusError(c *C) { s.proxy.Result = newDBusError() err := s.download.Pause() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "pause") c.Assert(err, NotNil) } func (s *DownloadSuite) TestPauseError(c *C) { s.proxy.Result = newDBusReturn() s.proxy.Err = errors.New("Fake error") err := s.download.Pause() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "pause") c.Assert(err, NotNil) } func (s *DownloadSuite) TestResumeDBusError(c *C) { s.proxy.Result = newDBusError() err := s.download.Resume() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "resume") c.Assert(err, NotNil) } func (s *DownloadSuite) TestResumeError(c *C) { s.proxy.Result = newDBusReturn() s.proxy.Err = errors.New("Fake error") err := s.download.Resume() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "resume") c.Assert(err, NotNil) } func (s *DownloadSuite) TestCancelDBusError(c *C) { s.proxy.Result = newDBusError() err := s.download.Cancel() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "cancel") c.Assert(err, NotNil) } func (s *DownloadSuite) TestCancelError(c *C) { s.proxy.Result = newDBusReturn() s.proxy.Err = errors.New("Fake error") err := s.download.Cancel() c.Assert(s.proxy.Interface, Equals, DOWNLOAD_INTERFACE) c.Assert(s.proxy.MethodName, Equals, "cancel") c.Assert(err, NotNil) } golang-udm-0.1+14.10.20140721/uploader.go0000644000015301777760000002472412363157430020156 0ustar pbusernogroup00000000000000/* * Copyright 2014 Canonical Ltd. * * Authors: * Manuel de la Pena: manuel.delapena@canonical.com * * This file is part of ubuntu-download-manager. * * ubuntu-download-manager is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * ubuntu-download-manager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Package udm provides a go interface to work with the ubuntu download manager package udm import ( "errors" "fmt" "runtime" "launchpad.net/go-dbus/v1" ) const ( UPLOAD_SERVICE = "com.canonical.applications.Uploader" UPLOAD_INTERFACE = "com.canonical.applications.Upload" UPLOAD_MANAGER_INTERFACE = "com.canonical.applications.UploadManager" ) // Upload is the common interface of an upload. It provides all the required // methods to interact with an upload created by udm. type Upload interface { Progress() (uint64, error) Metadata() (map[string]string, error) SetThrottle(uint64) error Throttle() (uint64, error) AllowMobileUpload(bool) error IsMobileUpload() (bool, error) Start() error Cancel() error Started() chan bool UploadProgress() chan Progress Canceled() chan bool Finished() chan string Error() chan error } // FileUpload represents a single file being uploaded by udm. type FileUpload struct { conn *dbus.Connection proxy proxy path dbus.ObjectPath started chan bool started_w watch canceled chan bool canceled_w watch finished chan string finished_w watch errors chan error error_w watch progress chan Progress progress_w watch } func (upload *FileUpload) free() { // cancel all watches so that goroutines are done and close the // channels upload.started_w.Cancel() upload.canceled_w.Cancel() upload.finished_w.Cancel() upload.error_w.Cancel() upload.progress_w.Cancel() } func cleanUploadData(upload *FileUpload) { upload.free() } func newFileUpload(conn *dbus.Connection, path dbus.ObjectPath) (*FileUpload, error) { proxy := conn.Object(UPLOAD_SERVICE, path) started_ch := make(chan bool) started_w, err := connectToSignal(conn, path, UPLOAD_SERVICE, UPLOAD_INTERFACE, "started") if err != nil { return nil, err } canceled_ch := make(chan bool) canceled_w, err := connectToSignal(conn, path, UPLOAD_SERVICE, UPLOAD_INTERFACE, "canceled") if err != nil { return nil, err } finished_ch := make(chan string) finished_w, err := connectToSignal(conn, path, UPLOAD_SERVICE, UPLOAD_INTERFACE, "finished") if err != nil { return nil, err } errors_ch := make(chan error) errors_w, err := connectToSignal(conn, path, UPLOAD_SERVICE, UPLOAD_INTERFACE, "error") if err != nil { return nil, err } progress_ch := make(chan Progress) progress_w, err := connectToSignal(conn, path, UPLOAD_SERVICE, UPLOAD_INTERFACE, "progress") if err != nil { return nil, err } u := FileUpload{conn, proxy, path, started_ch, started_w, canceled_ch, canceled_w, finished_ch, finished_w, errors_ch, errors_w, progress_ch, progress_w} // connect to the diff signals so that we have nice channels that do // not expose dbus watchers u.connectToStarted() u.connectToCanceled() u.connectToFinished() u.connectToError() u.connectToProgress() runtime.SetFinalizer(&u, cleanUploadData) return &u, nil } // Process returns the process so far in uploading the file. func (upload *FileUpload) Progress() (progress uint64, err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "progress") if err != nil { return 0, err } if reply != nil && reply.Type == dbus.TypeError { return 0, fmt.Errorf("DBus Error: %", reply.ErrorName) } if err = readArgs(reply, &progress); err != nil { return 0, err } return progress, nil } // Metadata returns the metadata that was provided at creating time to the upload. func (upload *FileUpload) Metadata() (metadata map[string]string, err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "metadata") if err != nil { return nil, err } if reply != nil && reply.Type == dbus.TypeError { return nil, fmt.Errorf("DBus Error: %", reply.ErrorName) } if err = readArgs(reply, &metadata); err != nil { return nil, err } return metadata, nil } // SetThrottle sets the network throttle to be used in the upload. func (upload *FileUpload) SetThrottle(throttle uint64) (err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "setThrottle", throttle) if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("DBus Error: %", reply.ErrorName) } return nil } // Throttle returns the network throttle that is currently used in the upload. func (upload *FileUpload) Throttle() (throttle uint64, err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "throttle") if err != nil { return 0, err } if reply != nil && reply.Type == dbus.TypeError { return 0, fmt.Errorf("DBus Error: %", reply.ErrorName) } if err = readArgs(reply, &throttle); err != nil { return 0, err } return throttle, nil } // AllowMobileUpload returns if the upload is allowed to use the mobile // connection. func (upload *FileUpload) AllowMobileUpload(allowed bool) (err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "allowMobileUpload", allowed) if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("DBus Error: %", reply.ErrorName) } return nil } // IsMobileUpload returns if the upload will be performed over the mobile data // connection. func (upload *FileUpload) IsMobileUpload() (allowed bool, err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "isMobileUploadAllowed", allowed) if err != nil { return false, err } if reply != nil && reply.Type == dbus.TypeError { return false, fmt.Errorf("DBus Error: %", reply.ErrorName) } if err = readArgs(reply, &allowed); err != nil { return false, err } return allowed, nil } func (upload *FileUpload) Start() (err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "start") if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("DBus Error: %", reply.ErrorName) } return nil } // Cancel cancels an upload that was in process and deletes any local files // that were created. func (upload *FileUpload) Cancel() (err error) { reply, err := upload.proxy.Call(UPLOAD_INTERFACE, "cancel") if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("DBus Error: %", reply.ErrorName) } return nil } func (upload *FileUpload) connectToStarted() { go func() { for msg := range upload.started_w.Channel() { var started bool readArgs(msg, &started) upload.started <- started } close(upload.started) }() } // Started returns a channel that will be used to communicate the started signals. func (upload *FileUpload) Started() chan bool { return upload.started } func (upload *FileUpload) connectToCanceled() { go func() { for msg := range upload.canceled_w.Channel() { var canceled bool readArgs(msg, &canceled) upload.canceled <- canceled } close(upload.canceled) }() } // Canceled returns a channel that will be used to communicate the canceled signals. func (upload *FileUpload) Canceled() chan bool { return upload.canceled } func (upload *FileUpload) connectToFinished() { go func() { for msg := range upload.finished_w.Channel() { var path string readArgs(msg, &path) upload.finished <- path } close(upload.finished) }() } // Finished returns a channel that will ne used to communicate the finished signals. func (upload *FileUpload) Finished() chan string { return upload.finished } func (upload *FileUpload) connectToError() { go func() { for msg := range upload.error_w.Channel() { var reason string readArgs(msg, &reason) upload.errors <- errors.New(reason) } close(upload.errors) }() } // Error returns the channel that will be used to communicate the error signals. func (upload *FileUpload) Error() chan error { return upload.errors } func (upload *FileUpload) connectToProgress() { go func() { for msg := range upload.progress_w.Channel() { var received uint64 var total uint64 readArgs(msg, &received, &total) upload.progress <- Progress{received, total} } close(upload.progress) }() } // UploadProgress returns a channel that will be used to communicate the progress // signals. func (upload *FileUpload) UploadProgress() chan Progress { return upload.progress } type UploadManager struct { conn *dbus.Connection proxy *dbus.ObjectProxy } // NewUploadManager creates a new manager that can be used to create an upload // in the udm daemon. func NewUploadManager() (*UploadManager, error) { conn, err := dbus.Connect(dbus.SessionBus) if err != nil { return nil, err } if err != nil { return nil, err } proxy := conn.Object(UPLOAD_SERVICE, "/") d := UploadManager{conn, proxy} return &d, nil } func (man *UploadManager) CreateUpload(url string, file string, metadata map[string]interface{}, headers map[string]string) (upload Upload, err error) { var t map[string]*dbus.Variant for key, value := range metadata { t[key] = &dbus.Variant{Value: value} } s := struct { U string F string M map[string]*dbus.Variant HD map[string]string }{url, file, t, headers} var path dbus.ObjectPath reply, err := man.proxy.Call(UPLOAD_MANAGER_INTERFACE, "createUpload", s) if err != nil { return nil, err } if reply != nil && reply.Type == dbus.TypeError { return nil, fmt.Errorf("DBus Error: %", reply.ErrorName) } if err = readArgs(reply, &path); err != nil { return nil, err } upload, err = newFileUpload(man.conn, path) return upload, err } func (man *UploadManager) CreateMmsUpload(url string, file string, hostname string, port int32) (upload Upload, err error) { var path dbus.ObjectPath reply, err := man.proxy.Call(UPLOAD_MANAGER_INTERFACE, "createMmsUpload", url, file, hostname, port) if err != nil { return nil, err } if reply != nil && reply.Type == dbus.TypeError { return nil, fmt.Errorf("DBus Error: %", reply.ErrorName) } if err = readArgs(reply, &path); err != nil { return nil, err } upload, err = newFileUpload(man.conn, path) return upload, err } golang-udm-0.1+14.10.20140721/common_test.go0000644000015301777760000000377512363157415020700 0ustar pbusernogroup00000000000000/* * Copyright 2014 Canonical Ltd. * * Authors: * Manuel de la Pena: manuel.delapena@canonical.com * * This file is part of ubuntu-download-manager. * * ubuntu-download-manager is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * ubuntu-download-manager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package udm import ( "launchpad.net/go-dbus/v1" . "launchpad.net/gocheck" "testing" ) func Test(t *testing.T) { TestingT(t) } type fakeProxy struct { Interface string MethodName string Args []interface{} Err error Result *dbus.Message } func (f *fakeProxy) Call(iface, method string, args ...interface{}) (*dbus.Message, error) { // store the called method and return Result f.Interface = iface f.MethodName = method f.Args = args if f.Err == nil { return f.Result, nil } return nil, f.Err } type FakeWatch struct { Canceled bool Ch chan *dbus.Message } func newFakeWatch() *FakeWatch { ch := make(chan *dbus.Message) fw := FakeWatch{false, ch} return &fw } func (w *FakeWatch) Cancel() error { w.Canceled = true return nil } func (w *FakeWatch) Channel() chan *dbus.Message { return w.Ch } // returns a new error that can be used in the tests func newDBusError() *dbus.Message { msg := dbus.NewMethodCallMessage("com.destination", "/path", "com.interface", "method") msg.Type = dbus.TypeError msg.ErrorName = "com.testing.udm" return msg } func newDBusReturn() *dbus.Message { msg := dbus.NewMethodCallMessage("com.destination", "/path", "com.interface", "method") msg.Type = dbus.TypeMethodReturn return msg } golang-udm-0.1+14.10.20140721/downloader.go0000644000015301777760000003542712363157430020503 0ustar pbusernogroup00000000000000/* * Copyright 2014 Canonical Ltd. * * Authors: * Manuel de la Pena: manuel.delapena@canonical.com * * This file is part of ubuntu-download-manager. * * ubuntu-download-manager is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * ubuntu-download-manager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Package udm provides a go interface to work with the ubuntu download manager package udm import ( "errors" "fmt" "launchpad.net/go-dbus/v1" "runtime" ) const ( DOWNLOAD_SERVICE = "com.canonical.applications.Downloader" DOWNLOAD_INTERFACE = "com.canonical.applications.Download" DOWNLOAD_MANAGER_INTERFACE = "com.canonical.applications.DownloadManager" ) type hashType string const ( MD5 hashType = "md5" SHA1 hashType = "sha1" SHA224 hashType = "sha224" SHA256 hashType = "sha256" SHA384 hashType = "sha384" SHA512 hashType = "sha512" ) const ( LOCAL_PATH = "local-path" OBJECT_PATH = "objectpath" POST_DOWNLOAD_COMMAND = "post-download-command" ) // Download is the common interface of a download. It provides all the required // methods to interact with a download created by udm. type Download interface { TotalSize() (uint64, error) Progress() (uint64, error) Metadata() (map[string]string, error) SetThrottle(uint64) error Throttle() (uint64, error) AllowMobileDownload(bool) error SetDestinationDir(string) error IsMobileDownload() (bool, error) Start() error Pause() error Resume() error Cancel() error Started() chan bool Paused() chan bool DownloadProgress() chan Progress Resumed() chan bool Canceled() chan bool Finished() chan string Error() chan error } // FileDownload represents a single file being downloaded by udm. type FileDownload struct { conn *dbus.Connection proxy proxy path dbus.ObjectPath started chan bool started_w watch paused chan bool paused_w watch resumed chan bool resumed_w watch canceled chan bool canceled_w watch finished chan string finished_w watch errors chan error error_w watch progress chan Progress progress_w watch } func (down *FileDownload) free() { // cancel all watches so that goroutines are done and close the // channels down.started_w.Cancel() down.paused_w.Cancel() down.resumed_w.Cancel() down.canceled_w.Cancel() down.finished_w.Cancel() down.error_w.Cancel() down.progress_w.Cancel() } func cleanDownloadData(down *FileDownload) { down.free() } func newFileDownload(conn *dbus.Connection, path dbus.ObjectPath) (*FileDownload, error) { proxy := conn.Object(DOWNLOAD_SERVICE, path) started_ch := make(chan bool) started_w, err := connectToSignal(conn, path, DOWNLOAD_SERVICE, DOWNLOAD_INTERFACE, "started") if err != nil { return nil, err } paused_ch := make(chan bool) paused_w, err := connectToSignal(conn, path, DOWNLOAD_SERVICE, DOWNLOAD_INTERFACE, "paused") if err != nil { return nil, err } resumed_ch := make(chan bool) resumed_w, err := connectToSignal(conn, path, DOWNLOAD_SERVICE, DOWNLOAD_INTERFACE, "resumed") if err != nil { return nil, err } canceled_ch := make(chan bool) canceled_w, err := connectToSignal(conn, path, DOWNLOAD_SERVICE, DOWNLOAD_INTERFACE, "canceled") if err != nil { return nil, err } finished_ch := make(chan string) finished_w, err := connectToSignal(conn, path, DOWNLOAD_SERVICE, DOWNLOAD_INTERFACE, "finished") if err != nil { return nil, err } errors_ch := make(chan error) errors_w, err := connectToSignal(conn, path, DOWNLOAD_SERVICE, DOWNLOAD_INTERFACE, "error") if err != nil { return nil, err } progress_ch := make(chan Progress) progress_w, err := connectToSignal(conn, path, DOWNLOAD_SERVICE, DOWNLOAD_INTERFACE, "progress") if err != nil { return nil, err } d := FileDownload{conn, proxy, path, started_ch, started_w, paused_ch, paused_w, resumed_ch, resumed_w, canceled_ch, canceled_w, finished_ch, finished_w, errors_ch, errors_w, progress_ch, progress_w} // connect to the diff signals so that we have nice channels that do // not expose dbus watchers d.connectToStarted() d.connectToPaused() d.connectToResumed() d.connectToCanceled() d.connectToFinished() d.connectToError() d.connectToProgress() runtime.SetFinalizer(&d, cleanDownloadData) return &d, nil } // TotalSize returns the total size of the file being downloaded. func (down *FileDownload) TotalSize() (size uint64, err error) { return getUint64Value(down.proxy, DOWNLOAD_INTERFACE, "totalSize") } // Process returns the process so far in downloading the file. func (down *FileDownload) Progress() (progress uint64, err error) { return getUint64Value(down.proxy, DOWNLOAD_INTERFACE, "progress") } // Metadata returns the metadata that was provided at creating time to the download. func (down *FileDownload) Metadata() (metadata map[string]string, err error) { return getMetadataMap(down.proxy, DOWNLOAD_INTERFACE, "metadata") } // SetThrottle sets the network throttle to be used in the download. func (down *FileDownload) SetThrottle(throttle uint64) (err error) { return setUint64Value(down.proxy, DOWNLOAD_INTERFACE, "setThrottle", throttle) } // Throttle returns the network throttle that is currently used in the download. func (down *FileDownload) Throttle() (throttle uint64, err error) { return getUint64Value(down.proxy, DOWNLOAD_INTERFACE, "throttle") } // AllowMobileDownload returns if the download is allow to use the mobile connect // connection. func (down *FileDownload) AllowMobileDownload(allowed bool) (err error) { reply, err := down.proxy.Call(DOWNLOAD_INTERFACE, "allowGSMDownload", allowed) if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("dbus error: %", reply.ErrorName) } return nil } // SetDestinationDir permits unconfined applications to set the destination // directory of the download. This method must be called BEFORE the download // is started else an error will be returned. func (down *FileDownload) SetDestinationDir(path string) (err error) { return setStringValue(down.proxy, DOWNLOAD_INTERFACE, "setDestinationDir", path) } // IsMobileDownload returns if the download will be performed over the mobile data. func (down *FileDownload) IsMobileDownload() (allowed bool, err error) { return getBoolValue(down.proxy, DOWNLOAD_INTERFACE, "isGSMDownloadAllowed") } // Start tells udm that the download is ready to be peformed and that the client is // ready to recieve signals. The following is a common pattern to be used when // creating downloads in udm. // // man, err := udm.NewDownloadManager() // if err != nil { // } // // // variables used to create the download // // url := "http://www.python.org/ftp/python/3.3.3/Python-3.3.3.tar.xz" // hash := "8af44d33ea3a1528fc56b3a362924500" // hashAlgo := MD5 // var metadata map[string]interface{} // var headers map[string]string // // // create the download BUT do not start downloading just yet // down, err := man.CreateDownload(url, hash, hashAlgo, metadata, headers) // // // connect routines to the download channels so that we can get the // // information of the download the channel will not get any data until the // // Start is called. // // started_signal := down.Started() // go func() { // <-started_signal // fmt.Println("Download started") // }() // progress_signal := down.DownloadProgress() // go func() { // for progress := range p { // fmt.Printf("Recieved %d out of %d\n", progress.Received, progress.Total) // } // }() // // finished_signal := down.Finished() // // // start download // down.Start() // // // block until we are finished downloading // <- finished_signal func (down *FileDownload) Start() (err error) { reply, err := down.proxy.Call(DOWNLOAD_INTERFACE, "start") if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("dbus error: %", reply.ErrorName) } return nil } // Pause pauses a download that was started and if not nothing is done. func (down *FileDownload) Pause() (err error) { reply, err := down.proxy.Call(DOWNLOAD_INTERFACE, "pause") if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("dbus error: %", reply.ErrorName) } return nil } // Resumes a download that was paused or does nothing otherwise. func (down *FileDownload) Resume() (err error) { reply, err := down.proxy.Call(DOWNLOAD_INTERFACE, "resume") if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("dbus error: %", reply.ErrorName) } return nil } // Cancel cancels a download that was in process and deletes any local files // that were created. func (down *FileDownload) Cancel() (err error) { reply, err := down.proxy.Call(DOWNLOAD_INTERFACE, "cancel") if err != nil { return err } if reply != nil && reply.Type == dbus.TypeError { return fmt.Errorf("dbus error: %", reply.ErrorName) } return nil } func (down *FileDownload) connectToStarted() { go func() { for msg := range down.started_w.Channel() { var started bool readArgs(msg, &started) down.started <- started } close(down.started) }() } // Started returns a channel that will be used to communicate the started signals. func (down *FileDownload) Started() chan bool { return down.started } func (down *FileDownload) connectToPaused() { go func() { for msg := range down.paused_w.Channel() { var paused bool readArgs(msg, &paused) down.paused <- paused } close(down.paused) }() } // Paused returns a channel that will be used to communicate the paused signals. func (down *FileDownload) Paused() chan bool { return down.paused } func (down *FileDownload) connectToProgress() { go func() { for msg := range down.progress_w.Channel() { var received uint64 var total uint64 readArgs(msg, &received, &total) down.progress <- Progress{received, total} } close(down.progress) }() } // DownloadProgress returns a channel that will be used to communicate the progress // signals. func (down *FileDownload) DownloadProgress() chan Progress { return down.progress } func (down *FileDownload) connectToResumed() { go func() { for msg := range down.resumed_w.Channel() { var resumed bool readArgs(msg, &resumed) down.resumed <- resumed } close(down.resumed) }() } // Resumed returns a channel that will be used to communicate the paused signals. func (down *FileDownload) Resumed() chan bool { return down.resumed } func (down *FileDownload) connectToCanceled() { go func() { for msg := range down.canceled_w.Channel() { var canceled bool readArgs(msg, &canceled) down.canceled <- canceled } close(down.canceled) }() } // Canceled returns a channel that will be used to communicate the canceled signals. func (down *FileDownload) Canceled() chan bool { return down.canceled } func (down *FileDownload) connectToFinished() { go func() { for msg := range down.finished_w.Channel() { var path string readArgs(msg, &path) down.finished <- path } close(down.finished) }() } // Finished returns a channel that will ne used to communicate the finished signals. func (down *FileDownload) Finished() chan string { return down.finished } func (down *FileDownload) connectToError() { go func() { for msg := range down.error_w.Channel() { var reason string readArgs(msg, &reason) down.errors <- errors.New(reason) } close(down.errors) }() } // Error returns the channel that will be used to communicate the error signals. func (down *FileDownload) Error() chan error { return down.errors } type DownloadManager struct { conn *dbus.Connection proxy *dbus.ObjectProxy } // NewDownloadManager creates a new manager that can be used to create download in the // udm daemon. func NewDownloadManager() (*DownloadManager, error) { conn, err := dbus.Connect(dbus.SessionBus) if err != nil { return nil, err } if err != nil { return nil, err } proxy := conn.Object(DOWNLOAD_SERVICE, "/") d := DownloadManager{conn, proxy} return &d, nil } // CreateDownload creates a new download in the udm daemon that can be used to get // a remote resource. Udm allows to pass a hash signature and method that will be // check once the download has been complited. // // The download hash can be one of the the following constants: // // MD5 // SHA1 // SHA224 // SHA256 // SHA384 // SHA512 // // The metadata attribute can be used to pass extra information to the udm daemon // that will just be considered if the caller is not a apparmor confined application. // // LOCAL_PATH => allows to provide the local path for the download. // OBJECT_PATH => allows to provide the object path to be used in the dbus daemon. // POST_DOWNLOAD_COMMAND => allows to provide a command that will be executed on the // download // // The headers attribute allows to provide extra headers to be used in the request used // to perform the download. func (man *DownloadManager) CreateDownload(url string, hash string, algo hashType, metadata map[string]interface{}, headers map[string]string) (down Download, err error) { var t map[string]*dbus.Variant for key, value := range metadata { t[key] = &dbus.Variant{Value: value} } s := struct { U string H string A string M map[string]*dbus.Variant HD map[string]string }{url, hash, string(algo), t, headers} var path dbus.ObjectPath reply, err := man.proxy.Call(DOWNLOAD_MANAGER_INTERFACE, "createDownload", s) if err != nil { return nil, err } if reply != nil && reply.Type == dbus.TypeError { return nil, fmt.Errorf("dbus error: %", reply.ErrorName) } if err = readArgs(reply, &path); err != nil { return nil, err } down, err = newFileDownload(man.conn, path) return down, err } // CreateMmsDownload creates an mms download that will be performed right away. An // mms download only uses mobile that and an apn proxy to download a multime media // message. func (man *DownloadManager) CreateMmsDownload(url string, hostname string, port int32) (down Download, err error) { var path dbus.ObjectPath reply, err := man.proxy.Call(DOWNLOAD_MANAGER_INTERFACE, "createMmsDownload", url, hostname, port) if err != nil { return nil, err } if reply != nil && reply.Type == dbus.TypeError { return nil, fmt.Errorf("dbus error: %", reply.ErrorName) } if err = readArgs(reply, &path); err != nil { return nil, err } down, err = newFileDownload(man.conn, path) return down, err } golang-udm-0.1+14.10.20140721/common.go0000644000015301777760000000737512363157430017636 0ustar pbusernogroup00000000000000/* * Copyright 2014 Canonical Ltd. * * Authors: * Manuel de la Pena: manuel.delapena@canonical.com * * This file is part of ubuntu-download-manager. * * ubuntu-download-manager is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * ubuntu-download-manager is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // Package udm provides a go interface to work with the ubuntu download manager package udm import ( "fmt" "launchpad.net/go-dbus/v1" ) // Progress provides how much progress has been performed in a download that was // already started. type Progress struct { Received uint64 Total uint64 } // internal interface used to simplify testing type watch interface { Cancel() error Channel() chan *dbus.Message } // small wrapper used to simplify testing by using the watch interface type watchWrapper struct { watch *dbus.SignalWatch } func newWatchWrapper(sw *dbus.SignalWatch) *watchWrapper { w := watchWrapper{sw} return &w } func (w *watchWrapper) Cancel() error { return w.watch.Cancel() } func (w *watchWrapper) Channel() chan *dbus.Message { return w.watch.C } // interface added to simplify testing type proxy interface { Call(iface, method string, args ...interface{}) (*dbus.Message, error) } var readArgs = func(msg *dbus.Message, args ...interface{}) error { return msg.Args(args...) } func getUint64Value(p proxy, dbusInterface, valueName string) (uint64, error) { reply, err := p.Call(dbusInterface, valueName) if err != nil { return 0, err } if reply.Type == dbus.TypeError { return 0, fmt.Errorf("dbus error: %", reply.ErrorName) } var value uint64 if err = readArgs(reply, &value); err != nil { return 0, err } return value, nil } func setUint64Value(p proxy, dbusInterface, valueName string, value uint64) error { reply, err := p.Call(dbusInterface, valueName, value) if err != nil { return err } if reply.Type == dbus.TypeError { return fmt.Errorf("dbus error: %", reply.ErrorName) } return nil } func setStringValue(p proxy, dbusInterface, valueName string, value string) error { reply, err := p.Call(dbusInterface, valueName, value) if err != nil { return err } if reply.Type == dbus.TypeError { return fmt.Errorf("dbus error: %", reply.ErrorName) } return nil } func getBoolValue(p proxy, dbusInterface, valueName string) (bool, error) { reply, err := p.Call(dbusInterface, valueName) if err != nil { return false, err } if reply.Type == dbus.TypeError { return false, fmt.Errorf("dbus error: %", reply.ErrorName) } var value bool if err = readArgs(reply, &value); err != nil { return false, err } return value, nil } func getMetadataMap(p proxy, dbusInterface, valueName string) (metadata map[string]string, err error) { var value map[string]string reply, err := p.Call(dbusInterface, valueName) if err != nil { return value, err } if reply.Type == dbus.TypeError { return value, fmt.Errorf("dbus error: %", reply.ErrorName) } if err = readArgs(reply, &value); err != nil { return value, err } return value, nil } func connectToSignal(conn *dbus.Connection, path dbus.ObjectPath, sender, dbusInterface, signal string) (watch, error) { sw, err := conn.WatchSignal(&dbus.MatchRule{ Type: dbus.TypeSignal, Sender: sender, Interface: dbusInterface, Member: signal, Path: path}) w := newWatchWrapper(sw) return w, err }