Commits

Rune Halvorsen committed 6d5139c

Added readme and an example script

Comments (0)

Files changed (2)

+##########################################################################
+stpserver - lightweight server for communicating with Opera Scope Protocol
+###########################################################################
+
+Overview
+--------
+
+stpserver allows running servers that Opera clients can connect to through
+STP1 protocol.
+
+STP1 is the transport protocol for messages between an Opera instance and
+a debugger, or other software that needs to interact with the inards of
+the Opera browser.
+
+stpserver provides an extremely lightweight API. It's intended as the basis
+for more full featured APIs.
+
+The API is not threaded and blocking. Timeouts will be added to avoid
+blocking.
+
+Example
+-------
+
+See screenshot.py
+"""
+Example server using stpserver.
+
+When a client connects, the service tells it to open a url in a new window and takes
+a screeshot of that window.
+
+Note: It's expected that there will be built abstractions for
+scope messaging built on top of stpserver. It's not reasonable to
+expect people to hand craft messages with message IDs and json payloads.
+
+In other words, this is a demo that shows that it works. It's not
+showing off best practices
+"""
+
+import os.path
+from itertools import count
+from base64 import b64decode
+from stpserver import STPServer
+from anyjson import serialize, deserialize
+
+def wait_for_reply(server, tag):
+    """Helper that gets message until it gets one matching tag"""
+    while True:
+        msg = server.pop_message()
+        if hasattr(msg, "tag") and msg.tag == tag:
+            return msg
+
+def wait_for_event(server, service, command):
+    """Helper that gets messages until it gets an event matching the
+    service/command pair"""
+    while True:
+        msg = server.pop_message()
+        if msg.service == service and msg.commandID == command:
+            return msg
+
+
+def save_screenshot(data):
+    suffix = count()
+    path = None
+    while path is None or os.path.isfile(path):
+        path = "screenshot_%s.png" % suffix.next()
+    fp = open(path, "wb")
+    fp.write(b64decode(data))
+    fp.close()
+    return path
+
+tags = count(1)
+
+server = STPServer() # by default, listen on port 7001 on all ports
+
+# at this point we call accept to wait for an Opera instance to connect.
+# This is done by opening the page opera:debug and selecting the
+# appropriate address/socket
+server.accept()
+
+# we're now connected. Send a few message to the scope service to set up
+# the environment. First a message to select json as default payload format
+# and then two messages to enable the exec and window manager services
+# as default format for payloads
+server.send("scope", 3, 1, tags.next(), serialize(["json"]))
+server.send("scope", 5, 1, tags.next(), serialize(["exec"]))
+server.send("scope", 5, 1, tags.next(), serialize(["window-manager"]))
+
+# Then send a message that opens a URL in a new tab
+# Open link in new page
+server.send("exec", 1, 1, tags.next(), serialize([[["Open url in new page", "http://bash.org/?random"]]]))
+
+# wait for an event from the window manager that tells us the id of the
+# newly created window
+event = wait_for_event(server, "window-manager", 4)
+payload = deserialize(event.payload)
+windowid = payload[0]
+
+
+# wait for an event telling us that the window has finished loading
+while True:
+    event = wait_for_event(server, "window-manager", 7)
+    if deserialize(event.payload)[0] == windowid:
+        break
+
+
+# build the arguments to pass to the setupScreenWatcher msg
+args = [
+    1000, # ms until img should be taken
+    [0, 0, 800, 800], # area to screenshot. x, y, w, h
+    [],
+    windowid
+]
+
+tag = tags.next()
+# take the screenshot
+server.send("exec", 3, 1, tag, serialize(args))
+
+reply = wait_for_reply(server, tag)
+payload = deserialize(reply.payload)
+path = save_screenshot(payload[2])
+
+print "Saved screenshot as", path