#!/usr/bin/env python3
"""Draw Things CORS bridge for JUMI Ad Animator.

Draw Things' local API works, but if its responses lack CORS headers a web page
is not allowed to read them. This tiny bridge fixes that:

    it listens on http://127.0.0.1:7861
    forwards every request to Draw Things at http://127.0.0.1:7860
    and adds the CORS headers browsers require.

Usage (on the machine running Draw Things):
    python3 dt-bridge.py
Then, in the Ad Animator's AI settings, set the image endpoint to:
    http://127.0.0.1:7861

Only pages you open in your own browser can use it, it binds to 127.0.0.1
(this machine only), and it never touches the network beyond localhost.
"""
import http.server, urllib.request, urllib.error

DT = 'http://127.0.0.1:7860'
PORT = 7861

class Bridge(http.server.BaseHTTPRequestHandler):
    def log_message(self, fmt, *args):
        print(self.command, self.path, args[1] if len(args) > 1 else '')

    def _cors(self):
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Headers', 'content-type')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')

    def do_OPTIONS(self):
        self.send_response(204); self._cors(); self.end_headers()

    def _forward(self, body=None):
        req = urllib.request.Request(DT + self.path, data=body,
              headers={'content-type': self.headers.get('content-type', 'application/json')})
        try:
            with urllib.request.urlopen(req, timeout=600) as r:
                data = r.read()
                self.send_response(r.status); self._cors()
                self.send_header('content-type', r.headers.get('content-type', 'application/json'))
                self.send_header('content-length', str(len(data)))
                self.end_headers(); self.wfile.write(data)
        except urllib.error.HTTPError as e:
            data = e.read()
            self.send_response(e.code); self._cors()
            self.send_header('content-length', str(len(data)))
            self.end_headers(); self.wfile.write(data)
        except Exception as e:
            msg = ('Bridge could not reach Draw Things at ' + DT + ': ' + str(e)).encode()
            self.send_response(502); self._cors()
            self.send_header('content-length', str(len(msg)))
            self.end_headers(); self.wfile.write(msg)

    def do_GET(self):
        self._forward()

    def do_POST(self):
        body = self.rfile.read(int(self.headers.get('content-length', 0) or 0))
        self._forward(body)

print('Draw Things CORS bridge: http://127.0.0.1:%d  ->  %s' % (PORT, DT))
print('Point the Ad Animator image endpoint at http://127.0.0.1:%d and leave this running.' % PORT)
http.server.ThreadingHTTPServer(('127.0.0.1', PORT), Bridge).serve_forever()
