##// END OF EJS Templates
util: observable proxy objects for sockets...
Gregory Szorc -
r37028:8453699a default
parent child Browse files
Show More
@@ -689,6 +689,125 b' class observedbufferedinputpipe(buffered'
689
689
690 return res
690 return res
691
691
692 PROXIED_SOCKET_METHODS = {
693 r'makefile',
694 r'recv',
695 r'recvfrom',
696 r'recvfrom_into',
697 r'recv_into',
698 r'send',
699 r'sendall',
700 r'sendto',
701 r'setblocking',
702 r'settimeout',
703 r'gettimeout',
704 r'setsockopt',
705 }
706
707 class socketproxy(object):
708 """A proxy around a socket that tells a watcher when events occur.
709
710 This is like ``fileobjectproxy`` except for sockets.
711
712 This type is intended to only be used for testing purposes. Think hard
713 before using it in important code.
714 """
715 __slots__ = (
716 r'_orig',
717 r'_observer',
718 )
719
720 def __init__(self, sock, observer):
721 object.__setattr__(self, r'_orig', sock)
722 object.__setattr__(self, r'_observer', observer)
723
724 def __getattribute__(self, name):
725 if name in PROXIED_SOCKET_METHODS:
726 return object.__getattribute__(self, name)
727
728 return getattr(object.__getattribute__(self, r'_orig'), name)
729
730 def __delattr__(self, name):
731 return delattr(object.__getattribute__(self, r'_orig'), name)
732
733 def __setattr__(self, name, value):
734 return setattr(object.__getattribute__(self, r'_orig'), name, value)
735
736 def __nonzero__(self):
737 return bool(object.__getattribute__(self, r'_orig'))
738
739 __bool__ = __nonzero__
740
741 def _observedcall(self, name, *args, **kwargs):
742 # Call the original object.
743 orig = object.__getattribute__(self, r'_orig')
744 res = getattr(orig, name)(*args, **kwargs)
745
746 # Call a method on the observer of the same name with arguments
747 # so it can react, log, etc.
748 observer = object.__getattribute__(self, r'_observer')
749 fn = getattr(observer, name, None)
750 if fn:
751 fn(res, *args, **kwargs)
752
753 return res
754
755 def makefile(self, *args, **kwargs):
756 res = object.__getattribute__(self, r'_observedcall')(
757 r'makefile', *args, **kwargs)
758
759 # The file object may be used for I/O. So we turn it into a
760 # proxy using our observer.
761 observer = object.__getattribute__(self, r'_observer')
762 return makeloggingfileobject(observer.fh, res, observer.name,
763 reads=observer.reads,
764 writes=observer.writes,
765 logdata=observer.logdata)
766
767 def recv(self, *args, **kwargs):
768 return object.__getattribute__(self, r'_observedcall')(
769 r'recv', *args, **kwargs)
770
771 def recvfrom(self, *args, **kwargs):
772 return object.__getattribute__(self, r'_observedcall')(
773 r'recvfrom', *args, **kwargs)
774
775 def recvfrom_into(self, *args, **kwargs):
776 return object.__getattribute__(self, r'_observedcall')(
777 r'recvfrom_into', *args, **kwargs)
778
779 def recv_into(self, *args, **kwargs):
780 return object.__getattribute__(self, r'_observedcall')(
781 r'recv_info', *args, **kwargs)
782
783 def send(self, *args, **kwargs):
784 return object.__getattribute__(self, r'_observedcall')(
785 r'send', *args, **kwargs)
786
787 def sendall(self, *args, **kwargs):
788 return object.__getattribute__(self, r'_observedcall')(
789 r'sendall', *args, **kwargs)
790
791 def sendto(self, *args, **kwargs):
792 return object.__getattribute__(self, r'_observedcall')(
793 r'sendto', *args, **kwargs)
794
795 def setblocking(self, *args, **kwargs):
796 return object.__getattribute__(self, r'_observedcall')(
797 r'setblocking', *args, **kwargs)
798
799 def settimeout(self, *args, **kwargs):
800 return object.__getattribute__(self, r'_observedcall')(
801 r'settimeout', *args, **kwargs)
802
803 def gettimeout(self, *args, **kwargs):
804 return object.__getattribute__(self, r'_observedcall')(
805 r'gettimeout', *args, **kwargs)
806
807 def setsockopt(self, *args, **kwargs):
808 return object.__getattribute__(self, r'_observedcall')(
809 r'setsockopt', *args, **kwargs)
810
692 DATA_ESCAPE_MAP = {pycompat.bytechr(i): br'\x%02x' % i for i in range(256)}
811 DATA_ESCAPE_MAP = {pycompat.bytechr(i): br'\x%02x' % i for i in range(256)}
693 DATA_ESCAPE_MAP.update({
812 DATA_ESCAPE_MAP.update({
694 b'\\': b'\\\\',
813 b'\\': b'\\\\',
@@ -703,15 +822,7 b' def escapedata(s):'
703
822
704 return DATA_ESCAPE_RE.sub(lambda m: DATA_ESCAPE_MAP[m.group(0)], s)
823 return DATA_ESCAPE_RE.sub(lambda m: DATA_ESCAPE_MAP[m.group(0)], s)
705
824
706 class fileobjectobserver(object):
825 class baseproxyobserver(object):
707 """Logs file object activity."""
708 def __init__(self, fh, name, reads=True, writes=True, logdata=False):
709 self.fh = fh
710 self.name = name
711 self.logdata = logdata
712 self.reads = reads
713 self.writes = writes
714
715 def _writedata(self, data):
826 def _writedata(self, data):
716 if not self.logdata:
827 if not self.logdata:
717 self.fh.write('\n')
828 self.fh.write('\n')
@@ -731,6 +842,15 b' class fileobjectobserver(object):'
731 self.fh.write('%s> %s\n' % (self.name, escapedata(line)))
842 self.fh.write('%s> %s\n' % (self.name, escapedata(line)))
732 self.fh.flush()
843 self.fh.flush()
733
844
845 class fileobjectobserver(baseproxyobserver):
846 """Logs file object activity."""
847 def __init__(self, fh, name, reads=True, writes=True, logdata=False):
848 self.fh = fh
849 self.name = name
850 self.logdata = logdata
851 self.reads = reads
852 self.writes = writes
853
734 def read(self, res, size=-1):
854 def read(self, res, size=-1):
735 if not self.reads:
855 if not self.reads:
736 return
856 return
@@ -793,6 +913,119 b' def makeloggingfileobject(logh, fh, name'
793 logdata=logdata)
913 logdata=logdata)
794 return fileobjectproxy(fh, observer)
914 return fileobjectproxy(fh, observer)
795
915
916 class socketobserver(baseproxyobserver):
917 """Logs socket activity."""
918 def __init__(self, fh, name, reads=True, writes=True, states=True,
919 logdata=False):
920 self.fh = fh
921 self.name = name
922 self.reads = reads
923 self.writes = writes
924 self.states = states
925 self.logdata = logdata
926
927 def makefile(self, res, mode=None, bufsize=None):
928 if not self.states:
929 return
930
931 self.fh.write('%s> makefile(%r, %r)\n' % (
932 self.name, mode, bufsize))
933
934 def recv(self, res, size, flags=0):
935 if not self.reads:
936 return
937
938 self.fh.write('%s> recv(%d, %d) -> %d' % (
939 self.name, size, flags, len(res)))
940 self._writedata(res)
941
942 def recvfrom(self, res, size, flags=0):
943 if not self.reads:
944 return
945
946 self.fh.write('%s> recvfrom(%d, %d) -> %d' % (
947 self.name, size, flags, len(res[0])))
948 self._writedata(res[0])
949
950 def recvfrom_into(self, res, buf, size, flags=0):
951 if not self.reads:
952 return
953
954 self.fh.write('%s> recvfrom_into(%d, %d) -> %d' % (
955 self.name, size, flags, res[0]))
956 self._writedata(buf[0:res[0]])
957
958 def recv_into(self, res, buf, size=0, flags=0):
959 if not self.reads:
960 return
961
962 self.fh.write('%s> recv_into(%d, %d) -> %d' % (
963 self.name, size, flags, res))
964 self._writedata(buf[0:res])
965
966 def send(self, res, data, flags=0):
967 if not self.writes:
968 return
969
970 self.fh.write('%s> send(%d, %d) -> %d' % (
971 self.name, len(data), flags, len(res)))
972 self._writedata(data)
973
974 def sendall(self, res, data, flags=0):
975 if not self.writes:
976 return
977
978 # Returns None on success. So don't bother reporting return value.
979 self.fh.write('%s> sendall(%d, %d)' % (
980 self.name, len(data), flags))
981 self._writedata(data)
982
983 def sendto(self, res, data, flagsoraddress, address=None):
984 if not self.writes:
985 return
986
987 if address:
988 flags = flagsoraddress
989 else:
990 flags = 0
991
992 self.fh.write('%s> sendto(%d, %d, %r) -> %d' % (
993 self.name, len(data), flags, address, res))
994 self._writedata(data)
995
996 def setblocking(self, res, flag):
997 if not self.states:
998 return
999
1000 self.fh.write('%s> setblocking(%r)\n' % (self.name, flag))
1001
1002 def settimeout(self, res, value):
1003 if not self.states:
1004 return
1005
1006 self.fh.write('%s> settimeout(%r)\n' % (self.name, value))
1007
1008 def gettimeout(self, res):
1009 if not self.states:
1010 return
1011
1012 self.fh.write('%s> gettimeout() -> %f\n' % (self.name, res))
1013
1014 def setsockopt(self, level, optname, value):
1015 if not self.states:
1016 return
1017
1018 self.fh.write('%s> setsockopt(%r, %r, %r) -> %r\n' % (
1019 self.name, level, optname, value))
1020
1021 def makeloggingsocket(logh, fh, name, reads=True, writes=True, states=True,
1022 logdata=False):
1023 """Turn a socket into a logging socket."""
1024
1025 observer = socketobserver(logh, name, reads=reads, writes=writes,
1026 states=states, logdata=logdata)
1027 return socketproxy(fh, observer)
1028
796 def version():
1029 def version():
797 """Return version information if available."""
1030 """Return version information if available."""
798 try:
1031 try:
General Comments 0
You need to be logged in to leave comments. Login now