1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package import1
18
19 import (
20 "fmt"
21 "os"
22 "strconv"
23 "strings"
24
25 "github.com/godbus/dbus/v5"
26 )
27
28 const (
29 dbusInterface = "org.freedesktop.import1.Manager"
30 dbusPath = "/org/freedesktop/import1"
31 )
32
33
34 type Conn struct {
35 conn *dbus.Conn
36 object dbus.BusObject
37 }
38
39
40 type Transfer struct {
41 Id uint32
42 Path dbus.ObjectPath
43 }
44
45
46 type TransferStatus struct {
47 Id uint32
48 Local string
49 Remote string
50 Type string
51 Verify string
52 Progress float64
53 }
54
55
56
57 func New() (*Conn, error) {
58 c := new(Conn)
59
60 if err := c.initConnection(); err != nil {
61 return nil, err
62 }
63
64 return c, nil
65 }
66
67
68 func (c *Conn) Connected() bool {
69 return c.conn.Connected()
70 }
71
72 func (c *Conn) initConnection() error {
73 var err error
74 c.conn, err = dbus.SystemBusPrivate()
75 if err != nil {
76 return err
77 }
78
79
80
81
82 methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(os.Getuid()))}
83
84 err = c.conn.Auth(methods)
85 if err != nil {
86 c.conn.Close()
87 return err
88 }
89
90 err = c.conn.Hello()
91 if err != nil {
92 c.conn.Close()
93 return err
94 }
95
96 c.object = c.conn.Object("org.freedesktop.import1", dbus.ObjectPath(dbusPath))
97
98 return nil
99 }
100
101
102
103
104 func (c *Conn) getResult(method string, args ...interface{}) (*Transfer, error) {
105 result := c.object.Call(fmt.Sprintf("%s.%s", dbusInterface, method), 0, args...)
106 if result.Err != nil {
107 return nil, result.Err
108 }
109
110 if len(result.Body) < 2 {
111 return nil, fmt.Errorf("invalid number of result fields: %v", result.Body)
112 }
113
114 ok := false
115 transfer := &Transfer{}
116
117 transfer.Id, ok = result.Body[0].(uint32)
118 if !ok {
119 return nil, fmt.Errorf("unable to convert dbus response '%v' to uint32", result.Body[0])
120 }
121
122 transfer.Path, ok = result.Body[1].(dbus.ObjectPath)
123 if !ok {
124 return nil, fmt.Errorf("unable to convert dbus response '%v' to dbus.ObjectPath", result.Body[1])
125 }
126 return transfer, nil
127 }
128
129
130 func (c *Conn) ImportTar(
131 f *os.File, local_name string, force, read_only bool,
132 ) (*Transfer, error) {
133 return c.getResult("ImportTar", dbus.UnixFD(f.Fd()), local_name, force, read_only)
134 }
135
136
137 func (c *Conn) ImportRaw(
138 f *os.File, local_name string, force, read_only bool,
139 ) (*Transfer, error) {
140 return c.getResult("ImportRaw", dbus.UnixFD(f.Fd()), local_name, force, read_only)
141 }
142
143
144 func (c *Conn) ExportTar(
145 local_name string, f *os.File, format string,
146 ) (*Transfer, error) {
147 return c.getResult("ExportTar", local_name, dbus.UnixFD(f.Fd()), format)
148 }
149
150
151 func (c *Conn) ExportRaw(
152 local_name string, f *os.File, format string,
153 ) (*Transfer, error) {
154 return c.getResult("ExportRaw", local_name, dbus.UnixFD(f.Fd()), format)
155 }
156
157
158 func (c *Conn) PullTar(
159 url, local_name, verify_mode string, force bool,
160 ) (*Transfer, error) {
161 return c.getResult("PullTar", url, local_name, verify_mode, force)
162 }
163
164
165 func (c *Conn) PullRaw(
166 url, local_name, verify_mode string, force bool,
167 ) (*Transfer, error) {
168 return c.getResult("PullRaw", url, local_name, verify_mode, force)
169 }
170
171
172 func (c *Conn) ListTransfers() ([]TransferStatus, error) {
173 result := make([][]interface{}, 0)
174 if err := c.object.Call(dbusInterface+".ListTransfers", 0).Store(&result); err != nil {
175 return nil, err
176 }
177
178 transfers := make([]TransferStatus, 0)
179 for _, v := range result {
180 transfer, err := transferFromInterfaces(v)
181 if err != nil {
182 return nil, err
183 }
184 transfers = append(transfers, *transfer)
185 }
186
187 return transfers, nil
188 }
189
190
191 func (c *Conn) CancelTransfer(transfer_id uint32) error {
192 return c.object.Call(dbusInterface+".CancelTransfer", 0, transfer_id).Err
193 }
194
195 func transferFromInterfaces(transfer []interface{}) (*TransferStatus, error) {
196
197 if len(transfer) < 5 {
198 return nil, fmt.Errorf("invalid number of transfer fields: %d", len(transfer))
199 }
200
201 ok := false
202 ret := &TransferStatus{}
203
204 ret.Id, ok = transfer[0].(uint32)
205 if !ok {
206 return nil, fmt.Errorf("failed to typecast transfer field 0 to uint32")
207 }
208 ret.Local, ok = transfer[1].(string)
209 if !ok {
210 return nil, fmt.Errorf("failed to typecast transfer field 1 to string")
211 }
212 ret.Remote, ok = transfer[2].(string)
213 if !ok {
214 return nil, fmt.Errorf("failed to typecast transfer field 2 to string")
215 }
216 ret.Type, ok = transfer[3].(string)
217 if !ok {
218 return nil, fmt.Errorf("failed to typecast transfer field 3 to string")
219 }
220
221
222 if !strings.HasPrefix(ret.Type, "pull-") {
223 ret.Progress, ok = transfer[4].(float64)
224 if !ok {
225 return nil, fmt.Errorf("failed to typecast transfer field 4 to float64")
226 }
227 return ret, nil
228 }
229
230 ret.Verify, ok = transfer[4].(string)
231 if !ok {
232 return nil, fmt.Errorf("failed to typecast transfer field 4 to string")
233 }
234 ret.Progress, ok = transfer[5].(float64)
235 if !ok {
236 return nil, fmt.Errorf("failed to typecast transfer field 5 to float64")
237 }
238 return ret, nil
239 }
240
View as plain text