Files
ascendhuawei a61dda4612 upload
2020-09-16 11:50:53 -07:00

292 lines
12 KiB
Python

# =======================================================================
#
# Copyright (C) 2018, Hisilicon Technologies Co., Ltd. All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1 Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2 Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3 Neither the names of the copyright holders nor the names of the
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# =======================================================================
#
"""presenter channel manager module"""
import logging
import threading
# max support 10 channels
MAX_CHANNEL_NUM = 10
# when a channel have receive data,
# the active status will last 3 seconds
ACTIVE_LAST_TIME = 3
class ChannelResource():
"""every channel has a ChannelResource object, contains a ChannelHandler object
and a socket fileno. it corresponding to the ChannelFd one by one
"""
def __init__(self, handler, socket=None):
self.handler = handler
self.socket = socket
class ChannelFd():
"""every channel has a ChannelFd object, contains a ChannelHandler
object and channel name. It corresponds to the ChannelResource one by one
"""
def __init__(self, channel_name, handler):
self.channel_name = channel_name
self.handler = handler
class Channel():
"""record user register channels
self.image: if channel type is image, save the image here
"""
def __init__(self, channel_name):
self.channel_name = channel_name
self.image = None
self.rectangle_list = None
class ChannelManager():
"""manage all the api about channel
__instance: ensure it is a single instance
_channel_resources: a dict
key: channel name
value: a ChannelResource() object.
_channel_fds: a dict
key: socket fileno
value: a ChannelFd() object.
_channel_list: a list, member is a Channel() object."""
__instance = None
channel_resources = {}
channel_fds = {}
channel_list = []
channel_resource_lock = threading.Lock()
channel_fds_lock = threading.Lock()
channel_lock = threading.Lock()
err_code_ok = 0
err_code_too_many_channel = 1
err_code_repeat_channel = 2
def __init__(self, channel_list=None):
"""init func"""
def __new__(cls, channel_list=None):
"""ensure only a single instance created. """
if cls.__instance is None:
cls.__instance = object.__new__(cls)
# default create 2 channels: image and video
# if channel_list is not None and isinstance(channel_list, list):
# for i in channel_list:
# cls.channel_list.append(Channel(channel_name=i))
# logging.info("register channel %s", i)
return cls.__instance
def _register_channel_fd(self, sock_fileno, channel_name):
"""Internal func, create a ChannelFd object"""
if self.channel_fds.get(sock_fileno):
del self.channel_fds[sock_fileno]
handler = self.channel_resources[channel_name].handler
self.channel_fds[sock_fileno] = ChannelFd(channel_name, handler)
def create_channel_resource(self, channel_name,
channel_fd,
media_type,
handler):
"""create a ChannelResource object which contains all the resources
binding a channel.
channel_name: channel name.
channel_fd: socket fileno binding the channel.
media_type: support image or video.
handler: an channel handler process image data.
"""
with self.channel_resource_lock:
log_info = "create channel resource,"
log_info += " channel_name:%s, channel_fd:%u, media_type:%s"
logging.info(log_info, channel_name, channel_fd, media_type)
self.channel_resources[channel_name] = \
ChannelResource(handler=handler, socket=channel_fd)
self._register_channel_fd(channel_fd, channel_name)
def _clean_channel_resource(self, channel_name):
"""Internal func, clean channel resource by channel name"""
if self.channel_resources.get(channel_name):
self.channel_resources[channel_name].handler.close_thread()
self.channel_resources[channel_name].handler.web_event.set()
self.channel_resources[channel_name].handler.image_event.set()
del self.channel_resources[channel_name]
logging.info("clean channel: %s's resource", channel_name)
def clean_channel_resource_by_fd(self, sock_fileno):
"""
clean channel resource by socket fileno
sock_fileno: socket fileno which binding to an channel
"""
with self.channel_fds_lock:
with self.channel_resource_lock:
if self.channel_fds.get(sock_fileno):
self._clean_channel_resource(
self.channel_fds[sock_fileno].channel_name)
del self.channel_fds[sock_fileno]
def clean_channel_resource_by_name(self, channel_name):
"""clean channel resource by channel_name
channel_name: channel name"""
if self.channel_resources.get(channel_name):
self.clean_channel_resource_by_fd(
self.channel_resources[channel_name].socket)
def get_channel_handler_by_fd(self, sock_fileno):
"""get channel handler by socket fileno"""
with self.channel_fds_lock:
if self.channel_fds.get(sock_fileno):
return self.channel_fds[sock_fileno].handler
return None
def is_channel_busy(self, channel_name):
"""check if channel is busy """
with self.channel_resource_lock:
if self.channel_resources.get(channel_name):
return True
return False
def close_all_thread(self):
"""if a channel process video type, it will create a thread.
this func can close the thread.
"""
with self.channel_resource_lock:
for channel_name in self.channel_resources:
self.channel_resources[channel_name].handler.close_thread()
def get_channel_handler_by_name(self, channel_name):
"""
get the channel handlerby channel name
"""
with self.channel_resource_lock:
if self.channel_resources.get(channel_name):
return self.channel_resources[channel_name].handler
return None
def list_channels(self):
"""
return all the channel name and the status
status is indicating active state or not
"""
with self.channel_lock:
return [{'status': self.is_channel_busy(i.channel_name),
'name': i.channel_name} for i in self.channel_list]
def register_one_channel(self, channel_name):
"""
register a channel path, user create a channel via browser
"""
with self.channel_lock:
if len(self.channel_list) >= MAX_CHANNEL_NUM:
logging.info("register channel: %s fail, \
exceed max number 10.", channel_name)
return self.err_code_too_many_channel
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
logging.info("register channel: %s fail, \
already exist.", channel_name)
return self.err_code_repeat_channel
self.channel_list.append(Channel(channel_name=channel_name))
logging.info("register channel: %s", channel_name)
return self.err_code_ok
def unregister_one_channel(self, channel_name):
"""
unregister a channel path, user delete a channel via browser
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
self.clean_channel_resource_by_name(channel_name)
logging.info("unregister channel: %s", channel_name)
del self.channel_list[i]
break
def is_channel_exist(self, channel_name):
"""
Check if a channel is exist
True: exist
False: not exist
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
return True
return False
def save_channel_image(self, channel_name, image_data, rectangle_list):
"""
when a channel bounding to image type,
server will permanent hold an image for it.
this func save a image in memory
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
self.channel_list[i].image = image_data
self.channel_list[i].rectangle_list = rectangle_list
break
def get_channel_image(self, channel_name):
"""
when a channel bounding to image type,
server will permanent hold an image for it.
this func get the image
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
return self.channel_list[i].image
# channel not exist
return None
def get_channel_image_with_rectangle(self, channel_name):
"""
A new method for display server,
return the image and rectangle list
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
return (self.channel_list[i].image, self.channel_list[i].rectangle_list)
return (None, None)
def clean_channel_image(self, channel_name):
"""
when a channel bounding to image type,
server will permanent hold an image for it.
this func clean the image
"""
with self.channel_lock:
for i in range(len(self.channel_list)):
if self.channel_list[i].channel_name == channel_name:
self.channel_list[i].image = None
break