6 from select
import EPOLLIN
, EPOLLPRI
, EPOLLERR
8 from collections
import namedtuple
11 TIMEOUT
= 1.0 # seconds
13 VERSION_HEADER
= bytearray('MesaOverlayControlVersion', 'utf-8')
14 DEVICE_NAME_HEADER
= bytearray('DeviceName', 'utf-8')
15 MESA_VERSION_HEADER
= bytearray('MesaVersion', 'utf-8')
17 DEFAULT_SERVER_ADDRESS
= "\0mesa_overlay"
20 def __init__(self
, path
):
21 # Create a Unix Domain socket and connect
22 sock
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_STREAM
)
25 except socket
.error
as msg
:
31 # initialize poll interface and register socket
32 epoll
= select
.epoll()
33 epoll
.register(sock
, EPOLLIN | EPOLLPRI | EPOLLERR
)
36 def recv(self
, timeout
):
38 timeout as float in seconds
40 - None on error or disconnection
41 - bytes() (empty) on timeout
44 events
= self
.epoll
.poll(timeout
)
47 if fd
!= self
.sock
.fileno():
50 # check for socket error
54 # EPOLLIN or EPOLLPRI, just read the message
55 msg
= self
.sock
.recv(4096)
69 MSGBEGIN
= bytes(':', 'utf-8')[0]
70 MSGEND
= bytes(';', 'utf-8')[0]
71 MSGSEP
= bytes('=', 'utf-8')[0]
73 def __init__(self
, conn
):
77 self
.reading_cmd
= False
78 self
.reading_param
= False
80 self
.cmd
= bytearray(4096)
81 self
.param
= bytearray(4096)
85 def readCmd(self
, ncmds
, timeout
=TIMEOUT
):
88 - None on error or disconnection
89 - bytes() (empty) on timeout
96 while remaining
> 0 and ncmds
> 0:
97 now
= time
.monotonic()
99 if self
.buffer == None:
100 self
.buffer = self
.conn
.recv(remaining
)
103 # disconnected or error
104 if self
.buffer == None:
107 for i
in range(self
.bufferpos
, len(self
.buffer)):
110 if c
== self
.MSGBEGIN
:
113 self
.reading_cmd
= True
114 self
.reading_param
= False
115 elif c
== self
.MSGEND
:
116 if not self
.reading_cmd
:
118 self
.reading_cmd
= False
119 self
.reading_param
= False
121 cmd
= self
.cmd
[0:self
.cmdpos
]
122 param
= self
.param
[0:self
.parampos
]
123 self
.reading_cmd
= False
124 self
.reading_param
= False
126 parsed
.append((cmd
, param
))
130 elif c
== self
.MSGSEP
:
132 self
.reading_param
= True
134 if self
.reading_param
:
135 self
.param
[self
.parampos
] = c
137 elif self
.reading_cmd
:
138 self
.cmd
[self
.cmdpos
] = c
141 # if we read the entire buffer and didn't finish the command,
145 # check if we have time for another iteration
146 elapsed
= time
.monotonic() - now
147 remaining
= max(0, remaining
- elapsed
)
154 address
= '\0' + args
.socket
156 address
= DEFAULT_SERVER_ADDRESS
158 conn
= Connection(address
)
159 msgparser
= MsgParser(conn
)
165 msgs
= msgparser
.readCmd(3)
169 if cmd
== VERSION_HEADER
:
171 elif cmd
== DEVICE_NAME_HEADER
:
172 name
= param
.decode('utf-8')
173 elif cmd
== MESA_VERSION_HEADER
:
174 mesa_version
= param
.decode('utf-8')
176 if version
!= 1 or name
== None or mesa_version
== None:
177 print('ERROR: invalid protocol')
182 info
= "Protocol Version: {}\n"
183 info
+= "Device Name: {}\n"
184 info
+= "Mesa Version: {}"
185 print(info
.format(version
, name
, mesa_version
))
187 if args
.cmd
== 'start-capture':
188 conn
.send(bytearray(':capture=1;', 'utf-8'))
189 elif args
.cmd
== 'stop-capture':
190 conn
.send(bytearray(':capture=0;', 'utf-8'))
192 if __name__
== '__main__':
193 parser
= argparse
.ArgumentParser(description
='MESA_overlay control client')
194 parser
.add_argument('--info', action
='store_true', help='Print info from socket')
195 parser
.add_argument('--socket', '-s', type=str, help='Path to socket')
197 commands
= parser
.add_subparsers(help='commands to run', dest
='cmd')
198 commands
.add_parser('start-capture')
199 commands
.add_parser('stop-capture')
201 args
= parser
.parse_args()