commit 21ccf060336f33dc7dd1dffd9cff661a2bb0ee75 Author: Andika Wasisto Date: Thu May 21 21:05:12 2020 +0700 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5179e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__/ +*.iml +.idea/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2105aad --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Andika Wasisto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..31b360d --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +Quanttp +======= + +An HTTP API that wraps [ComScire quantum random number generator API](https://comscire.com/downloads/qwqngdoc/). + +Running +------- + +1. Install ComScire driver from https://comscire.com/downloads/ +2. Run the following commands + ``` + pip install -r requirements.txt + python -m quanttp + ``` + +Usage Example +------------- + +### REST API + + http://localhost:62456/api/randint32 + < -1741405968 + + http://localhost:62456/api/randuniform + < 0.20340009994 + + http://localhost:62456/api/randnormal + < 1.02206840644 + + http://localhost:62456/api/randbytes?length=8 + < ���E��s_�b����G� + + http://localhost:62456/api/reset + < OK + + +### WebSocket API + + ws://localhost:62456/ws + > RANDINT32 + < 585865374 + > RANDUNIFORM + < 0.70137183786 + > RANDNORMAL + < -1.6120135370 + > RANDBYTES 16 + < �����9L).�!:���@Nh������d����_q� + > RESET + < OK + +License +------- + + Copyright (c) 2020 Andika Wasisto + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. \ No newline at end of file diff --git a/quanttp/__main__.py b/quanttp/__main__.py new file mode 100644 index 0000000..e081154 --- /dev/null +++ b/quanttp/__main__.py @@ -0,0 +1,95 @@ +# Copyright (c) 2020 Andika Wasisto +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from flask import Flask, request, Response +from flask_sockets import Sockets +from gevent import pywsgi +from geventwebsocket.handler import WebSocketHandler + +app = Flask(__name__) +sockets = Sockets(app) + +from quanttp.data.qng_wrapper import QngWrapper +qng_wrapper = QngWrapper() + +# from quanttp.data.qng_wrapper_mock import QngWrapperMock +# qng_wrapper = QngWrapperMock() + + +@app.route('/api/randint32') +def api_randint32(): + return Response(str(qng_wrapper.randint32()), content_type='text/plain') + + +@app.route('/api/randuniform') +def api_randuniform(): + return Response(str(qng_wrapper.randuniform()), content_type='text/plain') + + +@app.route('/api/randnormal') +def api_randnormal(): + return Response(str(qng_wrapper.randnormal()), content_type='text/plain') + + +@app.route('/api/randbytes') +def api_randbytes(): + try: + length = int(request.args.get('length')) + return Response(qng_wrapper.randbytes(length), content_type='application/octet-stream') + except ValueError as e: + return Response(str(e), status=400, content_type='text/plain') + + +@app.route('/api/reset') +def api_reset(): + qng_wrapper.reset() + return Response('OK', content_type='text/plain') + + +@sockets.route('/ws') +def ws(websocket): + while not websocket.closed: + try: + message = websocket.receive().strip().lower() + split_message = message.split(' ') + if split_message[0] == 'randint32': + websocket.send(str(qng_wrapper.randint32())) + elif split_message[0] == 'randuniform': + websocket.send(str(qng_wrapper.randuniform())) + elif split_message[0] == 'randnormal': + websocket.send(str(qng_wrapper.randnormal())) + elif split_message[0] == 'randbytes': + websocket.send(qng_wrapper.randbytes(int(split_message[1]))) + elif split_message[0] == 'reset': + qng_wrapper.reset() + websocket.send('OK') + except ValueError as e: + websocket.close(code=1003, message=str(e)) + except Exception as e: + websocket.close(code=1011, message=str(e)) + + +@app.errorhandler(Exception) +def handle_exception(e): + return Response(e.description, status=e.code, content_type='text/plain') + + +server = pywsgi.WSGIServer(('0.0.0.0', 62456), application=app, handler_class=WebSocketHandler) +server.serve_forever() diff --git a/quanttp/data/qng_wrapper.py b/quanttp/data/qng_wrapper.py new file mode 100644 index 0000000..025083d --- /dev/null +++ b/quanttp/data/qng_wrapper.py @@ -0,0 +1,46 @@ +# Copyright (c) 2020 Andika Wasisto +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import win32com.client + + +class QngWrapper: + + def __init__(self): + self.qng = win32com.client.Dispatch("QWQNG.QNG") + + def randint32(self): + self.qng.Clear() + return self.qng.RandInt32 + + def randuniform(self): + self.qng.Clear() + return self.qng.RandUniform + + def randnormal(self): + self.qng.Clear() + return self.qng.RandNormal + + def randbytes(self, length): + self.qng.Clear() + return self.qng.RandBytes(length) + + def reset(self): + self.qng.Reset() diff --git a/quanttp/data/qng_wrapper_mock.py b/quanttp/data/qng_wrapper_mock.py new file mode 100644 index 0000000..9af9337 --- /dev/null +++ b/quanttp/data/qng_wrapper_mock.py @@ -0,0 +1,40 @@ +# Copyright (c) 2020 Andika Wasisto +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import random +import secrets + + +class QngWrapperMock: + + def randint32(self): + return random.randint(-2147483648, +2147483647) + + def randuniform(self): + return random.random() + + def randnormal(self): + return random.gauss(mu=0.0, sigma=1.0) + + def randbytes(self, length): + return secrets.token_bytes(nbytes=length) + + def reset(self): + pass diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..850fa69 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +Flask==1.1.2 +Flask-Sockets==0.2.1 +gevent==20.5.0 +gevent-websocket==0.10.1 +pywin32==227 \ No newline at end of file