Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <mpg@redhat.com>2006-05-16 20:32:08 (GMT)
committer Marco Pesenti Gritti <mpg@redhat.com>2006-05-16 20:32:08 (GMT)
commit8162cc84680a7afdbf61cb93dc6f7d7b93e20123 (patch)
tree8720e78f85853313eeef80e475c817c0dec13609
parent0f7dc51ac0af54b3d11b6d635785be9fe77118f9 (diff)
Do not rely on dbus auto-activation.
-rw-r--r--README4
-rw-r--r--configure.ac3
-rw-r--r--sugar/Makefile.am2
-rw-r--r--sugar/__uninstalled__.py3
-rw-r--r--sugar/browser/Makefile.am14
-rw-r--r--sugar/browser/com.redhat.Sugar.Browser.service.in3
-rw-r--r--sugar/p2p/MostlyReliablePipe.py319
-rw-r--r--sugar/session/Makefile.am4
-rw-r--r--sugar/session/__init__.py0
-rw-r--r--sugar/session/session.py18
-rw-r--r--sugar/shell/Makefile.am16
-rw-r--r--sugar/shell/com.redhat.Sugar.Shell.service.in3
-rwxr-xr-xsugar/shell/shell.py5
-rwxr-xr-xsugar/sugar36
14 files changed, 44 insertions, 386 deletions
diff --git a/README b/README
index 5d8d3a4..4458b74 100644
--- a/README
+++ b/README
@@ -24,6 +24,10 @@ Once installed you can run sugar with
To run the python sources from your source tree run
+ $ sugar/sugar
+
+You can also run the components separately:
+
$ source ./setup-run-from-source.sh # needs bash
in the top-level directory. Icons and other resources are still loaded
diff --git a/configure.ac b/configure.ac
index 10a350d..aca7065 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([Sugar],[0.3],[],[sugar])
+AC_INIT([Sugar],[0.2],[],[sugar])
AC_PREREQ([2.59])
@@ -24,4 +24,5 @@ sugar/chat/Makefile
sugar/p2p/Makefile
sugar/p2p/model/Makefile
sugar/shell/Makefile
+sugar/session/Makefile
])
diff --git a/sugar/Makefile.am b/sugar/Makefile.am
index 626a56b..cb4eb03 100644
--- a/sugar/Makefile.am
+++ b/sugar/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = chat browser p2p shell
+SUBDIRS = chat browser p2p shell session
bin_SCRIPTS = sugar
diff --git a/sugar/__uninstalled__.py b/sugar/__uninstalled__.py
index 4ffafc8..dd7818e 100644
--- a/sugar/__uninstalled__.py
+++ b/sugar/__uninstalled__.py
@@ -1,10 +1,9 @@
import os
+basedir = os.path.dirname(os.path.dirname(__file__))
data_dirs = [ 'sugar/browser', 'sugar/chat' ]
def internal_get_data_file(filename):
- basedir = os.path.dirname(os.path.dirname(__file__))
-
for data_dir in data_dirs:
path = os.path.abspath(os.path.join(basedir, data_dir, filename))
if os.path.isfile(path):
diff --git a/sugar/browser/Makefile.am b/sugar/browser/Makefile.am
index b433177..b6440e5 100644
--- a/sugar/browser/Makefile.am
+++ b/sugar/browser/Makefile.am
@@ -8,19 +8,5 @@ icon_DATA = \
fold.png \
unfold.png
-# Dbus service file
-servicedir = $(datadir)/dbus-1/services
-service_in_files = com.redhat.Sugar.Browser.service.in
-service_DATA = $(service_in_files:.service.in=.service)
-
-# Rule to make the service file with bindir expanded
-$(service_DATA): $(service_in_files) Makefile
- @sed -e "s|\@bindir\@|$(bindir)|" $< > $@
-
EXTRA_DIST = \
- $(service_in_files) \
- $(service_DATA) \
$(icon_DATA)
-
-DISTCLEANFILES = \
- $(service_DATA)
diff --git a/sugar/browser/com.redhat.Sugar.Browser.service.in b/sugar/browser/com.redhat.Sugar.Browser.service.in
deleted file mode 100644
index 654095a..0000000
--- a/sugar/browser/com.redhat.Sugar.Browser.service.in
+++ /dev/null
@@ -1,3 +0,0 @@
-[D-BUS Service]
-Name=com.redhat.Sugar.Browser
-Exec=@bindir@/sugar browser
diff --git a/sugar/p2p/MostlyReliablePipe.py b/sugar/p2p/MostlyReliablePipe.py
deleted file mode 100644
index f85a815..0000000
--- a/sugar/p2p/MostlyReliablePipe.py
+++ /dev/null
@@ -1,319 +0,0 @@
-import socket
-import time
-import sha
-import struct
-import StringIO
-import binascii
-
-import pygtk
-pygtk.require('2.0')
-import gtk, gobject
-
-
-_MTU = 482
-_HEADER_LEN = 30
-_MAGIC = 0xbaea4304
-_TTL = 120 # 2 minutes
-
-def _stringify_sha(sha):
- print_sha = ""
- for char in sha:
- print_sha = print_sha + binascii.b2a_hex(char)
- return print_sha
-
-def _sha_data(data):
- sha_hash = sha.new()
- sha_hash.update(data)
- return sha_hash.digest()
-
-class MessageSegment(object):
- # 4: magic (0xbaea4304)
- # 2: segment number
- # 2: total segments
- # 2: message sequence number
- #20: total data sha1
- _HEADER_TEMPLATE = "! IHHH20s"
-
- def _new_from_parts(self, msg_seq_num, segno, total_segs, data, master_sha):
- """Construct a new message segment from individual attributes."""
- if not data:
- raise ValueError("Must have valid data.")
- if segno > 65535:
- raise ValueError("Segment number cannot be more than 65535.")
- if segno < 1:
- raise ValueError("Segment number must be greater than zero.")
- if total_segs > 65535:
- raise ValueError("Message cannot have more than 65535 segments.")
- if total_segs < 1:
- raise ValueError("Message must have at least one segment.")
- if msg_seq_num < 1:
- raise ValueError("Message sequence number must be greater than 0.")
- self._stime = time.time()
- self._data = data
- self._data_len = len(data)
- self._master_sha = master_sha
- self._segno = segno
- self._total_segs = total_segs
- self._msg_seq_num = msg_seq_num
- self._addr = None
-
- # Make the header
- self._header = struct.pack(self._HEADER_TEMPLATE, _MAGIC, self._segno,
- self._total_segs, self._msg_seq_num, self._master_sha)
-
- def _new_from_data(self, addr, data):
- """Verify and construct a new message segment from network data."""
- if len(data) < _HEADER_LEN + 1:
- raise ValueError("Message is less then minimum required length")
- stream = StringIO.StringIO(data)
- self._stime = None
- self._addr = addr
-
- # Determine and verify the length of included data
- stream.seek(0, 2)
- header_size = struct.calcsize(self._HEADER_TEMPLATE)
- self._data_len = stream.tell() - header_size
- if self._data_len < 1:
- raise ValueError("Message must have some data.")
- if self._data_len > _MTU:
- raise ValueError("Data length must not be larger than the MTU (%s)." % _MTU)
- stream.seek(0)
-
- # Read the header attributes
- (magic, segno, total_segs, msg_seq_num, master_sha) = struct.unpack(self._HEADER_TEMPLATE,
- stream.read(header_size))
-
- # Sanity checks on the message attributes
- if magic != _MAGIC:
- raise ValueError("Message does not have the correct magic.")
- if segno < 1:
- raise ValueError("Segment number must be greater than 0.")
- if segno > total_segs:
- raise ValueError("Segment number cannot be larger than message segment total.")
- if total_segs < 1:
- raise ValueError("Message must have at least one segment.")
- if msg_seq_num < 1:
- raise ValueError("Message sequence number must be greater than 0.")
-
- self._segno = segno
- self._total_segs = total_segs
- self._msg_seq_num = msg_seq_num
- self._master_sha = master_sha
-
- # Reconstruct the data
- self._data = struct.unpack("! %ds" % self._data_len, stream.read(self._data_len))[0]
-
- def new_from_parts(msg_seq_num, segno, total_segs, data, master_sha):
- """Static constructor for creation from individual attributes."""
- segment = MessageSegment()
- segment._new_from_parts(msg_seq_num, segno, total_segs, data, master_sha)
- return segment
- new_from_parts = staticmethod(new_from_parts)
-
- def new_from_data(addr, data):
- """Static constructor for creation from a packed data stream."""
- segment = MessageSegment()
- segment._new_from_data(addr, data)
- return segment
- new_from_data = staticmethod(new_from_data)
-
- def stime(self):
- return self._stime
-
- def addr(self):
- return self._addr
-
- def segment_number(self):
- return self._segno
-
- def total_segments(self):
- return self._total_segs
-
- def message_sequence_number(self):
- return self._msg_seq_num
-
- def data(self):
- return self._data
-
- def master_sha(self):
- return self._master_sha
-
- def segment(self):
- """Return a correctly formatted message that can be immediately sent."""
- return self._header + self._data
-
-class MostlyReliablePipe(object):
- """Implement Mostly-Reliable UDP. We don't actually care about guaranteeing
- delivery or receipt, just a better effort than no effort at all."""
-
- def __init__(self, local_addr, remote_addr, port, data_cb, user_data=None):
- self._local_addr = local_addr
- self._remote_addr = remote_addr
- self._port = port
- self._data_cb = data_cb
- self._user_data = user_data
- self._started = False
- self._worker = 0
- self._seq_counter = 0
-
- self._outgoing = []
- self._sent = []
-
- self._incoming = {} # (message sha, # of segments) -> [segment1, segment2, ...]
-
- self._setup_listener()
- self._setup_sender()
-
- def _setup_sender(self):
- """Setup the send socket for multicast."""
- self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # Make the socket multicast-aware, and set TTL.
- self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
-
- def _setup_listener(self):
- """Set up the listener socket for multicast traffic."""
- # Listener socket
- self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-
- # Set some options to make it multicast-friendly
- self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
-
- def start(self):
- """Let the listener socket start listening for network data."""
- # Set some more multicast options
- self._listen_sock.bind((self._local_addr, self._port)) # Bind to all interfaces
- self._listen_sock.settimeout(2)
- intf = socket.gethostbyname(socket.gethostname())
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF,
- socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
- socket.inet_aton(self._remote_addr) + socket.inet_aton('0.0.0.0'))
-
- # Watch the listener socket for data
- gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
- gobject.timeout_add(120000, self._segment_ttl_worker)
-
- self._started = True
-
- def _segment_ttl_worker(self):
- """Cull already-sent message segments that are past their TTL."""
- now = time.time()
- for segment in self._sent[:]:
- if segment.stime() < now - _MSG_TTL:
- self._sent.remove(segment)
- return True
-
- def _dispatch_message(self, addr, message):
- """Send complete message data to the owner's data callback."""
- self._data_cb(addr, message, self._user_data)
-
- def _process_incoming(self, segment):
- """Handle a new message segment. First checks if there is only one
- segment to the message, and if the checksum from the header matches
- that computed from the data, dispatches it. Otherwise, it adds the
- new segment to the list of other segments for that message, and
- checks to see if the message is complete. If all segments are present,
- the message is reassembled and dispatched."""
-
- string_sha = _stringify_sha(segment.master_sha())
- nsegs = segment.total_segments()
- addr = segment.addr()
- segno = segment.segment_number()
-
- # Short-circuit single-segment messages
- if segno == 1 and nsegs == 1:
- # Ensure the header's master sha actually equals the data's sha
- if string_sha == _stringify_sha(_sha_data(segment.data())):
- self._dispatch_message(addr, segment.data())
- return
-
- # Otherwise, track the new segment
- msg_seq_num = segment.message_sequence_number()
- msg_key = (addr[0], msg_seq_num, string_sha, nsegs)
- if not self._incoming.has_key(msg_key):
- self._incoming[msg_key] = {}
-
- # Look for a dupe, and if so, drop the new segment
- if self._incoming[msg_key].has_key(segno):
- return
- self._incoming[msg_key][segno] = segment
-
- # Dispatch the message if all segments are present and the sha is correct
- if len(self._incoming[msg_key]) == nsegs:
- all_data = ''
- for i in range(1, nsegs + 1):
- all_data = all_data + self._incoming[msg_key][i].data()
- if string_sha == _stringify_sha(_sha_data(all_data)):
- self._dispatch_message(addr, all_data)
- del self._incoming[msg_key]
-
- def _handle_incoming_data(self, source, condition):
- """Handle incoming network data by making a message segment out of it
- sending it off to the processing function."""
- if not (condition & gobject.IO_IN):
- return True
- msg = {}
- data, addr = source.recvfrom(_MTU + _HEADER_LEN)
- try:
- segment = MessageSegment.new_from_data(addr, data)
- self._process_incoming(segment)
- except ValueError, exc:
- pass
- return True
-
- def send(self, data):
- """Break data up into chunks and queue for later transmission."""
- if not self._started:
- raise Exception("Can't send anything until started!")
-
- self._seq_counter = self._seq_counter + 1
- if self._seq_counter > 65535:
- self._seq_counter = 1
-
- # Pack the data into network byte order
- template = "! %ds" % len(data)
- data = struct.pack(template, data)
- master_sha = _sha_data(data)
-
- # Split up the data into segments
- left = length = len(data)
- nmessages = length / _MTU
- if length % _MTU > 0:
- nmessages = nmessages + 1
- msg_num = 1
- while left > 0:
- msg = MessageSegment.new_from_parts(self._seq_counter, msg_num,
- nmessages, data[:_MTU], master_sha)
- self._outgoing.append(msg)
- msg_num = msg_num + 1
- data = data[_MTU:]
- left = left - _MTU
- if len(self._outgoing) > 0 and self._worker == 0:
- self._worker = gobject.idle_add(self._send_worker)
-
- def _send_worker(self):
- """Send all queued segments that have yet to be transmitted."""
- self._worker = 0
- for segment in self._outgoing:
- data = segment.segment()
- self._send_sock.sendto(data, (self._remote_addr, self._port))
- self._sent = self._outgoing
- self._outgoing = []
- return False
-
-
-def got_data(addr, data, user_data=None):
- print "Data (%s): %s" % (addr, data)
-
-def main():
- pipe = MostlyReliablePipe('', '224.0.0.222', 2293, got_data)
- pipe.start()
- pipe.send('The quick brown fox jumps over the lazy dog')
- gtk.main()
-
-
-if __name__ == "__main__":
- main()
-
diff --git a/sugar/session/Makefile.am b/sugar/session/Makefile.am
new file mode 100644
index 0000000..db74987
--- /dev/null
+++ b/sugar/session/Makefile.am
@@ -0,0 +1,4 @@
+sugardir = $(pythondir)/sugar/session
+sugar_PYTHON = \
+ __init__.py \
+ session.py
diff --git a/sugar/session/__init__.py b/sugar/session/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sugar/session/__init__.py
diff --git a/sugar/session/session.py b/sugar/session/session.py
new file mode 100644
index 0000000..c3043af
--- /dev/null
+++ b/sugar/session/session.py
@@ -0,0 +1,18 @@
+import os
+import sys
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+
+from sugar.shell import shell
+
+def start():
+ shell.main()
+
+ activities = ['sugar/chat/chat', 'sugar/browser/browser']
+
+ for activity in activities:
+ os.spawnvp(os.P_NOWAIT, 'python', [ 'python', '-m', activity ])
+
+ gtk.main()
diff --git a/sugar/shell/Makefile.am b/sugar/shell/Makefile.am
index f765295..a768aad 100644
--- a/sugar/shell/Makefile.am
+++ b/sugar/shell/Makefile.am
@@ -3,19 +3,3 @@ sugar_PYTHON = \
__init__.py \
activity.py \
shell.py
-
-# Dbus service file
-servicedir = $(datadir)/dbus-1/services
-service_in_files = com.redhat.Sugar.Shell.service.in
-service_DATA = $(service_in_files:.service.in=.service)
-
-# Rule to make the service file with bindir expanded
-$(service_DATA): $(service_in_files) Makefile
- @sed -e "s|\@bindir\@|$(bindir)|" $< > $@
-
-EXTRA_DIST = \
- $(service_in_files) \
- $(service_DATA)
-
-DISTCLEANFILES = \
- $(service_DATA)
diff --git a/sugar/shell/com.redhat.Sugar.Shell.service.in b/sugar/shell/com.redhat.Sugar.Shell.service.in
deleted file mode 100644
index 2a069a1..0000000
--- a/sugar/shell/com.redhat.Sugar.Shell.service.in
+++ /dev/null
@@ -1,3 +0,0 @@
-[D-BUS Service]
-Name=com.redhat.Sugar.Shell
-Exec=@bindir@/sugar shell
diff --git a/sugar/shell/shell.py b/sugar/shell/shell.py
index 0dd3ea9..a72a864 100755
--- a/sugar/shell/shell.py
+++ b/sugar/shell/shell.py
@@ -294,8 +294,3 @@ def main():
activityContainer = ActivityContainer(service, session_bus)
activityContainer.show()
-
- gtk.main()
-
-if __name__ == "__main__":
- main()
diff --git a/sugar/sugar b/sugar/sugar
index 4c6ec88..5d42118 100755
--- a/sugar/sugar
+++ b/sugar/sugar
@@ -3,26 +3,18 @@
import sys
import os
-if len(sys.argv) == 1:
- # FIXME Start a session
-
- # We are lucky and this
- # currently behave as we want.
- # The chat depends on the
- # web browser, so both activities
- # are spanned. But obviously we
- # need something better.
-
- from sugar.chat import chat
- chat.main()
-elif sys.argv[1] == 'shell':
- from sugar.shell import shell
- shell.main()
-elif sys.argv[1] == 'chat':
- from sugar.chat import chat
- chat.main()
-elif sys.argv[1] == 'browser':
- from sugar.browser import browser
- browser.main()
+basedir = os.path.dirname(os.path.dirname(__file__))
+if os.path.isfile(os.path.join(basedir, 'sugar', '__uninstalled__.py')):
+ if basedir == '':
+ print "Running sugar from current directory..."
+ else:
+ print "Running sugar from " + basedir + " ..."
+ sys.path.append(basedir)
+ os.environ['PYTHONPATH'] = basedir
else:
- print "Unknown activity"
+ print "Running the installed sugar..."
+
+from sugar.session import session
+
+session.start()
+