1c340398c2dbf5095c87adba8cda83ed6890807a
[monitor.git] / Rpyc / Demo / demo-6.py
1 # as you can see - the import line now requires even less typing!\r
2 from Rpyc import *\r
3 c = SocketConnection("localhost")\r
4 \r
5 #------------------------------------------------------------------------------ \r
6 # this demo shows the new `execute` and `namespace` features of rpyc\r
7 #------------------------------------------------------------------------------ \r
8 \r
9 \r
10 # the code below will run AT THE OTHER SIDE OF THE CONNECTION... so you'll see\r
11 # 'hello world' on the server's console\r
12 c.execute("print 'hello world'")\r
13 \r
14 import sys\r
15 c.modules.sys.stdout = sys.stdout\r
16 \r
17 # and this time, on our console\r
18 c.execute("print 'brave new world'")\r
19 \r
20 # restore that\r
21 c.modules.sys.stdout = c.modules.sys.__stdout__\r
22 \r
23 # anyway, the `execute` method runs the given code at the other side of the connection\r
24 # and works in the `namespace` dict. what?\r
25 c.execute("x = [1,2,3]")\r
26 print c.namespace.x\r
27 \r
28 # now it makes sense, doesn't it? the 'namespace' attribute is something i called \r
29 # AttrFrontend -- it wraps a dict with the attribute protocol, so you can access\r
30 # it with the dot notation, instead of the braces notation (more intuitive).\r
31 # this namespace works both ways -- executing code affects the namespace, while\r
32 # altering the namespace directly also affects it:\r
33 c.namespace.x.append(4)\r
34 c.execute("x.append(5)")\r
35 print c.namespace.x\r
36 \r
37 # but you should not assign complex objects (not int/float/str, etc) to this namespace\r
38 # directy, or NetProxies will be created. there's nothing wrong with that, but keep\r
39 # in mind it might cause blocking (and even deadlocks), as i'll explain later.\r
40 \r
41 # another cool thing i want to show is the second, optional parameter to execute: mode.\r
42 # the mode controls how the code is compiled. the default mode is "exec", which means \r
43 # it executes the code as a module. the other option is "eval" which returns a value.\r
44 # so if you want to _do_ something, like printing of assigning a variable, you do it \r
45 # with "exec", and if you want to evaluate something, you do it with "eval"\r
46 # for example:\r
47 \r
48 # this will print None\r
49 print c.execute("1+2")\r
50 \r
51 # while this will print 3\r
52 print c.execute("1+2", "eval")\r
53 \r
54 # but there's a time in a man's life when he asks himself, why the heck? you can, as i \r
55 # showed in other places, just do this:\r
56 #     c.modules.__builtin__.eval("1+2")\r
57 # so what's the point? \r
58 #\r
59 # well, i've been waiting for this question. the rationale behind this seemingly useless \r
60 # feature is for times you NEED to have the code executing remotely, but writing a \r
61 # dedicated module for it is overdoing it:\r
62 #  * more files to update ==> more chance that you'll forget to update\r
63 #  * distributing the module to all of the machines\r
64 #  * making a mess on the file system\r
65 #  * it's really not a module... it's just some code that logically belongs to one single \r
66 #    module, but technical difficulties prevent it\r
67 #\r
68 # and to show you what i mean -- i want to start a thread on the server, like it did in \r
69 # several places over the demos. this thread will send me an event every second. what i \r
70 # used to do was, creating another module, like testmodule.py to define the thread \r
71 # function, so it will exist on the server, and i could call it.\r
72 # if i defined thread_func at the client side, then the thread will block when trying \r
73 # to execute the code, because the client holds it. so this new mechanism lets you \r
74 # distribute code in a volatile fashion:\r
75 #  * when the connection is closed, everything you defined is gone\r
76 #  * no file-system mess\r
77 #  * no need to distribute files across the network\r
78 #  * only one place to maintain\r
79 \r
80 c.execute("""\r
81 my_thread_active = True\r
82 \r
83 def my_thread_func(callback):\r
84     import time\r
85     from Rpyc import Async\r
86 \r
87     callback = Async(callback)\r
88     while my_thread_active:\r
89         callback(time.time())\r
90         time.sleep(1)\r
91     print "the thread says goodbye"\r
92 """)\r
93 \r
94 def callback(timestamp):\r
95     print "the timestamp is", timestamp\r
96 \r
97 c.modules.thread.start_new_thread(c.namespace.my_thread_func, (callback,))\r
98 c.modules.time.sleep(5)\r
99 c.namespace.my_thread_active = False\r
100 c.close()\r
101 \r
102 # it's not only for threads of course. there are many times when you NEED the code/objects \r
103 # on the remote side. for example:\r
104 #  * situations that would block (like having the thread func on the client)\r
105 #  * code that check the type of the object (type or isinstance), and a NetProxy would make\r
106 #    it cry. DONT CHECK THE TYPE OF OBJECTS, PEOPLE, JUST USE THEM! that's why they invented \r
107 #    duck-typing. argh.\r
108 #  * other places i didnt think of as of yet. i want to sleep. leave me alone ;) zzzZZZ\r
109 #\r
110 # so enjoy!\r
111 \r
112 \r
113 \r
114 \r
115 \r
116 \r
117 \r
118 \r
119 \r
120 \r
121 \r
122 \r
123 \r
124 \r
125 \r
126 \r
127 \r
128 \r
129 \r
130 \r