├── lib
└── rpyc
│ ├── utils
│ ├── __init__.py
│ ├── logger.py
│ ├── authenticators.py
│ ├── helpers.py
│ ├── twisted_integration.py
│ ├── lib.py
│ ├── factory.py
│ ├── server.py
│ ├── classic.py
│ └── registry.py
│ ├── servers
│ ├── __init__.py
│ ├── registry_server.py
│ ├── vdbconf.py
│ └── classic_server.py
│ ├── core
│ ├── __init__.py
│ ├── consts.py
│ ├── channel.py
│ ├── async.py
│ ├── vinegar.py
│ ├── service.py
│ ├── netref.py
│ ├── brine.py
│ ├── stream.py
│ └── protocol.py
│ ├── license.py
│ └── __init__.py
├── HComNuke
├── HCom_History
│ └── hinfo.inf
├── HCom_Icons
│ ├── bgeo.png
│ ├── close.png
│ ├── gnm.wav
│ ├── hcom.png
│ ├── help.png
│ ├── nuke.png
│ ├── obj.png
│ ├── alembic.png
│ ├── connect.png
│ ├── folder.png
│ ├── houdini.png
│ ├── picture.png
│ ├── clearmsg.png
│ ├── disconnect.png
│ ├── settings.png
│ ├── unreadmsg.png
│ ├── digitalasset.png
│ ├── folder_hist.png
│ ├── maya_hengine.png
│ ├── maya_no_hengine.png
│ ├── sendoutputnode.png
│ └── digitalasset_settings.png
├── HCom_Received_Files
│ └── info.inf
├── _globals.py
├── menu
│ └── menu.py
├── HCom.ini
├── install.txt
├── HComNukeUtils.py
└── HComNukeClient.py
├── HComHoudini
├── HCom_History
│ └── hinfo.inf
├── HCom_Icons
│ ├── bgeo.png
│ ├── gnm.wav
│ ├── hcom.png
│ ├── help.png
│ ├── nuke.png
│ ├── obj.png
│ ├── alembic.png
│ ├── close.png
│ ├── connect.png
│ ├── folder.png
│ ├── houdini.png
│ ├── picture.png
│ ├── clearmsg.png
│ ├── settings.png
│ ├── unreadmsg.png
│ ├── digitalasset.png
│ ├── disconnect.png
│ ├── folder_hist.png
│ ├── maya_hengine.png
│ ├── maya_no_hengine.png
│ └── digitalasset_settings.png
├── HCom_Received_Files
│ └── info.inf
├── HCom.ini
├── install.txt
├── PyPanel
│ └── HCom.pypanel
├── HComHoudiniClient.py
└── HComHoudiniUtils.py
├── hCom_help.pdf
├── .gitignore
├── HComMaya
├── HCom_Icons
│ ├── bgeo.png
│ ├── close.png
│ ├── gnm.wav
│ ├── hcom.png
│ ├── help.png
│ ├── nuke.png
│ ├── obj.png
│ ├── alembic.png
│ ├── connect.png
│ ├── folder.png
│ ├── houdini.png
│ ├── picture.png
│ ├── clearmsg.png
│ ├── disconnect.png
│ ├── settings.png
│ ├── unreadmsg.png
│ ├── digitalasset.png
│ ├── folder_hist.png
│ ├── maya_hengine.png
│ ├── maya_no_hengine.png
│ └── digitalasset_settings.png
├── shelf
│ ├── hcom_shelf.png
│ └── shelf_HCom.mel
├── HCom_Received_Files
│ └── info.inf
├── _globals.py
├── install.txt
├── HCom.ini
├── HComMayaUtils.py
└── HComMayaClient.py
├── README.md
└── HComServer.py
/lib/rpyc/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/HComNuke/HCom_History/hinfo.inf:
--------------------------------------------------------------------------------
1 | all history files will be saved here.
--------------------------------------------------------------------------------
/HComHoudini/HCom_History/hinfo.inf:
--------------------------------------------------------------------------------
1 | all history files will be saved here.
--------------------------------------------------------------------------------
/hCom_help.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/hCom_help.pdf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | HComClient.pyc
3 | *.pyc
4 | *.project
5 | *.pydevproject
6 |
--------------------------------------------------------------------------------
/lib/rpyc/servers/__init__.py:
--------------------------------------------------------------------------------
1 | __import__("pkg_resources").declare_namespace(__name__)
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/bgeo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/bgeo.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/close.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/gnm.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/gnm.wav
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/hcom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/hcom.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/help.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/nuke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/nuke.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/obj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/obj.png
--------------------------------------------------------------------------------
/HComMaya/shelf/hcom_shelf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/shelf/hcom_shelf.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/bgeo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/bgeo.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/close.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/gnm.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/gnm.wav
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/hcom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/hcom.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/help.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/nuke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/nuke.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/obj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/obj.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/bgeo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/bgeo.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/gnm.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/gnm.wav
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/hcom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/hcom.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/help.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/nuke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/nuke.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/obj.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/obj.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/alembic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/alembic.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/connect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/connect.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/folder.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/houdini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/houdini.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/picture.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/alembic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/alembic.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/connect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/connect.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/folder.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/houdini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/houdini.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/picture.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/alembic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/alembic.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/close.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/connect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/connect.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/folder.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/houdini.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/houdini.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/picture.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/clearmsg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/clearmsg.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/disconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/disconnect.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/settings.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/unreadmsg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/unreadmsg.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Received_Files/info.inf:
--------------------------------------------------------------------------------
1 | all files: otls, mesh ( obj, bgeo ) and pictures will be saved by default here.
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/clearmsg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/clearmsg.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/disconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/disconnect.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/settings.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/unreadmsg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/unreadmsg.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Received_Files/info.inf:
--------------------------------------------------------------------------------
1 | all files: otls, mesh ( obj, bgeo ) and pictures will be saved by default here.
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/clearmsg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/clearmsg.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/settings.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/unreadmsg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/unreadmsg.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Received_Files/info.inf:
--------------------------------------------------------------------------------
1 | all files: otls, mesh ( obj, bgeo ) and pictures will be saved by default here.
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/digitalasset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/digitalasset.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/folder_hist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/folder_hist.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/maya_hengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/maya_hengine.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/digitalasset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/digitalasset.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/folder_hist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/folder_hist.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/maya_hengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/maya_hengine.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/digitalasset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/digitalasset.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/disconnect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/disconnect.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/folder_hist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/folder_hist.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/maya_hengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/maya_hengine.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/maya_no_hengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/maya_no_hengine.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/maya_no_hengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/maya_no_hengine.png
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/sendoutputnode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/sendoutputnode.png
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/maya_no_hengine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/maya_no_hengine.png
--------------------------------------------------------------------------------
/HComMaya/HCom_Icons/digitalasset_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComMaya/HCom_Icons/digitalasset_settings.png
--------------------------------------------------------------------------------
/HComMaya/_globals.py:
--------------------------------------------------------------------------------
1 | class MayaGlobals():
2 |
3 | MAIN_UI = None
4 | HCOM_TABS = {}
5 | CUR_ID = None
6 | HCOMCLIENT = None
--------------------------------------------------------------------------------
/HComNuke/HCom_Icons/digitalasset_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComNuke/HCom_Icons/digitalasset_settings.png
--------------------------------------------------------------------------------
/HComNuke/_globals.py:
--------------------------------------------------------------------------------
1 | class NukeGlobals():
2 |
3 | MAIN_UI = None
4 | HCOM_TABS = {}
5 | CUR_ID = None
6 | HCOMCLIENT = None
--------------------------------------------------------------------------------
/HComNuke/menu/menu.py:
--------------------------------------------------------------------------------
1 | import HComNukeUi
2 | toolbar = nuke.menu("Nodes")
3 | toolbar.addCommand("HCom", "HComNukeUi.main()", icon="hcom.png")
--------------------------------------------------------------------------------
/HComHoudini/HCom_Icons/digitalasset_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cgtoolbox/HCom/HEAD/HComHoudini/HCom_Icons/digitalasset_settings.png
--------------------------------------------------------------------------------
/HComMaya/install.txt:
--------------------------------------------------------------------------------
1 | copy the HComMaya in your $PYTHONPATH
2 | add $HOME/houdini14.0/scripts/python/HComHoudini in your $PYTHONPATH ( using userSetup.py)
3 |
--------------------------------------------------------------------------------
/HComMaya/HCom.ini:
--------------------------------------------------------------------------------
1 | #HCom info file -MAYA CLIENT-
2 |
3 | PLAY_SOUND=False
4 | MY_RECEIVED_FILES=DEFAULT
5 | PORT=5000
6 | SAVE_HISTORY=True
7 | SERVER=127.0.0.1
8 |
--------------------------------------------------------------------------------
/HComHoudini/HCom.ini:
--------------------------------------------------------------------------------
1 | #HCom info file
2 | SWITCH_TO_MANUAL_UPDATE=True
3 | SAVE_HISTORY=True
4 | SERVER=127.0.0.1
5 | PLAY_SOUND=False
6 | MY_RECEIVED_FILES=DEFAULT
7 | PORT=5000
8 |
--------------------------------------------------------------------------------
/HComNuke/HCom.ini:
--------------------------------------------------------------------------------
1 | #HCom info file -MAYA CLIENT-
2 |
3 | SAVE_HISTORY=True
4 | OUTPUT_IMAGE_FORMAT=png
5 | SERVER=127.0.0.1
6 | PLAY_SOUND=False
7 | MY_RECEIVED_FILES=DEFAULT
8 | PORT=5000
9 |
--------------------------------------------------------------------------------
/HComHoudini/install.txt:
--------------------------------------------------------------------------------
1 | copy the HComHoudini to $HOME/houdini14.0/scripts/python or in your $PYTHONPATH
2 | add $HOME/houdini14.0/scripts/python/HComHoudini in your $PYTHONPATH (using 123.py for houdinifx, hescape.py for other versions)
3 |
--------------------------------------------------------------------------------
/HComNuke/install.txt:
--------------------------------------------------------------------------------
1 | copy the HComNuke on your hardrive as well as the lib folder
2 |
3 | in the file C:\Users\%USER_NAME%\.nuke\init.py
4 |
5 | add these lines:
6 | nuke.pluginAddPath(PATH_TO_HCOM:HComNuke)
7 | nuke.pluginAddPath(PATH_TO_HCOM:\lib)
8 | nuke.pluginAddPath(PATH_TO_HCOM:\HComNuke\HCom_Icons)
--------------------------------------------------------------------------------
/lib/rpyc/core/__init__.py:
--------------------------------------------------------------------------------
1 | from rpyc.core.stream import SocketStream, PipeStream
2 | from rpyc.core.channel import Channel
3 | from rpyc.core.protocol import Connection
4 | from rpyc.core.netref import BaseNetref
5 | from rpyc.core.async import AsyncResult, AsyncResultTimeout
6 | from rpyc.core.service import Service, VoidService, SlaveService
7 | from rpyc.core.vinegar import GenericException, install_rpyc_excepthook
8 |
9 |
10 | install_rpyc_excepthook()
11 |
12 |
--------------------------------------------------------------------------------
/HComHoudini/PyPanel/HCom.pypanel:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/lib/rpyc/core/consts.py:
--------------------------------------------------------------------------------
1 | """
2 | constants used by the protocol
3 | """
4 |
5 | # messages
6 | MSG_REQUEST = 1
7 | MSG_REPLY = 2
8 | MSG_EXCEPTION = 3
9 |
10 | # boxing
11 | LABEL_VALUE = 1
12 | LABEL_TUPLE = 2
13 | LABEL_LOCAL_REF = 3
14 | LABEL_REMOTE_REF = 4
15 |
16 | # action handlers
17 | HANDLE_PING = 1
18 | HANDLE_CLOSE = 2
19 | HANDLE_GETROOT = 3
20 | HANDLE_GETATTR = 4
21 | HANDLE_DELATTR = 5
22 | HANDLE_SETATTR = 6
23 | HANDLE_CALL = 7
24 | HANDLE_CALLATTR = 8
25 | HANDLE_REPR = 9
26 | HANDLE_STR = 10
27 | HANDLE_CMP = 11
28 | HANDLE_HASH = 12
29 | HANDLE_DIR = 13
30 | HANDLE_PICKLE = 14
31 | HANDLE_DEL = 15
32 | HANDLE_INSPECT = 16
33 | HANDLE_BUFFITER = 17
34 |
35 | # optimized exceptions
36 | EXC_STOP_ITERATION = 1
37 |
38 | # DEBUG
39 | #for k in globals().keys():
40 | # globals()[k] = k
41 |
42 |
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HCom
2 | HCom is a client / server communication system which allows the user to send data between software like Houdini and Maya through local network. It allows to send meshes, bitmaps, alembic cache data and houdini digital assets ( more to come soon ... ).
3 |
4 | It is based on Python 2.7 and the rpyc library, the UI is written with PySide ( shipped with Houdini and Maya ).
5 |
6 | How it works:
7 |
8 | - A hCom python server runs on a machine on the network
9 | - On each user machine you can connect an hCom client ( from Maya or/and Houdini ) to the server.
10 | - you can send data to any user connected to hCom, for houdini digital assets, only maya with Houdini Engine installed can receive them.
11 |
12 | Demo on vimeo:
13 |
14 | Help : http://guillaumejobst.blogspot.fr/p/hcom.html
15 |
16 | https://vimeo.com/127091487 ( Houdini to Houdini )
17 |
18 | https://vimeo.com/127655675 ( Houdini to Maya )
19 |
20 | https://vimeo.com/128033450 ( Alembic support )
21 |
22 |
23 |
--------------------------------------------------------------------------------
/lib/rpyc/license.py:
--------------------------------------------------------------------------------
1 | """\
2 | Copyright (c) 2005-2009
3 | Tomer Filiba (tomerfiliba@gmail.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 | """
23 |
--------------------------------------------------------------------------------
/HComMaya/shelf/shelf_HCom.mel:
--------------------------------------------------------------------------------
1 | global proc shelf_HCom () {
2 | global string $gBuffStr;
3 | global string $gBuffStr0;
4 | global string $gBuffStr1;
5 |
6 |
7 | shelfButton
8 | -enableCommandRepeat 1
9 | -enable 1
10 | -width 35
11 | -height 35
12 | -manage 1
13 | -visible 1
14 | -preventOverride 0
15 | -annotation "HCom Maya Client"
16 | -enableBackground 0
17 | -align "center"
18 | -label "HCom Maya Client"
19 | -labelOffset 0
20 | -font "plainLabelFont"
21 | -imageOverlayLabel "HCom"
22 | -overlayLabelColor 0.8 0.8 0.8
23 | -overlayLabelBackColor 0 0 0 0.2
24 | -image "hcom_shelf.png"
25 | -image1 "hcom_shelf.png"
26 | -style "iconOnly"
27 | -marginWidth 1
28 | -marginHeight 1
29 | -command "from maya import OpenMayaUI as omui \nfrom shiboken import wrapInstance \nfrom PySide import QtGui\nfrom HComMayaClient import HComMayaUi\nreload(HComMayaUi)\n\nmayaMainWindowPtr = omui.MQtUtil.mainWindow() \nmayaMainWindow= wrapInstance(long(mayaMainWindowPtr), QtGui.QMainWindow)\n\nui = HComMayaUi.main()\nui.show(dockable=True)\n"
30 | -sourceType "python"
31 | -commandRepeatable 1
32 | -flat 1
33 | ;
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/lib/rpyc/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | .
3 | ##### ##### ####
4 | ## ## ## ## ## ####
5 | ## ## ## ## ## #
6 | ##### ##### ## ## ## ##
7 | ## ## ## ## ## ## #
8 | ## ## ## ### ## ###
9 | ## ## ## ## #####
10 | -------------------- ## ------------------------------------------
11 | ##
12 |
13 | Remote Python Call (RPyC) v 3.0.7 (22 Sep 2009)
14 | Licensed under the MIT license (see license.py)
15 |
16 | A transparent, symmetric and light-weight RPC and distributed computing
17 | library for python.
18 |
19 | Usage:
20 | import rpyc
21 | c = rpyc.connect_by_service("SERVICENAME")
22 | print c.root.some_function(1, 2, 3)
23 |
24 | Classic-style usage:
25 | import rpyc
26 | # `hostname` is assumed to be running a slave-service server
27 | c = rpyc.classic.connect("hostname")
28 | print c.execute("x = 5")
29 | print c.eval("x + 2")
30 | print c.modules.os.listdir(".")
31 | print c.modules["xml.dom.minidom"].parseString("")
32 | f = c.builtin.open("foobar.txt", "rb")
33 | print f.read(100)
34 | """
35 | from rpyc.core import (SocketStream, PipeStream, Channel, Connection, Service,
36 | BaseNetref, AsyncResult, GenericException, AsyncResultTimeout, VoidService,
37 | SlaveService)
38 | from rpyc.utils.factory import (connect_stream, connect_channel, connect_pipes,
39 | connect_stdpipes, connect, tls_connect, discover, connect_by_service,
40 | connect_subproc, connect_thread)
41 | from rpyc.utils.helpers import async, timed, buffiter, BgServingThread
42 | from rpyc.utils import classic
43 | from rpyc.license import __doc__ as license
44 |
45 |
46 | __author__ = "Tomer Filiba (tomerfiliba@gmail.com)"
47 | version = __version__ = (3, 0, 7)
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/lib/rpyc/core/channel.py:
--------------------------------------------------------------------------------
1 | """
2 | channel - an abstraction layer over streams that works with data frames
3 | (rather than bytes) and supports compression.
4 | Note: in order to avoid problems with all sorts of line-buffered transports,
5 | we deliberately add \\n at the end of each frame.
6 |
7 | note: unlike previous versions, this is no longer thread safe
8 | """
9 | import zlib
10 | from rpyc.utils.lib import Struct
11 |
12 | # * 64 bit length field?
13 | # * separate \n into a FlushingChannel subclass?
14 | # * add thread safety as a subclass?
15 |
16 | class Channel(object):
17 | COMPRESSION_THRESHOLD = 3000
18 | COMPRESSION_LEVEL = 1
19 | FRAME_HEADER = Struct("!LB")
20 | FLUSHER = "\n" # cause any line-buffered layers below us to flush
21 | __slots__ = ["stream", "compress"]
22 |
23 | def __init__(self, stream, compress = True):
24 | self.stream = stream
25 | self.compress = compress
26 | def close(self):
27 | self.stream.close()
28 | @property
29 | def closed(self):
30 | return self.stream.closed
31 | def fileno(self):
32 | return self.stream.fileno()
33 | def poll(self, timeout):
34 | return self.stream.poll(timeout)
35 | def recv(self):
36 | header = self.stream.read(self.FRAME_HEADER.size)
37 | length, compressed = self.FRAME_HEADER.unpack(header)
38 | data = self.stream.read(length + len(self.FLUSHER))[:-len(self.FLUSHER)]
39 | if compressed:
40 | data = zlib.decompress(data)
41 | return data
42 | def send(self, data):
43 | if self.compress and len(data) > self.COMPRESSION_THRESHOLD:
44 | compressed = 1
45 | data = zlib.compress(data, self.COMPRESSION_LEVEL)
46 | else:
47 | compressed = 0
48 | header = self.FRAME_HEADER.pack(len(data), compressed)
49 | buf = header + data + self.FLUSHER
50 | self.stream.write(buf)
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/lib/rpyc/servers/registry_server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | The registry server listens to broadcasts on UDP port 18812, answering to
4 | discovery queries by clients and registering keepalives from all running
5 | servers. In order for clients to use discovery, a registry service must
6 | be running somewhere on their local network.
7 | """
8 | from optparse import OptionParser
9 | from rpyc.utils.registry import REGISTRY_PORT, DEFAULT_PRUNING_TIMEOUT
10 | from rpyc.utils.registry import UDPRegistryServer, TCPRegistryServer
11 |
12 |
13 | parser = OptionParser()
14 | parser.add_option("-m", "--mode", action="store", dest="mode", metavar="MODE",
15 | default="udp", type="string", help="mode can be 'udp' or 'tcp'")
16 | parser.add_option("-p", "--port", action="store", dest="port", type="int",
17 | metavar="PORT", default=REGISTRY_PORT, help="specify a different UDP/TCP listener port")
18 | parser.add_option("-f", "--file", action="store", dest="logfile", type="str",
19 | metavar="FILE", default=None, help="specify the log file to use; the default is stderr")
20 | parser.add_option("-q", "--quiet", action="store_true", dest="quiet",
21 | default=False, help="quiet mode (no logging)")
22 | parser.add_option("-t", "--timeout", action="store", dest="pruning_timeout",
23 | type="int", default=DEFAULT_PRUNING_TIMEOUT, help="sets a custom pruning timeout")
24 |
25 | options, args = parser.parse_args()
26 | if args:
27 | raise ValueError("does not take positional arguments: %r" % (args,))
28 |
29 | if options.port < 1 or options.port > 65535:
30 | raise ValueError("invalid TCP/UDP port %r" % (options.port,))
31 |
32 | if options.mode.lower() == "udp":
33 | server = UDPRegistryServer(port = options.port,
34 | pruning_timeout = options.pruning_timeout)
35 | elif options.mode.lower() == "tcp":
36 | server = TCPRegistryServer(port = options.port,
37 | pruning_timeout = options.pruning_timeout)
38 | else:
39 | raise ValueError("invalid mode %r" % (options.mode,))
40 |
41 | server.logger.quiet = options.quiet
42 | if options.logfile:
43 | server.logger.console = open(options.logfile)
44 |
45 | server.start()
46 |
47 |
48 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/logger.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import thread
4 | import time
5 | import traceback
6 |
7 |
8 | class Logger(object):
9 | def __init__(self, name, console = sys.stderr, file = None, show_name = True,
10 | show_pid = False, show_tid = False, show_date = False, show_time = True,
11 | show_label = True, quiet = False):
12 | self.name = name
13 | self.console = console
14 | self.file = file
15 | self.show_name = show_name
16 | self.show_pid = show_pid
17 | self.show_tid = show_tid
18 | self.show_date = show_date
19 | self.show_time = show_time
20 | self.show_label = show_label
21 | self.quiet = quiet
22 | self.filter = set()
23 |
24 | def log(self, label, msg):
25 | if label in self.filter:
26 | return
27 | header = []
28 | if self.show_name:
29 | header.append("%-10s" % (self.name,))
30 | if self.show_label:
31 | header.append("%-10s" % (label,))
32 | if self.show_date:
33 | header.append(time.strftime("%Y-%m-%d"))
34 | if self.show_time:
35 | header.append(time.strftime("%H:%M:%S"))
36 | if self.show_pid:
37 | header.append("pid=%d" % (os.getpid(),))
38 | if self.show_tid:
39 | header.append("tid=%d" % (thread.get_ident(),))
40 | if header:
41 | header = "[" + " ".join(header) + "] "
42 | sep = "\n...." + " " * (len(header) - 4)
43 | text = header + sep.join(msg.splitlines()) + "\n"
44 | if self.console:
45 | self.console.write(text)
46 | if self.file:
47 | self.file.write(text)
48 |
49 | def debug(self, msg, *args, **kwargs):
50 | if self.quiet: return
51 | if args: msg %= args
52 | self.log("DEBUG", msg)
53 | def info(self, msg, *args, **kwargs):
54 | if self.quiet: return
55 | if args: msg %= args
56 | self.log("INFO", msg)
57 | def warn(self, msg, *args, **kwargs):
58 | if self.quiet: return
59 | if args: msg %= args
60 | self.log("WARNING", msg)
61 | def error(self, msg, *args, **kwargs):
62 | if args: msg %= args
63 | self.log("ERROR", msg)
64 | def traceback(self, excinfo = None):
65 | if not excinfo:
66 | excinfo = sys.exc_info()
67 | self.log("TRACEBACK", "".join(traceback.format_exception(*excinfo)))
68 |
69 |
70 | logger = Logger("root", show_name = False)
71 |
72 |
73 | if __name__ == "__main__":
74 | try:
75 | logger.info("hello")
76 | 1/0
77 | except:
78 | logger.traceback()
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/lib/rpyc/servers/vdbconf.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | """%prog [options]
3 |
4 | A simple configurator for tlslite's verifier databases (VDB), which allows you to:
5 | 1) list the usernames in a given vdb file
6 | 2) add / modify a username in the given vdb file
7 | 3) delete an existing username from the vdb file
8 |
9 | Examples:
10 | vdbconf -l : list all users in `filename`
11 | vdbconf -a : add/replace `username` in `filename`
12 | vdbconf -d : delete `username` from `filename`
13 |
14 | SECURITY NOTE:
15 | Make sure the vdb file has the correct write permissions!
16 | """
17 | import sys
18 | import getpass
19 | from optparse import OptionParser
20 | from rpyc.utils.authenticators import VdbAuthenticator
21 |
22 |
23 | parser = OptionParser(usage = __doc__)
24 | parser.add_option("-l", "--list", action="store_true", dest="listonly",
25 | default=False, help="List usernames and exit")
26 | parser.add_option("-a", "--add", action="store", dest="add", metavar="USERNAME",
27 | default=None, help="Set the given username (required for -d or adding)")
28 | parser.add_option("-d", "--delete", action="store", dest="delete", metavar="USERNAME",
29 | default=None, help="Deletes the given username")
30 |
31 | def get_options():
32 | options, args = parser.parse_args()
33 | if len(args) != 1:
34 | parser.error("Missing filename!")
35 | if options.add and options.delete:
36 | parser.error("Options -a and -d are mutually exclusive!")
37 |
38 | options.filename = args[0]
39 | return options
40 |
41 | def list_users(vdb, options):
42 | users = sorted(vdb.list_users())
43 | if not users:
44 | print "No users defined in %s:" % (options.filename,)
45 | else:
46 | print "Existing users in %s:" % (options.filename,)
47 | for user in users:
48 | print " %s" % (user,)
49 |
50 | def del_user(vdb, options):
51 | username = options.delete
52 | if username not in vdb.list_users():
53 | sys.exit("User %s doesn't exist in %s" % (username, options.filename))
54 |
55 | print "Removing user %s from %s" % (username, options.filename)
56 | vdb.del_user(username)
57 | vdb.sync()
58 |
59 | def set_user(vdb, options):
60 | username = options.add
61 | if username in vdb.list_users():
62 | print "Adding user %s to %s" % (username, options.filename)
63 | else:
64 | print "Changing user %s in %s" % (username, options.filename)
65 |
66 | password1 = getpass.getpass("Password: ")
67 | password2 = getpass.getpass("Retype password: ")
68 |
69 | if password1 != password2:
70 | sys.exit("Passwords do not match!")
71 | if not password1:
72 | sys.exit("Password cannot be empty!")
73 |
74 | vdb.set_user(username, password1)
75 | vdb.sync()
76 |
77 | def main():
78 | options = get_options()
79 | vdb = VdbAuthenticator.from_file(options.filename)
80 |
81 | if options.listonly:
82 | list_users(vdb, options)
83 | elif options.delete:
84 | del_user(vdb, options)
85 | print "OK"
86 | elif options.add:
87 | set_user(vdb, options)
88 | print "OK"
89 | else:
90 | parser.error("No action specified")
91 |
92 |
93 | if __name__ == "__main__":
94 | main()
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/authenticators.py:
--------------------------------------------------------------------------------
1 | """
2 | authenticators: the server instance accepts an authenticator object,
3 | which is basically any callable (i.e., a function) that takes the newly
4 | connected socket and "authenticates" it.
5 |
6 | the authenticator should return a socket-like object with its associated
7 | credentials (a tuple), or raise AuthenticationError if it fails.
8 |
9 | a very trivial authenticator might be
10 |
11 | def magic_word_authenticator(sock):
12 | if sock.recv(5) != "Ma6ik":
13 | raise AuthenticationError("wrong magic word")
14 | return sock, None
15 |
16 | s = ThreadedServer(...., authenticator = magic_word_authenticator)
17 |
18 | your authenticator can return any socket-like object. for instance, it may
19 | authenticate the client and return a TLS/SSL-wrapped socket object that
20 | encrypts the transport.
21 |
22 | the credentials returned alongside with the new socket can be any object.
23 | it will be stored in the rpyc connection configruation under the key
24 | "credentials", and may be used later by the service logic. if no credentials
25 | are applicable, just return None as in the example above.
26 |
27 | rpyc includes integration with tlslite, a TLS/SSL library:
28 | the VdbAuthenticator class authenticates clients based on username-password
29 | pairs.
30 | """
31 | import os
32 | import anydbm
33 | from rpyc.utils.lib import safe_import
34 | tlsapi = safe_import("tlslite.api")
35 |
36 |
37 | class AuthenticationError(Exception):
38 | pass
39 |
40 |
41 | def _load_vdb_with_mode(vdb, mode):
42 | """taken from tlslite/BaseDB.py -- patched for file mode"""
43 | # {{
44 | db = anydbm.open(vdb.filename, mode)
45 | try:
46 | if db["--Reserved--type"] != vdb.type:
47 | raise ValueError("Not a %s database" % (vdb.type,))
48 | except KeyError:
49 | raise ValueError("Not a recognized database")
50 | vdb.db = db
51 | # }}
52 |
53 | class VdbAuthenticator(object):
54 | __slots__ = ["vdb"]
55 | BITS = 2048
56 |
57 | def __init__(self, vdb):
58 | self.vdb = vdb
59 |
60 | @classmethod
61 | def from_dict(cls, users):
62 | inst = cls(tlsapi.VerifierDB())
63 | for username, password in users.iteritems():
64 | inst.set_user(username, password)
65 | return inst
66 |
67 | @classmethod
68 | def from_file(cls, filename, mode = "w"):
69 | vdb = tlsapi.VerifierDB(filename)
70 | if os.path.exists(filename):
71 | _load_vdb_with_mode(vdb, mode)
72 | else:
73 | if mode not in "ncw":
74 | raise ValueError("%s does not exist but mode does not allow "
75 | "writing (%r)" % (filename, mode))
76 | vdb.create()
77 | return cls(vdb)
78 |
79 | def sync(self):
80 | self.vdb.db.sync()
81 |
82 | def set_user(self, username, password):
83 | self.vdb[username] = self.vdb.makeVerifier(username, password, self.BITS)
84 |
85 | def del_user(self, username):
86 | del self.vdb[username]
87 |
88 | def list_users(self):
89 | return self.vdb.keys()
90 |
91 | def __call__(self, sock):
92 | sock2 = tlsapi.TLSConnection(sock)
93 | sock2.fileno = lambda fd=sock.fileno(): fd # tlslite omitted fileno
94 | try:
95 | sock2.handshakeServer(verifierDB = self.vdb)
96 | except Exception, ex:
97 | raise AuthenticationError(str(ex))
98 | return sock2, sock2.allegedSrpUsername
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/helpers.py:
--------------------------------------------------------------------------------
1 | """
2 | helpers and wrappers for common rpyc tasks
3 | """
4 | import threading
5 | from rpyc.utils.lib import WeakValueDict, callable
6 | from rpyc.core.consts import HANDLE_BUFFITER, HANDLE_CALL
7 | from rpyc.core.netref import BaseNetref, syncreq, asyncreq
8 |
9 |
10 | def buffiter(obj, chunk = 10, max_chunk = 1000, factor = 2):
11 | """buffering iterator - reads the remote iterator in chunks starting with
12 | `chunk` up to `max_chunk`, multiplying by `factor` as an exponential
13 | backoff"""
14 | if factor < 1:
15 | raise ValueError("factor must be >= 1, got %r" % (factor,))
16 | it = iter(obj)
17 | count = chunk
18 | while True:
19 | items = syncreq(it, HANDLE_BUFFITER, count)
20 | count = min(count * factor, max_chunk)
21 | if not items:
22 | break
23 | for elem in items:
24 | yield elem
25 |
26 | class _Async(object):
27 | """creates an async proxy wrapper over an existing proxy. async proxies
28 | are cached. invoking an async proxy will return an AsyncResult instead of
29 | blocking"""
30 |
31 | __slots__ = ("proxy", "__weakref__")
32 | def __init__(self, proxy):
33 | self.proxy = proxy
34 | def __call__(self, *args, **kwargs):
35 | return asyncreq(self.proxy, HANDLE_CALL, args, tuple(kwargs.items()))
36 | def __repr__(self):
37 | return "async(%r)" % (self.proxy,)
38 |
39 | _async_proxies_cache = WeakValueDict()
40 | def async(proxy):
41 | pid = id(proxy)
42 | if pid in _async_proxies_cache:
43 | return _async_proxies_cache[pid]
44 | if not hasattr(proxy, "____conn__") or not hasattr(proxy, "____oid__"):
45 | raise TypeError("'proxy' must be a Netref: %r", (proxy,))
46 | if not callable(proxy):
47 | raise TypeError("'proxy' must be callable: %r" % (proxy,))
48 | caller = _Async(proxy)
49 | _async_proxies_cache[id(caller)] = _async_proxies_cache[pid] = caller
50 | return caller
51 |
52 | async.__doc__ = _Async.__doc__
53 |
54 | class timed(object):
55 | """creates a timed asynchronous proxy. invoking the timed proxy will
56 | run in the background and will raise an AsyncResultTimeout exception
57 | if the computation does not terminate within the given timeout"""
58 |
59 | __slots__ = ("__weakref__", "proxy", "timeout")
60 | def __init__(self, proxy, timeout):
61 | self.proxy = async(proxy)
62 | self.timeout = timeout
63 | def __call__(self, *args, **kwargs):
64 | res = self.proxy(*args, **kwargs)
65 | res.set_expiry(self.timeout)
66 | return res
67 | def __repr__(self):
68 | return "timed(%r, %r)" % (self.proxy.proxy, self.timeout)
69 |
70 | class BgServingThread(object):
71 | """runs an RPyC server in the background to serve all requests and replies
72 | that arrive on the given RPyC connection. the thread is created along with
73 | the object; you can use the stop() method to stop the server thread"""
74 | INTERVAL = 0.1
75 | def __init__(self, conn):
76 | self._conn = conn
77 | self._thread = threading.Thread(target = self._bg_server)
78 | self._thread.setDaemon(True)
79 | self._active = True
80 | self._thread.start()
81 | def __del__(self):
82 | if self._active:
83 | self.stop()
84 | def _bg_server(self):
85 | try:
86 | while self._active:
87 | self._conn.serve(self.INTERVAL)
88 | except Exception:
89 | if self._active:
90 | raise
91 | def stop(self):
92 | """stop the server thread. once stopped, it cannot be resumed. you will
93 | have to create a new BgServingThread object later."""
94 | self._active = False
95 | self._thread.join()
96 | self._conn = None
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/lib/rpyc/core/async.py:
--------------------------------------------------------------------------------
1 | import time
2 |
3 |
4 | class AsyncResultTimeout(Exception):
5 | pass
6 |
7 | class AsyncResult(object):
8 | """AsyncResult is an object that represent a computation that occurs in
9 | the background and will eventually have a result. Use the .value property
10 | to access the result (which will block if the result has not yet arrived)
11 | """
12 | __slots__ = ["_conn", "_is_ready", "_is_exc", "_callbacks", "_obj", "_ttl"]
13 | def __init__(self, conn):
14 | self._conn = conn
15 | self._is_ready = False
16 | self._is_exc = None
17 | self._obj = None
18 | self._callbacks = []
19 | self._ttl = None
20 | def __repr__(self):
21 | if self._is_ready:
22 | state = "ready"
23 | elif self._is_exc:
24 | state = "error"
25 | elif self.expired:
26 | state = "expired"
27 | else:
28 | state = "pending"
29 | return "" % (state, id(self))
30 | def __call__(self, is_exc, obj):
31 | if self.expired:
32 | return
33 | self._is_ready = True
34 | self._is_exc = is_exc
35 | self._obj = obj
36 | for cb in self._callbacks:
37 | cb(self)
38 | del self._callbacks[:]
39 |
40 | def wait(self):
41 | """wait for the result to arrive. if the AsyncResult object has an
42 | expiry set, and the result does not arrive within that timeout,
43 | an AsyncResultTimeout exception is raised"""
44 | if self._is_ready:
45 | return
46 | if self._ttl is None:
47 | while not self._is_ready:
48 | self._conn.serve()
49 | else:
50 | while True:
51 | timeout = self._ttl - time.time()
52 | self._conn.poll(timeout = max(timeout, 0))
53 | if self._is_ready:
54 | break
55 | if timeout <= 0:
56 | raise AsyncResultTimeout("result expired")
57 | def add_callback(self, func):
58 | """adds a callback to be invoked when the result arrives. the
59 | callback function takes a single argument, which is the current
60 | AsyncResult (self)"""
61 | if self._is_ready:
62 | func(self)
63 | else:
64 | self._callbacks.append(func)
65 | def set_expiry(self, timeout):
66 | """set the expiry time (in seconds, relative to now) or None for
67 | unlimited time"""
68 | if timeout is None:
69 | self._ttl = None
70 | else:
71 | self._ttl = time.time() + timeout
72 |
73 | @property
74 | def ready(self):
75 | """a predicate of whether the result has arrived"""
76 | if self.expired:
77 | return False
78 | if not self._is_ready:
79 | self._conn.poll_all()
80 | return self._is_ready
81 | @property
82 | def error(self):
83 | """a predicate of whether the returned result is an exception"""
84 | if self.ready:
85 | return self._is_exc
86 | return False
87 | @property
88 | def expired(self):
89 | """a predicate of whether the async result has expired"""
90 | if self._is_ready or self._ttl is None:
91 | return False
92 | else:
93 | return time.time() > self._ttl
94 |
95 | @property
96 | def value(self):
97 | """returns the result of the operation. if the result has not yet
98 | arrived, accessing this property will wait for it. if the result does
99 | not arrive before the expiry time elapses, AsyncResultTimeout is
100 | raised. if the returned result is an exception, it will be raised here.
101 | otherwise, the result is returned directly."""
102 | self.wait()
103 | if self._is_exc:
104 | raise self._obj
105 | else:
106 | return self._obj
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/twisted_integration.py:
--------------------------------------------------------------------------------
1 | """
2 | rpyc-twisted integration, based on code originally contributed by noam raphael
3 |
4 | Note: rpyc normally works in blocking (synchornous) fashion, for instance,
5 | getting an attribute of an object (foo.bar.baz). the twistedish solution
6 | would be using @inlineCallbacks and `yield (yield foo.bar).baz`... which is
7 | rather less pythonistic.
8 |
9 | function calls, however, can be made asynchronous easily with the async()
10 | wrapper, so these will play nicely with twisted.
11 |
12 | all in all, the integration with twisted is limited and rather fake.
13 | working with rpyc might block the reactor -- a bad thing -- but a necessary
14 | evil if we wish to combine the two methodologies.
15 |
16 | if you find a better solution, please tell me.
17 | """
18 | import socket
19 | import rpyc
20 | from rpyc.core import SocketStream, Channel
21 | import twisted.internet.protocol as tip
22 | from twisted.internet import reactor
23 | from twisted.python import log
24 |
25 |
26 | class TwistedSocketStream(SocketStream):
27 | def __init__(self, transport):
28 | SocketStream.__init__(self, transport.socket)
29 | self.transport = transport
30 | self._buffer = ""
31 | def push(self, data):
32 | self._buffer += data
33 |
34 | def poll(self, timeout):
35 | if self._buffer:
36 | return True
37 | self.sock.setblocking(True)
38 | try:
39 | return SocketStream.poll(self, timeout)
40 | finally:
41 | try:
42 | self.sock.setblocking(False)
43 | except socket.error:
44 | pass
45 |
46 | def read(self, count):
47 | if count <= len(self._buffer):
48 | data = self._buffer[:count]
49 | self._buffer = self._buffer[count:]
50 | else:
51 | self.sock.setblocking(True)
52 | try:
53 | data2 = SocketStream.read(self, count - len(self._buffer))
54 | finally:
55 | try:
56 | self.sock.setblocking(False)
57 | except socket.error:
58 | pass
59 | data = self._buffer + data2
60 | self._buffer = ""
61 | #log.msg("%s.read(%r)" % (self, data))
62 | return data
63 |
64 | def write(self, data):
65 | #log.msg("%s.write(%r)" % (self, data))
66 | self.sock.setblocking(True)
67 | try:
68 | SocketStream.write(self, data)
69 | finally:
70 | self.sock.setblocking(False)
71 |
72 |
73 | class TwistedRpycProtocol(tip.Protocol):
74 | def __init__(self):
75 | self.stream = None
76 | self.conn = None
77 | def connectionMade(self):
78 | self.stream = TwistedSocketStream(self.transport)
79 | self.conn = rpyc.Connection(self.factory.service, Channel(self.stream),
80 | config = self.factory.config, _lazy = True)
81 | self.conn._init_service()
82 | if self.factory.logging:
83 | log.msg("%s: connected %s" % (self, self.conn))
84 | if self.factory.on_connected is not None:
85 | reactor.callLater(0, self.factory.on_connected, self.conn)
86 | def connectionLost(self, reason=None):
87 | if self.conn:
88 | if self.factory.logging:
89 | log.msg("%s: closing connection %s" % (self, self.conn))
90 | c = self.conn
91 | self.conn = None
92 | c.close(_catchall = True)
93 | def dataReceived(self, data):
94 | self.stream.push(data)
95 | self.conn.poll_all()
96 |
97 |
98 | class RpycClientFactory(tip.ClientFactory):
99 | protocol = TwistedRpycProtocol
100 | def __init__(self, service, on_connected = None, config = {}, logging = False):
101 | self.service = service
102 | self.config = config
103 | self.on_connected = on_connected
104 | self.logging = logging
105 |
106 |
107 | RpycServerFactory = RpycClientFactory
108 |
109 |
110 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/lib.py:
--------------------------------------------------------------------------------
1 | """
2 | various library utilities (also for compatibility with python2.4)
3 | """
4 | try:
5 | from struct import Struct
6 | except ImportError:
7 | import struct
8 | class Struct(object):
9 | __slots__ = ["format", "size"]
10 | def __init__(self, format):
11 | self.format = format
12 | self.size = struct.calcsize(format)
13 | def pack(self, *args):
14 | return struct.pack(self.format, *args)
15 | def unpack(self, data):
16 | return struct.unpack(self.format, data)
17 |
18 | try:
19 | all = all
20 | except NameError:
21 | def all(seq):
22 | for elem in seq:
23 | if not elem:
24 | return False
25 | return True
26 |
27 | try:
28 | callable = callable
29 | except NameError:
30 | def callable(obj):
31 | return hasattr(obj, "__call__")
32 |
33 | from threading import Lock, RLock, Event
34 |
35 | import weakref
36 | #from weakref import WeakValueDictionary as WeakValueDict
37 |
38 | class WeakValueDict(object):
39 | """a light-weight version of weakref.WeakValueDictionary"""
40 | __slots__ = ("_dict",)
41 | def __init__(self):
42 | self._dict = {}
43 | def __repr__(self):
44 | return repr(self._dict)
45 | def __iter__(self):
46 | return self.iterkeys()
47 | def __len__(self):
48 | return len(self._dict)
49 | def __contains__(self, key):
50 | try:
51 | self[key]
52 | except KeyError:
53 | return False
54 | else:
55 | return True
56 | def get(self, key, default = None):
57 | try:
58 | return self[key]
59 | except KeyError:
60 | return default
61 | def __getitem__(self, key):
62 | obj = self._dict[key]()
63 | if obj is None:
64 | raise KeyError(key)
65 | return obj
66 | def __setitem__(self, key, value):
67 | def remover(wr, _dict = self._dict, key = key):
68 | _dict.pop(key, None)
69 | self._dict[key] = weakref.ref(value, remover)
70 | def __delitem__(self, key):
71 | del self._dict[key]
72 | def iterkeys(self):
73 | return self._dict.iterkeys()
74 | def keys(self):
75 | return self._dict.keys()
76 | def itervalues(self):
77 | for k in self:
78 | yield self[k]
79 | def values(self):
80 | return list(self.itervalues())
81 | def iteritems(self):
82 | for k in self:
83 | yield k, self[k]
84 | def items(self):
85 | return list(self.iteritems())
86 | def clear(self):
87 | self._dict.clear()
88 |
89 | class RefCountingColl(object):
90 | """a set-like object that implements refcounting on its contained objects"""
91 | __slots__ = ("_lock", "_dict")
92 | def __init__(self):
93 | self._lock = Lock()
94 | self._dict = {}
95 | def __repr__(self):
96 | return repr(self._dict)
97 | def add(self, obj):
98 | self._lock.acquire()
99 | try:
100 | key = id(obj)
101 | slot = self._dict.get(key, None)
102 | if slot is None:
103 | slot = [obj, 0]
104 | else:
105 | slot[1] += 1
106 | self._dict[key] = slot
107 | finally:
108 | self._lock.release()
109 | def clear(self):
110 | self._lock.acquire()
111 | try:
112 | self._dict.clear()
113 | finally:
114 | self._lock.release()
115 | def decref(self, key):
116 | self._lock.acquire()
117 | try:
118 | slot = self._dict[key]
119 | if slot[1] <= 1:
120 | del self._dict[key]
121 | else:
122 | slot[1] -= 1
123 | self._dict[key] = slot
124 | finally:
125 | self._lock.release()
126 | def __getitem__(self, key):
127 | self._lock.acquire()
128 | try:
129 | return self._dict[key][0]
130 | finally:
131 | self._lock.release()
132 |
133 |
134 | class MissingModule(object):
135 | __slots__ = ["__name"]
136 | def __init__(self, name):
137 | self.__name = name
138 | def __getattr__(self, name):
139 | raise ImportError("module %r not found" % (self.__name,))
140 |
141 | def safe_import(name):
142 | try:
143 | mod = __import__(name, None, None, "*")
144 | except ImportError:
145 | mod = MissingModule(name)
146 | return mod
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/lib/rpyc/core/vinegar.py:
--------------------------------------------------------------------------------
1 | """
2 | vinegar ('when things go sour'): safe serialization of exceptions.
3 |
4 | note that by changing the configuration parameters, this module can be
5 | made non-secure
6 | """
7 | import sys
8 | import exceptions
9 | import traceback
10 | from types import InstanceType, ClassType
11 | from rpyc.core import brine
12 | from rpyc.core import consts
13 |
14 |
15 | class GenericException(Exception):
16 | pass
17 |
18 | _generic_exceptions_cache = {}
19 |
20 | STOP_ITERATION_MAGIC = 0
21 |
22 | def dump(typ, val, tb, include_local_traceback):
23 | if type(typ) is str:
24 | return typ
25 | if typ is StopIteration:
26 | return consts.EXC_STOP_ITERATION # optimization
27 |
28 | if include_local_traceback:
29 | tbtext = "".join(traceback.format_exception(typ, val, tb))
30 | else:
31 | tbtext = ""
32 | attrs = []
33 | args = []
34 | for name in dir(val):
35 | if name == "args":
36 | for a in val.args:
37 | if brine.dumpable(a):
38 | args.append(a)
39 | else:
40 | args.append(repr(a))
41 | elif not name.startswith("_") or name == "_remote_tb":
42 | attrval = getattr(val, name)
43 | if not brine.dumpable(attrval):
44 | attrval = repr(attrval)
45 | attrs.append((name, attrval))
46 | return (typ.__module__, typ.__name__), tuple(args), tuple(attrs), tbtext
47 |
48 | try:
49 | BaseException
50 | except NameError:
51 | # python 2.4 compatible
52 | BaseException = Exception
53 |
54 | def load(val, import_custom_exceptions, instantiate_custom_exceptions, instantiate_oldstyle_exceptions):
55 | if val == consts.EXC_STOP_ITERATION:
56 | return StopIteration # optimization
57 | if type(val) is str:
58 | return val # deprecated string exceptions
59 |
60 | (modname, clsname), args, attrs, tbtext = val
61 | if import_custom_exceptions and modname not in sys.modules:
62 | try:
63 | mod = __import__(modname, None, None, "*")
64 | except ImportError:
65 | pass
66 | if instantiate_custom_exceptions:
67 | cls = getattr(sys.modules[modname], clsname, None)
68 | elif modname == "exceptions":
69 | cls = getattr(exceptions, clsname, None)
70 | else:
71 | cls = None
72 |
73 | if not isinstance(cls, (type, ClassType)):
74 | cls = None
75 | elif issubclass(cls, ClassType) and not instantiate_oldstyle_exceptions:
76 | cls = None
77 | elif not issubclass(cls, BaseException):
78 | cls = None
79 |
80 | if cls is None:
81 | fullname = "%s.%s" % (modname, clsname)
82 | if fullname not in _generic_exceptions_cache:
83 | fakemodule = {"__module__" : "%s.%s" % (__name__, modname)}
84 | if isinstance(GenericException, ClassType):
85 | _generic_exceptions_cache[fullname] = ClassType(fullname, (GenericException,), fakemodule)
86 | else:
87 | _generic_exceptions_cache[fullname] = type(fullname, (GenericException,), fakemodule)
88 | cls = _generic_exceptions_cache[fullname]
89 |
90 | # support old-style exception classes
91 | if isinstance(cls, ClassType):
92 | exc = InstanceType(cls)
93 | else:
94 | exc = cls.__new__(cls)
95 |
96 | exc.args = args
97 | for name, attrval in attrs:
98 | setattr(exc, name, attrval)
99 | if hasattr(exc, "_remote_tb"):
100 | exc._remote_tb += (tbtext,)
101 | else:
102 | exc._remote_tb = (tbtext,)
103 | return exc
104 |
105 |
106 | #===============================================================================
107 | # customized except hook
108 | #===============================================================================
109 | if hasattr(sys, "excepthook"):
110 | _orig_excepthook = sys.excepthook
111 | else:
112 | # ironpython forgot to implement excepthook, scheisse
113 | _orig_excepthook = None
114 |
115 | def rpyc_excepthook(typ, val, tb):
116 | if hasattr(val, "_remote_tb"):
117 | sys.stderr.write("======= Remote traceback =======\n")
118 | tbtext = "\n--------------------------------\n\n".join(val._remote_tb)
119 | sys.stderr.write(tbtext)
120 | sys.stderr.write("\n======= Local exception ========\n")
121 | _orig_excepthook(typ, val, tb)
122 |
123 | def install_rpyc_excepthook():
124 | if _orig_excepthook is not None:
125 | sys.excepthook = rpyc_excepthook
126 |
127 | def uninstall_rpyc_excepthook():
128 | if _orig_excepthook is not None:
129 | sys.excepthook = _orig_excepthook
130 |
131 |
132 |
--------------------------------------------------------------------------------
/lib/rpyc/core/service.py:
--------------------------------------------------------------------------------
1 | class Service(object):
2 | """The service base-class. Subclass this class to implement custom RPyC
3 | services:
4 | * The name of the class implementing the 'Foo' service should match the
5 | pattern 'FooService' (suffixed by the word 'Service'):
6 | class FooService(Service):
7 | pass
8 | FooService.get_service_name() # 'FOO'
9 | FooService.get_service_aliases() # ['FOO']
10 | * To supply a different name or aliases, use the ALIASES class attribute:
11 | class Foobar(Service):
12 | ALIASES = ["foo", "bar", "lalaland"]
13 | Foobar.get_service_name() # 'FOO'
14 | Foobar.get_service_aliases() # ['FOO', 'BAR', 'LALALAND']
15 | * Override on_connect to perform custom initialization
16 | * Override on_disconnect to perform custom finilization
17 | * To add exposed methods or attributes, simply define them as normally,
18 | but make sure their name is prefixed by 'exposed_', e.g.:
19 | class FooService(Service):
20 | def exposed_foo(self, x, y):
21 | return x + y
22 | * All other names (not prefixed by 'exposed_') are local (not accessible
23 | by the other party)
24 | """
25 | __slots__ = ["_conn"]
26 | ALIASES = ()
27 |
28 | def __init__(self, conn):
29 | self._conn = conn
30 | def on_connect(self):
31 | """called when the connection is established"""
32 | pass
33 | def on_disconnect(self):
34 | """called when the connection had already terminated for cleanup
35 | (must not perform any IO on the connection)"""
36 | pass
37 |
38 | def _rpyc_getattr(self, name):
39 | if name.startswith("exposed_"):
40 | name = name
41 | else:
42 | name = "exposed_" + name
43 | return getattr(self, name)
44 | def _rpyc_delattr(self, name):
45 | raise AttributeError("access denied")
46 | def _rpyc_setattr(self, name, value):
47 | raise AttributeError("access denied")
48 |
49 | @classmethod
50 | def get_service_aliases(cls):
51 | if cls.ALIASES:
52 | return tuple(str(n).upper() for n in cls.ALIASES)
53 | name = cls.__name__.upper()
54 | if name.endswith("SERVICE"):
55 | name = name[:-7]
56 | return (name,)
57 | @classmethod
58 | def get_service_name(cls):
59 | return cls.get_service_aliases()[0]
60 |
61 | exposed_get_service_aliases = get_service_aliases
62 | exposed_get_service_name = get_service_name
63 |
64 |
65 | class VoidService(Service):
66 | """void service - an empty service"""
67 | __slots__ = ()
68 |
69 |
70 | class ModuleNamespace(object):
71 | """used by the SlaveService to implement the magic 'module namespace'"""
72 | __slots__ = ["__getmodule", "__cache", "__weakref__"]
73 | def __init__(self, getmodule):
74 | self.__getmodule = getmodule
75 | self.__cache = {}
76 | def __getitem__(self, name):
77 | if type(name) is tuple:
78 | name = ".".join(name)
79 | if name not in self.__cache:
80 | self.__cache[name] = self.__getmodule(name)
81 | return self.__cache[name]
82 | def __getattr__(self, name):
83 | return self[name]
84 |
85 | class SlaveService(Service):
86 | """The SlaveService allows the other side to perform arbitrary imports and
87 | code execution on the server. This is provided for compatibility with
88 | the classic RPyC (2.6) modus operandi.
89 | This service is very useful in local, secured networks, but it exposes
90 | a major security risk otherwise."""
91 | __slots__ = ["exposed_namespace"]
92 |
93 | def on_connect(self):
94 | self.exposed_namespace = {}
95 | self._conn._config.update(dict(
96 | allow_all_attrs = True,
97 | allow_pickle = True,
98 | allow_getattr = True,
99 | allow_setattr = True,
100 | allow_delattr = True,
101 | import_custom_exceptions = True,
102 | instantiate_custom_exceptions = True,
103 | instantiate_oldstyle_exceptions = True,
104 | ))
105 | # shortcuts
106 | self._conn.modules = ModuleNamespace(self._conn.root.getmodule)
107 | self._conn.eval = self._conn.root.eval
108 | self._conn.execute = self._conn.root.execute
109 | self._conn.namespace = self._conn.root.namespace
110 | self._conn.builtin = self._conn.modules.__builtin__
111 |
112 | def exposed_execute(self, text):
113 | exec text in self.exposed_namespace
114 | def exposed_eval(self, text):
115 | return eval(text, self.exposed_namespace)
116 | def exposed_getmodule(self, name):
117 | return __import__(name, None, None, "*")
118 | def exposed_getconn(self):
119 | return self._conn
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/HComServer.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import rpyc
3 | import copy
4 | from rpyc.utils.server import ThreadedServer
5 |
6 |
7 | class HCom_Server(rpyc.Service):
8 |
9 | '''
10 | Main server, CLIENTS is a dict of clients registered on the server
11 | '''
12 | CLIENTS = {}
13 | CLIENTS_TYPE = {}
14 |
15 | def on_disconnect(self):
16 | '''
17 | Remove the client when is disconnected from the registred dict
18 | '''
19 | clientDisconnected = ""
20 | clientDisconnected_type = "None"
21 | for k in self.CLIENTS.keys():
22 | try:
23 | if self.CLIENTS[k] == self._conn:
24 | clientDisconnected = k
25 | break
26 | except:
27 | continue
28 |
29 |
30 | if clientDisconnected:
31 | del(self.CLIENTS[clientDisconnected])
32 | clientDisconnected_type = self.CLIENTS_TYPE[clientDisconnected]
33 | del(self.CLIENTS_TYPE[clientDisconnected])
34 | sys.stdout.write("=> HCOM_INFO: Client " + str(clientDisconnected) + " left the server !\n")
35 |
36 | # Send update to clients
37 | for k in self.CLIENTS.keys():
38 | if k == clientDisconnected: continue
39 | self.CLIENTS[k].root.exposed_sendIDUpdate(clientDisconnected, "left", clientDisconnected_type)
40 |
41 | def exposed_registerClient(self, clientID, clientType):
42 | '''
43 | Save the given client ( from _conn ) to the CLIENTS dict, using the client ID as key
44 | '''
45 | if not clientID in self.CLIENTS.keys():
46 | self.CLIENTS[clientID] = self._conn
47 | self.CLIENTS_TYPE[clientID] = clientType
48 | sys.stdout.write("=> HCOM_INFO: Client " + str(clientID) + " registered !\n")
49 |
50 | # Send update to clients
51 | for k in self.CLIENTS.keys():
52 | self.CLIENTS[k].root.exposed_sendIDUpdate(clientID, "join", clientType)
53 |
54 | print("=> HCOM_INFO: Registered clients: " + str(self.CLIENTS.keys()).replace("[", "").replace("]", ""))
55 |
56 | return True
57 | else:
58 | return False
59 |
60 | def exposed_removeClient(self, clientID):
61 | '''
62 | Remove client from server registered clients.
63 | '''
64 | if clientID in self.CLIENTS.keys():
65 | del(self.CLIENTS[clientID])
66 | del(self.CLIENTS_TYPE[clientID])
67 | sys.stdout.write("=> HCOM_INFO: Client " + str(clientID) + " removed from server !\n")
68 | sys.stdout.write("=> HCOM_INFO: Registered clients: " + str(self.CLIENTS.keys()).replace("[", "").replace("]", ""))
69 |
70 | def exposed_getClient(self, clientID):
71 | '''
72 | return given client.
73 | '''
74 | if not clientID in self.CLIENTS.keys():
75 | return None
76 |
77 | return self.CLIENTS[clientID]
78 |
79 | def exposed_getClientType(self, clientID):
80 |
81 | if not clientID in self.CLIENTS_TYPE.keys():
82 | return None
83 |
84 | return self.CLIENTS_TYPE[clientID]
85 |
86 | def exposed_getAllClientTypes(self):
87 |
88 | return self.CLIENTS_TYPE
89 |
90 | def exposed_getAllClients(self):
91 | '''
92 | return all clients registered on the server.
93 | '''
94 | return self.CLIENTS
95 |
96 | def exposed_getAllCientInfos(self):
97 | return [self.CLIENTS, self.CLIENTS_TYPE]
98 |
99 | def exposed_sendDataToClient(self, clientID, dataType, sender, data, tabTarget):
100 | '''
101 | Invoke the 'catchData' of the client(s) from the given ID(s).
102 | '''
103 |
104 | c_data = copy.copy(data)
105 |
106 | notReached = []
107 | if not isinstance(clientID, list):
108 | clientID = [clientID,]
109 |
110 | if 'OPEN_CHAT_ROOM' in clientID or tabTarget == 'OPEN_CHAT_ROOM':
111 |
112 | for k in self.CLIENTS.keys():
113 | if k == sender:
114 | continue
115 | self.CLIENTS[k].root.exposed_catchData(dataType, sender, c_data, tabTarget, [None, None])
116 | else:
117 | for client in clientID:
118 | if not client in self.CLIENTS.keys():
119 | notReached.append(client)
120 | continue
121 | self.CLIENTS[client].root.exposed_catchData(dataType, sender, c_data, tabTarget, self.CLIENTS_TYPE[client])
122 |
123 | if not notReached:
124 | return True
125 | else:
126 | return notReached
127 |
128 |
129 | if __name__ == "__main__":
130 |
131 | print("LAUNCHING HCOM SERVER ...")
132 | print("SERVER VERSION: 1.0")
133 |
134 | t = ThreadedServer(HCom_Server, port = 5000, protocol_config={"allow_public_attrs" : True, "allow_pickle" : True})
135 | t.start()
--------------------------------------------------------------------------------
/lib/rpyc/servers/classic_server.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | classic rpyc server (threaded, forking or std) running a SlaveService
4 | usage:
5 | classic_server.py # default settings
6 | classic_server.py -m forking -p 12345 # custom settings
7 | classic_server.py --vdb file.vdb # tlslite-authenticated server
8 | """
9 | import sys
10 | import os
11 | import rpyc
12 | from optparse import OptionParser
13 | from rpyc.utils.server import ThreadedServer, ForkingServer
14 | from rpyc.utils.classic import DEFAULT_SERVER_PORT
15 | from rpyc.utils.registry import REGISTRY_PORT
16 | from rpyc.utils.registry import UDPRegistryClient, TCPRegistryClient
17 | from rpyc.utils.authenticators import VdbAuthenticator
18 | from rpyc.core import SlaveService
19 |
20 |
21 | parser = OptionParser()
22 | parser.add_option("-m", "--mode", action="store", dest="mode", metavar="MODE",
23 | default="threaded", type="string", help="mode can be 'threaded', 'forking', "
24 | "or 'stdio' to operate over the standard IO pipes (for inetd, etc.). "
25 | "Default is 'threaded'")
26 | parser.add_option("-p", "--port", action="store", dest="port", type="int",
27 | metavar="PORT", default=DEFAULT_SERVER_PORT, help="specify a different "
28 | "TCP listener port. Default is 18812")
29 | parser.add_option("--host", action="store", dest="host", type="str",
30 | metavar="HOST", default="0.0.0.0", help="specify a different "
31 | "host to bind to. Default is 0.0.0.0")
32 | parser.add_option("--logfile", action="store", dest="logfile", type="str",
33 | metavar="FILE", default=None, help="specify the log file to use; the "
34 | "default is stderr")
35 | parser.add_option("-q", "--quiet", action="store_true", dest="quiet",
36 | default=False, help="quiet mode (no logging). in stdio mode, "
37 | "writes to /dev/null")
38 | parser.add_option("--vdb", action="store", dest="vdbfile", metavar="FILENAME",
39 | default=None, help="starts an TLS/SSL authenticated server (using tlslite);"
40 | "the credentials are loaded from the vdb file. if not given, the server"
41 | "is not secure (unauthenticated). use vdbconf.py to manage vdb files"
42 | )
43 | parser.add_option("--dont-register", action="store_false", dest="auto_register",
44 | default=True, help="disables this server from registering at all. "
45 | "By default, the server will attempt to register")
46 | parser.add_option("--registry-type", action="store", dest="regtype", type="str",
47 | default="udp", help="can be 'udp' or 'tcp', default is 'udp'")
48 | parser.add_option("--registry-port", action="store", dest="regport", type="int",
49 | default=REGISTRY_PORT, help="the UDP/TCP port. default is %s" % (REGISTRY_PORT,))
50 | parser.add_option("--registry-host", action="store", dest="reghost", type="str",
51 | default=None, help="the registry host machine. for UDP, the default is "
52 | "255.255.255.255; for TCP, a value is required")
53 |
54 |
55 | def get_options():
56 | options, args = parser.parse_args()
57 | if args:
58 | parser.error("does not take positional arguments: %r" % (args,))
59 |
60 | options.mode = options.mode.lower()
61 |
62 | if options.regtype.lower() == "udp":
63 | if options.reghost is None:
64 | options.reghost = "255.255.255.255"
65 | options.registrar = UDPRegistryClient(ip = options.reghost, port = options.regport)
66 | elif options.regtype.lower() == "tcp":
67 | if options.reghost is None:
68 | parser.error("must specific --registry-host")
69 | options.registrar = TCPRegistryClient(ip = options.reghost, port = options.regport)
70 | else:
71 | parse.error("invalid registry type %r" % (options.regtype,))
72 |
73 | if options.vdbfile:
74 | if not os.path.exists(options.vdbfile):
75 | parser.error("vdb file does not exist")
76 | options.authenticator = VdbAuthenticator.from_file(options.vdbfile, mode = "r")
77 | else:
78 | options.authenticator = None
79 |
80 | options.handler = "serve_%s" % (options.mode,)
81 | if options.handler not in globals():
82 | parser.error("invalid mode %r" % (options.mode,))
83 |
84 | return options
85 |
86 | def serve_threaded(options):
87 | t = ThreadedServer(SlaveService, hostname = options.host,
88 | port = options.port, reuse_addr = True,
89 | authenticator = options.authenticator, registrar = options.registrar,
90 | auto_register = options.auto_register)
91 | t.logger.quiet = options.quiet
92 | if options.logfile:
93 | t.logger.console = open(options.logfile, "w")
94 | t.start()
95 |
96 | def serve_forking(options):
97 | t = ForkingServer(SlaveService, hostname = options.host,
98 | port = options.port, reuse_addr = True,
99 | authenticator = options.authenticator, registrar = options.registrar,
100 | auto_register = options.auto_register)
101 | t.logger.quiet = options.quiet
102 | if options.logfile:
103 | t.logger.console = open(options.logfile, "w")
104 | t.start()
105 |
106 | def serve_stdio(options):
107 | origstdin = sys.stdin
108 | origstdout = sys.stdout
109 | if options.quiet:
110 | dev = os.devnull
111 | elif sys.platform == "win32":
112 | dev = "con:"
113 | else:
114 | dev = "/dev/tty"
115 | try:
116 | sys.stdin = open(dev, "r")
117 | sys.stdout = open(dev, "w")
118 | except (IOError, OSError):
119 | sys.stdin = open(os.devnull, "r")
120 | sys.stdout = open(os.devnull, "w")
121 | conn = rpyc.classic.connect_pipes(origstdin, origstdout)
122 | try:
123 | try:
124 | conn.serve_all()
125 | except KeyboardInterrupt:
126 | print "User interrupt!"
127 | finally:
128 | conn.close()
129 |
130 |
131 | def main():
132 | options = get_options()
133 | handler = globals()[options.handler]
134 | handler(options)
135 |
136 |
137 | if __name__ == "__main__":
138 | main()
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/factory.py:
--------------------------------------------------------------------------------
1 | """
2 | rpyc connection factories
3 | """
4 | import socket
5 | import thread, threading
6 | import rpyc
7 | from rpyc import Connection, Channel, SocketStream, PipeStream, VoidService
8 | from rpyc.utils.registry import UDPRegistryClient, TCPRegistryClient
9 |
10 |
11 | class DiscoveryError(Exception):
12 | pass
13 |
14 |
15 | #------------------------------------------------------------------------------
16 | # API
17 | #------------------------------------------------------------------------------
18 | def connect_channel(channel, service = VoidService, config = {}):
19 | """creates a connection over a given channel
20 | channel - the channel to use
21 | service - the local service to expose (defaults to Void)
22 | config - configuration dict"""
23 | return Connection(service, channel, config = config)
24 |
25 | def connect_stream(stream, service = VoidService, config = {}):
26 | """creates a connection over a given stream
27 | stream - the stream to use
28 | service - the local service to expose (defaults to Void)
29 | config - configuration dict"""
30 | return connect_channel(Channel(stream), service = service, config = config)
31 |
32 | def connect_pipes(input, output, service = VoidService, config = {}):
33 | """creates a connection over the given input/output pipes
34 | input - the input pipe
35 | output - the output pipe
36 | service - the local service to expose (defaults to Void)
37 | config - configuration dict"""
38 | return connect_stream(PipeStream(input, output), service = service, config = config)
39 |
40 | def connect_stdpipes(service = VoidService, config = {}):
41 | """creates a connection over the standard input/output pipes
42 | service - the local service to expose (defaults to Void)
43 | config - configuration dict"""
44 | return connect_stream(PipeStream.from_std(), service = service, config = config)
45 |
46 | def connect(host, port, service = VoidService, config = {}):
47 | """creates a socket-connection to the given host
48 | host - the hostname to connect to
49 | port - the TCP port to use
50 | service - the local service to expose (defaults to Void)
51 | config - configuration dict"""
52 | return Connection(service, Channel(SocketStream.connect(host, port)), config = config)
53 |
54 | def tls_connect(host, port, username, password, service = VoidService, config = {}):
55 | """creates a TLS-connection to the given host (encrypted and authenticated)
56 | username - the username used to authenticate the client
57 | password - the password used to authenticate the client
58 | host - the hostname to connect to
59 | port - the TCP port to use
60 | service - the local service to expose (defaults to Void)
61 | config - configuration dict"""
62 | s = SocketStream.tls_connect(host, port, username, password)
63 | return Connection(service, Channel(s), config = config)
64 |
65 | def discover(service_name, host = None, registrar = None, timeout = 2):
66 | """discovers hosts running the given service
67 | service_name - the service to look for
68 | host - limit the discovery to the given host only (None means any host)
69 | registrar - use this registry client to discover services. if None,
70 | use the default UDPRegistryClient with the default settings.
71 | timeout - the number of seconds to wait for a reply from the registry
72 | if no hosts are found, raises DiscoveryError
73 | returns a list of (ip, port) pairs
74 | """
75 | if registrar is None:
76 | registrar = UDPRegistryClient(timeout = timeout)
77 | addrs = registrar.discover(service_name)
78 | if not addrs:
79 | raise DiscoveryError("no servers exposing %r were found" % (service_name,))
80 | if host:
81 | ips = socket.gethostbyname_ex(host)[2]
82 | addrs = [(h, p) for h, p in addrs if h in ips]
83 | if not addrs:
84 | raise DiscoveryError("no servers exposing %r were found on %r" % (service_name, host))
85 | return addrs
86 |
87 | def connect_by_service(service_name, host = None, service = VoidService, config = {}):
88 | """create a connection to an arbitrary server that exposes the requested service
89 | service_name - the service to discover
90 | host - limit discovery to the given host only (None means any host)
91 | service - the local service to expose (defaults to Void)
92 | config - configuration dict"""
93 | host, port = discover(service_name, host = host)[0]
94 | return connect(host, port, service, config = config)
95 |
96 | def connect_subproc(args, service = VoidService, config = {}):
97 | """runs an rpyc server on a child process that and connects to it over
98 | the stdio pipes. uses the subprocess module.
99 | args - the args to Popen, e.g., ["python", "-u", "myfile.py"]
100 | service - the local service to expose (defaults to Void)
101 | config - configuration dict"""
102 | from subprocess import Popen, PIPE
103 | proc = Popen(args, stdin = PIPE, stdout = PIPE)
104 | conn = connect_pipes(proc.stdout, proc.stdin, service = service, config = config)
105 | conn.proc = proc # just so you can have control over the processs
106 | return conn
107 |
108 | def connect_thread(service = VoidService, config = {}, remote_service = VoidService, remote_config = {}):
109 | """starts an rpyc server on a thread and connects to it over a socket.
110 | service - the local service to expose (defaults to Void)
111 | config - configuration dict
112 | server_service - the remote service to expose (of the server; defaults to Void)
113 | server_config - remote configuration dict (of the server)
114 | """
115 | listener = socket.socket()
116 | listener.bind(("localhost", 0))
117 | listener.listen(1)
118 |
119 | def server(listener = listener):
120 | client = listener.accept()[0]
121 | listener.close()
122 | conn = connect_stream(SocketStream(client), service = remote_service,
123 | config = remote_config)
124 | try:
125 | conn.serve_all()
126 | except KeyboardInterrupt:
127 | thread.interrupt_main()
128 |
129 | t = threading.Thread(target = server)
130 | t.setDaemon(True)
131 | t.start()
132 | host, port = listener.getsockname()
133 | return connect(host, port, service = service, config = config)
134 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/HComNuke/HComNukeUtils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import subprocess
4 | import random
5 | import threading
6 | import nuke
7 |
8 | HISTORY_FOLDER = os.path.dirname(__file__) + "\\HCom_History\\"
9 | ICONPATH = os.path.dirname(__file__) + "\\HCom_Icons\\"
10 |
11 | def readIni():
12 |
13 | iniValues = {}
14 |
15 | ini = os.path.dirname(__file__) + "\\HCom.ini"
16 | with open(ini, 'r') as f:
17 | for i in f.readlines():
18 | if i.startswith("#"):
19 | continue
20 | elif i == "\n":
21 | continue
22 | else:
23 | data = i.split("=")
24 | if len(data) <= 1:
25 | continue
26 |
27 | val = data[1].replace("\n", "").replace("\r", "")
28 | if val.isdigit() and "." in val:
29 | val = float(val)
30 | elif val.isdigit() and not "." in val:
31 | val = int(val)
32 | elif val.lower() == "true":
33 | val = True
34 | elif val.lower() == "false":
35 | val = False
36 | else:
37 | val = str(val)
38 |
39 | iniValues[str(data[0]).replace("\r", "")] = val
40 |
41 | return iniValues
42 |
43 | def writeIni(settings):
44 |
45 | ini = os.path.dirname(__file__) + "\\HCom.ini"
46 | with open(ini, 'w') as f:
47 | f.write('')
48 |
49 | data = ["#HCom info file -MAYA CLIENT-\r\n"]
50 | for k in settings.keys():
51 | data.append(k + "=" + str(settings[k]))
52 |
53 | with open(ini, 'a') as f:
54 | for d in data: f.write(d + "\r\n")
55 |
56 |
57 | def writeHistory(sender, timeStamp, data):
58 |
59 | historyFile = HISTORY_FOLDER + sender.lower() + "_history.txt"
60 | with open(historyFile, 'a') as f:
61 | f.write(timeStamp + "\n")
62 | f.write(" " + str(data) + "\n")
63 |
64 | def coloredString(string, hexColor=None, rgb=None, italic=False, bold=False):
65 |
66 | in_italic_tag = ""
67 | out_italic_tag = ""
68 | if italic:
69 | in_italic_tag = ""
70 | out_italic_tag = ""
71 |
72 | in_bold_tag = ""
73 | out_bold_tag = ""
74 | if bold:
75 | in_bold_tag = ""
76 | out_bold_tag = ""
77 |
78 | if not hexColor and not rgb:
79 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag)
80 |
81 | if hexColor:
82 | if hexColor.startswith("#"):
83 | hexColor = hexColor.replace("#", "")
84 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag, hexColor)
85 | else:
86 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag, rgb[0], rgb[1], rgb[2])
87 |
88 | def incrementFile(filePath):
89 |
90 | if not os.path.exists(filePath):
91 | return filePath
92 |
93 | baseName = os.path.basename(filePath)
94 | name = baseName.split(".")[0]
95 | fileType = baseName.split(".")[1]
96 | dirName = os.path.dirname(filePath)
97 |
98 | fileInc = dirName + os.sep + name + "_1." + fileType
99 | i = 2
100 | while os.path.exists(fileInc):
101 | fileInc = dirName + os.sep + name + "_" + str(i) + "." + fileType
102 |
103 | return fileInc
104 |
105 | def createAlembic(data, sender = "", settings=None):
106 |
107 | name = data["NAME"]
108 | binary = data["DATA"]
109 |
110 | abcFile = fetchMyReceivedFilesFolder() + os.sep + name + ".abc"
111 | abcFile = incrementFile(abcFile)
112 |
113 | with open(abcFile, 'wb') as f:
114 | f.write(binary)
115 |
116 | fileName = name = name + "_from_" + sender
117 |
118 | nuke.executeInMainThread(_importAlembic, args=(fileName, abcFile))
119 |
120 | return True
121 |
122 | def _importAlembic(fileName, filePath):
123 |
124 | n = nuke.createNode('ReadGeo2')
125 | n["file"].setValue(filePath.replace("\\", "/"))
126 | n.setName(fileName)
127 |
128 | def createOtl(data, sender="", settings=None):
129 | return False
130 |
131 | def setOtlSettings(data, sender="", settings=None):
132 | return False
133 |
134 | def createMesh(data, sender="", settings=None):
135 |
136 | meshType = data["MESH_TYPE"]
137 | if meshType != ".obj":
138 | print("ERROR: Mesh type not supported (" + meshType + ")")
139 | return False
140 |
141 | meshName = data["MESH_NAME"]
142 | meshData = data["MESH_DATA"]
143 |
144 | obj = fetchMyReceivedFilesFolder() + os.sep + meshName + meshType
145 | obj = incrementFile(obj)
146 | with open(obj, 'wb') as f:
147 | f.write(meshData)
148 |
149 | nuke.nodes.ReadGeo(name = meshName + "_from_" + sender,
150 | file = obj.replace("\\", "/"))
151 |
152 |
153 | def createPic(data, sender="", settings=None):
154 |
155 | imageName = data["IMAGE_NAME"]
156 | imageData = data["BINARY_DATA"]
157 |
158 | imageNameAndFile = imageName.split(".")
159 |
160 | outFile = fetchMyReceivedFilesFolder() + os.sep + imageNameAndFile[0] + "." + imageNameAndFile[1]
161 | outFile = incrementFile(outFile)
162 |
163 | with open(outFile, 'wb') as f:
164 | f.write(imageData)
165 |
166 | nuke.nodes.Read(name = imageName + "_from_" + sender,
167 | file = outFile.replace("\\", "/"))
168 | return True
169 |
170 |
171 | def fetchMyReceivedFilesFolder():
172 |
173 | p = readIni()["MY_RECEIVED_FILES"].replace("\r", "")
174 | if p == "DEFAULT":
175 | p = os.path.dirname(__file__) + "\\HCom_Received_Files"
176 |
177 | if not os.path.exists(p):
178 | os.makedirs(p)
179 |
180 | return p
181 |
182 | def rdnname():
183 | names = ["Motoko", "Bato", "Kusanagi", "Frodon", "Sheldon", "Pipo", "Sam", "Gandalf", "Fitz", "Henry"]
184 | names += ["Leonard", "Batman", "Bobleponge", "rincewind", "carrot", "HelloWorld", "Python", "Houdini"]
185 | return names[random.randint(0, len(names)-1)]
186 |
187 | class CLIENT_TYPE():
188 |
189 | NONE = "NONE"
190 | HOUDINI = "Houdini"
191 | MAYA_NO_HENGINE = "Maya_no_hengine"
192 | MAYA_HENGINE = "Maya_hengine"
193 | NUKE = "nuke"
194 |
--------------------------------------------------------------------------------
/lib/rpyc/core/netref.py:
--------------------------------------------------------------------------------
1 | """
2 | NetRef - transparent network references implementation.
3 |
4 | SURGEON GENERAL'S WARNING: Black magaic is known to causes Lung Cancer,
5 | Heart Disease, Emphysema, and May Complicate Pregnancy. Close your eyes!
6 | """
7 | import sys
8 | import inspect
9 | import types
10 | import cPickle as pickle
11 | from rpyc.core import consts
12 |
13 |
14 | _local_netref_attrs = frozenset([
15 | '____conn__', '____oid__', '__class__', '__cmp__', '__del__', '__delattr__',
16 | '__dir__', '__doc__', '__getattr__', '__getattribute__', '__hash__',
17 | '__init__', '__metaclass__', '__module__', '__new__', '__reduce__',
18 | '__reduce_ex__', '__repr__', '__setattr__', '__slots__', '__str__',
19 | '__weakref__', '__dict__', '__members__', '__methods__',
20 | ])
21 |
22 | _builtin_types = [
23 | type, object, types.InstanceType, types.ClassType, bool, complex, dict,
24 | file, float, int, list, long, slice, str, basestring, tuple, unicode,
25 | str, set, frozenset, Exception, types.NoneType, types.DictProxyType,
26 | types.BuiltinFunctionType, types.GeneratorType, types.MethodType,
27 | types.CodeType, types.FrameType, types.TracebackType, xrange,
28 | types.ModuleType, types.FunctionType,
29 |
30 | type(int.__add__), # wrapper_descriptor
31 | type((1).__add__), # method-wrapper
32 | type(iter([])), # listiterator
33 | type(iter(())), # tupleiterator
34 | type(iter(xrange(10))), # rangeiterator
35 | type(iter(set())), # setiterator
36 | ]
37 |
38 | _normalized_builtin_types = dict(((t.__name__, t.__module__), t)
39 | for t in _builtin_types)
40 |
41 | def syncreq(proxy, handler, *args):
42 | """performs a synchronous request on the given proxy object"""
43 | conn = object.__getattribute__(proxy, "____conn__")
44 | oid = object.__getattribute__(proxy, "____oid__")
45 | return conn().sync_request(handler, oid, *args)
46 |
47 | def asyncreq(proxy, handler, *args):
48 | """performs an asynchronous request on the given proxy object,
49 | retuning an AsyncResult"""
50 | conn = object.__getattribute__(proxy, "____conn__")
51 | oid = object.__getattribute__(proxy, "____oid__")
52 | return conn().async_request(handler, oid, *args)
53 |
54 | class NetrefMetaclass(type):
55 | """a metaclass just to customize the __repr__ of netref classes"""
56 | __slots__ = ()
57 | def __repr__(self):
58 | if self.__module__:
59 | return "" % (self.__module__, self.__name__)
60 | else:
61 | return "" % (self.__name__,)
62 |
63 | class BaseNetref(object):
64 | """the base netref object, from which all netref classes derive"""
65 | __metaclass__ = NetrefMetaclass
66 | __slots__ = ["____conn__", "____oid__", "__weakref__"]
67 | def __init__(self, conn, oid):
68 | self.____conn__ = conn
69 | self.____oid__ = oid
70 | def __del__(self):
71 | try:
72 | asyncreq(self, consts.HANDLE_DEL)
73 | except:
74 | pass
75 |
76 | def __getattribute__(self, name):
77 | if name in _local_netref_attrs:
78 | if name == "__class__":
79 | cls = object.__getattribute__(self, "__class__")
80 | if cls is None:
81 | cls = self.__getattr__("__class__")
82 | return cls
83 | elif name == "__doc__":
84 | return self.__getattr__("__doc__")
85 | elif name == "__members__": # sys.version_info < (2, 6)
86 | return self.__dir__()
87 | else:
88 | return object.__getattribute__(self, name)
89 | else:
90 | return syncreq(self, consts.HANDLE_GETATTR, name)
91 | def __getattr__(self, name):
92 | return syncreq(self, consts.HANDLE_GETATTR, name)
93 | def __delattr__(self, name):
94 | if name in _local_netref_attrs:
95 | object.__delattr__(self, name)
96 | else:
97 | syncreq(self, consts.HANDLE_DELATTR, name)
98 | def __setattr__(self, name, value):
99 | if name in _local_netref_attrs:
100 | object.__setattr__(self, name, value)
101 | else:
102 | syncreq(self, consts.HANDLE_SETATTR, name, value)
103 | def __dir__(self):
104 | return list(syncreq(self, consts.HANDLE_DIR))
105 |
106 | # support for metaclasses
107 | def __hash__(self):
108 | return syncreq(self, consts.HANDLE_HASH)
109 | def __cmp__(self, other):
110 | return syncreq(self, consts.HANDLE_CMP, other)
111 | def __repr__(self):
112 | return syncreq(self, consts.HANDLE_REPR)
113 | def __str__(self):
114 | return syncreq(self, consts.HANDLE_STR)
115 | # support for pickle
116 | def __reduce_ex__(self, proto):
117 | return pickle.loads, (syncreq(self, consts.HANDLE_PICKLE, proto),)
118 |
119 | def _make_method(name, doc):
120 | if name == "__call__":
121 | def __call__(_self, *args, **kwargs):
122 | kwargs = tuple(kwargs.items())
123 | return syncreq(_self, consts.HANDLE_CALL, args, kwargs)
124 | __call__.__doc__ = doc
125 | return __call__
126 | else:
127 | def method(_self, *args, **kwargs):
128 | kwargs = tuple(kwargs.items())
129 | return syncreq(_self, consts.HANDLE_CALLATTR, name, args, kwargs)
130 | method.__name__ = name
131 | method.__doc__ = doc
132 | return method
133 |
134 | def inspect_methods(obj):
135 | """returns a list of (method name, docstring) tuples of all the methods of
136 | the given object"""
137 | methods = {}
138 | attrs = {}
139 | if isinstance(obj, type):
140 | # don't forget the darn metaclass
141 | mros = list(reversed(type(obj).__mro__)) + list(reversed(obj.__mro__))
142 | else:
143 | mros = reversed(type(obj).__mro__)
144 | for basecls in mros:
145 | attrs.update(basecls.__dict__)
146 | for name, attr in attrs.iteritems():
147 | if name not in _local_netref_attrs and hasattr(attr, "__call__"):
148 | methods[name] = inspect.getdoc(attr)
149 | return methods.items()
150 |
151 | def class_factory(clsname, modname, methods):
152 | ns = {"__slots__" : ()}
153 | for name, doc in methods:
154 | if name not in _local_netref_attrs:
155 | ns[name] = _make_method(name, doc)
156 | ns["__module__"] = modname
157 | if modname in sys.modules and hasattr(sys.modules[modname], clsname):
158 | ns["__class__"] = getattr(sys.modules[modname], clsname)
159 | elif (clsname, modname) in _normalized_builtin_types:
160 | ns["__class__"] = _normalized_builtin_types[clsname, modname]
161 | else:
162 | ns["__class__"] = None # to be resolved by the instance
163 | return type(clsname, (BaseNetref,), ns)
164 |
165 | builtin_classes_cache = {}
166 | for cls in _builtin_types:
167 | builtin_classes_cache[cls.__name__, cls.__module__] = class_factory(
168 | cls.__name__, cls.__module__, inspect_methods(cls))
169 |
170 |
171 |
--------------------------------------------------------------------------------
/HComMaya/HComMayaUtils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import subprocess
4 | import random
5 | import threading
6 |
7 | import maya.mel as mel
8 | import maya.cmds as cmds
9 | import maya.utils as mUtils
10 |
11 | HISTORY_FOLDER = os.path.dirname(__file__) + "\\HCom_History\\"
12 | ICONPATH = os.path.dirname(__file__) + "\\HCom_Icons\\"
13 |
14 | def readIni():
15 |
16 | iniValues = {}
17 |
18 | ini = os.path.dirname(__file__) + "\\HCom.ini"
19 | with open(ini, 'r') as f:
20 | for i in f.readlines():
21 | if i.startswith("#"):
22 | continue
23 | elif i == "\n":
24 | continue
25 | else:
26 | data = i.split("=")
27 | if len(data) <= 1:
28 | continue
29 |
30 | val = data[1].replace("\n", "").replace("\r", "")
31 | if val.isdigit() and "." in val:
32 | val = float(val)
33 | elif val.isdigit() and not "." in val:
34 | val = int(val)
35 | elif val.lower() == "true":
36 | val = True
37 | elif val.lower() == "false":
38 | val = False
39 | else:
40 | val = str(val)
41 |
42 | iniValues[str(data[0]).replace("\r", "")] = val
43 |
44 | return iniValues
45 |
46 | def writeIni(settings):
47 |
48 | ini = os.path.dirname(__file__) + "\\HCom.ini"
49 | with open(ini, 'w') as f:
50 | f.write('')
51 |
52 | data = ["#HCom info file -MAYA CLIENT-\r\n"]
53 | for k in settings.keys():
54 | data.append(k + "=" + str(settings[k]))
55 |
56 | with open(ini, 'a') as f:
57 | for d in data: f.write(d + "\r\n")
58 |
59 |
60 | def writeHistory(sender, timeStamp, data):
61 |
62 | historyFile = HISTORY_FOLDER + sender.lower() + "_history.txt"
63 | with open(historyFile, 'a') as f:
64 | f.write(timeStamp + "\n")
65 | f.write(" " + str(data) + "\n")
66 |
67 | def coloredString(string, hexColor=None, rgb=None, italic=False, bold=False):
68 |
69 | in_italic_tag = ""
70 | out_italic_tag = ""
71 | if italic:
72 | in_italic_tag = ""
73 | out_italic_tag = ""
74 |
75 | in_bold_tag = ""
76 | out_bold_tag = ""
77 | if bold:
78 | in_bold_tag = ""
79 | out_bold_tag = ""
80 |
81 | if not hexColor and not rgb:
82 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag)
83 |
84 | if hexColor:
85 | if hexColor.startswith("#"):
86 | hexColor = hexColor.replace("#", "")
87 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag, hexColor)
88 | else:
89 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag, rgb[0], rgb[1], rgb[2])
90 |
91 | def incrementFile(filePath):
92 |
93 | if not os.path.exists(filePath):
94 | return filePath
95 |
96 | baseName = os.path.basename(filePath)
97 | name = baseName.split(".")[0]
98 | fileType = baseName.split(".")[1]
99 | dirName = os.path.dirname(filePath)
100 |
101 | fileInc = dirName + os.sep + name + "_1." + fileType
102 | i = 2
103 | while os.path.exists(fileInc):
104 | fileInc = dirName + os.sep + name + "_" + str(i) + "." + fileType
105 |
106 | return fileInc
107 |
108 | def createAlembic(data, sender = "", settings=None):
109 |
110 | name = data["NAME"]
111 | binary = data["DATA"]
112 |
113 | abcFile = fetchMyReceivedFilesFolder() + os.sep + name + ".abc"
114 | abcFile = incrementFile(abcFile)
115 |
116 | with open(abcFile, 'wb') as f:
117 | f.write(binary)
118 |
119 | try:
120 | mUtils.executeInMainThreadWithResult(lambda: cmds.AbcImport(fetchMyReceivedFilesFolder() + os.sep + name + ".abc"))
121 | return True
122 | except AttributeError:
123 | print("ERROR: ALEMBIC PLUGIN NOT LOADED")
124 | return False
125 |
126 | def createOtl(data, sender="", settings=None):
127 |
128 |
129 | nodeType = data["OTL_TYPE"]
130 | subOtlLibs = data["OTL_ALL_LIBS"]
131 |
132 | libPath = None
133 | otlToAdd = None
134 |
135 | # Check otl libs
136 | if subOtlLibs:
137 |
138 | for e in subOtlLibs:
139 | libName = e[0]
140 | libData = e[1]
141 |
142 | otlLibToInstall = str(fetchMyReceivedFilesFolder() + os.sep).replace("\\","/") + libName
143 |
144 | with open(otlLibToInstall, 'wb') as f:
145 | f.write(libData)
146 |
147 | libs = mel.eval('houdiniAsset -listAssets "' + otlLibToInstall + '"')
148 | if libs:
149 | for lib in libs:
150 | if nodeType in str(lib):
151 | libPath = otlLibToInstall
152 | otlToAdd = lib
153 |
154 | if libPath and otlToAdd:
155 | melcmd = 'houdiniAsset -loadAsset "' + libPath + '" "' + otlToAdd + '"'
156 |
157 | try:
158 | mUtils.executeInMainThreadWithResult(lambda: mel.eval(melcmd))
159 | return True
160 | except Exception as e:
161 | print str(e)
162 | return False
163 |
164 | else:
165 | print("ERROR: Incoming object is not a valid digital asset")
166 | return None
167 |
168 |
169 | def setOtlSettings(data, sender="", settings=None):
170 | return False
171 |
172 | def createMesh(data, sender="", settings=None):
173 |
174 | meshType = data["MESH_TYPE"]
175 | if meshType != ".obj":
176 | print("ERROR: Mesh type not supported (" + meshType + ")")
177 | return False
178 |
179 | meshName = data["MESH_NAME"]
180 | meshData = data["MESH_DATA"]
181 |
182 | obj = fetchMyReceivedFilesFolder() + os.sep + meshName + meshType
183 | obj = incrementFile(obj)
184 | with open(obj, 'wb') as f:
185 | f.write(meshData)
186 |
187 | try:
188 | mUtils.executeInMainThreadWithResult(lambda: cmds.file(obj,i=True,dns=True))
189 | return True
190 | except Exception as e:
191 | print str(e)
192 | return False
193 |
194 |
195 | def createPic(data, sender="", settings=None):
196 |
197 | imageName = data["IMAGE_NAME"]
198 | imageData = data["BINARY_DATA"]
199 |
200 | imageNameAndFile = imageName.split(".")
201 |
202 | outFile = fetchMyReceivedFilesFolder() + os.sep + imageNameAndFile[0] + "." + imageNameAndFile[1]
203 | outFile = incrementFile(outFile)
204 |
205 | with open(outFile, 'wb') as f:
206 | f.write(imageData)
207 |
208 | openPicFile(outFile)
209 | return True
210 |
211 | def openPicFile(picFile):
212 |
213 | try:
214 | subprocess.Popen("fcheck " + picFile, shell=True)
215 |
216 | except Exception as e:
217 |
218 | print "FCHECK ERROR: " + str(e)
219 |
220 | try:
221 | subprocess.Popen("explorer " + picFile, shell=True)
222 |
223 | except Exception as e:
224 | print "EXPLORER ERROR: " + str(e)
225 |
226 |
227 | def fetchMyReceivedFilesFolder():
228 |
229 | p = readIni()["MY_RECEIVED_FILES"].replace("\r", "")
230 | if p == "DEFAULT":
231 | p = os.path.dirname(__file__) + "\\HCom_Received_Files"
232 |
233 | if not os.path.exists(p):
234 | os.makedirs(p)
235 |
236 | return p
237 |
238 | def rdnname():
239 | names = ["Motoko", "Bato", "Kusanagi", "Frodon", "Sheldon", "Pipo", "Sam", "Gandalf", "Fitz", "Henry"]
240 | names += ["Leonard", "Batman", "Bobleponge", "rincewind", "carrot", "HelloWorld", "Python", "Houdini"]
241 | return names[random.randint(0, len(names)-1)]
242 |
243 | class CLIENT_TYPE():
244 |
245 | NONE = "NONE"
246 | HOUDINI = "Houdini"
247 | MAYA_NO_HENGINE = "Maya_no_hengine"
248 | MAYA_HENGINE = "Maya_hengine"
249 | NUKE = "nuke"
250 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/server.py:
--------------------------------------------------------------------------------
1 | """
2 | rpyc plug-in server (threaded or forking)
3 | """
4 | import sys
5 | import os
6 | import socket
7 | import time
8 | import threading
9 | import select
10 | import signal
11 | import errno
12 | from rpyc.core import brine, SocketStream, Channel, Connection
13 | from rpyc.utils.logger import Logger
14 | from rpyc.utils.registry import UDPRegistryClient, TCPRegistryClient
15 | from rpyc.utils.authenticators import AuthenticationError
16 |
17 |
18 | class Server(object):
19 | def __init__(self, service, hostname = "0.0.0.0", port = 0, backlog = 10,
20 | reuse_addr = True, authenticator = None, registrar = None,
21 | auto_register = True, protocol_config = {}, logger = None):
22 | self.active = False
23 | self._closed = False
24 | self.service = service
25 | self.authenticator = authenticator
26 | self.backlog = backlog
27 | self.auto_register = auto_register
28 | self.protocol_config = protocol_config
29 | self.clients = set()
30 | if logger is None:
31 | logger = self._get_logger()
32 | self.logger = logger
33 | if registrar is None:
34 | registrar = UDPRegistryClient(logger = self.logger)
35 | self.registrar = registrar
36 |
37 | self.listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
38 | if reuse_addr and sys.platform != "win32":
39 | # warning: reuseaddr is not what you expect on windows!
40 | self.listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
41 |
42 | self.listener.bind((hostname, port))
43 | self.port = self.listener.getsockname()[1]
44 |
45 | def _get_logger(self):
46 | raise NotImplementedError()
47 |
48 | def close(self):
49 | if self._closed:
50 | return
51 | self._closed = True
52 | self.active = False
53 | if self.auto_register:
54 | try:
55 | self.registrar.unregister(self.port)
56 | except Exception:
57 | self.logger.traceback()
58 | self.listener.close()
59 | self.logger.info("listener closed")
60 | for c in set(self.clients):
61 | try:
62 | c.shutdown(socket.SHUT_RDWR)
63 | except Exception:
64 | pass
65 | c.close()
66 | self.clients.clear()
67 |
68 | def fileno(self):
69 | return self.listener.fileno()
70 |
71 | def accept(self):
72 | while True:
73 | try:
74 | sock, (h, p) = self.listener.accept()
75 | except socket.timeout:
76 | pass
77 | except socket.error, ex:
78 | if ex[0] == errno.EINTR:
79 | pass
80 | else:
81 | raise EOFError()
82 | else:
83 | break
84 |
85 | sock.setblocking(True)
86 | self.logger.info("accepted %s:%s", h, p)
87 | self.clients.add(sock)
88 | self._accept_method(sock)
89 |
90 | def _accept_method(self, sock):
91 | """this method should start a thread, fork a child process, or
92 | anything else in order to serve the client. once the mechanism has
93 | been created, it should invoke _authenticate_and_serve_client with
94 | `sock` as the argument"""
95 | raise NotImplementedError
96 |
97 | def _authenticate_and_serve_client(self, sock):
98 | try:
99 | if self.authenticator:
100 | h, p = sock.getpeername()
101 | try:
102 | sock, credentials = self.authenticator(sock)
103 | except AuthenticationError:
104 | self.logger.info("%s:%s failed to authenticate, rejecting connection", h, p)
105 | return
106 | else:
107 | self.logger.info("%s:%s authenticated successfully", h, p)
108 | else:
109 | credentials = None
110 | self._serve_client(sock, credentials)
111 | finally:
112 | try:
113 | sock.shutdown(socket.SHUT_RDWR)
114 | except Exception:
115 | pass
116 | sock.close()
117 | self.clients.discard(sock)
118 |
119 | def _serve_client(self, sock, credentials):
120 | h, p = sock.getpeername()
121 | self.logger.info("welcome %s:%s", h, p)
122 | try:
123 | config = dict(self.protocol_config, credentials = credentials)
124 | conn = Connection(self.service, Channel(SocketStream(sock)),
125 | config = config, _lazy = True)
126 | conn._init_service()
127 | conn.serve_all()
128 | finally:
129 | self.logger.info("goodbye %s:%s", h, p)
130 |
131 | def _bg_register(self):
132 | interval = self.registrar.REREGISTER_INTERVAL
133 | self.logger.info("started background auto-register thread "
134 | "(interval = %s)", interval)
135 | tnext = 0
136 | try:
137 | while self.active:
138 | t = time.time()
139 | if t >= tnext:
140 | tnext = t + interval
141 | try:
142 | self.registrar.register(self.service.get_service_aliases(),
143 | self.port)
144 | except Exception:
145 | self.logger.traceback()
146 | time.sleep(1)
147 | finally:
148 | if not self._closed:
149 | self.logger.info("background auto-register thread finished")
150 |
151 | def start(self):
152 | """starts the server. use close() to stop"""
153 | self.listener.listen(self.backlog)
154 | h, p = self.listener.getsockname()
155 | self.logger.info("server started on %s:%s", h, p)
156 | self.active = True
157 | if self.auto_register:
158 | t = threading.Thread(target = self._bg_register)
159 | t.setDaemon(True)
160 | t.start()
161 | #if sys.platform == "win32":
162 | # hack so we can receive Ctrl+C on windows
163 | self.listener.settimeout(0.5)
164 | try:
165 | try:
166 | while True:
167 | self.accept()
168 | except EOFError:
169 | pass # server closed by another thread
170 | except KeyboardInterrupt:
171 | print
172 | self.logger.warn("keyboard interrupt!")
173 | finally:
174 | self.logger.info("server has terminated")
175 | self.close()
176 |
177 |
178 | class ThreadedServer(Server):
179 | def _get_logger(self):
180 | return Logger(self.service.get_service_name(), show_tid = True)
181 |
182 | def _accept_method(self, sock):
183 | t = threading.Thread(target = self._authenticate_and_serve_client, args = (sock,))
184 | t.setDaemon(True)
185 | t.start()
186 |
187 |
188 | class ForkingServer(Server):
189 | def __init__(self, *args, **kwargs):
190 | Server.__init__(self, *args, **kwargs)
191 | # setup sigchld handler
192 | self._prevhandler = signal.signal(signal.SIGCHLD, self._handle_sigchld)
193 |
194 | def close(self):
195 | Server.close(self)
196 | signal.signal(signal.SIGCHLD, self._prevhandler)
197 |
198 | def _get_logger(self):
199 | return Logger(self.service.get_service_name(), show_pid = True)
200 |
201 | @staticmethod
202 | def _handle_sigchld(signum, unused):
203 | try:
204 | while True:
205 | os.waitpid(-1, os.WNOHANG)
206 | except OSError:
207 | pass
208 | # re-register signal handler (see man signal(2), under Portability)
209 | signal.signal(signal.SIGCHLD, self._handle_sigchld)
210 |
211 | def _accept_method(self, sock):
212 | pid = os.fork()
213 | if pid == 0:
214 | # child
215 | try:
216 | try:
217 | self.logger.info("child process created")
218 | signal.signal(signal.SIGCHLD, self._prevhandler)
219 | self.listener.close()
220 | self.clients.clear()
221 | self._authenticate_and_serve_client(sock)
222 | except:
223 | self.logger.traceback()
224 | finally:
225 | self.logger.info("child terminated")
226 | os._exit(0)
227 | else:
228 | # parent
229 | sock.close()
230 |
231 |
232 |
233 |
234 |
235 |
236 |
--------------------------------------------------------------------------------
/lib/rpyc/utils/classic.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import inspect
4 | import pdb
5 | import cPickle as pickle
6 | import rpyc
7 | from rpyc import SlaveService
8 | from rpyc.utils import factory
9 |
10 |
11 | SERVER_FILE = os.path.join(os.path.dirname(rpyc.__file__), "servers", "classic_server.py")
12 | DEFAULT_SERVER_PORT = 18812
13 |
14 |
15 | #===============================================================================
16 | # connecting
17 | #===============================================================================
18 | def connect_channel(channel):
19 | return factory.connect_channel(channel, SlaveService)
20 |
21 | def connect_stream(stream):
22 | return factory.connect_stream(stream, SlaveService)
23 |
24 | def connect_stdpipes():
25 | return factory.connect_stdpipes(SlaveService)
26 |
27 | def connect_pipes(input, output):
28 | return factory.connect_pipes(input, output, SlaveService)
29 |
30 | def connect(host, port = DEFAULT_SERVER_PORT):
31 | """creates a socket connection to the given host and port"""
32 | return factory.connect(host, port, SlaveService)
33 |
34 | def tls_connect(host, username, password, port = DEFAULT_SERVER_PORT):
35 | """creates a secure (TLS) socket connection to the given host and port,
36 | authenticating with the given username and password"""
37 | return factory.tls_connect(host, port, username, password, SlaveService)
38 |
39 | def connect_subproc():
40 | """runs an rpyc classic server as a subprocess and return an rpyc
41 | connection to it"""
42 | return factory.connect_subproc(["python", "-u", SERVER_FILE, "-q", "-m", "stdio"],
43 | SlaveService)
44 |
45 | def connect_thread():
46 | """starts a SlaveService on a thread and connects to it"""
47 | return factory.connect_thread(SlaveService, remote_service = SlaveService)
48 |
49 |
50 | #===============================================================================
51 | # remoting utilities
52 | #===============================================================================
53 | def upload(conn, localpath, remotepath, filter = None, ignore_invalid = False):
54 | """uploads a file or a directory to the given remote path
55 | localpath - the local file or directory
56 | remotepath - the remote path
57 | filter - a predicate that accepts the filename and determines whether
58 | it should be uploaded; None means any file"""
59 | if os.path.isdir(localpath):
60 | upload_dir(conn, localpath, remotepath, filter)
61 | elif os.path.isfile(localpath):
62 | upload_file(conn, localpath, remotepath)
63 | else:
64 | if not ignore_invalid:
65 | raise ValueError("cannot upload %r" % (localpath,))
66 |
67 | def upload_file(conn, localpath, remotepath):
68 | lf = open(localpath, "rb")
69 | rf = conn.modules.__builtin__.open(remotepath, "wb")
70 | while True:
71 | buf = lf.read(16000)
72 | if not buf:
73 | break
74 | rf.write(buf)
75 | lf.close()
76 | rf.close()
77 |
78 | def upload_dir(conn, localpath, remotepath, filter = None):
79 | if not conn.modules.os.path.isdir(remotepath):
80 | conn.modules.os.makedirs(remotepath)
81 | for fn in os.listdir(localpath):
82 | if not filter or filter(fn):
83 | lfn = os.path.join(localpath, fn)
84 | rfn = conn.modules.os.path.join(remotepath, fn)
85 | upload(conn, lfn, rfn, filter = filter, ignore_invalid = True)
86 |
87 | def download(conn, remotepath, localpath, filter = None, ignore_invalid = False):
88 | """download a file or a directory to the given remote path
89 | localpath - the local file or directory
90 | remotepath - the remote path
91 | filter - a predicate that accepts the filename and determines whether
92 | it should be downloaded; None means any file"""
93 | if conn.modules.os.path.isdir(remotepath):
94 | download_dir(conn, remotepath, localpath, filter)
95 | elif conn.modules.os.path.isfile(remotepath):
96 | download_file(conn, remotepath, localpath)
97 | else:
98 | if not ignore_invalid:
99 | raise ValueError("cannot download %r" % (remotepath,))
100 |
101 | def download_file(conn, remotepath, localpath):
102 | rf = conn.modules.__builtin__.open(remotepath, "rb")
103 | lf = open(localpath, "wb")
104 | while True:
105 | buf = rf.read(16000)
106 | if not buf:
107 | break
108 | lf.write(buf)
109 | lf.close()
110 | rf.close()
111 |
112 | def download_dir(conn, remotepath, localpath, filter = None):
113 | if not os.path.isdir(localpath):
114 | os.makedirs(localpath)
115 | for fn in conn.modules.os.listdir(remotepath):
116 | if not filter or filter(fn):
117 | rfn = conn.modules.os.path.join(remotepath, fn)
118 | lfn = os.path.join(localpath, fn)
119 | download(conn, rfn, lfn, filter = filter, ignore_invalid = True)
120 |
121 | def upload_package(conn, module, remotepath = None):
122 | """uploads a module or a package to the remote party"""
123 | if remotepath is None:
124 | site = conn.modules["distutils.sysconfig"].get_python_lib()
125 | remotepath = conn.modules.os.path.join(site, module.__name__)
126 | localpath = os.path.dirname(inspect.getsourcefile(module))
127 | upload(conn, localpath, remotepath)
128 |
129 | upload_module = upload_package
130 |
131 | def update_module(conn, module):
132 | """replaces a module on the remote party"""
133 | rmodule = conn.modules[module.__name__]
134 | lf = inspect.getsourcefile(module)
135 | rf = conn.modules.inspect.getsourcefile(rmodule)
136 | upload_file(conn, lf, rf)
137 | c.modules.__builtin__.reload(rmodule)
138 |
139 | def obtain(proxy):
140 | """obtains (recreates) a remote object proxy from the other party.
141 | the object is moved by *value*, so changes made to it will not reflect
142 | on the remote object"""
143 | return pickle.loads(pickle.dumps(proxy))
144 |
145 | def deliver(conn, localobj):
146 | """delivers (recreates) a local object on the other party. the object is
147 | moved by *value*, so changes made to it will not reflect on the local
148 | object. returns a proxy to the remote object"""
149 | return conn.modules.cPickle.loads(pickle.dumps(localobj))
150 |
151 | class redirected_stdio(object):
152 | """redirects the other party's stdin, stdout and stderr to those of the
153 | local party, so remote STDIO will occur locally"""
154 | def __init__(self, conn):
155 | self._restored = True
156 | self.conn = conn
157 | self.orig_stdin = self.conn.modules.sys.stdin
158 | self.orig_stdout = self.conn.modules.sys.stdout
159 | self.orig_stderr = self.conn.modules.sys.stderr
160 | self.conn.modules.sys.stdin = sys.stdin
161 | self.conn.modules.sys.stdout = sys.stdout
162 | self.conn.modules.sys.stderr = sys.stderr
163 | self._restored = False
164 | def __del__(self):
165 | self.restore()
166 | def restore(self):
167 | if self._restored:
168 | return
169 | self._restored = True
170 | self.conn.modules.sys.stdin = self.orig_stdin
171 | self.conn.modules.sys.stdout = self.orig_stdout
172 | self.conn.modules.sys.stderr = self.orig_stderr
173 | def __enter__(self):
174 | return self
175 | def __exit__(self, t, v, tb):
176 | self.restore()
177 |
178 | #== compatibility with python 2.4 ==
179 | #@contextmanager
180 | #def redirected_stdio(conn):
181 | # orig_stdin = conn.modules.sys.stdin
182 | # orig_stdout = conn.modules.sys.stdout
183 | # orig_stderr = conn.modules.sys.stderr
184 | # try:
185 | # conn.modules.sys.stdin = sys.stdin
186 | # conn.modules.sys.stdout = sys.stdout
187 | # conn.modules.sys.stderr = sys.stderr
188 | # yield
189 | # finally:
190 | # conn.modules.sys.stdin = orig_stdin
191 | # conn.modules.sys.stdout = orig_stdout
192 | # conn.modules.sys.stderr = orig_stderr
193 |
194 | def pm(conn):
195 | """pdb.pm on a remote exception"""
196 | #pdb.post_mortem(conn.root.getconn()._last_traceback)
197 | redir = redirected_stdio(conn)
198 | try:
199 | conn.modules.pdb.post_mortem(conn.root.getconn()._last_traceback)
200 | finally:
201 | redir.restore()
202 |
203 | def interact(conn, namespace = None):
204 | """remote interactive interpreter"""
205 | if namespace is None:
206 | namespace = {}
207 | namespace["conn"] = conn
208 | redir = redirected_stdio(conn)
209 | try:
210 | conn.execute("""def _rinteract(ns):
211 | import code
212 | code.interact(local = dict(ns))""")
213 | conn.namespace["_rinteract"](namespace)
214 | finally:
215 | redir.restore()
216 |
217 |
218 |
219 |
220 |
--------------------------------------------------------------------------------
/HComMaya/HComMayaClient.py:
--------------------------------------------------------------------------------
1 | import rpyc
2 | import sys
3 | import getpass
4 | import os
5 |
6 | import maya.cmds as cmds
7 | import maya.utils as mUtils
8 |
9 | from PySide import QtGui
10 |
11 | import threading
12 |
13 | from _globals import MayaGlobals
14 |
15 | import HComMayaUi
16 | import HComMayaUtils
17 | import HComMayaWidgets
18 |
19 | global server_conn
20 | server_conn = None
21 |
22 | global server_id
23 | server_id = None
24 |
25 | global bgsrv
26 | bgsrv = None
27 |
28 | # Decorator tor send new data to client
29 | # into a new thread
30 | def threaded_sendata(func):
31 |
32 | def wrapper(*args, **kwargs):
33 | t = threading.Thread(target=func, args=args, kwargs=kwargs)
34 | t.start()
35 |
36 | return wrapper
37 |
38 | class HCom_ClientService(rpyc.Service):
39 | '''
40 | This is the client service called to fetch data from server.
41 | '''
42 |
43 | def on_disconnect(self):
44 | server_is_disconnected()
45 |
46 | def exposed_catchData(self, dataType, sender, data, tabTarget, clientType):
47 |
48 | HComMayaUi.receiveData(sender, data, dataType, tabTarget, clientType)
49 |
50 | def exposed_sendIDUpdate(self, ID, action, clientType):
51 |
52 | HComMayaUi.receiveIDUpdate(ID, action, clientType)
53 |
54 |
55 | def connectToServer(ID=None, clientType="NONE"):
56 | '''
57 | Try to connect to the server and launch the BG thread service
58 | '''
59 |
60 | if not ID:
61 | ID = getpass.getuser()
62 |
63 | global server_conn
64 | global bgsrv
65 |
66 | try:
67 | server_conn = rpyc.connect(HComMayaUtils.readIni()["SERVER"].replace(" ",""), int(str(HComMayaUtils.readIni()["PORT"]).replace(" ","")), service=HCom_ClientService, config={"allow_pickle":True})
68 | except Exception as e:
69 | print("ERROR: Can not connect to server: " + str(e))
70 | return False, False
71 | else:
72 | if ID in server_conn.root.getAllClients().keys():
73 | ask = QtGui.QMessageBox()
74 | ask.setText("User ID already registered on the server")
75 | ask.setIcon(QtGui.QMessageBox.Critical)
76 | ask.exec_()
77 | server_conn.close()
78 | return False
79 |
80 | MayaGlobals.HCOMCLIENT = [server_conn, ID]
81 |
82 | global server_id
83 | server_id = ID
84 |
85 | bgsrv = rpyc.BgServingThread(server_conn)
86 | result = server_conn.root.registerClient(ID, clientType)
87 |
88 | if result:
89 | return ID
90 | else:
91 | return False
92 |
93 | def _sendData(target_clientID, sender, data, datatype, tabTarget):
94 | '''
95 | Send data the to target client, could be message, otl or settings.
96 | '''
97 |
98 | global server_conn
99 |
100 | if not server_conn:
101 | print("ERROR: Client is not connected.")
102 | return False
103 |
104 | try:
105 | setDataAsync = rpyc.async(server_conn.root.sendDataToClient)
106 | result = setDataAsync(target_clientID, datatype, sender, data, tabTarget)
107 | return result
108 | except AttributeError:
109 | return False
110 | print("ERROR: client " + target_clientID + " not found.")
111 |
112 | @threaded_sendata
113 | def sendMessage(target_clientID, sender, message, tabTarget):
114 |
115 | result = _sendData(target_clientID, sender, message, "msg", tabTarget)
116 | return result
117 |
118 | def sendAlembic(target_clientID, sender, tabTarget):
119 |
120 | result = mUtils.executeInMainThreadWithResult(_exportAlembic)
121 | if not result:
122 | return False
123 |
124 | fileName = result[0]
125 | filePath = result[1]
126 | frameRange = result[2]
127 |
128 | with open(filePath, 'rb') as f:
129 | data = f.read()
130 |
131 | outData = {}
132 | outData["TYPE"] = "alembic_cache"
133 | outData["NAME"] = fileName
134 | outData["FRAME_RANGE"] = frameRange
135 | outData["DATA"] = data
136 |
137 | try:
138 | os.remove(filePath)
139 | except:
140 | pass
141 |
142 | result = _sendData(target_clientID, sender, outData, "alembic", tabTarget)
143 |
144 | return result
145 |
146 | def sendSettings(target_clientID, sender, tabTarget):
147 | return
148 |
149 | def sendOtl(target_clientID, sender, tabTarget):
150 | return
151 |
152 | def sendBgeo(target_clientID, sender, tabTarget, isObj=False):
153 | return
154 |
155 | def sendObjMesh(target_clientID, sender, tabTarget):
156 |
157 | meshOut = {}
158 | meshOut["MESH_TYPE"] = ".obj"
159 |
160 | meshName, objtmp = mUtils.executeInMainThreadWithResult(_exportObj)
161 |
162 | if not meshName:
163 | return False
164 |
165 | if not objtmp:
166 | return False
167 |
168 | with open(objtmp, 'rb') as f:
169 | meshOut["MESH_DATA"] = f.read()
170 |
171 | try:
172 | os.remove(objtmp)
173 | except:
174 | pass
175 |
176 | meshOut["MESH_TYPE"] = ".obj"
177 | meshOut["MESH_NAME"] = meshName
178 |
179 | result = _sendData(target_clientID, sender, meshOut, "mesh", tabTarget)
180 |
181 | return result
182 |
183 | def _exportAlembic():
184 |
185 | if not "AbcExport" in cmds.pluginInfo( query=True, listPlugins=True ):
186 | ask = QtGui.QMessageBox()
187 | ask.setText("Error: Alembic export plugin not loaded (AbcExport) !")
188 | ask.setIcon(QtGui.QMessageBox.Warning)
189 | ask.exec_()
190 | return False
191 |
192 | selection = cmds.ls(sl=True)
193 | if not selection:
194 | ask = QtGui.QMessageBox()
195 | ask.setText("Error: Nothing selected !")
196 | ask.setIcon(QtGui.QMessageBox.Warning)
197 | ask.exec_()
198 | return False
199 |
200 | name = str(selection[0]).replace("|", "_") + ".abc"
201 | abcFile = HComMayaUtils.fetchMyReceivedFilesFolder() + os.sep + name
202 | abcFile = HComMayaUtils.incrementFile(abcFile)
203 | start = cmds.playbackOptions(query=True, minTime=True)
204 | end = cmds.playbackOptions(query=True, maxTime=True)
205 |
206 | frameRangeUi = HComMayaWidgets.FrameRangeSelection(start=start, end=end)
207 | frameRangeUi.exec_()
208 |
209 | if not frameRangeUi.VALID:
210 | return False
211 |
212 | else:
213 | frames = frameRangeUi.frameRange
214 |
215 | cmd = "-fr {0} {1} -f {2}".format(frames[0], frames[1], abcFile)
216 | cmds.AbcExport(sl=True, j=cmd)
217 |
218 | if os.path.exists(abcFile):
219 | return name, abcFile, frames
220 |
221 | return False
222 |
223 | def _exportObj():
224 |
225 | selection = cmds.ls(sl=True)
226 | if not selection:
227 | ask = QtGui.QMessageBox()
228 | ask.setText("Error: Nothing selected !")
229 | ask.setIcon(QtGui.QMessageBox.Warning)
230 | ask.exec_()
231 | return False, False
232 |
233 | meshName = str(selection[0]).replace("|", "_")
234 |
235 | objtmp = HComMayaUtils.fetchMyReceivedFilesFolder() + os.sep + meshName + "_tmp.obj"
236 | objtmp = HComMayaUtils.incrementFile(objtmp)
237 |
238 | try:
239 | cmds.file(objtmp, force=True, type="OBJexport", es=True, shader=False, )
240 | except Exception as e:
241 | print("ERROR: " + str(e))
242 | return False, False
243 |
244 | return meshName, objtmp
245 |
246 |
247 |
248 | def sendPic(target_clientID, _sender, tabTarget, imagePath):
249 |
250 | with open(imagePath, 'rb') as f:
251 | imageData = f.read()
252 |
253 | outImdageData = {}
254 | outImdageData["IMAGE_NAME"] = os.path.basename(imagePath)
255 | outImdageData["BINARY_DATA"] = imageData
256 |
257 | result = _sendData(target_clientID, _sender, outImdageData, "pic", tabTarget)
258 | if result:
259 | return True
260 | else:
261 | return False
262 |
263 | def sendDataReceivedInfo(targetClient, sender, data, tabTarget):
264 |
265 | _sendData(targetClient, sender, data, "dataReceivedUpdate", tabTarget)
266 |
267 |
268 | def getAllClientRegistred():
269 |
270 | global server_conn
271 |
272 | if not server_conn:
273 | print("ERROR: Client is not connected.")
274 | return False
275 |
276 | return server_conn.root.getAllClients().keys()
277 |
278 | def disconnect():
279 | '''
280 | Disconect client and stop BG thread
281 | '''
282 |
283 | global server_conn
284 | global bgsrv
285 | global server_id
286 |
287 | if not server_conn:
288 | return
289 | try:
290 | bgsrv.stop()
291 | bgsrv = None
292 | except:
293 | pass
294 |
295 | try:
296 | server_conn.root.removeClient(server_id)
297 | except EOFError:
298 | pass
299 |
300 | try:
301 | server_conn.close()
302 |
303 | except:
304 | pass
305 | server_conn = None
306 | MayaGlobals.MAIN_UI.updateUiThread.data = {"ACTION":"server_disconnect", "ID":None, "CLIENT_TYPE":None}
307 |
308 |
309 | def server_is_disconnected():
310 | disconnect()
--------------------------------------------------------------------------------
/HComNuke/HComNukeClient.py:
--------------------------------------------------------------------------------
1 | import rpyc
2 | import sys
3 | import getpass
4 | import os
5 | import random
6 | import tempfile
7 |
8 | import nuke
9 |
10 |
11 | from PySide import QtGui
12 |
13 | import threading
14 |
15 | from _globals import NukeGlobals
16 | import HComNukeUtils
17 | import HComNukeUi
18 |
19 | global server_conn
20 | server_conn = None
21 |
22 | global server_id
23 | server_id = None
24 |
25 | global bgsrv
26 | bgsrv = None
27 |
28 | # Decorator tor send new data to client
29 | # into a new thread
30 | def threaded_sendata(func):
31 |
32 | def wrapper(*args, **kwargs):
33 | t = threading.Thread(target=func, args=args, kwargs=kwargs)
34 | t.start()
35 |
36 | return wrapper
37 |
38 | class HCom_ClientService(rpyc.Service):
39 | '''
40 | This is the client service called to fetch data from server.
41 | '''
42 |
43 | def on_disconnect(self):
44 | server_is_disconnected()
45 |
46 | def exposed_catchData(self, dataType, sender, data, tabTarget, clientType):
47 |
48 | HComNukeUi.receiveData(sender, data, dataType, tabTarget, clientType)
49 |
50 | def exposed_sendIDUpdate(self, ID, action, clientType):
51 |
52 | HComNukeUi.receiveIDUpdate(ID, action, clientType)
53 |
54 |
55 | def connectToServer(ID=None, clientType="NONE"):
56 | '''
57 | Try to connect to the server and launch the BG thread service
58 | '''
59 |
60 | if not ID:
61 | ID = getpass.getuser()
62 |
63 | global server_conn
64 | global bgsrv
65 |
66 | try:
67 | server_conn = rpyc.connect(HComNukeUtils.readIni()["SERVER"].replace(" ",""), int(str(HComNukeUtils.readIni()["PORT"]).replace(" ","")), service=HCom_ClientService, config={"allow_pickle":True})
68 | except Exception as e:
69 | print("ERROR: Can not connect to server: " + str(e))
70 | return False, False
71 | else:
72 | if ID in server_conn.root.getAllClients().keys():
73 | ask = QtGui.QMessageBox()
74 | ask.setText("User ID already registered on the server")
75 | ask.setIcon(QtGui.QMessageBox.Critical)
76 | ask.exec_()
77 | server_conn.close()
78 | return False
79 |
80 | NukeGlobals.HCOMCLIENT = [server_conn, ID]
81 |
82 | global server_id
83 | server_id = ID
84 |
85 | bgsrv = rpyc.BgServingThread(server_conn)
86 | result = server_conn.root.registerClient(ID, clientType)
87 |
88 | if result:
89 | return ID
90 | else:
91 | return False
92 |
93 | def _sendData(target_clientID, sender, data, datatype, tabTarget):
94 | '''
95 | Send data the to target client, could be message, otl or settings.
96 | '''
97 |
98 | global server_conn
99 |
100 | if not server_conn:
101 | print("ERROR: Client is not connected.")
102 | return False
103 |
104 | try:
105 | setDataAsync = rpyc.async(server_conn.root.sendDataToClient)
106 | result = setDataAsync(target_clientID, datatype, sender, data, tabTarget)
107 | return result
108 | except AttributeError:
109 | return False
110 | print("ERROR: client " + target_clientID + " not found.")
111 |
112 | @threaded_sendata
113 | def sendMessage(target_clientID, sender, message, tabTarget):
114 |
115 | result = _sendData(target_clientID, sender, message, "msg", tabTarget)
116 | return result
117 |
118 | def sendNodeOuput(target_clientID, sender, tabTarget):
119 |
120 | fileType = HComNukeUtils.readIni()["OUTPUT_IMAGE_FORMAT"]
121 |
122 | try:
123 | selectedNode = nuke.selectedNode()
124 | except ValueError:
125 | return False
126 |
127 | curFrame = int(nuke.knob("frame"))
128 | tmpfilePath = tempfile.gettempdir() + "\\hcom_tmp_" + ''.join([random.choice("abcdef0123456789") for n in xrange(5)]) + "." + fileType
129 | tmpWriterName = "tmp_writer_" + ''.join([random.choice("abcdef0123456789") for n in xrange(5)])
130 |
131 | result = nuke.executeInMainThreadWithResult(_createWriter, args=(tmpWriterName, tmpfilePath, selectedNode, curFrame))
132 |
133 | if not result:
134 | return False
135 |
136 | with open(tmpfilePath, 'rb') as f:
137 | data = f.read()
138 |
139 | outImdageData = {}
140 | outImdageData["IMAGE_NAME"] = os.path.basename(selectedNode.name()) + "." + fileType
141 | outImdageData["BINARY_DATA"] = data
142 |
143 | try:
144 | os.remove(tmpfilePath)
145 | except:
146 | pass
147 |
148 | w = nuke.toNode(tmpWriterName)
149 | if w:
150 | nuke.delete(w)
151 |
152 | result = _sendData(target_clientID, sender, outImdageData, "pic", tabTarget)
153 |
154 | return result
155 |
156 | def _createWriter(name, filePath, selectedNode, curFrame):
157 |
158 | n = nuke.createNode('Write', inpanel=False)
159 | n.setName(name)
160 | n["file"].setValue(filePath.replace("\\", "/"))
161 | n.setInput(0, selectedNode)
162 |
163 | try:
164 | nuke.execute(name, curFrame, curFrame, 1)
165 | except RuntimeError as e:
166 | print str(e)
167 | return False
168 |
169 | return True
170 |
171 | def sendSettings(target_clientID, sender, tabTarget):
172 | return
173 |
174 |
175 | def sendObjMesh(target_clientID, sender, tabTarget, alembic=False, frames=[0,0]):
176 |
177 | try:
178 | selectedNode = nuke.selectedNode()
179 | except ValueError:
180 | return False
181 |
182 | meshOut = {}
183 |
184 | geoType = ".obj"
185 | if alembic:
186 | geoType = ".abc"
187 |
188 | curFrame = int(nuke.knob("frame"))
189 | tmpfilePath = tempfile.gettempdir() + "\\hcom_tmp_" + ''.join([random.choice("abcdef0123456789") for n in xrange(5)]) + geoType
190 | tmpWriterName = "tmp_geoWriter_" + ''.join([random.choice("abcdef0123456789") for n in xrange(5)])
191 |
192 | result = nuke.executeInMainThreadWithResult(_createObjWriter, args=(tmpWriterName, tmpfilePath, selectedNode, curFrame, alembic, frames))
193 |
194 | if not result:
195 | return False
196 |
197 |
198 | with open(tmpfilePath, 'rb') as f:
199 | data = f.read()
200 |
201 |
202 | try:
203 | os.remove(tmpfilePath)
204 | except:
205 | pass
206 |
207 | meshOut["MESH_TYPE"] = geoType
208 | meshOut["MESH_NAME"] = selectedNode.name()
209 | meshOut["MESH_DATA"] = data
210 |
211 | w = nuke.toNode(tmpWriterName)
212 | if w:
213 | nuke.delete(w)
214 |
215 | outType = "mesh"
216 | if alembic:
217 | outType = "alembic"
218 | meshOut["NAME"]= selectedNode.name()
219 | meshOut["FRAME_RANGE"] = frames
220 | meshOut["DATA"]= data
221 |
222 | result = _sendData(target_clientID, sender, meshOut, outType, tabTarget)
223 |
224 | return result
225 |
226 | def _createObjWriter(tmpWriterName, tmpfilePath, selectedNode, curFrame, alembic, frames):
227 |
228 | w = nuke.createNode('WriteGeo', inpanel=False)
229 | w.setName(tmpWriterName)
230 | w["file"].setValue(tmpfilePath.replace("\\", "/"))
231 | w.setInput(0, selectedNode)
232 |
233 | try:
234 |
235 | if alembic:
236 | w["use_limit"].setValue(True)
237 | w["first"].setValue(int(frames[0]))
238 | w["last"].setValue(int(frames[1]))
239 | w["file_type"].setValue(1)
240 | nuke.execute(tmpWriterName, int(frames[0]), int(frames[1]), 1)
241 | else:
242 | w["file_type"].setValue(3)
243 | nuke.execute(tmpWriterName, curFrame, curFrame, 1)
244 |
245 | except RuntimeError as e:
246 |
247 | print str(e)
248 | return False
249 |
250 | return True
251 |
252 |
253 | def sendPic(target_clientID, sender, tabTarget, imagePath):
254 |
255 | with open(imagePath, 'rb') as f:
256 | imageData = f.read()
257 |
258 | outImdageData = {}
259 | outImdageData["IMAGE_NAME"] = os.path.basename(imagePath)
260 | outImdageData["BINARY_DATA"] = imageData
261 |
262 | result = _sendData(target_clientID, sender, outImdageData, "pic", tabTarget)
263 | if result:
264 | return True
265 | else:
266 | return False
267 |
268 | def sendDataReceivedInfo(targetClient, sender, data, tabTarget):
269 |
270 | _sendData(targetClient, sender, data, "dataReceivedUpdate", tabTarget)
271 |
272 |
273 | def getAllClientRegistred():
274 |
275 | global server_conn
276 |
277 | if not server_conn:
278 | print("ERROR: Client is not connected.")
279 | return False
280 |
281 | return server_conn.root.getAllClients().keys()
282 |
283 | def disconnect():
284 | '''
285 | Disconect client and stop BG thread
286 | '''
287 |
288 | global server_conn
289 | global bgsrv
290 | global server_id
291 |
292 | if not server_conn:
293 | return
294 | try:
295 | bgsrv.stop()
296 | bgsrv = None
297 | except:
298 | pass
299 |
300 | try:
301 | server_conn.root.removeClient(server_id)
302 | except EOFError:
303 | pass
304 |
305 | try:
306 | server_conn.close()
307 |
308 | except:
309 | pass
310 | server_conn = None
311 | NukeGlobals.MAIN_UI.updateUiThread.data = {"ACTION":"server_disconnect", "ID":None, "CLIENT_TYPE":None}
312 |
313 |
314 | def server_is_disconnected():
315 | disconnect()
--------------------------------------------------------------------------------
/lib/rpyc/core/brine.py:
--------------------------------------------------------------------------------
1 | """
2 | brine - a simple, fast and secure object serializer for immutable objects,
3 | optimized for small integers [-48..160).
4 | the following types are supported: int, long, bool, str, float, unicode,
5 | slice, complex, tuple(of simple types), forzenset(of simple types)
6 | as well as the following singletons: None, NotImplemented, Ellipsis
7 | """
8 | from cStringIO import StringIO
9 | from rpyc.utils.lib import Struct, all
10 |
11 |
12 | # singletons
13 | TAG_NONE = "\x00"
14 | TAG_EMPTY_STR = "\x01"
15 | TAG_EMPTY_TUPLE = "\x02"
16 | TAG_TRUE = "\x03"
17 | TAG_FALSE = "\x04"
18 | TAG_NOT_IMPLEMENTED = "\x05"
19 | TAG_ELLIPSIS = "\x06"
20 | # types
21 | TAG_UNICODE = "\x08"
22 | TAG_LONG = "\x09"
23 | TAG_STR1 = "\x0a"
24 | TAG_STR2 = "\x0b"
25 | TAG_STR3 = "\x0c"
26 | TAG_STR4 = "\x0d"
27 | TAG_STR_L1 = "\x0e"
28 | TAG_STR_L4 = "\x0f"
29 | TAG_TUP1 = "\x10"
30 | TAG_TUP2 = "\x11"
31 | TAG_TUP3 = "\x12"
32 | TAG_TUP4 = "\x13"
33 | TAG_TUP_L1 = "\x14"
34 | TAG_TUP_L4 = "\x15"
35 | TAG_INT_L1 = "\x16"
36 | TAG_INT_L4 = "\x17"
37 | TAG_FLOAT = "\x18"
38 | TAG_SLICE = "\x19"
39 | TAG_FSET = "\x1a"
40 | TAG_COMPLEX = "\x1b"
41 | IMM_INTS = dict((i, chr(i + 0x50)) for i in range(-0x30, 0xa0))
42 |
43 | I1 = Struct("!B")
44 | I4 = Struct("!L")
45 | F8 = Struct("!d")
46 | C16 = Struct("!dd")
47 |
48 | _dump_registry = {}
49 | _load_registry = {}
50 | IMM_INTS_LOADER = dict((v, k) for k, v in IMM_INTS.iteritems())
51 |
52 | def register(coll, key):
53 | def deco(func):
54 | coll[key] = func
55 | return func
56 | return deco
57 |
58 | #===============================================================================
59 | # dumping
60 | #===============================================================================
61 | @register(_dump_registry, type(None))
62 | def _dump_none(obj, stream):
63 | stream.append(TAG_NONE)
64 |
65 | @register(_dump_registry, type(NotImplemented))
66 | def _dump_notimplemeted(obj, stream):
67 | stream.append(TAG_NOT_IMPLEMENTED)
68 |
69 | @register(_dump_registry, type(Ellipsis))
70 | def _dump_ellipsis(obj, stream):
71 | stream.append(TAG_ELLIPSIS)
72 |
73 | @register(_dump_registry, bool)
74 | def _dump_bool(obj, stream):
75 | if obj:
76 | stream.append(TAG_TRUE)
77 | else:
78 | stream.append(TAG_FALSE)
79 |
80 | @register(_dump_registry, slice)
81 | def _dump_slice(obj, stream):
82 | stream.append(TAG_SLICE)
83 | _dump((obj.start, obj.stop, obj.step), stream)
84 |
85 | @register(_dump_registry, frozenset)
86 | def _dump_frozenset(obj, stream):
87 | stream.append(TAG_FSET)
88 | _dump(tuple(obj), stream)
89 |
90 | @register(_dump_registry, int)
91 | def _dump_int(obj, stream):
92 | if obj in IMM_INTS:
93 | stream.append(IMM_INTS[obj])
94 | else:
95 | obj = str(obj)
96 | l = len(obj)
97 | if l < 256:
98 | stream.append(TAG_INT_L1 + I1.pack(l) + obj)
99 | else:
100 | stream.append(TAG_INT_L4 + I4.pack(l) + obj)
101 |
102 | @register(_dump_registry, long)
103 | def _dump_long(obj, stream):
104 | stream.append(TAG_LONG)
105 | _dump_int(obj, stream)
106 |
107 | @register(_dump_registry, str)
108 | def _dump_str(obj, stream):
109 | l = len(obj)
110 | if l == 0:
111 | stream.append(TAG_EMPTY_STR)
112 | elif l == 1:
113 | stream.append(TAG_STR1 + obj)
114 | elif l == 2:
115 | stream.append(TAG_STR2 + obj)
116 | elif l == 3:
117 | stream.append(TAG_STR3 + obj)
118 | elif l == 4:
119 | stream.append(TAG_STR4 + obj)
120 | elif l < 256:
121 | stream.append(TAG_STR_L1 + I1.pack(l) + obj)
122 | else:
123 | stream.append(TAG_STR_L4 + I4.pack(l) + obj)
124 |
125 | @register(_dump_registry, float)
126 | def _dump_float(obj, stream):
127 | stream.append(TAG_FLOAT + F8.pack(obj))
128 |
129 | @register(_dump_registry, complex)
130 | def _dump_complex(obj, stream):
131 | stream.append(TAG_COMPLEX + C16.pack(obj.real, obj.imag))
132 |
133 | @register(_dump_registry, unicode)
134 | def _dump_unicode(obj, stream):
135 | stream.append(TAG_UNICODE)
136 | _dump_str(obj.encode("utf8"), stream)
137 |
138 | @register(_dump_registry, tuple)
139 | def _dump_tuple(obj, stream):
140 | l = len(obj)
141 | if l == 0:
142 | stream.append(TAG_EMPTY_TUPLE)
143 | elif l == 1:
144 | stream.append(TAG_TUP1)
145 | elif l == 2:
146 | stream.append(TAG_TUP2)
147 | elif l == 3:
148 | stream.append(TAG_TUP3)
149 | elif l == 4:
150 | stream.append(TAG_TUP4)
151 | elif l < 256:
152 | stream.append(TAG_TUP_L1 + I1.pack(l))
153 | else:
154 | stream.append(TAG_TUP_L4 + I4.pack(l))
155 | for item in obj:
156 | _dump(item, stream)
157 |
158 | def _undumpable(obj, stream):
159 | raise TypeError("cannot dump %r" % (obj,))
160 |
161 | def _dump(obj, stream):
162 | _dump_registry.get(type(obj), _undumpable)(obj, stream)
163 |
164 | #===============================================================================
165 | # loading
166 | #===============================================================================
167 | @register(_load_registry, TAG_NONE)
168 | def _load_none(stream):
169 | return None
170 | @register(_load_registry, TAG_NOT_IMPLEMENTED)
171 | def _load_nonimp(stream):
172 | return NotImplemented
173 | @register(_load_registry, TAG_ELLIPSIS)
174 | def _load_elipsis(stream):
175 | return Ellipsis
176 | @register(_load_registry, TAG_TRUE)
177 | def _load_true(stream):
178 | return True
179 | @register(_load_registry, TAG_FALSE)
180 | def _load_false(stream):
181 | return False
182 | @register(_load_registry, TAG_EMPTY_TUPLE)
183 | def _load_empty_tuple(stream):
184 | return ()
185 | @register(_load_registry, TAG_EMPTY_STR)
186 | def _load_empty_str(stream):
187 | return ""
188 | @register(_load_registry, TAG_UNICODE)
189 | def _load_unicode(stream):
190 | obj = _load(stream)
191 | return obj.decode("utf-8")
192 | @register(_load_registry, TAG_LONG)
193 | def _load_long(stream):
194 | obj = _load(stream)
195 | return long(obj)
196 |
197 | @register(_load_registry, TAG_FLOAT)
198 | def _load_float(stream):
199 | return F8.unpack(stream.read(8))[0]
200 | @register(_load_registry, TAG_COMPLEX)
201 | def _load_complex(stream):
202 | real, imag = C16.unpack(stream.read(16))
203 | return complex(real, imag)
204 |
205 | @register(_load_registry, TAG_STR1)
206 | def _load_str1(stream):
207 | return stream.read(1)
208 | @register(_load_registry, TAG_STR2)
209 | def _load_str2(stream):
210 | return stream.read(2)
211 | @register(_load_registry, TAG_STR3)
212 | def _load_str3(stream):
213 | return stream.read(3)
214 | @register(_load_registry, TAG_STR4)
215 | def _load_str4(stream):
216 | return stream.read(4)
217 | @register(_load_registry, TAG_STR_L1)
218 | def _load_str_l1(stream):
219 | l, = I1.unpack(stream.read(1))
220 | return stream.read(l)
221 | @register(_load_registry, TAG_STR_L4)
222 | def _load_str_l4(stream):
223 | l, = I4.unpack(stream.read(4))
224 | return stream.read(l)
225 |
226 | @register(_load_registry, TAG_TUP1)
227 | def _load_tup1(stream):
228 | return (_load(stream),)
229 | @register(_load_registry, TAG_TUP2)
230 | def _load_tup2(stream):
231 | return (_load(stream), _load(stream))
232 | @register(_load_registry, TAG_TUP3)
233 | def _load_tup3(stream):
234 | return (_load(stream), _load(stream), _load(stream))
235 | @register(_load_registry, TAG_TUP4)
236 | def _load_tup4(stream):
237 | return (_load(stream), _load(stream), _load(stream), _load(stream))
238 | @register(_load_registry, TAG_TUP_L1)
239 | def _load_tup_l1(stream):
240 | l, = I1.unpack(stream.read(1))
241 | return tuple(_load(stream) for i in range(l))
242 | @register(_load_registry, TAG_TUP_L4)
243 | def _load_tup_l4(stream):
244 | l, = I4.unpack(stream.read(4))
245 | return tuple(_load(stream) for i in xrange(l))
246 |
247 | @register(_load_registry, TAG_SLICE)
248 | def _load_slice(stream):
249 | start, stop, step = _load(stream)
250 | return slice(start, stop, step)
251 | @register(_load_registry, TAG_FSET)
252 | def _load_frozenset(stream):
253 | return frozenset(_load(stream))
254 |
255 | @register(_load_registry, TAG_INT_L1)
256 | def _load_int_l1(stream):
257 | l, = I1.unpack(stream.read(1))
258 | return int(stream.read(l))
259 | @register(_load_registry, TAG_INT_L4)
260 | def _load_int_l4(stream):
261 | l, = I4.unpack(stream.read(4))
262 | return int(stream.read(l))
263 |
264 | def _load(stream):
265 | tag = stream.read(1)
266 | if tag in IMM_INTS_LOADER:
267 | return IMM_INTS_LOADER[tag]
268 | return _load_registry.get(tag)(stream)
269 |
270 | #===============================================================================
271 | # API
272 | #===============================================================================
273 | def dump(obj):
274 | """dumps the given object to a byte-string representation"""
275 | stream = []
276 | _dump(obj, stream)
277 | return "".join(stream)
278 |
279 | def load(data):
280 | """loads the given byte-string representation to an object"""
281 | stream = StringIO(data)
282 | return _load(stream)
283 |
284 | simple_types = frozenset([type(None), int, long, bool, str, float, unicode,
285 | slice, complex, type(NotImplemented), type(Ellipsis)])
286 | def dumpable(obj):
287 | """indicates whether the object is dumpable by brine"""
288 | if type(obj) in simple_types:
289 | return True
290 | if type(obj) in (tuple, frozenset):
291 | return all(dumpable(item) for item in obj)
292 | return False
293 |
294 |
295 | if __name__ == "__main__":
296 | x = ("he", 7, u"llo", 8, (), 900, None, True, Ellipsis, 18.2, 18.2j + 13,
297 | slice(1,2,3), frozenset([5,6,7]), NotImplemented)
298 | assert dumpable(x)
299 | y = dump(x)
300 | z = load(y)
301 | assert x == z
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
--------------------------------------------------------------------------------
/lib/rpyc/core/stream.py:
--------------------------------------------------------------------------------
1 | """
2 | abstraction layer over OS-depenedent byte streams
3 | """
4 | import sys
5 | import os
6 | import socket
7 | import time
8 | import errno
9 | from select import select
10 | from rpyc.utils.lib import safe_import
11 | win32file = safe_import("win32file")
12 | win32pipe = safe_import("win32pipe")
13 | msvcrt = safe_import("msvcrt")
14 |
15 |
16 | retry_errnos = set([errno.EAGAIN])
17 | if hasattr(errno, "WSAEWOULDBLOCK"):
18 | retry_errnos.add(errno.WSAEWOULDBLOCK)
19 |
20 |
21 | class Stream(object):
22 | __slots__ = ()
23 | def close(self):
24 | raise NotImplementedError()
25 | @property
26 | def closed(self):
27 | raise NotImplementedError()
28 | def fileno(self):
29 | raise NotImplementedError()
30 | def poll(self, timeout):
31 | """indicate whether the stream has data to read"""
32 | rl, wl, xl = select([self], [], [], timeout)
33 | return bool(rl)
34 | def read(self, count):
35 | """read exactly `count` bytes, or raise EOFError"""
36 | raise NotImplementedError()
37 | def write(self, data):
38 | """write the entire `data`, or raise EOFError"""
39 | raise NotImplementedError()
40 |
41 |
42 | class ClosedFile(object):
43 | """represents a closed file object (singleton)"""
44 | __slots__ = ()
45 | def __getattr__(self, name):
46 | raise EOFError("stream has been closed")
47 | def close(self):
48 | pass
49 | @property
50 | def closed(self):
51 | return True
52 | def fileno(self):
53 | raise EOFError("stream has been closed")
54 | ClosedFile = ClosedFile()
55 |
56 |
57 | class SocketStream(Stream):
58 | __slots__ = ("sock",)
59 | MAX_IO_CHUNK = 8000
60 | def __init__(self, sock):
61 | self.sock = sock
62 | @classmethod
63 | def _connect(cls, host, port, family = socket.AF_INET, type = socket.SOCK_STREAM,
64 | proto = 0, timeout = 3):
65 | s = socket.socket(family, type, proto)
66 | s.settimeout(timeout)
67 | s.connect((host, port))
68 | return s
69 | @classmethod
70 | def connect(cls, host, port, **kwargs):
71 | return cls(cls._connect(host, port, **kwargs))
72 | @classmethod
73 | def tls_connect(cls, host, port, username, password, **kwargs):
74 | from tlslite.api import TLSConnection
75 | s = cls._connect(host, port, **kwargs)
76 | s2 = TLSConnection(s)
77 | s2.fileno = lambda fd=s.fileno(): fd
78 | s2.handshakeClientSRP(username, password)
79 | return cls(s2)
80 | @property
81 | def closed(self):
82 | return self.sock is ClosedFile
83 | def close(self):
84 | if not self.closed:
85 | try:
86 | self.sock.shutdown(socket.SHUT_RDWR)
87 | except Exception:
88 | pass
89 | self.sock.close()
90 | self.sock = ClosedFile
91 | def fileno(self):
92 | return self.sock.fileno()
93 | def read(self, count):
94 | data = []
95 | while count > 0:
96 | try:
97 | buf = self.sock.recv(min(self.MAX_IO_CHUNK, count))
98 | except socket.timeout:
99 | continue
100 | except socket.error, ex:
101 | if ex[0] in retry_errnos:
102 | # windows just has to be a bitch
103 | continue
104 | self.close()
105 | raise EOFError(ex)
106 | if not buf:
107 | self.close()
108 | raise EOFError("connection closed by peer")
109 | data.append(buf)
110 | count -= len(buf)
111 | return "".join(data)
112 | def write(self, data):
113 | try:
114 | while data:
115 | count = self.sock.send(data[:self.MAX_IO_CHUNK])
116 | data = data[count:]
117 | except socket.error, ex:
118 | self.close()
119 | raise EOFError(ex)
120 |
121 | class PipeStream(Stream):
122 | __slots__ = ("incoming", "outgoing")
123 | MAX_IO_CHUNK = 32000
124 | def __init__(self, incoming, outgoing):
125 | outgoing.flush()
126 | self.incoming = incoming
127 | self.outgoing = outgoing
128 | @classmethod
129 | def from_std(cls):
130 | return cls(sys.stdin, sys.stdout)
131 | @classmethod
132 | def create_pair(cls):
133 | r1, w1 = os.pipe()
134 | r2, w2 = os.pipe()
135 | side1 = cls(os.fdopen(r1, "rb"), os.fdopen(w2, "wb"))
136 | side2 = cls(os.fdopen(r2, "rb"), os.fdopen(w1, "wb"))
137 | return side1, side2
138 | @property
139 | def closed(self):
140 | return self.incoming is ClosedFile
141 | def close(self):
142 | self.incoming.close()
143 | self.outgoing.close()
144 | self.incoming = ClosedFile
145 | self.outgoing = ClosedFile
146 | def fileno(self):
147 | return self.incoming.fileno()
148 | def read(self, count):
149 | data = []
150 | try:
151 | while count > 0:
152 | buf = os.read(self.incoming.fileno(), min(self.MAX_IO_CHUNK, count))
153 | if not buf:
154 | raise EOFError("connection closed by peer")
155 | data.append(buf)
156 | count -= len(buf)
157 | except EOFError:
158 | self.close()
159 | raise
160 | except EnvironmentError, ex:
161 | self.close()
162 | raise EOFError(ex)
163 | return "".join(data)
164 | def write(self, data):
165 | try:
166 | while data:
167 | chunk = data[:self.MAX_IO_CHUNK]
168 | written = os.write(self.outgoing.fileno(), chunk)
169 | data = data[written:]
170 | except EnvironmentError, ex:
171 | self.close()
172 | raise EOFError(ex)
173 |
174 |
175 | class Win32PipeStream(Stream):
176 | """win32 has to suck"""
177 | __slots__ = ("incoming", "outgoing", "_fileno")
178 | PIPE_BUFFER_SIZE = 130000
179 | MAX_IO_CHUNK = 32000
180 |
181 | def __init__(self, incoming, outgoing):
182 | if hasattr(incoming, "fileno"):
183 | self._fileno = incoming.fileno()
184 | incoming = msvcrt.get_osfhandle(incoming.fileno())
185 | if hasattr(outgoing, "fileno"):
186 | outgoing = msvcrt.get_osfhandle(outgoing.fileno())
187 | self.incoming = incoming
188 | self.outgoing = outgoing
189 | @classmethod
190 | def from_std(cls):
191 | return cls(sys.stdin, sys.stdout)
192 | @classmethod
193 | def create_pair(cls):
194 | r1, w1 = win32pipe.CreatePipe(None, cls.PIPE_BUFFER_SIZE)
195 | r2, w2 = win32pipe.CreatePipe(None, cls.PIPE_BUFFER_SIZE)
196 | return cls(r1, w2), cls(r2, w1)
197 |
198 | def fileno(self):
199 | return self._fileno
200 | @property
201 | def closed(self):
202 | return self.incoming is ClosedFile
203 | def close(self):
204 | if self.closed:
205 | return
206 | win32file.CloseHandle(self.incoming)
207 | win32file.CloseHandle(self.outgoing)
208 | self.incoming = ClosedFile
209 | self.outgoing = ClosedFile
210 | def read(self, count):
211 | try:
212 | data = []
213 | while count > 0:
214 | dummy, buf = win32file.ReadFile(self.incoming, min(self.MAX_IO_CHUNK, count))
215 | count -= len(buf)
216 | data.append(buf)
217 | except TypeError, ex:
218 | if not self.closed:
219 | raise
220 | raise EOFError(ex)
221 | except win32file.error, ex:
222 | self.close()
223 | raise EOFError(ex)
224 | return "".join(data)
225 | def write(self, data):
226 | try:
227 | while data:
228 | dummy, count = win32file.WriteFile(self.outgoing, data[:self.MAX_IO_CHUNK])
229 | data = data[count:]
230 | except TypeError, ex:
231 | if not self.closed:
232 | raise
233 | raise EOFError(ex)
234 | except win32file.error, ex:
235 | self.close()
236 | raise EOFError(ex)
237 |
238 | def poll(self, timeout, interval = 0.1):
239 | """a poor man's version of select()"""
240 | if timeout is None:
241 | timeout = sys.maxint
242 | length = 0
243 | tmax = time.time() + timeout
244 | try:
245 | while length == 0:
246 | length = win32pipe.PeekNamedPipe(self.incoming, 0)[1]
247 | if time.time() >= tmax:
248 | break
249 | time.sleep(interval)
250 | except TypeError, ex:
251 | if not self.closed:
252 | raise
253 | raise EOFError(ex)
254 | return length != 0
255 |
256 |
257 | class NamedPipeStream(Win32PipeStream):
258 | NAMED_PIPE_PREFIX = r'\\.\pipe\rpyc_'
259 | PIPE_IO_TIMEOUT = 3
260 | CONNECT_TIMEOUT = 3
261 | __slots__ = ("is_server_side",)
262 |
263 | def __init__(self, handle, is_server_side):
264 | Win32PipeStream.__init__(self, handle, handle)
265 | self.is_server_side = is_server_side
266 | @classmethod
267 | def from_std(cls):
268 | raise NotImplementedError()
269 | @classmethod
270 | def create_pair(cls):
271 | raise NotImplementedError()
272 |
273 | @classmethod
274 | def create_server(cls, pipename, connect = True):
275 | if not pipename.startswith("\\\\."):
276 | pipename = cls.NAMED_PIPE_PREFIX + pipename
277 | handle = win32pipe.CreateNamedPipe(
278 | pipename,
279 | win32pipe.PIPE_ACCESS_DUPLEX,
280 | win32pipe.PIPE_TYPE_BYTE | win32pipe.PIPE_READMODE_BYTE | win32pipe.PIPE_WAIT,
281 | 1,
282 | cls.PIPE_BUFFER_SIZE,
283 | cls.PIPE_BUFFER_SIZE,
284 | cls.PIPE_IO_TIMEOUT * 1000,
285 | None
286 | )
287 | inst = cls(handle, True)
288 | if connect:
289 | inst.connect_server()
290 | return inst
291 |
292 | def connect_server(self):
293 | if not self.is_server_side:
294 | raise ValueError("this must be the server side")
295 | win32pipe.ConnectNamedPipe(self.incoming, None)
296 |
297 | @classmethod
298 | def create_client(cls, pipename, timeout = CONNECT_TIMEOUT):
299 | if not pipename.startswith("\\\\."):
300 | pipename = cls.NAMED_PIPE_PREFIX + pipename
301 | handle = win32file.CreateFile(
302 | pipename,
303 | win32file.GENERIC_READ | win32file.GENERIC_WRITE,
304 | 0,
305 | None,
306 | win32file.OPEN_EXISTING,
307 | 0,
308 | None
309 | )
310 | return cls(handle, False)
311 |
312 | def close(self):
313 | if self.closed:
314 | return
315 | if self.is_server_side:
316 | win32file.FlushFileBuffers(self.outgoing)
317 | win32pipe.DisconnectNamedPipe(self.outgoing)
318 | Win32PipeStream.close(self)
319 |
320 |
321 | if sys.platform == "win32":
322 | PipeStream = Win32PipeStream
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
--------------------------------------------------------------------------------
/HComHoudini/HComHoudiniClient.py:
--------------------------------------------------------------------------------
1 | import hou
2 |
3 | import rpyc
4 | import sys
5 | import getpass
6 | import os
7 |
8 | import threading
9 | import HComHoudiniUi
10 | import HComHoudiniUtils
11 |
12 | pysidePath = os.environ["PYTHONHOME"] + r"lib\site-packages-forced"
13 | if not pysidePath in sys.path:
14 | sys.path.append(pysidePath)
15 |
16 | global server_conn
17 | server_conn = None
18 |
19 | global server_id
20 | server_id = None
21 |
22 | global bgsrv
23 | bgsrv = None
24 |
25 | # Decorator tor send new data to client
26 | # into a new thread
27 | def threaded_sendata(func):
28 |
29 | def wrapper(*args, **kwargs):
30 | t = threading.Thread(target=func, args=args, kwargs=kwargs)
31 | t.start()
32 |
33 | return wrapper
34 |
35 | class HCom_ClientService(rpyc.Service):
36 | '''
37 | This is the client service called to fetch data from server.
38 | '''
39 |
40 | def on_disconnect(self):
41 | server_is_disconnected()
42 |
43 | def exposed_catchData(self, dataType, _sender, data, tabTarget, clientType):
44 |
45 | HComHoudiniUi.receiveData(_sender, data, dataType, tabTarget, clientType)
46 |
47 | def exposed_sendIDUpdate(self, ID, action, clientType):
48 |
49 | HComHoudiniUi.receiveIDUpdate(ID, action, clientType)
50 |
51 |
52 | def connectToServer(ID=None, clientType="NONE"):
53 | '''
54 | Try to connect to the server and launch the BG thread service
55 | '''
56 |
57 | if not ID:
58 | ID = getpass.getuser()
59 |
60 | global server_conn
61 | global bgsrv
62 |
63 | try:
64 | server_conn = rpyc.connect(HComHoudiniUtils.readIni()["SERVER"], int(HComHoudiniUtils.readIni()["PORT"]), service=HCom_ClientService, config={"allow_pickle":True})
65 | except Exception as e:
66 | print("ERROR: Can not connect to server: " + str(e))
67 | return False, False
68 | else:
69 | if ID in server_conn.root.getAllClients().keys():
70 | hou.ui.displayMessage("User ID already registered on the server")
71 | server_conn.close()
72 | return False
73 |
74 | hou.session.HCOMCLIENT = [server_conn, ID]
75 |
76 | global server_id
77 | server_id = ID
78 |
79 | bgsrv = rpyc.BgServingThread(server_conn)
80 | result = server_conn.root.registerClient(ID, clientType)
81 |
82 | if result:
83 | return ID
84 | else:
85 | return False
86 |
87 | def _sendData(target_clientID, sender, data, datatype, tabTarget):
88 | '''
89 | Send data the to target client, could be message, otl or settings.
90 | '''
91 |
92 | global server_conn
93 |
94 | if not server_conn:
95 | print("ERROR: Client is not connected.")
96 | return False
97 |
98 | try:
99 | setDataAsync = rpyc.async(server_conn.root.sendDataToClient)
100 | result = setDataAsync(target_clientID, datatype, sender, data, tabTarget)
101 | return result
102 | except AttributeError:
103 | return False
104 | print("ERROR: client " + target_clientID + " not found.")
105 |
106 | @threaded_sendata
107 | def sendMessage(target_clientID, sender, message, tabTarget):
108 |
109 | result = _sendData(target_clientID, sender, message, "msg", tabTarget)
110 | return result
111 |
112 |
113 | def sendSettings(target_clientID, sender, tabTarget, tabClientType=None):
114 |
115 | settingsData = {}
116 |
117 | n = hou.selectedNodes()
118 | if not n:
119 | hou.ui.displayMessage("Nothing is selected")
120 | return False
121 | sel = n[0]
122 |
123 | settingsData["OTL_TYPE"] = sel.type().name()
124 |
125 | parmDict = {}
126 | parms = sel.parms()
127 | for p in parms:
128 | parmDict[p.name()] = p.eval()
129 |
130 | settingsData["OTL_PARMS"] = parmDict
131 |
132 | result = _sendData(target_clientID, sender, settingsData, "settings", tabTarget)
133 | return [result, settingsData["OTL_TYPE"] + " settings"]
134 |
135 |
136 | def sendOtl(target_clientID, sender, tabTarget, tabClientType=None):
137 |
138 | n = hou.selectedNodes()
139 | if not n:
140 | hou.ui.displayMessage("Nothing is selected")
141 | return False
142 | sel = n[0]
143 |
144 | if tabClientType[0] != HComHoudiniUtils.CLIENT_TYPE.HOUDINI:
145 | if not sel.type().definition():
146 | hou.ui.displayMessage("Invalid node")
147 | return False
148 |
149 | else:
150 | if hou.expandString("$HH") in sel.type().definition().libraryFilePath():
151 | hou.ui.displayMessage("Invalid node")
152 | return False
153 |
154 | parentType = ""
155 | if sel.__class__ == hou.SopNode:
156 | parentType = "geo"
157 |
158 | elif sel.__class__ == hou.ObjNode:
159 | parentType = "obj"
160 |
161 | elif sel.__class__ == hou.ShopNode:
162 | parentType = "shop"
163 |
164 | elif sel.__class__ == hou.CopNode:
165 | parentType = "cop"
166 |
167 | elif sel.__class__ == hou.DopNode:
168 | parentType = "dop"
169 |
170 | elif sel.__class__ == hou.RopNode:
171 | parentType = "rop"
172 |
173 | elif sel.__class__ == hou.VopNode:
174 |
175 | parentType = "vop;"
176 | parentType += sel.parent().type().name() + ";"
177 |
178 | if sel.parent().__class__ == hou.SopNode:
179 | parentType += "sop"
180 |
181 | elif sel.parent().__class__ == hou.ShopNode:
182 | parentType += "material"
183 |
184 | elif sel.parent().__class__ == hou.CopNode:
185 | parentType += "cop"
186 |
187 | else:
188 | hou.ui.displayMessage("The current node type is not supported by HCom yet.")
189 | return False
190 |
191 | else:
192 | hou.ui.displayMessage("The current node type is not supported by HCom yet.")
193 | return False
194 |
195 | otlData = {}
196 | otlData["OTL_PARENT_TYPE"] = parentType
197 | otlData["PY_CODE"] = sel.asCode(recurse=True)
198 | otlData["OTL_NAME"] = sel.name()
199 | otlData["OTL_TYPE"] = sel.type().name()
200 | otlData["OTL_ALL_LIBS"] = HComHoudiniUtils.getAllLib(sel)
201 |
202 | result = _sendData(target_clientID, sender, otlData, "otl", tabTarget)
203 | if result:
204 | return True
205 | else:
206 | return False
207 |
208 | def sendAlembic(target_clientID, sender, tabTarget, tabClientType=None):
209 |
210 | selection = hou.selectedNodes()
211 | if not selection:
212 | hou.ui.displayMessage("Nothing is selected")
213 | return False
214 |
215 | selection = selection[0]
216 | if not selection.__class__ == hou.ObjNode:
217 | hou.ui.displayMessage("Selection must be a geo node")
218 | return False
219 |
220 | start = 1
221 | end = 100
222 | cancelled = False
223 | inputValid = False
224 | while not inputValid:
225 |
226 | pickFrameUI = hou.ui.readMultiInput("Enter a frame range:",
227 | ["Start Frame", "End Frame"],
228 | buttons = ["Ok", "Cancel"],
229 | initial_contents=(hou.expandString("$FSTART"), hou.expandString("$FEND")),
230 | title="Pick Frame Range",
231 | help="Must be two integers")
232 | if pickFrameUI[0] == 1:
233 | cancelled = True
234 | inputValid = True
235 | else:
236 | start = pickFrameUI[1][0]
237 | end = pickFrameUI[1][1]
238 |
239 | if not start.isdigit() or not end.isdigit():
240 | inputValid = False
241 |
242 | else:
243 | if int(start) > int(end):
244 | inputValid = False
245 | else:
246 | start = int(start)
247 | end = int(end)
248 | inputValid = True
249 |
250 | if cancelled:
251 | return False
252 |
253 | name = selection.name()
254 | frames = [start, end]
255 |
256 | nodePath = selection.path()
257 | tmpGeo = hou.node("/obj").createNode("geo", run_init_scripts=False)
258 | tmpGeo.setName('alembic_tmp_exporter', unique_name=True)
259 |
260 | objectMerge = tmpGeo.createNode("object_merge")
261 | objectMerge.parm("objpath1").set(nodePath)
262 |
263 | alembicExport = tmpGeo.createNode("rop_alembic")
264 | alembicExport.parm("trange").set(1)
265 | alembicExport.parm("f1").deleteAllKeyframes()
266 | alembicExport.parm("f1").set(int(frames[0]))
267 | alembicExport.parm("f2").deleteAllKeyframes()
268 | alembicExport.parm("f2").set(int(frames[1]))
269 |
270 | alembicExport.parm("save_attributes").set(0)
271 |
272 | alembicExport.setInput(0, objectMerge)
273 |
274 | outFile = HComHoudiniUtils.fetchMyReceivedFilesFolder() + os.sep + name + "_tmpCacheAlembic.abc"
275 |
276 | alembicExport.parm("filename").set(outFile)
277 | alembicExport.render()
278 |
279 | tmpGeo.destroy()
280 |
281 | with open(outFile, 'rb') as f:
282 | data = f.read()
283 |
284 | # Clean tmp file
285 | try:
286 | os.remove(outFile)
287 | except:
288 | pass
289 |
290 | outDic = {}
291 | outDic["NAME"] = name
292 | outDic["FRAME_RANGE"] = frames
293 | outDic["DATA"]= data
294 |
295 | result = _sendData(target_clientID, sender, outDic, "alembic", tabTarget)
296 | if result:
297 | return True
298 | else:
299 | return False
300 |
301 |
302 | def sendBgeo(target_clientID, sender, tabTarget, isObj=False, tabClientType=None):
303 |
304 | n = hou.selectedNodes()
305 | if not n:
306 | hou.ui.displayMessage("Nothing is selected")
307 | return False
308 | sel = n[0]
309 |
310 | if sel.__class__ != hou.SopNode:
311 | hou.ui.displayMessage("Node selected is not a sop node")
312 | return False
313 |
314 | geo = sel.geometry()
315 |
316 | if isObj:
317 | if not geo.points():
318 | hou.ui.displayMessage("No points found on geometry")
319 | return False
320 |
321 | fileType = ".bgeo"
322 | if isObj:
323 | fileType = ".obj"
324 |
325 | # Dump geo on disk in a tmp file if data() not supported by houdini's version
326 | # If it is an obj file it must pass by saveToFile() methode
327 | if hasattr(geo, "data") and not isObj:
328 | binaryData = geo.data()
329 | else:
330 | tmpFile = hou.expandString("$HOME") + "/" + "tmphcom__" + fileType
331 | geo.saveToFile(tmpFile)
332 | binaryData = ""
333 | with open(tmpFile, 'rb') as f:
334 | binaryData = f.read()
335 | os.remove(tmpFile)
336 |
337 | meshData = {}
338 | meshData["MESH_TYPE"] = fileType
339 | meshData["MESH_NAME"] = sel.name()
340 | meshData["MESH_DATA"] = binaryData
341 |
342 | result = _sendData(target_clientID, sender, meshData, "mesh", tabTarget)
343 | if result:
344 | return True
345 | else:
346 | return False
347 |
348 |
349 | def sendObjMesh(target_clientID, sender, tabTarget, tabClientType=None):
350 | result = sendBgeo(target_clientID, sender, tabTarget, isObj=True)
351 | return result
352 |
353 |
354 | def sendPic(target_clientID, _sender, tabTarget, imagePath, tabClientType=None):
355 |
356 | with open(imagePath, 'rb') as f:
357 | imageData = f.read()
358 |
359 | outImdageData = {}
360 | outImdageData["IMAGE_NAME"] = os.path.basename(imagePath)
361 | outImdageData["BINARY_DATA"] = imageData
362 |
363 | result = _sendData(target_clientID, _sender, outImdageData, "pic", tabTarget)
364 | if result:
365 | return True
366 | else:
367 | return False
368 |
369 | def sendDataReceivedInfo(targetClient, sender, data, tabTarget):
370 |
371 | _sendData(targetClient, sender, data, "dataReceivedUpdate", tabTarget)
372 |
373 |
374 | def getAllClientRegistred():
375 |
376 | global server_conn
377 |
378 | if not server_conn:
379 | print("ERROR: Client is not connected.")
380 | return False
381 |
382 | return server_conn.root.getAllClients().keys()
383 |
384 | def disconnect():
385 | '''
386 | Disconect client and stop BG thread
387 | '''
388 |
389 | global server_conn
390 | global bgsrv
391 | global server_id
392 |
393 | if not server_conn:
394 | return
395 | try:
396 | bgsrv.stop()
397 | bgsrv = None
398 | except:
399 | pass
400 |
401 | try:
402 | server_conn.root.removeClient(server_id)
403 | except EOFError:
404 | pass
405 |
406 | try:
407 | server_conn.close()
408 |
409 | except:
410 | pass
411 | server_conn = None
412 |
413 | HComHoudiniUi.HComMainUi.updateUiThread.data = {"ACTION":"server_disconnect", "ID":None, "CLIENT_TYPE":None}
414 |
415 |
416 | def server_is_disconnected():
417 | disconnect()
--------------------------------------------------------------------------------
/lib/rpyc/utils/registry.py:
--------------------------------------------------------------------------------
1 | """
2 | rpyc registry server implementation
3 | """
4 | import sys
5 | import socket
6 | import time
7 | from rpyc.core import brine
8 | from rpyc.utils.logger import Logger
9 |
10 |
11 | DEFAULT_PRUNING_TIMEOUT = 4 * 60
12 | MAX_DGRAM_SIZE = 1500
13 | REGISTRY_PORT = 18811
14 |
15 |
16 | #------------------------------------------------------------------------------
17 | # servers
18 | #------------------------------------------------------------------------------
19 |
20 | class RegistryServer(object):
21 | def __init__(self, listenersock, pruning_timeout = None, logger = None):
22 | self.sock = listenersock
23 | self.active = False
24 | self.services = {}
25 | if pruning_timeout is None:
26 | pruning_timeout = DEFAULT_PRUNING_TIMEOUT
27 | self.pruning_timeout = pruning_timeout
28 | if logger is None:
29 | logger = Logger("REGSRV")
30 | self.logger = logger
31 |
32 | def on_service_added(self, name, addrinfo):
33 | """called when a new service joins the registry (but on keepalives).
34 | override this to add custom logic"""
35 |
36 | def on_service_removed(self, name, addrinfo):
37 | """called when a service unregisters or is pruned.
38 | override this to add custom logic"""
39 |
40 | def add_service(self, name, addrinfo):
41 | if name not in self.services:
42 | self.services[name] = {}
43 | is_new = addrinfo not in self.services
44 | self.services[name][addrinfo] = time.time()
45 | if is_new:
46 | try:
47 | self.on_service_added(name, addrinfo)
48 | except Exception:
49 | self.logger.traceback()
50 |
51 | def remove_service(self, name, addrinfo):
52 | self.services[name].pop(addrinfo, None)
53 | if not self.services[name]:
54 | del self.services[name]
55 | try:
56 | self.on_service_removed(name, addrinfo)
57 | except Exception:
58 | self.logger.traceback()
59 |
60 | def cmd_query(self, host, name):
61 | name = name.upper()
62 | self.logger.debug("querying for %r", name)
63 | if name not in self.services:
64 | self.logger.debug("no such service")
65 | return ()
66 |
67 | oldest = time.time() - self.pruning_timeout
68 | all_servers = sorted(self.services[name].items(), key = lambda x: x[1])
69 | servers = []
70 | for addrinfo, t in all_servers:
71 | if t < oldest:
72 | self.logger.debug("discarding stale %s:%s", *addrinfo)
73 | self.remove_service(name, addrinfo)
74 | else:
75 | servers.append(addrinfo)
76 |
77 | self.logger.debug("replying with %r", servers)
78 | return tuple(servers)
79 |
80 | def cmd_register(self, host, names, port):
81 | self.logger.debug("registering %s:%s as %s", host, port, ", ".join(names))
82 | for name in names:
83 | self.add_service(name.upper(), (host, port))
84 | return "OK"
85 |
86 | def cmd_unregister(self, host, port):
87 | self.logger.debug("unregistering %s:%s", host, port)
88 | for name in self.services.keys():
89 | self.remove_service(name, (host, port))
90 | return "OK"
91 |
92 | def _recv(self):
93 | raise NotImplementedError()
94 |
95 | def _send(self, data, addrinfo):
96 | raise NotImplementedError()
97 |
98 | def _work(self):
99 | while self.active:
100 | try:
101 | data, addrinfo = self._recv()
102 | except (socket.error, socket.timeout):
103 | continue
104 | try:
105 | magic, cmd, args = brine.load(data)
106 | except Exception:
107 | continue
108 | if magic != "RPYC":
109 | self.logger.warn("invalid magic: %r", magic)
110 | continue
111 | cmdfunc = getattr(self, "cmd_%s" % (cmd.lower(),), None)
112 | if not cmdfunc:
113 | self.logger.warn("unknown command: %r", cmd)
114 | continue
115 |
116 | try:
117 | reply = cmdfunc(addrinfo[0], *args)
118 | except Exception:
119 | self.logger.traceback()
120 | else:
121 | self._send(brine.dump(reply), addrinfo)
122 |
123 | def start(self):
124 | if self.active:
125 | raise ValueError("server is already running")
126 | if self.sock is None:
127 | raise ValueError("object disposed")
128 | self.logger.debug("server started on %s:%s", *self.sock.getsockname())
129 | try:
130 | try:
131 | self.active = True
132 | self._work()
133 | except KeyboardInterrupt:
134 | self.logger.warn("User interrupt!")
135 | finally:
136 | self.active = False
137 | self.logger.debug("server closed")
138 | self.sock.close()
139 | self.sock = None
140 |
141 | def close(self):
142 | if not self.active:
143 | raise ValueError("server is not running")
144 | self.logger.debug("stopping server...")
145 | self.active = False
146 |
147 | class UDPRegistryServer(RegistryServer):
148 | def __init__(self, host = "0.0.0.0", port = REGISTRY_PORT,
149 | pruning_timeout = None, logger = None):
150 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
151 | sock.bind((host, port))
152 | sock.settimeout(0.5)
153 | super(UDPRegistryServer, self).__init__(sock,
154 | pruning_timeout = pruning_timeout, logger = logger)
155 |
156 | def _recv(self):
157 | return self.sock.recvfrom(MAX_DGRAM_SIZE)
158 |
159 | def _send(self, data, addrinfo):
160 | try:
161 | self.sock.sendto(data, addrinfo)
162 | except (socket.error, socket.timeout):
163 | pass
164 |
165 | class TCPRegistryServer(RegistryServer):
166 | def __init__(self, host = "0.0.0.0", port = REGISTRY_PORT,
167 | pruning_timeout = None, logger = None, reuse_addr = True):
168 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
169 | if reuse_addr and sys.platform != "win32":
170 | # warning: reuseaddr is not what you expect on windows!
171 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
172 | sock.bind((host, port))
173 | sock.listen(10)
174 | sock.settimeout(0.5)
175 | super(TCPRegistryServer, self).__init__(sock,
176 | pruning_timeout = pruning_timeout, logger = logger)
177 | self._connected_sockets = {}
178 |
179 | def _recv(self):
180 | sock2 = self.sock.accept()[0]
181 | addrinfo = sock2.getpeername()
182 | data = sock2.recv(MAX_DGRAM_SIZE)
183 | self._connected_sockets[addrinfo] = sock2
184 | return data, addrinfo
185 |
186 | def _send(self, data, addrinfo):
187 | sock2 = self._connected_sockets.pop(addrinfo)
188 | try:
189 | sock2.send(data)
190 | except (socket.error, socket.timeout):
191 | pass
192 |
193 | #------------------------------------------------------------------------------
194 | # clients (registrars)
195 | #------------------------------------------------------------------------------
196 | class RegistryClient(object):
197 | REREGISTER_INTERVAL = 60
198 |
199 | def __init__(self, ip, port, timeout, logger = None):
200 | self.ip = ip
201 | self.port = port
202 | self.timeout = timeout
203 | if logger is None:
204 | logger = Logger("REGCLNT")
205 | self.logger = logger
206 |
207 | def discover(self, name):
208 | raise NotImplementedError
209 |
210 | def register(self, aliases, port):
211 | raise NotImplementedError
212 |
213 | def unregister(self, port):
214 | raise NotImplementedError
215 |
216 | class UDPRegistryClient(RegistryClient):
217 | def __init__(self, ip = "255.255.255.255", port = REGISTRY_PORT, timeout = 2,
218 | bcast = None, logger = None):
219 | super(UDPRegistryClient, self).__init__(ip = ip, port = port,
220 | timeout = timeout, logger = logger)
221 | if bcast is None:
222 | bcast = "255" in ip.split(".")
223 | self.bcast = bcast
224 |
225 | def discover(self, name):
226 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
227 | if self.bcast:
228 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
229 | data = brine.dump(("RPYC", "QUERY", (name,)))
230 | sock.sendto(data, (self.ip, self.port))
231 | sock.settimeout(self.timeout)
232 |
233 | try:
234 | try:
235 | data, addrinfo = sock.recvfrom(MAX_DGRAM_SIZE)
236 | except (socket.error, socket.timeout):
237 | servers = ()
238 | else:
239 | servers = brine.load(data)
240 | finally:
241 | sock.close()
242 | return servers
243 |
244 | def register(self, aliases, port):
245 | self.logger.info("registering on %s:%s", self.ip, self.port)
246 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
247 | if self.bcast:
248 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
249 | data = brine.dump(("RPYC", "REGISTER", (aliases, port)))
250 | sock.sendto(data, (self.ip, self.port))
251 |
252 | tmax = time.time() + self.timeout
253 | while time.time() < tmax:
254 | sock.settimeout(tmax - time.time())
255 | try:
256 | data, (rip, rport) = sock.recvfrom(MAX_DGRAM_SIZE)
257 | except socket.timeout:
258 | self.logger.warn("no registry acknowledged")
259 | break
260 | if rport != self.port:
261 | continue
262 | try:
263 | reply = brine.load(data)
264 | except Exception:
265 | continue
266 | if reply == "OK":
267 | self.logger.info("registry %s:%s acknowledged", rip, rport)
268 | break
269 | else:
270 | self.logger.warn("no registry acknowledged")
271 | sock.close()
272 |
273 | def unregister(self, port):
274 | self.logger.info("unregistering from %s:%s", self.ip, self.port)
275 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
276 | if self.bcast:
277 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
278 | data = brine.dump(("RPYC", "UNREGISTER", (port,)))
279 | sock.sendto(data, (self.ip, self.port))
280 | sock.close()
281 |
282 |
283 | class TCPRegistryClient(RegistryClient):
284 | def __init__(self, ip, port = REGISTRY_PORT, timeout = 2, logger = None):
285 | super(TCPRegistryClient, self).__init__(ip = ip, port = port,
286 | timeout = timeout, logger = logger)
287 |
288 | def discover(self, name):
289 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
290 | sock.settimeout(self.timeout)
291 | data = brine.dump(("RPYC", "QUERY", (name,)))
292 | sock.connect((self.ip, self.port))
293 | sock.send(data)
294 |
295 | try:
296 | try:
297 | data = sock.recv(MAX_DGRAM_SIZE)
298 | except (socket.error, socket.timeout):
299 | servers = ()
300 | else:
301 | servers = brine.load(data)
302 | finally:
303 | sock.close()
304 | return servers
305 |
306 | def register(self, aliases, port):
307 | self.logger.info("registering on %s:%s", self.ip, self.port)
308 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
309 | sock.settimeout(self.timeout)
310 | data = brine.dump(("RPYC", "REGISTER", (aliases, port)))
311 |
312 | try:
313 | try:
314 | sock.connect((self.ip, self.port))
315 | sock.send(data)
316 | except (socket.error, socket.timeout):
317 | self.logger.warn("could not connect to registry")
318 | return
319 | try:
320 | data = sock.recv(MAX_DGRAM_SIZE)
321 | except socket.timeout:
322 | self.logger.warn("registry did not acknowledge")
323 | return
324 | try:
325 | reply = brine.load(data)
326 | except Exception:
327 | self.logger.warn("received corrupted data from registry")
328 | return
329 | if reply == "OK":
330 | self.logger.info("registry %s:%s acknowledged", self.ip, self.port)
331 | finally:
332 | sock.close()
333 |
334 | def unregister(self, port):
335 | self.logger.info("unregistering from %s:%s", self.ip, self.port)
336 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
337 | sock.settimeout(self.timeout)
338 | data = brine.dump(("RPYC", "UNREGISTER", (port,)))
339 | try:
340 | sock.connect((self.ip, self.port))
341 | sock.send(data)
342 | except (socket.error, socket.timeout):
343 | self.logger.warn("could not connect to registry")
344 | sock.close()
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
--------------------------------------------------------------------------------
/HComHoudini/HComHoudiniUtils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import time
3 | import hou
4 | import subprocess
5 | import random
6 | import threading
7 |
8 | HISTORY_FOLDER = os.path.dirname(__file__) + "\\HCom_History\\"
9 | ICONPATH = os.path.dirname(__file__) + "\\HCom_Icons\\"
10 |
11 | def readIni():
12 |
13 | iniValues = {}
14 |
15 | ini = os.path.dirname(__file__) + "\\HCom.ini"
16 | with open(ini, 'r') as f:
17 | for i in f.readlines():
18 | if i.startswith("#"):
19 | continue
20 | elif i == "\n":
21 | continue
22 | else:
23 | data = i.split("=")
24 |
25 | val = data[1].replace("\n", "")
26 | if val.isdigit() and "." in val:
27 | val = float(val)
28 | elif val.isdigit() and not "." in val:
29 | val = int(val)
30 | elif val.lower() == "true":
31 | val = True
32 | elif val.lower() == "false":
33 | val = False
34 | else:
35 | val = str(val)
36 |
37 | iniValues[data[0]] = val
38 |
39 | return iniValues
40 |
41 | def writeIni(settings):
42 | ini = os.path.dirname(__file__) + "\\HCom.ini"
43 | with open(ini, 'w') as f:
44 |
45 | f.write("#HCom info file\n")
46 |
47 | for k in settings.keys():
48 | f.write(k + "=" + str(settings[k]) + "\n")
49 |
50 | def getAllLib(node):
51 | '''
52 | Fetch all library path of sub otls and selected otl.
53 | returns a dict {lib_file:binary_data}
54 | '''
55 |
56 | libFound = False
57 | libData = []
58 | libNameList = []
59 |
60 | # All sub children nodes
61 | allChildrens = list(node.allSubChildren())
62 | allChildrens.append(node)
63 |
64 | for childrenNode in allChildrens:
65 |
66 | nodeDefinition = childrenNode.type().definition()
67 | if not nodeDefinition:
68 | continue
69 |
70 | libPath = nodeDefinition.libraryFilePath()
71 | libName = os.path.basename(libPath)
72 |
73 | if libName in libNameList:
74 | continue
75 |
76 | # Skip built-in otl
77 | if libPath.startswith(hou.expandString("$HH")):
78 | continue
79 |
80 | if not os.path.exists(libPath):
81 | continue
82 |
83 | binaryData = ""
84 | with open(libPath, 'rb') as f:
85 | binaryData = f.read()
86 |
87 | libData.append([libName, binaryData])
88 | libNameList.append(libName)
89 | libFound = True
90 |
91 | if libFound:
92 | return libData
93 | return False
94 |
95 | def writeHistory(sender, timeStamp, data):
96 |
97 | historyFile = HISTORY_FOLDER + sender.lower() + "_history.txt"
98 | with open(historyFile, 'a') as f:
99 | f.write(timeStamp + "\n")
100 | f.write(" " + str(data) + "\n")
101 |
102 | def coloredString(string, hexColor=None, rgb=None, italic=False, bold=False):
103 |
104 | in_italic_tag = ""
105 | out_italic_tag = ""
106 | if italic:
107 | in_italic_tag = ""
108 | out_italic_tag = ""
109 |
110 | in_bold_tag = ""
111 | out_bold_tag = ""
112 | if bold:
113 | in_bold_tag = ""
114 | out_bold_tag = ""
115 |
116 | if not hexColor and not rgb:
117 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag)
118 |
119 | if hexColor:
120 | if hexColor.startswith("#"):
121 | hexColor = hexColor.replace("#", "")
122 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag, hexColor)
123 | else:
124 | return "{0}{1}{2}{3}{4}".format(in_italic_tag, in_bold_tag, string, out_bold_tag, out_italic_tag, rgb[0], rgb[1], rgb[2])
125 |
126 | def incrementFile(filePath):
127 |
128 | if not os.path.exists(filePath):
129 | return filePath
130 |
131 | baseName = os.path.basename(filePath)
132 | name = baseName.split(".")[0]
133 | fileType = baseName.split(".")[1]
134 | dirName = os.path.dirname(filePath)
135 |
136 | fileInc = dirName + os.sep + name + "_1." + fileType
137 | i = 2
138 | while os.path.exists(fileInc):
139 | fileInc = dirName + os.sep + name + "_" + str(i) + "." + fileType
140 |
141 | return fileInc
142 |
143 | def createAlembic(data, sender="", settings=None):
144 |
145 | hou.setUpdateMode(hou.updateMode.Manual)
146 |
147 | fileName = data["NAME"]
148 | filePath = fetchMyReceivedFilesFolder() + os.sep + fileName
149 | filePath = incrementFile(filePath)
150 |
151 | with open(filePath, 'wb') as f:
152 | f.write(data["DATA"])
153 |
154 | geo = hou.node("/obj").createNode("geo", run_init_scripts=False)
155 | geo.setName("Alembic_container_from_" + sender, unique_name=True)
156 | geo.appendComment("Alembic_container_from_" + sender)
157 |
158 | alembicNode = geo.createNode("alembic")
159 | alembicNode.parm("fileName").set(filePath)
160 |
161 | return True
162 |
163 | def createOtl(data, sender="", settings=None):
164 |
165 | nodeName = data["OTL_NAME"]
166 | parentType = data["OTL_PARENT_TYPE"]
167 | subOtlLibs = data["OTL_ALL_LIBS"]
168 |
169 | # Switch houdini to manual update according to settings
170 | if settings["SWITCH_TO_MANUAL_UPDATE"]:
171 | hou.setUpdateMode(hou.updateMode.Manual)
172 |
173 | # Check otl libs
174 | if subOtlLibs:
175 |
176 | allLoadedFiles = [os.path.basename(n) for n in hou.hda.loadedFiles()]
177 |
178 | for e in subOtlLibs:
179 | libName = e[0]
180 | libData = e[1]
181 |
182 | if libName in allLoadedFiles:
183 | continue
184 |
185 | otlLibToInstall = fetchMyReceivedFilesFolder() + os.sep + libName
186 |
187 | with open(otlLibToInstall, 'wb') as f:
188 | f.write(libData)
189 |
190 | hou.hda.installFile(otlLibToInstall)
191 |
192 | comment = " Node sent by {0} ({1})".format(str(sender), time.ctime())
193 | pyCode = data["PY_CODE"].split("\n")
194 |
195 | outPyCode = ""
196 | houNodeFound = False
197 | for c in pyCode:
198 |
199 | # Change code to create a geo container for sop node
200 | if parentType == "geo":
201 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
202 | houNodeFound = True
203 | outPyCode += c + "\n"
204 | outPyCode += "hou_parent = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
205 | outPyCode += "hou_parent.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
206 | outPyCode += "hou_parent.appendComment('HCom:')\n"
207 | outPyCode += "hou_parent.appendComment('{0}')\n".format(comment)
208 | else:
209 | outPyCode += c + "\n"
210 |
211 | # Change parent to shopnet for shop nodes
212 | elif parentType == "shop":
213 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
214 | houNodeFound = True
215 | outPyCode += c + "\n"
216 | outPyCode += "container = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
217 | outPyCode += "container.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
218 | outPyCode += "container.appendComment('HCom:')\n"
219 | outPyCode += "container.appendComment('{0}')\n".format(comment)
220 | outPyCode += "hou_parent = container.createNode('shopnet', run_init_scripts=False)\n"
221 | else:
222 | outPyCode += c + "\n"
223 |
224 | # Change parent to dopnet for dop nodes
225 | elif parentType == "dop":
226 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
227 | houNodeFound = True
228 | outPyCode += c + "\n"
229 | outPyCode += "container = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
230 | outPyCode += "container.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
231 | outPyCode += "container.appendComment('HCom:')\n"
232 | outPyCode += "container.appendComment('{0}')\n".format(comment)
233 | outPyCode += "hou_parent = container.createNode('dopnet', run_init_scripts=False)\n"
234 | else:
235 | outPyCode += c + "\n"
236 |
237 | # Change parent to copnet for cop nodes
238 | elif parentType == "cop":
239 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
240 | houNodeFound = True
241 | outPyCode += c + "\n"
242 | outPyCode += "container = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
243 | outPyCode += "container.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
244 | outPyCode += "container.appendComment('HCom:')\n"
245 | outPyCode += "container.appendComment('{0}')\n".format(comment)
246 | outPyCode += "hou_parent = container.createNode('cop2net', run_init_scripts=False)\n"
247 | else:
248 | outPyCode += c + "\n"
249 |
250 | # Change parent to ropnet for rop nodes
251 | elif parentType == "rop":
252 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
253 | houNodeFound = True
254 | outPyCode += c + "\n"
255 | outPyCode += "container = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
256 | outPyCode += "container.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
257 | outPyCode += "container.appendComment('HCom:')\n"
258 | outPyCode += "container.appendComment('{0}')\n".format(comment)
259 | outPyCode += "hou_parent = container.createNode('ropnet', run_init_scripts=False)\n"
260 | else:
261 | outPyCode += c + "\n"
262 |
263 | # Change code to change node name
264 | elif parentType == "obj":
265 | if c.startswith("hou_node") and not houNodeFound:
266 | houNodeFound = True
267 | outPyCode += c + "\n"
268 | outPyCode += "hou_node.setName('{0}' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
269 | outPyCode += "hou_node.appendComment('HCom:')\n"
270 | outPyCode += "hou_node.appendComment('{0}')\n".format(comment)
271 | else:
272 | outPyCode += c + "\n"
273 |
274 | # Change parent to vopsop for vex nodes
275 | elif "vop" in parentType:
276 |
277 | parentTypeContainer = parentType.split(";")[1]
278 | parentClass = parentType.split(";")[2]
279 |
280 | # is a sop vop network
281 | if parentClass == "sop":
282 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
283 | houNodeFound = True
284 | outPyCode += c + "\n"
285 | outPyCode += "container = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
286 | outPyCode += "container.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
287 | outPyCode += "container.appendComment('HCom:')\n"
288 | outPyCode += "container.appendComment('{0}')\n".format(comment)
289 | outPyCode += "hou_parent = container.createNode('{0}', run_init_scripts=False)\n".format(parentTypeContainer)
290 | else:
291 | outPyCode += c + "\n"
292 |
293 | # it's a material network
294 | elif parentClass == "material":
295 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
296 | houNodeFound = True
297 | outPyCode += c + "\n"
298 | outPyCode += "container = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
299 | outPyCode += "container.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
300 | outPyCode += "container.appendComment('HCom:')\n"
301 | outPyCode += "container.appendComment('{0}')\n".format(comment)
302 | outPyCode += "shopnet = container.createNode('shopnet', run_init_scripts=False)\n"
303 | outPyCode += "hou_parent = shopnet.createNode('{0}', run_init_scripts=False)\n".format(parentTypeContainer)
304 | else:
305 | outPyCode += c + "\n"
306 |
307 | # it's a cop network
308 | elif parentClass == "cop":
309 | if c.replace(" ", "").startswith("hou_parent") and not houNodeFound:
310 | houNodeFound = True
311 | outPyCode += c + "\n"
312 | outPyCode += "container = hou.node('/obj').createNode('geo', run_init_scripts=False)\n"
313 | outPyCode += "container.setName('{0}_container_' + '_from_{1}', unique_name=True)\n".format(nodeName, str(sender))
314 | outPyCode += "container.appendComment('HCom:')\n"
315 | outPyCode += "container.appendComment('{0}')\n".format(comment)
316 | outPyCode += "copnet = container.createNode('cop2net', run_init_scripts=False)\n"
317 | outPyCode += "hou_parent = copnet.createNode('{0}', run_init_scripts=False)\n".format(parentTypeContainer)
318 | else:
319 | outPyCode += c + "\n"
320 | try:
321 |
322 | exec(outPyCode)
323 | except Exception as e:
324 | print("ERROR: exec pyCode " + str(e))
325 |
326 | def setOtlSettings(data, sender="", settings=None):
327 |
328 | nodeType = data["OTL_TYPE"]
329 |
330 | selNode = hou.ui.selectNode()
331 | if not selNode:
332 | return False
333 | else:
334 | selection = hou.node(selNode)
335 |
336 | if selection.type().name() != nodeType:
337 | hou.ui.displayMessage("You must select a node of type: " + nodeType)
338 | return
339 |
340 | parms = data["OTL_PARMS"]
341 | for p in parms:
342 |
343 | parm = selection.parm(p)
344 | if parm:
345 | parm.set(parms[p])
346 | else:
347 | print("Parm '{0}' not found, skipped.".format(p))
348 |
349 | def createMesh(data, sender="", settings=None):
350 |
351 | meshType = data["MESH_TYPE"]
352 | meshName = data["MESH_NAME"]
353 | meshData = data["MESH_DATA"]
354 |
355 | bgeoFile = fetchMyReceivedFilesFolder() + os.sep + meshName + meshType
356 | bgeoFile = incrementFile(bgeoFile)
357 | with open(bgeoFile, 'wb') as f:
358 | f.write(meshData)
359 |
360 | comment = " Node sent by {0} ({1})".format(str(sender), time.ctime())
361 | container = hou.node("/obj").createNode("geo", run_init_scripts=False)
362 | container.setName(meshName + "_{0}_from_".format(meshType.replace(".", "")) + sender, unique_name=True)
363 | container.appendComment(comment)
364 |
365 | fileNode = container.createNode("file")
366 | fileNode.setName(meshName + "_{0}_model".format(meshType.replace(".", "")))
367 | fileNode.parm("file").set(bgeoFile)
368 |
369 | def createPic(data, sender="", settings=None):
370 |
371 | imageName = data["IMAGE_NAME"]
372 | imageData = data["BINARY_DATA"]
373 |
374 | imageNameAndFile = imageName.split(".")
375 |
376 | outFile = fetchMyReceivedFilesFolder() + os.sep + imageNameAndFile[0] + "." + imageNameAndFile[1]
377 | outFile = incrementFile(outFile)
378 |
379 | with open(outFile, 'wb') as f:
380 | f.write(imageData)
381 |
382 | t = threading.Thread(target = openPicFile, args=(outFile,))
383 | t.start()
384 |
385 | def openPicFile(picFile):
386 |
387 | try:
388 | subprocess.Popen(["mplay.exe", picFile])
389 | except Exception as e:
390 | print "MPLAY ERROR: " + str(e)
391 | try:
392 | subprocess.Popen(["explorer", picFile])
393 | except Exception as e:
394 | print "EXPLORER ERROR: " + str(e)
395 |
396 |
397 | def fetchMyReceivedFilesFolder():
398 |
399 | p = readIni()["MY_RECEIVED_FILES"]
400 | if p == "DEFAULT":
401 | p = os.path.dirname(__file__) + "\\HCom_Received_Files"
402 |
403 | if not os.path.exists(p):
404 | os.makedirs(p)
405 |
406 | return p
407 |
408 | def rdnname():
409 | names = ["Motoko", "Bato", "Kusanagi", "Frodon", "Sheldon", "Pipo", "Sam", "Gandalf", "Fitz", "Henry"]
410 | names += ["Leonard", "Batman", "Bobleponge", "rincewind", "carrot", "HelloWorld", "Python", "Houdini"]
411 | return names[random.randint(0, len(names)-1)]
412 |
413 | class CLIENT_TYPE():
414 |
415 | NONE = "NONE"
416 | HOUDINI = "Houdini"
417 | MAYA_NO_HENGINE = "Maya_no_hengine"
418 | MAYA_HENGINE = "Maya_hengine"
419 | NUKE = "nuke"
420 |
--------------------------------------------------------------------------------
/lib/rpyc/core/protocol.py:
--------------------------------------------------------------------------------
1 | """
2 | The RPyC protocol
3 | """
4 | import sys
5 | import select
6 | import weakref
7 | import itertools
8 | import cPickle as pickle
9 | from threading import Lock
10 | from rpyc.utils.lib import WeakValueDict, RefCountingColl
11 | from rpyc.core import consts, brine, vinegar, netref
12 | from rpyc.core.async import AsyncResult
13 |
14 |
15 | class PingError(Exception):
16 | pass
17 |
18 | DEFAULT_CONFIG = dict(
19 | # ATTRIBUTES
20 | allow_safe_attrs = True,
21 | allow_exposed_attrs = True,
22 | allow_public_attrs = False,
23 | allow_all_attrs = False,
24 | safe_attrs = set(['__abs__', '__add__', '__and__', '__cmp__', '__contains__',
25 | '__delitem__', '__delslice__', '__div__', '__divmod__', '__doc__',
26 | '__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__',
27 | '__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__',
28 | '__idiv__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__',
29 | '__index__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__',
30 | '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__',
31 | '__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
32 | '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__',
33 | '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__repr__',
34 | '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__',
35 | '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__',
36 | '__rxor__', '__setitem__', '__setslice__', '__str__', '__sub__',
37 | '__truediv__', '__xor__', 'next', '__length_hint__', '__enter__',
38 | '__exit__', ]),
39 | exposed_prefix = "exposed_",
40 | allow_getattr = True,
41 | allow_setattr = False,
42 | allow_delattr = False,
43 | # EXCEPTIONS
44 | include_local_traceback = True,
45 | instantiate_custom_exceptions = False,
46 | import_custom_exceptions = False,
47 | instantiate_oldstyle_exceptions = False, # which don't derive from Exception
48 | propagate_SystemExit_locally = False, # whether to propagate SystemExit locally or to the other party
49 | # MISC
50 | allow_pickle = False,
51 | connid = None,
52 | credentials = None,
53 | )
54 |
55 | _connection_id_generator = itertools.count(1)
56 |
57 | class Connection(object):
58 | """The RPyC connection (also know as the RPyC protocol).
59 | * service: the service to expose
60 | * channel: the channcel over which messages are passed
61 | * config: this connection's config dict (overriding parameters from the
62 | default config dict)
63 | * _lazy: whether or not to initialize the service with the creation of the
64 | connection. default is True. if set to False, you will need to call
65 | _init_service manually later
66 | """
67 | def __init__(self, service, channel, config = {}, _lazy = False):
68 | self._closed = True
69 | self._config = DEFAULT_CONFIG.copy()
70 | self._config.update(config)
71 | if self._config["connid"] is None:
72 | self._config["connid"] = "conn%d" % (_connection_id_generator.next(),)
73 |
74 | self._channel = channel
75 | self._seqcounter = itertools.count()
76 | self._recvlock = Lock()
77 | self._sendlock = Lock()
78 | self._sync_replies = {}
79 | self._async_callbacks = {}
80 | self._local_objects = RefCountingColl()
81 | self._last_traceback = None
82 | self._proxy_cache = WeakValueDict()
83 | self._netref_classes_cache = {}
84 | self._remote_root = None
85 | self._local_root = service(weakref.proxy(self))
86 | if not _lazy:
87 | self._init_service()
88 | self._closed = False
89 | def _init_service(self):
90 | self._local_root.on_connect()
91 |
92 | def __del__(self):
93 | self.close()
94 | def __enter__(self):
95 | return self
96 | def __exit__(self, t, v, tb):
97 | self.close()
98 | def __repr__(self):
99 | a, b = object.__repr__(self).split(" object ")
100 | return "%s %r object %s" % (a, self._config["connid"], b)
101 |
102 | #
103 | # IO
104 | #
105 | def _cleanup(self, _anyway = True):
106 | if self._closed and not _anyway:
107 | return
108 | self._closed = True
109 | self._channel.close()
110 | self._local_root.on_disconnect()
111 | self._sync_replies.clear()
112 | self._async_callbacks.clear()
113 | self._local_objects.clear()
114 | self._proxy_cache.clear()
115 | self._netref_classes_cache.clear()
116 | self._last_traceback = None
117 | self._last_traceback = None
118 | self._remote_root = None
119 | self._local_root = None
120 | #self._seqcounter = None
121 | #self._config.clear()
122 | def close(self, _catchall = True):
123 | if self._closed:
124 | return
125 | self._closed = True
126 | try:
127 | try:
128 | self._async_request(consts.HANDLE_CLOSE)
129 | except EOFError:
130 | pass
131 | except Exception:
132 | if not _catchall:
133 | raise
134 | finally:
135 | self._cleanup(_anyway = True)
136 |
137 | @property
138 | def closed(self):
139 | return self._closed
140 | def fileno(self):
141 | return self._channel.fileno()
142 |
143 | def ping(self, data = "the world is a vampire!" * 20, timeout = 3):
144 | """assert that the other party is functioning properly"""
145 | res = self.async_request(consts.HANDLE_PING, data, timeout = timeout)
146 | if res.value != data:
147 | raise PingError("echo mismatches sent data")
148 |
149 | def _send(self, msg, seq, args):
150 | data = brine.dump((msg, seq, args))
151 | self._sendlock.acquire()
152 | try:
153 | self._channel.send(data)
154 | finally:
155 | self._sendlock.release()
156 | def _send_request(self, handler, args):
157 | seq = self._seqcounter.next()
158 | self._send(consts.MSG_REQUEST, seq, (handler, self._box(args)))
159 | return seq
160 | def _send_reply(self, seq, obj):
161 | self._send(consts.MSG_REPLY, seq, self._box(obj))
162 | def _send_exception(self, seq, exctype, excval, exctb):
163 | exc = vinegar.dump(exctype, excval, exctb,
164 | include_local_traceback = self._config["include_local_traceback"])
165 | self._send(consts.MSG_EXCEPTION, seq, exc)
166 |
167 | #
168 | # boxing
169 | #
170 | def _box(self, obj):
171 | """store a local object in such a way that it could be recreated on
172 | the remote party either by-value or by-reference"""
173 | if brine.dumpable(obj):
174 | return consts.LABEL_VALUE, obj
175 | if type(obj) is tuple:
176 | return consts.LABEL_TUPLE, tuple(self._box(item) for item in obj)
177 | elif isinstance(obj, netref.BaseNetref) and obj.____conn__() is self:
178 | return consts.LABEL_LOCAL_REF, obj.____oid__
179 | else:
180 | self._local_objects.add(obj)
181 | cls = getattr(obj, "__class__", type(obj))
182 | return consts.LABEL_REMOTE_REF, (id(obj), cls.__name__, cls.__module__)
183 |
184 | def _unbox(self, package):
185 | """recreate a local object representation of the remote object: if the
186 | object is passed by value, just return it; if the object is passed by
187 | reference, create a netref to it"""
188 | label, value = package
189 | if label == consts.LABEL_VALUE:
190 | return value
191 | if label == consts.LABEL_TUPLE:
192 | return tuple(self._unbox(item) for item in value)
193 | if label == consts.LABEL_LOCAL_REF:
194 | return self._local_objects[value]
195 | if label == consts.LABEL_REMOTE_REF:
196 | oid, clsname, modname = value
197 | if oid in self._proxy_cache:
198 | return self._proxy_cache[oid]
199 | proxy = self._netref_factory(oid, clsname, modname)
200 | self._proxy_cache[oid] = proxy
201 | return proxy
202 | raise ValueError("invalid label %r" % (label,))
203 |
204 | def _netref_factory(self, oid, clsname, modname):
205 | typeinfo = (clsname, modname)
206 | if typeinfo in self._netref_classes_cache:
207 | cls = self._netref_classes_cache[typeinfo]
208 | elif typeinfo in netref.builtin_classes_cache:
209 | cls = netref.builtin_classes_cache[typeinfo]
210 | else:
211 | info = self.sync_request(consts.HANDLE_INSPECT, oid)
212 | cls = netref.class_factory(clsname, modname, info)
213 | self._netref_classes_cache[typeinfo] = cls
214 | return cls(weakref.ref(self), oid)
215 |
216 | #
217 | # dispatching
218 | #
219 | def _dispatch_request(self, seq, raw_args):
220 | try:
221 | handler, args = raw_args
222 | args = self._unbox(args)
223 | res = self._HANDLERS[handler](self, *args)
224 | except KeyboardInterrupt:
225 | raise
226 | except:
227 | t, v, tb = sys.exc_info()
228 | self._last_traceback = tb
229 | if t is SystemExit and self._config["propagate_SystemExit_locally"]:
230 | raise
231 | self._send_exception(seq, t, v, tb)
232 | else:
233 | self._send_reply(seq, res)
234 |
235 | def _dispatch_reply(self, seq, raw):
236 | obj = self._unbox(raw)
237 | if seq in self._async_callbacks:
238 | self._async_callbacks.pop(seq)(False, obj)
239 | else:
240 | self._sync_replies[seq] = (False, obj)
241 |
242 | def _dispatch_exception(self, seq, raw):
243 | obj = vinegar.load(raw,
244 | import_custom_exceptions = self._config["import_custom_exceptions"],
245 | instantiate_custom_exceptions = self._config["instantiate_custom_exceptions"],
246 | instantiate_oldstyle_exceptions = self._config["instantiate_oldstyle_exceptions"])
247 | if seq in self._async_callbacks:
248 | self._async_callbacks.pop(seq)(True, obj)
249 | else:
250 | self._sync_replies[seq] = (True, obj)
251 |
252 | #
253 | # serving
254 | #
255 | def _recv(self, timeout, wait_for_lock):
256 | if not self._recvlock.acquire(wait_for_lock):
257 | return None
258 | try:
259 | try:
260 | if self._channel.poll(timeout):
261 | data = self._channel.recv()
262 | else:
263 | data = None
264 | except EOFError:
265 | self.close()
266 | raise
267 | finally:
268 | self._recvlock.release()
269 | return data
270 |
271 | def _dispatch(self, data):
272 | msg, seq, args = brine.load(data)
273 | if msg == consts.MSG_REQUEST:
274 | self._dispatch_request(seq, args)
275 | elif msg == consts.MSG_REPLY:
276 | self._dispatch_reply(seq, args)
277 | elif msg == consts.MSG_EXCEPTION:
278 | self._dispatch_exception(seq, args)
279 | else:
280 | raise ValueError("invalid message type: %r" % (msg,))
281 |
282 | def poll(self, timeout = 0):
283 | """serve a single transaction, should one arrives in the given
284 | interval. note that handling a request/reply may trigger nested
285 | requests, which are all part of the transaction.
286 |
287 | returns True if one was served, False otherwise"""
288 | data = self._recv(timeout, wait_for_lock = False)
289 | if not data:
290 | return False
291 | self._dispatch(data)
292 | return True
293 |
294 | def serve(self, timeout = 1):
295 | """serve a single request or reply that arrives within the given
296 | time frame (default is 1 sec). note that the dispatching of a request
297 | might trigger multiple (nested) requests, thus this function may be
298 | reentrant. returns True if a request or reply were received, False
299 | otherwise."""
300 |
301 | data = self._recv(timeout, wait_for_lock = True)
302 | if not data:
303 | return False
304 | self._dispatch(data)
305 | return True
306 |
307 | def serve_all(self):
308 | """serve all requests and replies while the connection is alive"""
309 | try:
310 | try:
311 | while True:
312 | self.serve(0.1)
313 | except select.error:
314 | if not self.closed:
315 | raise e
316 | except EOFError:
317 | pass
318 | finally:
319 | self.close()
320 |
321 | def poll_all(self, timeout = 0):
322 | """serve all requests and replies that arrive within the given interval.
323 | returns True if at least one was served, False otherwise"""
324 | at_least_once = False
325 | try:
326 | while self.poll(timeout):
327 | at_least_once = True
328 | except EOFError:
329 | pass
330 | return at_least_once
331 |
332 | #
333 | # requests
334 | #
335 | def sync_request(self, handler, *args):
336 | """send a request and wait for the reply to arrive"""
337 | seq = self._send_request(handler, args)
338 | while seq not in self._sync_replies:
339 | self.serve(0.1)
340 | isexc, obj = self._sync_replies.pop(seq)
341 | if isexc:
342 | raise obj
343 | else:
344 | return obj
345 |
346 | def _async_request(self, handler, args = (), callback = (lambda a, b: None)):
347 | seq = self._send_request(handler, args)
348 | self._async_callbacks[seq] = callback
349 | def async_request(self, handler, *args, **kwargs):
350 | """send a request and return an AsyncResult object, which will
351 | eventually hold the reply"""
352 | timeout = kwargs.pop("timeout", None)
353 | if kwargs:
354 | raise TypeError("got unexpected keyword argument %r" % (kwargs.keys()[0],))
355 | res = AsyncResult(weakref.proxy(self))
356 | self._async_request(handler, args, res)
357 | if timeout is not None:
358 | res.set_expiry(timeout)
359 | return res
360 |
361 | @property
362 | def root(self):
363 | """fetch the root object of the other party"""
364 | if self._remote_root is None:
365 | self._remote_root = self.sync_request(consts.HANDLE_GETROOT)
366 | return self._remote_root
367 |
368 | #
369 | # attribute access
370 | #
371 | def _check_attr(self, obj, name):
372 | if self._config["allow_exposed_attrs"]:
373 | if name.startswith(self._config["exposed_prefix"]):
374 | name2 = name
375 | else:
376 | name2 = self._config["exposed_prefix"] + name
377 | if hasattr(obj, name2):
378 | return name2
379 | if self._config["allow_all_attrs"]:
380 | return name
381 | if self._config["allow_safe_attrs"] and name in self._config["safe_attrs"]:
382 | return name
383 | if self._config["allow_public_attrs"] and not name.startswith("_"):
384 | return name
385 | return False
386 |
387 | def _access_attr(self, oid, name, args, overrider, param, default):
388 | if type(name) is not str:
389 | raise TypeError("attr name must be a string")
390 | obj = self._local_objects[oid]
391 | accessor = getattr(type(obj), overrider, None)
392 | if accessor is None:
393 | name2 = self._check_attr(obj, name)
394 | if not self._config[param] or not name2:
395 | raise AttributeError("cannot access %r" % (name,))
396 | accessor = default
397 | name = name2
398 | return accessor(obj, name, *args)
399 |
400 | #
401 | # handlers
402 | #
403 | def _handle_ping(self, data):
404 | return data
405 | def _handle_close(self):
406 | self._cleanup()
407 | def _handle_getroot(self):
408 | return self._local_root
409 | def _handle_del(self, oid):
410 | self._local_objects.decref(oid)
411 | def _handle_repr(self, oid):
412 | return repr(self._local_objects[oid])
413 | def _handle_str(self, oid):
414 | return str(self._local_objects[oid])
415 | def _handle_cmp(self, oid, other):
416 | # cmp() might enter recursive resonance... yet another workaround
417 | #return cmp(self._local_objects[oid], other)
418 | obj = self._local_objects[oid]
419 | try:
420 | return type(obj).__cmp__(obj, other)
421 | except TypeError:
422 | return NotImplemented
423 | def _handle_hash(self, oid):
424 | return hash(self._local_objects[oid])
425 | def _handle_call(self, oid, args, kwargs):
426 | return self._local_objects[oid](*args, **dict(kwargs))
427 | def _handle_dir(self, oid):
428 | return tuple(dir(self._local_objects[oid]))
429 | def _handle_inspect(self, oid):
430 | return tuple(netref.inspect_methods(self._local_objects[oid]))
431 | def _handle_getattr(self, oid, name):
432 | return self._access_attr(oid, name, (), "_rpyc_getattr", "allow_getattr", getattr)
433 | def _handle_delattr(self, oid, name):
434 | return self._access_attr(oid, name, (), "_rpyc_delattr", "allow_delattr", delattr)
435 | def _handle_setattr(self, oid, name, value):
436 | return self._access_attr(oid, name, (value,), "_rpyc_setattr", "allow_setattr", setattr)
437 | def _handle_callattr(self, oid, name, args, kwargs):
438 | return self._handle_getattr(oid, name)(*args, **dict(kwargs))
439 | def _handle_pickle(self, oid, proto):
440 | if not self._config["allow_pickle"]:
441 | raise ValueError("pickling is disabled")
442 | return pickle.dumps(self._local_objects[oid], proto)
443 | def _handle_buffiter(self, oid, count):
444 | items = []
445 | obj = self._local_objects[oid]
446 | for i in xrange(count):
447 | try:
448 | items.append(obj.next())
449 | except StopIteration:
450 | break
451 | return tuple(items)
452 |
453 | # collect handlers
454 | _HANDLERS = {}
455 | for name, obj in locals().items():
456 | if name.startswith("_handle_"):
457 | name2 = "HANDLE_" + name[8:].upper()
458 | if hasattr(consts, name2):
459 | _HANDLERS[getattr(consts, name2)] = obj
460 | else:
461 | raise NameError("no constant defined for %r", name)
462 | del name, name2, obj
463 |
464 |
465 |
--------------------------------------------------------------------------------