Fix formatting and add linters
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone Build is passing
				
			This commit is contained in:
		
							
								
								
									
										9
									
								
								.gitlint
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.gitlint
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | [general] | ||||||
|  | ignore=body-is-missing,T3 | ||||||
|  | ignore-stdin=true | ||||||
|  |  | ||||||
|  | [title-match-regex] | ||||||
|  | regex=[A-Z] | ||||||
|  |  | ||||||
|  | [author-valid-email] | ||||||
|  | regex=[^@]+@pinecrypt.com | ||||||
							
								
								
									
										11
									
								
								.pre-commit-config.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.pre-commit-config.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | repos: | ||||||
|  | -   repo: https://github.com/PyCQA/flake8 | ||||||
|  |     rev: 3.9.2 | ||||||
|  |     hooks: | ||||||
|  |     -   id: flake8 | ||||||
|  |         additional_dependencies: [flake8-typing-imports==1.10.0,flake8-quotes==3.2.0] | ||||||
|  |  | ||||||
|  | -   repo: https://github.com/jorisroovers/gitlint | ||||||
|  |     rev: v0.15.1 | ||||||
|  |     hooks: | ||||||
|  |     -   id: gitlint | ||||||
							
								
								
									
										57
									
								
								camdetect.py
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								camdetect.py
									
									
									
									
									
								
							| @@ -2,14 +2,13 @@ | |||||||
| import aiohttp | import aiohttp | ||||||
| import asyncio | import asyncio | ||||||
| import cv2 | import cv2 | ||||||
| import io |  | ||||||
| import numpy as np | import numpy as np | ||||||
| import os | import os | ||||||
| import json | import json | ||||||
| import socket | import socket | ||||||
| import sys | import sys | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
| from jpeg2dct.numpy import load, loads | from jpeg2dct.numpy import loads | ||||||
| from prometheus_client import Counter, Gauge | from prometheus_client import Counter, Gauge | ||||||
| from sanic import Sanic, response | from sanic import Sanic, response | ||||||
| from sanic.response import stream | from sanic.response import stream | ||||||
| @@ -25,6 +24,7 @@ DCT_BLOCK_SIZE = 8 | |||||||
| # How many blocks have changes to consider movement in frame | # How many blocks have changes to consider movement in frame | ||||||
| THRESHOLD_BLOCKS = 20 | THRESHOLD_BLOCKS = 20 | ||||||
| THRESHOLD_MOTION_START = 2 | THRESHOLD_MOTION_START = 2 | ||||||
|  | CHUNK_BOUNDARY = b"\n--frame\nContent-Type: image/jpeg\n\n" | ||||||
|  |  | ||||||
| counter_dropped_bytes = Counter( | counter_dropped_bytes = Counter( | ||||||
|     "camdetect_dropped_bytes", |     "camdetect_dropped_bytes", | ||||||
| @@ -44,6 +44,9 @@ counter_tx_frames = Counter( | |||||||
| counter_tx_events = Counter( | counter_tx_events = Counter( | ||||||
|     "camdetect_tx_events", |     "camdetect_tx_events", | ||||||
|     "Events emitted") |     "Events emitted") | ||||||
|  | counter_rx_chunks = Counter( | ||||||
|  |     "camdetect_rx_chunks", | ||||||
|  |     "HTTP chunks received") | ||||||
| counter_errors = Counter( | counter_errors = Counter( | ||||||
|     "camdetect_errors", |     "camdetect_errors", | ||||||
|     "Upstream connection errors", |     "Upstream connection errors", | ||||||
| @@ -59,24 +62,25 @@ gauge_active_blocks = Gauge( | |||||||
|     "camdetect_active_blocks", |     "camdetect_active_blocks", | ||||||
|     "Total active, threshold exceeding DCT blocks") |     "Total active, threshold exceeding DCT blocks") | ||||||
|  |  | ||||||
|  |  | ||||||
| class Frame(object): | class Frame(object): | ||||||
|     def __init__(self, blob): |     def __init__(self, blob): | ||||||
|         self.blob = blob |         self.blob = blob | ||||||
|         self.y, self.cb, self.cr = loads(blob) |         self.y, self.cb, self.cr = loads(blob) | ||||||
|         self.mask = np.int16(self.y[:, :, 0]) |         self.mask = np.int16(self.y[:, :, 0]) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def client_connect(resp): | async def client_connect(resp): | ||||||
|     buf = b"" |     buf = b"" | ||||||
|     print("Upstream connection opened with status:", resp.status) |     print("Upstream connection opened with status:", resp.status) | ||||||
|     async for data, end_of_http_chunk in resp.content.iter_chunks(): |     async for data, end_of_http_chunk in resp.content.iter_chunks(): | ||||||
|         counter_rx_bytes.inc(len(data)) |         counter_rx_bytes.inc(len(data)) | ||||||
|         if end_of_http_chunk: |         if end_of_http_chunk: | ||||||
|             counter_eos.inc() |             counter_rx_chunks.inc() | ||||||
|             break |  | ||||||
|  |  | ||||||
|         if buf: |         if buf: | ||||||
|             # seek end |             # seek end | ||||||
|             marker = data.find(b'\xff\xd9') |             marker = data.find(b"\xff\xd9") | ||||||
|             if marker < 0: |             if marker < 0: | ||||||
|                 buf += data |                 buf += data | ||||||
|                 continue |                 continue | ||||||
| @@ -95,10 +99,13 @@ async def client_connect(resp): | |||||||
|                     app.ctx.frames = app.ctx.frames[1:] |                     app.ctx.frames = app.ctx.frames[1:] | ||||||
|  |  | ||||||
|                 if len(app.ctx.frames) == 2 ** SLIDE_WINDOW: |                 if len(app.ctx.frames) == 2 ** SLIDE_WINDOW: | ||||||
|                     app.ctx.thresh = cv2.inRange(cv2.absdiff(app.ctx.last_frame.mask, app.ctx.avg >> SLIDE_WINDOW), 25, 65535) |                     app.ctx.thresh = cv2.inRange(cv2.absdiff( | ||||||
|  |                         app.ctx.last_frame.mask, | ||||||
|  |                         app.ctx.avg >> SLIDE_WINDOW), 25, 65535) | ||||||
|                 else: |                 else: | ||||||
|                     app.ctx.thresh = None |                     app.ctx.thresh = None | ||||||
|                 gauge_total_blocks.set(app.ctx.last_frame.mask.shape[0] * app.ctx.last_frame.mask.shape[1]) |                 gauge_total_blocks.set(app.ctx.last_frame.mask.shape[0] * | ||||||
|  |                                        app.ctx.last_frame.mask.shape[1]) | ||||||
|  |  | ||||||
|                 movement_detected = False |                 movement_detected = False | ||||||
|                 if app.ctx.thresh is not None: |                 if app.ctx.thresh is not None: | ||||||
| @@ -131,7 +138,7 @@ async def client_connect(resp): | |||||||
|                 counter_rx_frames.inc() |                 counter_rx_frames.inc() | ||||||
|  |  | ||||||
|         # seek begin |         # seek begin | ||||||
|         marker = data.find(b'\xff\xd8') |         marker = data.find(b"\xff\xd8") | ||||||
|         if marker >= 0: |         if marker >= 0: | ||||||
|             buf = data[marker:] |             buf = data[marker:] | ||||||
|         else: |         else: | ||||||
| @@ -140,7 +147,8 @@ async def client_connect(resp): | |||||||
|  |  | ||||||
| async def client(): | async def client(): | ||||||
|     while True: |     while True: | ||||||
|         async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(connect=5, sock_read=2)) as session: |         to = aiohttp.ClientTimeout(connect=5, sock_read=2) | ||||||
|  |         async with aiohttp.ClientSession(timeout=to) as session: | ||||||
|             print("Opening upstream connection to %s" % url) |             print("Opening upstream connection to %s" % url) | ||||||
|             try: |             try: | ||||||
|                 async with session.get(url) as resp: |                 async with session.get(url) as resp: | ||||||
| @@ -155,49 +163,46 @@ async def client(): | |||||||
| app = Sanic("lease") | app = Sanic("lease") | ||||||
| app.config["WTF_CSRF_ENABLED"] = False | app.config["WTF_CSRF_ENABLED"] = False | ||||||
|  |  | ||||||
| STREAM_RESPONSE = \ |  | ||||||
| b""" |  | ||||||
| --frame |  | ||||||
| Content-Type: image/jpeg |  | ||||||
|  |  | ||||||
| """ |  | ||||||
|  |  | ||||||
| @app.route("/bypass") | @app.route("/bypass") | ||||||
| async def bypass_stream_wrapper(request): | async def bypass_stream_wrapper(request): | ||||||
|     async def stream_camera(response): |     async def stream_camera(response): | ||||||
|         while True: |         while True: | ||||||
|             await app.ctx.event_frame.wait() |             await app.ctx.event_frame.wait() | ||||||
|             data = STREAM_RESPONSE + app.ctx.last_frame.blob |             data = CHUNK_BOUNDARY + app.ctx.last_frame.blob | ||||||
|             await response.write(data) |             await response.write(data) | ||||||
|             counter_tx_bytes.inc(len(data)) |             counter_tx_bytes.inc(len(data)) | ||||||
|             counter_tx_frames.inc() |             counter_tx_frames.inc() | ||||||
|  |  | ||||||
|     return response.stream( |     return response.stream( | ||||||
|                 stream_camera, |                 stream_camera, | ||||||
|                 content_type='multipart/x-mixed-replace; boundary=frame' |                 content_type="multipart/x-mixed-replace; boundary=frame" | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.route("/debug") | @app.route("/debug") | ||||||
| async def stream_wrapper(request): | async def stream_wrapper(request): | ||||||
|     async def stream_camera(response): |     async def stream_camera(response): | ||||||
|         while True: |         while True: | ||||||
|             await app.ctx.event_frame.wait() |             await app.ctx.event_frame.wait() | ||||||
|             img = cv2.imdecode(np.frombuffer(app.ctx.last_frame.blob, dtype=np.uint8), cv2.IMREAD_UNCHANGED) |             arr = np.frombuffer(app.ctx.last_frame.blob, dtype=np.uint8) | ||||||
|  |             img = cv2.imdecode(arr, cv2.IMREAD_UNCHANGED) | ||||||
|             if len(app.ctx.frames) == 2 ** SLIDE_WINDOW: |             if len(app.ctx.frames) == 2 ** SLIDE_WINDOW: | ||||||
|                 for y in range(0, len(app.ctx.last_frame.mask)): |                 for y in range(0, len(app.ctx.last_frame.mask)): | ||||||
|                     for x in range(0, len(app.ctx.last_frame.mask[0])): |                     for x in range(0, len(app.ctx.last_frame.mask[0])): | ||||||
|                         if app.ctx.thresh[y][x] > 0: |                         if app.ctx.thresh[y][x] > 0: | ||||||
|                             img[y*DCT_BLOCK_SIZE:(y+1)*DCT_BLOCK_SIZE,x*DCT_BLOCK_SIZE:(x+1)*DCT_BLOCK_SIZE,2] = 255 |                             img[y*DCT_BLOCK_SIZE:(y+1)*DCT_BLOCK_SIZE, | ||||||
|  |                                 x*DCT_BLOCK_SIZE:(x+1)*DCT_BLOCK_SIZE, 2] = 255 | ||||||
|  |  | ||||||
|             _, jpeg = cv2.imencode(".jpg", img, (cv2.IMWRITE_JPEG_QUALITY, 80)) |             _, jpeg = cv2.imencode(".jpg", img, (cv2.IMWRITE_JPEG_QUALITY, 80)) | ||||||
|             data = STREAM_RESPONSE + jpeg.tobytes() |             data = CHUNK_BOUNDARY + jpeg.tobytes() | ||||||
|             await response.write(data) |             await response.write(data) | ||||||
|             counter_tx_bytes.inc(len(data)) |             counter_tx_bytes.inc(len(data)) | ||||||
|             counter_tx_frames.inc() |             counter_tx_frames.inc() | ||||||
|  |  | ||||||
|     return response.stream( |     return response.stream( | ||||||
|         stream_camera, |         stream_camera, | ||||||
|         content_type='multipart/x-mixed-replace; boundary=frame' |         content_type="multipart/x-mixed-replace; boundary=frame" | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -208,20 +213,20 @@ async def ready_check(request): | |||||||
|     return response.text("Not enough frames", status=503) |     return response.text("Not enough frames", status=503) | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.route('/event') | @app.route("/event") | ||||||
| async def wrapper_stream_event(request): | async def wrapper_stream_event(request): | ||||||
|     async def stream_event(response): |     async def stream_event(response): | ||||||
|         while True: |         while True: | ||||||
|             await app.ctx.event_frame.wait() |             await app.ctx.event_frame.wait() | ||||||
|             if len(app.ctx.frames) < 2 ** SLIDE_WINDOW: |             if len(app.ctx.frames) < 2 ** SLIDE_WINDOW: | ||||||
|                 continue |                 continue | ||||||
|             s = 'data: ' + json.dumps(app.ctx.thresh.tolist()) + '\r\n\r\n' |             s = "data: " + json.dumps(app.ctx.thresh.tolist()) + "\r\n\r\n" | ||||||
|             await response.write(s.encode()) |             await response.write(s.encode()) | ||||||
|             counter_tx_events.inc() |             counter_tx_events.inc() | ||||||
|     return stream(stream_event, content_type='text/event-stream') |     return stream(stream_event, content_type="text/event-stream") | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.listener('before_server_start') | @app.listener("before_server_start") | ||||||
| async def setup_db(app, loop): | async def setup_db(app, loop): | ||||||
|     app.ctx.last_frame = None |     app.ctx.last_frame = None | ||||||
|     app.ctx.event_frame = asyncio.Event() |     app.ctx.event_frame = asyncio.Event() | ||||||
| @@ -230,7 +235,7 @@ async def setup_db(app, loop): | |||||||
|     app.ctx.motion_frames = 0 |     app.ctx.motion_frames = 0 | ||||||
|     app.ctx.motion_start = None |     app.ctx.motion_start = None | ||||||
|     app.ctx.motion_end = None |     app.ctx.motion_end = None | ||||||
|     task = asyncio.create_task(client()) |     asyncio.create_task(client()) | ||||||
|  |  | ||||||
| monitor(app).expose_endpoint() | monitor(app).expose_endpoint() | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user