Merge lp:~jderose/dmedia/dbus3 into lp:dmedia
- dbus3
- Merge into trunk
Proposed by
Jason Gerard DeRose
Status: | Merged |
---|---|
Merged at revision: | 291 |
Proposed branch: | lp:~jderose/dmedia/dbus3 |
Merge into: | lp:dmedia |
Diff against target: |
1259 lines (+489/-546) 17 files modified
debian/control (+2/-0) dmedia-browser (+3/-1) dmedia-cli (+146/-230) dmedia-gtk (+1/-1) dmedia-service (+132/-123) dmedia-service3 (+0/-181) dmedia/__init__.py (+1/-0) dmedia/constants.py (+1/-3) dmedia/core.py (+6/-0) dmedia/service/api.py (+2/-2) dmedia/service/avahi.py (+116/-0) dmedia/transfers.py (+2/-2) dmedia/units.py (+13/-0) setup.py (+1/-2) share/org.freedesktop.Dmedia.service (+1/-1) test-cli.py (+33/-0) test-service.py (+29/-0) |
To merge this branch: | bzr merge lp:~jderose/dmedia/dbus3 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
dmedia Dev | Pending | ||
Review via email: mp+88806@code.launchpad.net |
Commit message
Description of the change
The actual porting to python3-dbus was tiny, but then I also had to merge everything into a single real service, which is what most of the change is.
I also did a bit of cleanup and refinement:
1. Renamed DBus bus name from 'org.freedeskto
2. Moved Avahi integration into new dmedia.
3. Revamped the `dmedia-cli` script to be simpler and more maintainable, yet hopefully retain all the good UX enhancements that David Green did
4. Added Dmedia.Resolve() DBus method... this is needed for the Novacut render server, and is the start of the API 3rd party apps will use to integrate with Dmedia
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/control' |
2 | --- debian/control 2011-12-29 07:01:47 +0000 |
3 | +++ debian/control 2012-01-17 04:20:28 +0000 |
4 | @@ -11,6 +11,8 @@ |
5 | Package: dmedia |
6 | Architecture: all |
7 | Depends: ${misc:Depends}, python3 (>= 3.2), |
8 | + python3-gi | python3-gobject, |
9 | + python3-dbus, |
10 | python3-filestore (>= 12.01), |
11 | python3-microfiber (>= 12.01), |
12 | python3-userwebkit (>= 12.01), |
13 | |
14 | === modified file 'dmedia-browser' |
15 | --- dmedia-browser 2012-01-15 15:32:45 +0000 |
16 | +++ dmedia-browser 2012-01-17 04:20:28 +0000 |
17 | @@ -24,18 +24,20 @@ |
18 | from urllib.parse import urlparse |
19 | |
20 | from userwebkit import BaseApp |
21 | +import dmedia |
22 | from dmedia import local |
23 | |
24 | |
25 | class App(BaseApp): |
26 | name = 'dmedia' |
27 | dbname = 'dmedia-0' |
28 | + version = dmedia.__version__ |
29 | title = 'Dmedia Browser' |
30 | |
31 | splash = 'splash.html' |
32 | page = 'browser.html' |
33 | |
34 | - proxy_bus = 'org.freedesktop.DMedia' |
35 | + proxy_bus = dmedia.BUS |
36 | local = None |
37 | |
38 | def dmedia_resolver(self, uri): |
39 | |
40 | === modified file 'dmedia-cli' |
41 | --- dmedia-cli 2011-10-24 21:22:09 +0000 |
42 | +++ dmedia-cli 2012-01-17 04:20:28 +0000 |
43 | @@ -27,234 +27,150 @@ |
44 | Command line tool for talking to dmedia DBus services. |
45 | """ |
46 | |
47 | -from sys import argv, stderr |
48 | +import optparse |
49 | +from collections import OrderedDict |
50 | +import sys |
51 | +from gettext import ngettext |
52 | +from os import path |
53 | + |
54 | +import dbus |
55 | + |
56 | import dmedia |
57 | -from dmedia.service.api import DMedia |
58 | - |
59 | -class DBusCLI (object): |
60 | - """ |
61 | - DBusCLI allows you to easily create command line interfaces from |
62 | - DBus APIs. |
63 | - |
64 | - Example usage: |
65 | - my_cli = DBusCLI( |
66 | - 'mycli', '1.0', 'org.freedesktop.My', |
67 | - '/', 'org.freedesktop.My' |
68 | - ) |
69 | - my_cli.add_action("name1", function1, "usage of name1", "description of name1") |
70 | - my_cli.add_dbus_action("MethodName", "usage of MethodName", "description of MethodName") |
71 | - if __name__ == '__main__': |
72 | - my_cli.main(*sys.argv[1:]) |
73 | - """ |
74 | - def __init__(self, exec_name, version): |
75 | - """ |
76 | - `exec_name` is the name of the executable of the command line |
77 | - program. It should be what the user needs to run to use the |
78 | - program. |
79 | - |
80 | - `version` is the version string of the command line program. |
81 | - |
82 | - `dbus_bus` is the dbus bus name of the dbus API. |
83 | - |
84 | - `dbus_object` is the dbus object of the dbus API. |
85 | - |
86 | - `dbus_iface` is the dbus interface of the dbus API. |
87 | - """ |
88 | - self._exec = exec_name |
89 | - self._version = version |
90 | - self._action_methods = {} |
91 | - self._action_help = {} |
92 | - self._add_default_actions() |
93 | - self._dmedia = DMedia() |
94 | - |
95 | - def has_action(self, name): |
96 | - """ |
97 | - Return true if the action `name` exists, |
98 | - false otherwise. |
99 | - """ |
100 | - return (name in self._action_methods and name in self._action_help) |
101 | - |
102 | - def get_action_method(self, name): |
103 | - """ |
104 | - Return the function for action `name`. |
105 | - """ |
106 | - return self._action_methods[name] |
107 | - |
108 | - def get_usage(self): |
109 | - """ |
110 | - Return the usage string for this program. |
111 | - """ |
112 | - return """Usage: |
113 | -\t%s ACTION [ARGUMENTS] |
114 | - |
115 | -Run: |
116 | -\t%s help ACTION |
117 | -for help with a specific action. |
118 | - |
119 | -Run: |
120 | -\t%s actions |
121 | -for a list of available actions. |
122 | -""" % (self._exec, self._exec, self._exec) |
123 | - |
124 | - def get_help(self, *names): |
125 | - """ |
126 | - Return the help string for action(s) `names`. |
127 | - If no names are specified, the help string will show |
128 | - help for all available actions. |
129 | - """ |
130 | - if len(names) == 0: |
131 | - names = self.get_actions() |
132 | - return "\n".join(map( |
133 | - lambda name: "Action `%s`. Usage:\n\t%s %s %s\n%s\n" % ( |
134 | - (name, self._exec, name) + self._action_help[name] |
135 | - ), |
136 | - names |
137 | - )) |
138 | - |
139 | - def get_actions(self): |
140 | - """ |
141 | - Return all available actions as a tuple. |
142 | - """ |
143 | - return tuple(self._action_methods) |
144 | - |
145 | - def show_usage(self): |
146 | - """ |
147 | - Display the usage string for this program. |
148 | - """ |
149 | - print(self.get_usage()) |
150 | - |
151 | - def show_help(self, *names): |
152 | - """ |
153 | - Display the help string for `names`. See `get_help`. |
154 | - """ |
155 | - print(self.get_help(*names)) |
156 | - |
157 | - def show_actions(self): |
158 | - """ |
159 | - Display all available actions, each on a separate line. |
160 | - """ |
161 | - print("\n".join(self.get_actions())) |
162 | - |
163 | - def show_version(self): |
164 | - """ |
165 | - Display the version of this program. |
166 | - """ |
167 | - print(self._version) |
168 | - |
169 | - def dbus_run(self, name, *args): |
170 | - """ |
171 | - Run the dbus method `name` with arguments `args`. |
172 | - Catch any errors and print them to stderr. |
173 | - """ |
174 | - try: |
175 | - method = getattr(self._dmedia, name) |
176 | - print(str(method(*args))) |
177 | - except Exception as e: |
178 | - stderr.write("Error: {}\n".format(e)) |
179 | - |
180 | - def run_action(self, name, *args): |
181 | - """ |
182 | - Run the action `name` with arguments `args`. |
183 | - """ |
184 | - if self.has_action(name): |
185 | - self.get_action_method(name)(*args) |
186 | - else: |
187 | - stderr.write("No such action `%s`\n" % name) |
188 | - print(self.get_usage()) |
189 | - |
190 | - def run_action_with_bus(self, bus, name, *args): |
191 | - """ |
192 | - Run the action `name` with arguments `args`. |
193 | - Use a custom dbus bus name `bus`. |
194 | - """ |
195 | - self._bus = bus |
196 | - self.run_action(name, *args) |
197 | - |
198 | - def add_action(self, name, function=lambda *a:None, usage="", description=""): |
199 | - """ |
200 | - Add an action to the command line program. |
201 | - `name` is the name of the action. |
202 | - `function` is the function to be called for this action. |
203 | - `usage` is a string describing the arguments of the action to the user. |
204 | - `description` is a string describing what the action does. |
205 | - """ |
206 | - self._action_methods[name] = function |
207 | - self._action_help[name] = (usage, description) |
208 | - |
209 | - def add_dbus_action(self, name, usage="", description=""): |
210 | - """ |
211 | - Add an action to the command line program based upon a dbus method. |
212 | - `name` is the name of the action and the name of the dbus method. |
213 | - `usage` is a string describing the arguments of the action to the user. |
214 | - `description` is a string describing what the action does. |
215 | - """ |
216 | - self.add_action( |
217 | - name, |
218 | - lambda *args:self.dbus_run(name, *args), |
219 | - usage, |
220 | - description |
221 | - ) |
222 | - |
223 | - def _add_default_actions(self): |
224 | - #version |
225 | - self.add_action( |
226 | - "version", |
227 | - self.show_version, |
228 | - "", |
229 | - "Display the version of this program." |
230 | - ) |
231 | - #help |
232 | - self.add_action( |
233 | - "help", |
234 | - self.show_help, |
235 | - "[ACTION_1] [ACTION_2] ... [ACTION_N]", |
236 | - "Display help information for each of the listed actions. If no actions are listed, help will be displayed for all available actions." |
237 | - ) |
238 | - #usage |
239 | - self.add_action( |
240 | - "usage", |
241 | - self.show_usage, |
242 | - "", |
243 | - "Display a usage message." |
244 | - ) |
245 | - #actions |
246 | - self.add_action( |
247 | - "actions", |
248 | - self.show_actions, |
249 | - "", |
250 | - "Display the list of available actions." |
251 | - ) |
252 | - #bus |
253 | - self.add_action( |
254 | - "bus", |
255 | - self.run_action_with_bus, |
256 | - "BUS_NAME ACTION [ARGUMENTS]", |
257 | - "Run an action using the dbus bus `BUS_NAME` for any dbus interaction." |
258 | - ) |
259 | - |
260 | - def main(self, *args): |
261 | - """ |
262 | - Run the command line program with the specified arguments. |
263 | - """ |
264 | - args = list(args) |
265 | - if len(args) < 1: |
266 | - self.run_action("usage") |
267 | - else: |
268 | - self.run_action(args.pop(0), *args) |
269 | - |
270 | -dmedia_cli = DBusCLI("dmedia-cli", dmedia.__version__) |
271 | - |
272 | -dmedia_cli.add_dbus_action("Version", "", "Display the version of running `dmedia-service`.") |
273 | -dmedia_cli.add_dbus_action("Kill", "", "Shutdown `dmedia-service`.") |
274 | -dmedia_cli.add_dbus_action("AddFileStore", "PARENT_DIR", "Add a new dmedia file store. Create it in the `PARENT_DIR` directory (eg. /home/username).") |
275 | -dmedia_cli.add_dbus_action("RemoveFileStore", "PARENT_DIR", "Remove an existing dmedia file store.") |
276 | -#dmedia_cli.add_dbus_action("GetDoc", "DOC_ID", "Get a document from CouchDB. `DOC_ID` is the _id of the document.") |
277 | -#dmedia_cli.add_dbus_action("Upload", "FILE_ID STORE_ID", "Upload the file with id `FILE_ID` to the remote store with id `STORE_ID`.") |
278 | -#dmedia_cli.add_dbus_action("Download", "FILE_ID STORE_ID", "Download the file with id `FILE_ID` from the remote store with id `STORE_ID`.") |
279 | -#dmedia_cli.add_dbus_action("ListTransfers", "", "List active uploads and downloads.") |
280 | -dmedia_cli.add_dbus_action("GetEnv", "", "Display dmedia env as JSON.") |
281 | -#dmedia_cli.add_dbus_action("GetAuthURL", "", "Get URL with basic auth user and password.") |
282 | -#dmedia_cli.add_dbus_action("HasApp", "", "") |
283 | - |
284 | -if __name__ == '__main__': |
285 | - dmedia_cli.main(*argv[1:]) |
286 | +from dmedia.units import minsec |
287 | + |
288 | + |
289 | +methods = OrderedDict() |
290 | +session = dbus.SessionBus() |
291 | + |
292 | + |
293 | +def error(msg, code=1): |
294 | + print('ERROR:', msg) |
295 | + sys.exit(code) |
296 | + |
297 | + |
298 | +def print_methods(): |
299 | + print('DBus methods on {}:'.format(dmedia.BUS)) |
300 | + width = max(len(name) for name in methods) |
301 | + for name in methods: |
302 | + cls = methods[name] |
303 | + print(' {} {}'.format(name.ljust(width), cls.__doc__)) |
304 | + |
305 | + |
306 | +def print_usage(cls): |
307 | + print('Usage:') |
308 | + print(' ', *cls.usage()) |
309 | + |
310 | + |
311 | +class MethodMeta(type): |
312 | + def __new__(meta, name, bases, dict): |
313 | + cls = type.__new__(meta, name, bases, dict) |
314 | + if not name.startswith('_'): |
315 | + methods[name] = cls |
316 | + return cls |
317 | + |
318 | + |
319 | +class _Method(metaclass=MethodMeta): |
320 | + args = tuple() |
321 | + |
322 | + def __init__(self, bus): |
323 | + self.bus = bus |
324 | + self.proxy = session.get_object(bus, '/') |
325 | + |
326 | + @classmethod |
327 | + def usage(cls): |
328 | + script = path.basename(sys.argv[0]) |
329 | + cmd = [script, cls.__name__] |
330 | + cmd.extend(arg.upper() for arg in cls.args) |
331 | + return cmd |
332 | + |
333 | + def run(self, args): |
334 | + args = self.validate_args(*args) |
335 | + method = self.proxy.get_dbus_method(self.__class__.__name__) |
336 | + return self.format_output(method(*args)) |
337 | + |
338 | + def validate_args(self, *args): |
339 | + return args |
340 | + |
341 | + def format_output(self, output): |
342 | + return output |
343 | + |
344 | + |
345 | +class Version(_Method): |
346 | + 'Show version of running `dmedia-service`' |
347 | + |
348 | + |
349 | +class Kill(_Method): |
350 | + 'Shutdown `dmedia-service`' |
351 | + |
352 | + def format_output(self, seconds): |
353 | + return '{} was running for {}'.format(self.bus, minsec(seconds)) |
354 | + |
355 | + |
356 | +class GetEnv(_Method): |
357 | + 'Get the CouchDB and Dmedia environment info' |
358 | + |
359 | + |
360 | +class LocalDmedia(_Method): |
361 | + 'Get the _local/dmedia document (shows file-stores)' |
362 | + |
363 | + |
364 | +class LocalPeers(_Method): |
365 | + 'Get the _local/peers document' |
366 | + |
367 | + |
368 | +class AddFileStore(_Method): |
369 | + 'Add a file storage location' |
370 | + |
371 | + args = ['directory'] |
372 | + |
373 | + def validate_args(self, directory): |
374 | + return [path.abspath(directory)] |
375 | + |
376 | + |
377 | +class RemoveFileStore(AddFileStore): |
378 | + 'Add a file storage location' |
379 | + |
380 | + |
381 | +class Resolve(_Method): |
382 | + 'Resolve Dmedia file ID into a regular file path' |
383 | + |
384 | + args = ['file_id'] |
385 | + |
386 | + |
387 | +parser = optparse.OptionParser( |
388 | + usage='%prog METHOD [ARGS...]', |
389 | + version=dmedia.__version__, |
390 | +) |
391 | +parser.add_option('--bus', |
392 | + help='DBus bus name; default is {!r}'.format(dmedia.BUS), |
393 | + default=dmedia.BUS |
394 | +) |
395 | +(options, args) = parser.parse_args() |
396 | + |
397 | + |
398 | +if len(args) == 0: |
399 | + parser.print_help() |
400 | + print('') |
401 | + print_methods() |
402 | + sys.exit(0) |
403 | + |
404 | +name = args[0] |
405 | +args = args[1:] |
406 | +if name not in methods: |
407 | + print_methods() |
408 | + print('') |
409 | + error('Unknown method {!r}'.format(name)) |
410 | + |
411 | +cls = methods[name] |
412 | +if len(args) != len(cls.args): |
413 | + print_usage(cls) |
414 | + print('') |
415 | + msg = ngettext( |
416 | + '{!r} takes exactly {} argument', |
417 | + '{!r} takes exactly {} arguments', |
418 | + len(cls.args) |
419 | + ) |
420 | + error(msg.format(name, len(cls.args))) |
421 | + |
422 | +method = cls(options.bus) |
423 | +print(method.run(args)) |
424 | |
425 | === modified file 'dmedia-gtk' |
426 | --- dmedia-gtk 2012-01-04 10:10:10 +0000 |
427 | +++ dmedia-gtk 2012-01-17 04:20:28 +0000 |
428 | @@ -157,7 +157,7 @@ |
429 | splash = 'splash.html' |
430 | page = 'index.html' |
431 | title = 'Dmedia' |
432 | - proxy_bus = 'org.freedesktop.DMedia' |
433 | + proxy_bus = dmedia.BUS |
434 | |
435 | signals = { |
436 | 'create_project': ['title'], |
437 | |
438 | === modified file 'dmedia-service' |
439 | --- dmedia-service 2012-01-03 02:31:47 +0000 |
440 | +++ dmedia-service 2012-01-17 04:20:28 +0000 |
441 | @@ -1,4 +1,4 @@ |
442 | -#!/usr/bin/python |
443 | +#!/usr/bin/python3 |
444 | |
445 | # dmedia: distributed media library |
446 | # Copyright (C) 2011 Novacut Inc |
447 | @@ -22,159 +22,168 @@ |
448 | # Jason Gerard DeRose <jderose@novacut.com> |
449 | |
450 | """ |
451 | -Hacky shim till it's possible to implement DBus servers in PyGI. |
452 | - |
453 | -Note that because this script must be Python2, it can't import anything from the |
454 | -`dmedia` package as that will only be installed under Python3. |
455 | +Dmedia DBus service on org.freedesktop.Dmedia. |
456 | """ |
457 | |
458 | -import argparse |
459 | -import os |
460 | -from os import path |
461 | -from subprocess import Popen |
462 | +import time |
463 | +start_time = time.time() |
464 | + |
465 | +import optparse |
466 | import logging |
467 | -import time |
468 | -import sys |
469 | import json |
470 | +from os import path |
471 | |
472 | -import xdg.BaseDirectory |
473 | import dbus |
474 | import dbus.service |
475 | from dbus.mainloop.glib import DBusGMainLoop |
476 | -from dc3lib.microfiber import Database, NotFound |
477 | - |
478 | - |
479 | -__version__ = '12.01.0' |
480 | -BUS = 'org.freedesktop.DMedia' |
481 | +from microfiber import Database, NotFound |
482 | +from gi.repository import GObject |
483 | + |
484 | +import dmedia |
485 | +from dmedia.core import Core, start_file_server |
486 | +from dmedia.service.dbus import UDisks |
487 | +from dmedia.service.avahi import Avahi |
488 | + |
489 | + |
490 | +BUS = dmedia.BUS |
491 | IFACE = BUS |
492 | log = logging.getLogger() |
493 | -service3 = path.join(path.dirname(path.abspath(__file__)), 'dmedia-service3') |
494 | -assert path.isfile(service3) |
495 | |
496 | +GObject.threads_init() |
497 | DBusGMainLoop(set_as_default=True) |
498 | session = dbus.SessionBus() |
499 | |
500 | |
501 | -def configure_logging(): |
502 | - format = [ |
503 | - '%(levelname)s', |
504 | - '%(message)s', |
505 | - ] |
506 | - script = path.abspath(sys.argv[0]) |
507 | - namespace = path.basename(script) |
508 | - cache = path.join(xdg.BaseDirectory.xdg_cache_home, 'dmedia') |
509 | - if not path.exists(cache): |
510 | - os.makedirs(cache) |
511 | - filename = path.join(cache, namespace + '.log') |
512 | - if path.exists(filename): |
513 | - os.rename(filename, filename + '.previous') |
514 | - logging.basicConfig( |
515 | - filename=filename, |
516 | - filemode='w', |
517 | - level=logging.DEBUG, |
518 | - format='\t'.join(format), |
519 | - ) |
520 | - logging.info('script: %r', script) |
521 | - logging.info('dmedia.__file__: %r', __file__) |
522 | - logging.info('dmedia.__version__: %r', __version__) |
523 | - |
524 | - |
525 | -class DMedia(dbus.service.Object): |
526 | - def __init__(self, bus, mainloop): |
527 | - self._killed = False |
528 | - self._bus = bus |
529 | - self._mainloop = mainloop |
530 | - |
531 | - log.info('Binding to %r', bus) |
532 | - super(DMedia, self).__init__(session, object_path='/') |
533 | - self._busname = dbus.service.BusName(bus, session) |
534 | - |
535 | - self._dc3 = session.get_object('org.freedesktop.DC3', '/') |
536 | - self._machine_id = None |
537 | - env = self._get_env() |
538 | - |
539 | - log.info('Starting %r', service3) |
540 | - self._child = Popen([service3, '--bus', bus]) |
541 | - db = Database('dmedia-0', env) |
542 | - while True: |
543 | - try: |
544 | - time.sleep(0.1) |
545 | - doc = db.get('_local/dmedia') |
546 | - self._machine_id = doc['machine_id'] |
547 | - log.info('machine_id = %r', self._machine_id) |
548 | - break |
549 | - except NotFound: |
550 | - pass |
551 | - |
552 | - def _get_env(self): |
553 | - log.info('Calling DC3.GetEnv()') |
554 | - env = json.loads(self._dc3.GetEnv()) |
555 | - env['machine_id'] = self._machine_id |
556 | - return env |
557 | +def dumps(obj): |
558 | + return json.dumps(obj, sort_keys=True, separators=(',', ': '), indent=4) |
559 | + |
560 | + |
561 | +class Service(dbus.service.Object): |
562 | + httpd = None |
563 | + avahi = None |
564 | + |
565 | + def __init__(self, bus, env_s): |
566 | + self.bus = bus |
567 | + self.env_s = env_s |
568 | + self.mainloop = GObject.MainLoop() |
569 | + log.info('DBus: binding to %r', bus) |
570 | + super().__init__(session, object_path='/') |
571 | + self.busname = dbus.service.BusName(bus, session) |
572 | + |
573 | + def start_core(self): |
574 | + if self.env_s is None: |
575 | + self.dc3 = session.get_object('org.freedesktop.DC3', '/') |
576 | + env = json.loads(self.dc3.GetEnv()) |
577 | + else: |
578 | + env = json.loads(self.env_s) |
579 | + self.udisks = UDisks() |
580 | + self.core = Core(env, self.udisks.get_parentdir_info) |
581 | + self.env_s = dumps(self.core.env) |
582 | + if len(self.core.stores) == 0: |
583 | + self.core.add_filestore('/home') |
584 | + self.udisks.connect('store_added', self.on_store_added) |
585 | + self.udisks.connect('store_removed', self.on_store_removed) |
586 | + self.udisks.monitor() |
587 | + |
588 | + def start_httpd(self): |
589 | + (self.httpd, self.port) = start_file_server(self.core.env) |
590 | + self.avahi = Avahi(self.core.env, self.port) |
591 | + self.avahi.run() |
592 | + |
593 | + def run(self): |
594 | + self.start_core() |
595 | + self.start_httpd() |
596 | + self.mainloop.run() |
597 | + |
598 | + def kill(self): |
599 | + if self.avahi is not None: |
600 | + self.avahi.free() |
601 | + if self.httpd is not None: |
602 | + self.httpd.terminate() |
603 | + self.httpd.join() |
604 | + self.mainloop.quit() |
605 | + |
606 | + def on_store_added(self, udisks, obj, parentdir, partition, drive): |
607 | + log.info('UDisks store_added: %r', parentdir) |
608 | + try: |
609 | + self.AddFileStore(parentdir) |
610 | + except Exception: |
611 | + log.exception('Could not add FileStore %r', parentdir) |
612 | + |
613 | + def on_store_removed(self, udisks, obj, parentdir): |
614 | + log.info('UDisks store_removed: %r', parentdir) |
615 | + try: |
616 | + self.RemoveFileStore(parentdir) |
617 | + except Exception: |
618 | + log.exception('Could not remove FileStore %r', parentdir) |
619 | |
620 | @dbus.service.method(IFACE, in_signature='', out_signature='s') |
621 | def Version(self): |
622 | """ |
623 | Return dmedia version. |
624 | """ |
625 | - return __version__ |
626 | + return dmedia.__version__ |
627 | |
628 | - @dbus.service.method(IFACE, in_signature='', out_signature='') |
629 | + @dbus.service.method(IFACE, in_signature='', out_signature='i') |
630 | def Kill(self): |
631 | """ |
632 | Kill the `dmedia-service` process. |
633 | """ |
634 | - if self._killed: |
635 | - return |
636 | - self._killed = True |
637 | - log.info('Killing dmedia core service on %r', self._bus) |
638 | - self.FwdKill() |
639 | - self._child.wait() |
640 | - self._mainloop.quit() |
641 | - |
642 | - @dbus.service.signal(IFACE, signature='') |
643 | - def FwdKill(self): |
644 | - pass |
645 | + self.kill() |
646 | + return int(time.time() - start_time) |
647 | |
648 | @dbus.service.method(IFACE, in_signature='', out_signature='s') |
649 | def GetEnv(self): |
650 | """ |
651 | Return dmedia env as JSON string. |
652 | """ |
653 | - return json.dumps(self._get_env()) |
654 | - |
655 | - @dbus.service.method(IFACE, in_signature='s', out_signature='') |
656 | + return self.env_s |
657 | + |
658 | + @dbus.service.method(IFACE, in_signature='', out_signature='s') |
659 | + def LocalDmedia(self): |
660 | + """ |
661 | + Return the _local/dmedia doc. |
662 | + """ |
663 | + return dumps(self.core.db.get('_local/dmedia')) |
664 | + |
665 | + @dbus.service.method(IFACE, in_signature='', out_signature='s') |
666 | + def LocalPeers(self): |
667 | + """ |
668 | + Return the _local/peers doc. |
669 | + """ |
670 | + return dumps(self.core.db.get('_local/peers')) |
671 | + |
672 | + @dbus.service.method(IFACE, in_signature='s', out_signature='s') |
673 | def AddFileStore(self, parentdir): |
674 | - self.FwdAddFileStore(parentdir) |
675 | - |
676 | - @dbus.service.signal(IFACE, signature='s') |
677 | - def FwdAddFileStore(self, parentdir): |
678 | - pass |
679 | - |
680 | - @dbus.service.method(IFACE, in_signature='s', out_signature='') |
681 | + fs = self.core.add_filestore(parentdir) |
682 | + return self.LocalDmedia() |
683 | + |
684 | + @dbus.service.method(IFACE, in_signature='s', out_signature='s') |
685 | def RemoveFileStore(self, parentdir): |
686 | - self.FwdRemoveFileStore(parentdir) |
687 | - |
688 | - @dbus.service.signal(IFACE, signature='s') |
689 | - def FwdRemoveFileStore(self, parentdir): |
690 | - pass |
691 | - |
692 | - |
693 | -parser = argparse.ArgumentParser( |
694 | - description='DBus service @{}'.format(BUS), |
695 | -) |
696 | -parser.add_argument('--version', action='version', version=__version__) |
697 | -parser.add_argument('--bus', |
698 | - default=BUS, |
699 | - help='DBus bus name; default is %(default)r', |
700 | -) |
701 | -args = parser.parse_args() |
702 | -configure_logging() |
703 | - |
704 | -from gi.repository import GObject |
705 | -GObject.threads_init() |
706 | - |
707 | -mainloop = GObject.MainLoop() |
708 | -dmedia = DMedia(args.bus, mainloop) |
709 | -mainloop.run() |
710 | -dmedia.Kill() |
711 | + fs = self.core.remove_filestore(parentdir) |
712 | + return self.LocalDmedia() |
713 | + |
714 | + @dbus.service.method(IFACE, in_signature='s', out_signature='s') |
715 | + def Resolve(self, _id): |
716 | + return self.core.resolve(_id) |
717 | + |
718 | + |
719 | +parser = optparse.OptionParser( |
720 | + version=dmedia.__version__, |
721 | +) |
722 | +parser.add_option('--env', |
723 | + help='JSON-encoded CouchDB environment (for unit testing)', |
724 | +) |
725 | +parser.add_option('--bus', |
726 | + help='DBus bus name; default is {!r}'.format(BUS), |
727 | + default=BUS |
728 | +) |
729 | +(options, args) = parser.parse_args() |
730 | + |
731 | + |
732 | +dmedia.configure_logging() |
733 | +service = Service(options.bus, options.env) |
734 | +try: |
735 | + service.run() |
736 | +finally: |
737 | + service.kill() |
738 | |
739 | === removed file 'dmedia-service3' |
740 | --- dmedia-service3 2011-12-27 10:02:37 +0000 |
741 | +++ dmedia-service3 1970-01-01 00:00:00 +0000 |
742 | @@ -1,181 +0,0 @@ |
743 | -#!/usr/bin/python3 |
744 | - |
745 | -# dmedia: distributed media library |
746 | -# Copyright (C) 2011 Novacut Inc |
747 | -# |
748 | -# This file is part of `dmedia`. |
749 | -# |
750 | -# `dmedia` is free software: you can redistribute it and/or modify it under |
751 | -# the terms of the GNU Affero General Public License as published by the Free |
752 | -# Software Foundation, either version 3 of the License, or (at your option) any |
753 | -# later version. |
754 | -# |
755 | -# `dmedia` is distributed in the hope that it will be useful, but WITHOUT ANY |
756 | -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR |
757 | -# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
758 | -# details. |
759 | -# |
760 | -# You should have received a copy of the GNU Affero General Public License along |
761 | -# with `dmedia`. If not, see <http://www.gnu.org/licenses/>. |
762 | -# |
763 | -# Authors: |
764 | -# Jason Gerard DeRose <jderose@novacut.com> |
765 | - |
766 | -""" |
767 | -The real Python3 dmedia DBus service (well, almost). |
768 | -""" |
769 | - |
770 | -import sys |
771 | -import json |
772 | -from os import path |
773 | -import optparse |
774 | -import logging |
775 | - |
776 | -from gi.repository import GObject |
777 | -from microfiber import NotFound |
778 | - |
779 | -import dmedia |
780 | -from dmedia.service import dbus |
781 | -from dmedia.service.dbus import session, UDisks |
782 | -from dmedia.core import Core, start_file_server |
783 | - |
784 | -GObject.threads_init() |
785 | -log = logging.getLogger() |
786 | - |
787 | - |
788 | -class DMedia: |
789 | - def __init__(self, bus): |
790 | - self.mainloop = GObject.MainLoop() |
791 | - dc3 = session.get('org.freedesktop.DC3', '/') |
792 | - env = json.loads(dc3.GetEnv()) |
793 | - self.udisks = UDisks() |
794 | - self.core = Core(env, self.udisks.get_parentdir_info) |
795 | - if len(self.core.stores) == 0: |
796 | - self.core.add_filestore('/home') |
797 | - self._fwd = { |
798 | - 'AddFileStore': self.AddFileStore, |
799 | - 'RemoveFileStore': self.RemoveFileStore, |
800 | - 'Kill': self.Kill, |
801 | - } |
802 | - if bus: |
803 | - log.info('Listing to forwards from %r', bus) |
804 | - self.proxy = session.get(bus, '/', 'org.freedesktop.DMedia') |
805 | - self.proxy.connect('g-signal', self.on_g_signal) |
806 | - self.avahi = dbus.system.get( |
807 | - 'org.freedesktop.Avahi', |
808 | - '/', |
809 | - 'org.freedesktop.Avahi.Server' |
810 | - ) |
811 | - try: |
812 | - self._peers = self.core.db.get('_local/peers') |
813 | - except NotFound: |
814 | - self._peers = {'_id': '_local/peers'} |
815 | - self._peers['peers'] = {} |
816 | - self.core.db.save(self._peers) |
817 | - self.udisks.connect('store_added', self.on_store_added) |
818 | - self.udisks.connect('store_removed', self.on_store_removed) |
819 | - self.udisks.monitor() |
820 | - |
821 | - def run(self): |
822 | - (self.httpd, self.port) = start_file_server(self.core.env) |
823 | - self.group = dbus.system.get( |
824 | - 'org.freedesktop.Avahi', |
825 | - self.avahi.EntryGroupNew(), |
826 | - 'org.freedesktop.Avahi.EntryGroup' |
827 | - ) |
828 | - self.group.AddService('(iiussssqaay)', |
829 | - -1, # Interface |
830 | - 0, # Protocol -1 = both, 0 = ipv4, 1 = ipv6 |
831 | - 0, # Flags |
832 | - self.core.machine_id, |
833 | - '_dmedia._tcp', |
834 | - '', # Domain, default to .local |
835 | - '', # Host, default to localhost |
836 | - self.port, # Port |
837 | - None # TXT record |
838 | - ) |
839 | - self.group.Commit() |
840 | - browser_path = self.avahi.ServiceBrowserNew('(iissu)', |
841 | - -1, # Interface |
842 | - 0, # Protocol -1 = both, 0 = ipv4, 1 = ipv6 |
843 | - '_dmedia._tcp', |
844 | - 'local', |
845 | - 0 # Flags |
846 | - ) |
847 | - self.browser = dbus.system.get( |
848 | - 'org.freedesktop.Avahi', |
849 | - browser_path, |
850 | - 'org.freedesktop.Avahi.ServiceBrowser' |
851 | - ) |
852 | - self.browser.connect('g-signal', self.on_browser_g_signal) |
853 | - self.mainloop.run() |
854 | - |
855 | - def on_store_added(self, udisks, obj, parentdir, partition, drive): |
856 | - log.info('UDisks store_added: %r', parentdir) |
857 | - try: |
858 | - self.AddFileStore(parentdir) |
859 | - except Exception: |
860 | - log.exception('Could not add FileStore %r', parentdir) |
861 | - |
862 | - def on_store_removed(self, udisks, obj, parentdir): |
863 | - log.info('UDisks store_removed: %r', parentdir) |
864 | - try: |
865 | - self.RemoveFileStore(parentdir) |
866 | - except Exception: |
867 | - log.exception('Could not remove FileStore %r', parentdir) |
868 | - |
869 | - def on_g_signal(self, proxy, sender, signal, params): |
870 | - if signal.startswith('Fwd'): |
871 | - name = signal[3:] |
872 | - args = params.unpack() |
873 | - try: |
874 | - self._fwd[name](*args) |
875 | - except KeyError: |
876 | - pass |
877 | - |
878 | - def on_browser_g_signal(self, proxy, sender, signal, params): |
879 | - if signal == 'ItemNew': |
880 | - (interface, protocol, name, _type, domain, flags) = params.unpack() |
881 | - if name != self.core.machine_id: # Ignore what we publish ourselves |
882 | - (ip, port) = self.avahi.ResolveService('(iisssiu)', |
883 | - interface, protocol, name, _type, domain, -1, 0 |
884 | - )[7:9] |
885 | - url = 'http://{}:{}/'.format(ip, port) |
886 | - log.info('New peer %r at %r', name, url) |
887 | - self._peers['peers'][name] = url |
888 | - self.core.db.save(self._peers) |
889 | - elif signal == 'ItemRemove': |
890 | - (interface, protocol, name, _type, domain, flags) = params.unpack() |
891 | - log.info('Removing peer %r', name) |
892 | - try: |
893 | - del self._peers['peers'][name] |
894 | - self.core.db.save(self._peers) |
895 | - except KeyError: |
896 | - pass |
897 | - |
898 | - def AddFileStore(self, parentdir): |
899 | - self.core.add_filestore(path.abspath(parentdir)) |
900 | - |
901 | - def RemoveFileStore(self, parentdir): |
902 | - self.core.remove_filestore(path.abspath(parentdir)) |
903 | - |
904 | - def Kill(self): |
905 | - self.group.Reset() |
906 | - self.httpd.terminate() |
907 | - self.httpd.join() |
908 | - self.mainloop.quit() |
909 | - |
910 | - |
911 | -parser = optparse.OptionParser( |
912 | - usage='Usage: %prog FILE', |
913 | - version=dmedia.__version__, |
914 | -) |
915 | -parser.add_option('--bus', |
916 | - help='If provided, expect Python2 shim on this DBus bus', |
917 | -) |
918 | -(options, args) = parser.parse_args() |
919 | - |
920 | -dmedia.configure_logging() |
921 | -service = DMedia(options.bus) |
922 | -service.run() |
923 | -service.Kill() |
924 | |
925 | === modified file 'dmedia/__init__.py' |
926 | --- dmedia/__init__.py 2011-12-27 07:21:46 +0000 |
927 | +++ dmedia/__init__.py 2012-01-17 04:20:28 +0000 |
928 | @@ -27,6 +27,7 @@ |
929 | """ |
930 | |
931 | __version__ = '12.01.0' |
932 | +BUS = 'org.freedesktop.Dmedia' |
933 | |
934 | |
935 | def configure_logging(): |
936 | |
937 | === modified file 'dmedia/constants.py' |
938 | --- dmedia/constants.py 2012-01-03 02:12:57 +0000 |
939 | +++ dmedia/constants.py 2012-01-17 04:20:28 +0000 |
940 | @@ -45,10 +45,8 @@ |
941 | |
942 | |
943 | # D-Bus releated: |
944 | -BUS = 'org.freedesktop.DMedia' |
945 | +BUS = 'org.freedesktop.Dmedia' |
946 | IFACE = BUS |
947 | -IMPORT_BUS = 'org.freedesktop.DMediaImporter' |
948 | -IMPORT_IFACE = IMPORT_BUS |
949 | DC_BUS = 'org.desktopcouch.CouchDB' |
950 | DC_INTERFACE = DC_BUS |
951 | |
952 | |
953 | === modified file 'dmedia/core.py' |
954 | --- dmedia/core.py 2012-01-02 23:49:23 +0000 |
955 | +++ dmedia/core.py 2012-01-17 04:20:28 +0000 |
956 | @@ -39,6 +39,7 @@ |
957 | from microfiber import Database, NotFound, random_id2 |
958 | from filestore import FileStore, check_root_hash, check_id |
959 | |
960 | +import dmedia |
961 | from dmedia import schema |
962 | from dmedia.local import LocalStores |
963 | from dmedia.views import init_views |
964 | @@ -133,6 +134,7 @@ |
965 | self.db.save(machine) |
966 | self.machine_id = self.local['machine_id'] |
967 | self.env['machine_id'] = self.machine_id |
968 | + self.env['version'] = dmedia.__version__ |
969 | log.info('machine_id = %r', self.machine_id) |
970 | |
971 | def _init_stores(self): |
972 | @@ -207,3 +209,7 @@ |
973 | assert set(self.local['stores']) == set(self.stores.parentdirs) |
974 | assert set(s['id'] for s in self.local['stores'].values()) == set(self.stores.ids) |
975 | |
976 | + def resolve(self, _id): |
977 | + doc = self.db.get(_id) |
978 | + fs = self.stores.choose_local_store(doc) |
979 | + return fs.stat(_id).name |
980 | |
981 | === modified file 'dmedia/service/api.py' |
982 | --- dmedia/service/api.py 2011-10-24 21:36:05 +0000 |
983 | +++ dmedia/service/api.py 2012-01-17 04:20:28 +0000 |
984 | @@ -30,10 +30,10 @@ |
985 | |
986 | class DMedia: |
987 | """ |
988 | - Talk to "org.freedesktop.DMedia". |
989 | + Talk to "org.freedesktop.Dmedia". |
990 | """ |
991 | |
992 | - def __init__(self, bus='org.freedesktop.DMedia'): |
993 | + def __init__(self, bus='org.freedesktop.Dmedia'): |
994 | self.bus = bus |
995 | self._proxy = None |
996 | |
997 | |
998 | === added file 'dmedia/service/avahi.py' |
999 | --- dmedia/service/avahi.py 1970-01-01 00:00:00 +0000 |
1000 | +++ dmedia/service/avahi.py 2012-01-17 04:20:28 +0000 |
1001 | @@ -0,0 +1,116 @@ |
1002 | +# dmedia: distributed media library |
1003 | +# Copyright (C) 2011 Novacut Inc |
1004 | +# |
1005 | +# This file is part of `dmedia`. |
1006 | +# |
1007 | +# `dmedia` is free software: you can redistribute it and/or modify it under the |
1008 | +# terms of the GNU Affero General Public License as published by the Free |
1009 | +# Software Foundation, either version 3 of the License, or (at your option) any |
1010 | +# later version. |
1011 | +# |
1012 | +# `dmedia` is distributed in the hope that it will be useful, but WITHOUT ANY |
1013 | +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR |
1014 | +# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
1015 | +# details. |
1016 | +# |
1017 | +# You should have received a copy of the GNU Affero General Public License along |
1018 | +# with `dmedia`. If not, see <http://www.gnu.org/licenses/>. |
1019 | +# |
1020 | +# Authors: |
1021 | +# Jason Gerard DeRose <jderose@novacut.com> |
1022 | + |
1023 | +""" |
1024 | +Advertise Dmedia HTTP server over Avahi, discover other peers. |
1025 | +""" |
1026 | + |
1027 | +import logging |
1028 | + |
1029 | +from microfiber import Database, NotFound |
1030 | + |
1031 | +from dmedia.service.dbus import system |
1032 | + |
1033 | + |
1034 | +PEERS = '_local/peers' |
1035 | +log = logging.getLogger() |
1036 | + |
1037 | + |
1038 | +class Avahi: |
1039 | + group = None |
1040 | + |
1041 | + def __init__(self, env, port): |
1042 | + self.avahi = system.get( |
1043 | + 'org.freedesktop.Avahi', |
1044 | + '/', |
1045 | + 'org.freedesktop.Avahi.Server' |
1046 | + ) |
1047 | + self.db = Database('dmedia-0', env) |
1048 | + self.machine_id = env['machine_id'] |
1049 | + self.port = port |
1050 | + |
1051 | + def __del__(self): |
1052 | + self.free() |
1053 | + |
1054 | + def run(self): |
1055 | + try: |
1056 | + self.peers = self.db.get(PEERS) |
1057 | + if self.peers.get('peers') != {}: |
1058 | + self.peers['peers'] = {} |
1059 | + self.db.save(self.peers) |
1060 | + except NotFound: |
1061 | + self.peers = {'_id': PEERS, 'peers': {}} |
1062 | + self.db.save(self.peers) |
1063 | + self.group = system.get( |
1064 | + 'org.freedesktop.Avahi', |
1065 | + self.avahi.EntryGroupNew(), |
1066 | + 'org.freedesktop.Avahi.EntryGroup' |
1067 | + ) |
1068 | + log.info('Avahi: advertising %r on port %r', self.machine_id, self.port) |
1069 | + self.group.AddService('(iiussssqaay)', |
1070 | + -1, # Interface |
1071 | + 0, # Protocol -1 = both, 0 = ipv4, 1 = ipv6 |
1072 | + 0, # Flags |
1073 | + self.machine_id, |
1074 | + '_dmedia._tcp', |
1075 | + '', # Domain, default to .local |
1076 | + '', # Host, default to localhost |
1077 | + self.port, # Port |
1078 | + None # TXT record |
1079 | + ) |
1080 | + self.group.Commit() |
1081 | + browser_path = self.avahi.ServiceBrowserNew('(iissu)', |
1082 | + -1, # Interface |
1083 | + 0, # Protocol -1 = both, 0 = ipv4, 1 = ipv6 |
1084 | + '_dmedia._tcp', |
1085 | + 'local', |
1086 | + 0 # Flags |
1087 | + ) |
1088 | + self.browser = system.get( |
1089 | + 'org.freedesktop.Avahi', |
1090 | + browser_path, |
1091 | + 'org.freedesktop.Avahi.ServiceBrowser' |
1092 | + ) |
1093 | + self.browser.connect('g-signal', self.on_g_signal) |
1094 | + |
1095 | + def free(self): |
1096 | + if self.group is not None: |
1097 | + self.group.Reset() |
1098 | + |
1099 | + def on_g_signal(self, proxy, sender, signal, params): |
1100 | + if signal == 'ItemNew': |
1101 | + (interface, protocol, name, _type, domain, flags) = params.unpack() |
1102 | + if name != self.machine_id: # Ignore what we publish ourselves |
1103 | + (ip, port) = self.avahi.ResolveService('(iisssiu)', |
1104 | + interface, protocol, name, _type, domain, -1, 0 |
1105 | + )[7:9] |
1106 | + url = 'http://{}:{}/'.format(ip, port) |
1107 | + log.info('Avahi: new peer %r at %r', name, url) |
1108 | + self.peers['peers'][name] = url |
1109 | + self.db.save(self.peers) |
1110 | + elif signal == 'ItemRemove': |
1111 | + (interface, protocol, name, _type, domain, flags) = params.unpack() |
1112 | + log.info('Avahi: removing peer %r', name) |
1113 | + try: |
1114 | + del self.peers['peers'][name] |
1115 | + self.db.save(self.peers) |
1116 | + except KeyError: |
1117 | + pass |
1118 | |
1119 | === modified file 'dmedia/transfers.py' |
1120 | --- dmedia/transfers.py 2011-09-22 10:20:44 +0000 |
1121 | +++ dmedia/transfers.py 2012-01-17 04:20:28 +0000 |
1122 | @@ -41,7 +41,7 @@ |
1123 | _uploaders = {} |
1124 | _downloaders = {} |
1125 | |
1126 | -# Note: should probably export each download on the org.freedesktop.DMedia bus |
1127 | +# Note: should probably export each download on the org.freedesktop.Dmedia bus |
1128 | # at the object path /downloads/FILE_ID |
1129 | |
1130 | def download_key(file_id, store_id): |
1131 | @@ -63,7 +63,7 @@ |
1132 | """ |
1133 | return '/downloads/' + file_id |
1134 | |
1135 | -# Note: should probably export each upload on the org.freedesktop.DMedia bus |
1136 | +# Note: should probably export each upload on the org.freedesktop.Dmedia bus |
1137 | # at the object path /uploads/FILE_ID/REMOTE_ID |
1138 | |
1139 | def upload_key(file_id, store_id): |
1140 | |
1141 | === modified file 'dmedia/units.py' |
1142 | --- dmedia/units.py 2011-10-08 11:18:57 +0000 |
1143 | +++ dmedia/units.py 2012-01-17 04:20:28 +0000 |
1144 | @@ -68,3 +68,16 @@ |
1145 | return ( |
1146 | '{:.3g} {}'.format(s, BYTES10[i]) |
1147 | ) |
1148 | + |
1149 | + |
1150 | +def minsec(seconds): |
1151 | + """ |
1152 | + Format *seconds* as a M:SS string with minutes and seconds. |
1153 | + |
1154 | + For example: |
1155 | + |
1156 | + >>> minsec(123) |
1157 | + '2:03' |
1158 | + |
1159 | + """ |
1160 | + return '{:d}:{:02d}'.format(seconds // 60, seconds % 60) |
1161 | |
1162 | === modified file 'setup.py' |
1163 | --- setup.py 2012-01-15 15:21:24 +0000 |
1164 | +++ setup.py 2012-01-17 04:20:28 +0000 |
1165 | @@ -159,12 +159,11 @@ |
1166 | ('lib/dmedia', |
1167 | [ |
1168 | 'dmedia-service', |
1169 | - 'dmedia-service3', |
1170 | 'share/init-filestore', |
1171 | ] |
1172 | ), |
1173 | ('share/dbus-1/services/', |
1174 | - ['share/org.freedesktop.DMedia.service'] |
1175 | + ['share/org.freedesktop.Dmedia.service'] |
1176 | ), |
1177 | ], |
1178 | ) |
1179 | |
1180 | === renamed file 'share/org.freedesktop.DMedia.service' => 'share/org.freedesktop.Dmedia.service' |
1181 | --- share/org.freedesktop.DMedia.service 2011-04-10 11:02:23 +0000 |
1182 | +++ share/org.freedesktop.Dmedia.service 2012-01-17 04:20:28 +0000 |
1183 | @@ -1,3 +1,3 @@ |
1184 | [D-BUS Service] |
1185 | -Name=org.freedesktop.DMedia |
1186 | +Name=org.freedesktop.Dmedia |
1187 | Exec=/usr/lib/dmedia/dmedia-service |
1188 | |
1189 | === added file 'test-cli.py' |
1190 | --- test-cli.py 1970-01-01 00:00:00 +0000 |
1191 | +++ test-cli.py 2012-01-17 04:20:28 +0000 |
1192 | @@ -0,0 +1,33 @@ |
1193 | +#!/usr/bin/python3 |
1194 | + |
1195 | +from usercouch.misc import TempCouch |
1196 | +from microfiber import random_id |
1197 | +import json |
1198 | +import time |
1199 | +from subprocess import Popen, check_output |
1200 | + |
1201 | +bus = 'tmp' + random_id() + '.Dmedia' |
1202 | + |
1203 | +def call(*args): |
1204 | + cmd = ('./dmedia-cli', '--bus', bus) + args |
1205 | + print(check_output(cmd).decode('utf-8')) |
1206 | + |
1207 | +# Check that printing help doesn't connect to the DBus service: |
1208 | +call() |
1209 | + |
1210 | +# Start a tmp couchdb and the dbus service on a random bus name: |
1211 | +tmpcouch = TempCouch() |
1212 | +env = tmpcouch.bootstrap() |
1213 | +cmd = ['./dmedia-service', '--bus', bus, '--env', json.dumps(env)] |
1214 | +child = Popen(cmd) |
1215 | +time.sleep(1) |
1216 | + |
1217 | +try: |
1218 | + call('Version') |
1219 | + call('GetEnv') |
1220 | + call('LocalDmedia') |
1221 | + call('LocalPeers') |
1222 | + call('RemoveFileStore', '/home/') |
1223 | + call('AddFileStore', '/home/') |
1224 | +finally: |
1225 | + call('Kill') |
1226 | |
1227 | === added file 'test-service.py' |
1228 | --- test-service.py 1970-01-01 00:00:00 +0000 |
1229 | +++ test-service.py 2012-01-17 04:20:28 +0000 |
1230 | @@ -0,0 +1,29 @@ |
1231 | +#!/usr/bin/python3 |
1232 | + |
1233 | +from usercouch.misc import TempCouch |
1234 | +from microfiber import random_id |
1235 | +import json |
1236 | +import time |
1237 | +from subprocess import Popen |
1238 | +from dmedia.service.dbus import session |
1239 | + |
1240 | +bus = 'tmp' + random_id() + '.Dmedia' |
1241 | +tmpcouch = TempCouch() |
1242 | +env = tmpcouch.bootstrap() |
1243 | + |
1244 | +cmd = ['./dmedia-service', '--bus', bus, '--env', json.dumps(env)] |
1245 | + |
1246 | +child = Popen(cmd) |
1247 | +time.sleep(2) |
1248 | + |
1249 | +proxy = session.get(bus, '/', 'org.freedesktop.Dmedia') |
1250 | +try: |
1251 | + print(proxy.Version()) |
1252 | + print(proxy.GetEnv()) |
1253 | + print(proxy.LocalDmedia()) |
1254 | + print(proxy.LocalPeers()) |
1255 | + print(proxy.RemoveFileStore('(s)', '/home')) |
1256 | + print(proxy.AddFileStore('(s)', '/home')) |
1257 | +finally: |
1258 | + print(proxy.Kill()) |
1259 | + |