def setup(self): # S1: Setup socketio client. self.publ_info = self.sio_queue[0].get() self.cfg = self.sio_queue[0].get() assert isinstance(self.publ_info, ClientPublInfo) self.publ_info.cfg = self.cfg self.pvte_info.cfg = self.cfg self.ignore_events = ['submit'] # S1.1: Setup logger. self.setup_logger() # S1.2: Connect to Waldorf master. from waldorf.namespace.client import Namespace self.logger.debug( 'Connect to {}:{} with uid {}'.format( self.cfg.master_ip, self.cfg.waldorf_port, self.publ_info.uid)) if self.cfg.debug >= 2: sio = Client(logger=self.logger) else: sio = Client() self.pvte_info.sio = sio ns = Namespace('/client') ns.setup(self) self.pvte_info.ns = ns sio.register_namespace(ns) sio.connect('http://{}:{}'.format( self.cfg.master_ip, self.cfg.waldorf_port)) self.result_q = [queue.Queue(), self.submit_queue[0]] CeleryResultThread(self).start()
def setup(self): self.publ_info = self.sio_queue[0].get() self.cfg = self.sio_queue[0].get() assert isinstance(self.publ_info, SlavePublInfo) self.publ_info.cfg = self.cfg self.pvte_info.cfg = self.cfg self.setup_logger() self.publ_info.update_load() # S1.1: Setup namespace. from waldorf.namespace.slave import Namespace self.logger.debug( 'Connect to {}:{} with uid {}'.format( self.cfg.master_ip, self.cfg.waldorf_port, self.publ_info.uid)) if self.cfg.debug >= 2: sio = Client(logger=self.logger) else: sio = Client() self.pvte_info.sio = sio ns = Namespace('/slave') ns.setup(self) self.pvte_info.ns = ns sio.register_namespace(ns) sio.connect('http://{}:{}'.format( self.cfg.master_ip, self.cfg.waldorf_port))
def generate_request(beds=None): if beds is None: beds = api.API.get_instance().get_all_beds_info() for bed in beds: namespace = bed['UUID'] + "_" + bed['MAC'] print("Comenzamos a escuchar") sio = Client() max_tries = 6 tries = 0 flag = False while max_tries > tries and not flag: try: sio.connect(get_sio_connect()) flag = True except: tries += 1 eventlet.sleep(1) if flag: sio.emit("give_me_data", { "namespace": namespace, "bedname": "Cama 1" }) else: raise Exception("Conexión fallada") if v.version < 1: break # En esta situación solo se crea una request.
def test_admin_namespace_with_correct_token(server_url: str, client: socketio.Client): server_metric_event = "server metric" mock_ack = Mock() @client.on(server_metric_event, namespace="/admin") def _server_metric(data): assert data["name"] == "CPU_COUNT" assert data["value"] > 0 mock_ack(server_metric_event) client.connect(f"{server_url}?token=admin", namespaces=["/admin"]) mock_ack.assert_called_once_with(server_metric_event)
class SocketTaskLog(TaskLog): def __init__(self, uuid, url): self.uuid = uuid self.url = url # self.io = SocketIO(message_queue='redis://') self.io = Client() print(">>> Connecting to {}".format(url)) self.io.connect(url) self.io.emit('task_start', { 'uuid': self.uuid, }) def emit(self, message, data): self.io.emit('task_update', { 'uuid': self.uuid, 'type': message, 'data': data, }) def done(self): time.sleep(1.5) # pause to make sure buffers are flushed self.io.disconnect()
class Model: def __init__(self, render, render_change, endpoint='http://127.0.0.1:5000'): self.endpoint = endpoint self.render = render self.render_change = render_change # self.user = json.loads( # requests.get(f"{endpoint}/register").text)['id'] self.socket = Client(logger=False) self.socket.on('login', self.register_self) self.socket.connect(endpoint) self.socket.emit('login') # def get_data(self): # return json.loads(requests.get(self.endpoint + '/get_data', # data={'id': self.user}).text) def register_self(self, player): # to do this correctly you would need to use rooms self.namespace = f"/data{player}" self.socket = Client(logger=True) # this is bad self.socket.connect(self.endpoint, namespaces=[self.namespace]) self.socket.emit('logged_in', {'id': player}) self.socket.on('start', self.render, namespace=self.namespace) self.socket.on('change', self.render_change, namespace=self.namespace) def send_letter(self, letter): self.socket.emit('type', {'key': letter}, namespace=self.namespace) def remove_letter(self): self.socket.emit('remove', namespace=self.namespace) def publish_current_word(self): self.socket.emit('publish', namespace=self.namespace) def switch_typing_mode(self, event=None): self.socket.emit('toggle', namespace=self.namespace)
class PycilClient: def __init__(self, ip, port): self.ip = ip self.port = port self.socket = Client() @self.socket.on("new_msg") def on_new_msg(msg): remote.ee.emit("new_msg", msg) @remote.ee.on("send_msg") def send_msg(msg): self.socket.emit("send_msg", msg) @remote.ee.on("login") def login(room, name): def cb(data): remote.ee.emit("fetch_data", data) self.socket.emit("login", name, callback=cb) @remote.ee.on("logout") def logout(): self.socket.emit("logout", remote.user["name"]) self.socket.disconnect() @self.socket.on("new_user") def on_new_user(name): remote.ee.emit("new_user", name) @self.socket.on("remove_user") def on_remove_user(name): remote.ee.emit("remove_user", name) def connect(self): self.socket.connect("http://" + self.ip + ":" + str(self.port)) return True
# receiver.py from socketio import Client socketio = Client() socketio.connect("http://*****:*****@socketio.on("message") def on_message(message): jbt = message.get("message") print(jbt) socketio.wait()
class Database: def __init__(self, logger: Logger, config: Config, uri="sqlite:///data/crypto_trading.db"): self.logger = logger self.config = config self.engine = create_engine(uri) self.SessionMaker = sessionmaker(bind=self.engine) self.socketio_client = Client() def socketio_connect(self): if self.socketio_client.connected and self.socketio_client.namespaces: return True try: if not self.socketio_client.connected: self.socketio_client.connect("http://api:5123", namespaces=["/backend"]) while not self.socketio_client.connected or not self.socketio_client.namespaces: time.sleep(0.1) return True except SocketIOConnectionError: return False @contextmanager def db_session(self): """ Creates a context with an open SQLAlchemy session. """ session: Session = scoped_session(self.SessionMaker) yield session session.commit() session.close() def set_coins(self, symbols: List[str]): session: Session # Add coins to the database and set them as enabled or not with self.db_session() as session: # For all the coins in the database, if the symbol no longer appears # in the config file, set the coin as disabled coins: List[Coin] = session.query(Coin).all() for coin in coins: if coin.symbol not in symbols: coin.enabled = False # For all the symbols in the config file, add them to the database # if they don't exist for symbol in symbols: coin = next((coin for coin in coins if coin.symbol == symbol), None) if coin is None: session.add(Coin(symbol)) else: coin.enabled = True # For all the combinations of coins in the database, add a pair to the database with self.db_session() as session: coins: List[Coin] = session.query(Coin).filter(Coin.enabled).all() for from_coin in coins: for to_coin in coins: if from_coin != to_coin: pair = session.query(Pair).filter(Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() if pair is None: session.add(Pair(from_coin, to_coin)) def get_coins(self, only_enabled=True) -> List[Coin]: session: Session with self.db_session() as session: if only_enabled: coins = session.query(Coin).filter(Coin.enabled).all() else: coins = session.query(Coin).all() session.expunge_all() return coins def get_coin(self, coin: Union[Coin, str]) -> Coin: if isinstance(coin, Coin): return coin session: Session with self.db_session() as session: coin = session.query(Coin).get(coin) session.expunge(coin) return coin def set_current_coin(self, coin: Union[Coin, str]): coin = self.get_coin(coin) session: Session with self.db_session() as session: if isinstance(coin, Coin): coin = session.merge(coin) cc = CurrentCoin(coin) session.add(cc) self.send_update(cc) def get_current_coin(self) -> Optional[Coin]: session: Session with self.db_session() as session: current_coin = session.query(CurrentCoin).order_by(CurrentCoin.datetime.desc()).first() if current_coin is None: return None coin = current_coin.coin session.expunge(coin) return coin def get_pair(self, from_coin: Union[Coin, str], to_coin: Union[Coin, str]): from_coin = self.get_coin(from_coin) to_coin = self.get_coin(to_coin) session: Session with self.db_session() as session: pair: Pair = session.query(Pair).filter(Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() session.expunge(pair) return pair def get_pairs_from(self, from_coin: Union[Coin, str], only_enabled=True) -> List[Pair]: from_coin = self.get_coin(from_coin) session: Session with self.db_session() as session: pairs = session.query(Pair).filter(Pair.from_coin == from_coin) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def get_pairs(self, only_enabled=True) -> List[Pair]: session: Session with self.db_session() as session: pairs = session.query(Pair) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def log_scout( self, pair: Pair, target_ratio: float, current_coin_price: float, other_coin_price: float, ): session: Session with self.db_session() as session: pair = session.merge(pair) sh = ScoutHistory(pair, target_ratio, current_coin_price, other_coin_price) session.add(sh) session.commit() #self.send_update(sh) def prune_scout_history(self): time_diff = datetime.now() - timedelta(hours=self.config.SCOUT_HISTORY_PRUNE_TIME) session: Session with self.db_session() as session: session.query(ScoutHistory).filter(ScoutHistory.datetime < time_diff).delete() def prune_value_history(self): session: Session with self.db_session() as session: # Sets the first entry for each coin for each hour as 'hourly' hourly_entries: List[CoinValue] = ( session.query(CoinValue).group_by(CoinValue.coin_id, func.strftime("%H", CoinValue.datetime)).all() ) for entry in hourly_entries: entry.interval = Interval.HOURLY # Sets the first entry for each coin for each day as 'daily' daily_entries: List[CoinValue] = ( session.query(CoinValue).group_by(CoinValue.coin_id, func.date(CoinValue.datetime)).all() ) for entry in daily_entries: entry.interval = Interval.DAILY # Sets the first entry for each coin for each month as 'weekly' # (Sunday is the start of the week) weekly_entries: List[CoinValue] = ( session.query(CoinValue).group_by(CoinValue.coin_id, func.strftime("%Y-%W", CoinValue.datetime)).all() ) for entry in weekly_entries: entry.interval = Interval.WEEKLY # The last 24 hours worth of minutely entries will be kept, so # count(coins) * 1440 entries time_diff = datetime.now() - timedelta(hours=24) session.query(CoinValue).filter( CoinValue.interval == Interval.MINUTELY, CoinValue.datetime < time_diff ).delete() # The last 28 days worth of hourly entries will be kept, so count(coins) * 672 entries time_diff = datetime.now() - timedelta(days=28) session.query(CoinValue).filter( CoinValue.interval == Interval.HOURLY, CoinValue.datetime < time_diff ).delete() # The last years worth of daily entries will be kept, so count(coins) * 365 entries time_diff = datetime.now() - timedelta(days=365) session.query(CoinValue).filter( CoinValue.interval == Interval.DAILY, CoinValue.datetime < time_diff ).delete() # All weekly entries will be kept forever def create_database(self): Base.metadata.create_all(self.engine) def start_trade_log(self, from_coin: Coin, to_coin: Coin, selling: bool): return TradeLog(self, from_coin, to_coin, selling) def get_last_trade(self, previous_trade:Trade=None): session: Session with self.db_session() as session: last_trade = session.query(Trade).filter( Trade.crypto_trade_amount is not None, Trade.state == "COMPLETE", Trade.selling == "0" ) if previous_trade is not None: last_trade = last_trade.filter(Trade.alt_coin_id == previous_trade.alt_coin_id, Trade.datetime < previous_trade.datetime) last_trade = last_trade.order_by(Trade.datetime.desc()) last_trade = last_trade.first() session.expunge_all() return last_trade def send_update(self, model): if not self.socketio_connect(): return self.socketio_client.emit( "update", {"table": model.__tablename__, "data": model.info()}, namespace="/backend", ) def migrate_old_state(self): """ For migrating from old dotfile format to SQL db. This method should be removed in the future. """ if os.path.isfile(".current_coin"): with open(".current_coin") as f: coin = f.read().strip() self.logger.info(f".current_coin file found, loading current coin {coin}") self.set_current_coin(coin) os.rename(".current_coin", ".current_coin.old") self.logger.info(f".current_coin renamed to .current_coin.old - You can now delete this file") if os.path.isfile(".current_coin_table"): with open(".current_coin_table") as f: self.logger.info(f".current_coin_table file found, loading into database") table: dict = json.load(f) session: Session with self.db_session() as session: for from_coin, to_coin_dict in table.items(): for to_coin, ratio in to_coin_dict.items(): if from_coin == to_coin: continue pair = session.merge(self.get_pair(from_coin, to_coin)) pair.ratio = ratio session.add(pair) os.rename(".current_coin_table", ".current_coin_table.old") self.logger.info(".current_coin_table renamed to .current_coin_table.old - " "You can now delete this file")
from socketio import Client from time import sleep c = Client() c.connect('http://*****:*****@c.on('new_hand', namespace='/event') def event(data): print('new_hand') print(data) c.emit('new_hand', data={ 'user_id': 'hoge', 'room_id': 'fuga', 'hand': 1 }, namespace='/event')
sio.emit("updated_targets", ans, namespace="/sensor") url = config['hub_url'] + "/sensor?api_key=" + config["api_key"] connected = False delay = 1 device = DefaultDevice() device.load_from_config(config) print("Starting") while True: if not connected: try: sio.connect(url) print("Connected and working") connected = True except ConnectionError as e: print(e) print(f"Connection to {url} failed, try again after delay") connected = False try: start = time.time() data = device.get_sensor_values() print(data) if connected: print("Sending", data) sio.emit("new_data", {"data": data}, namespace="/sensor")
send('is-provisioned', ssh=ssh, web=web, web_ro=web_ro) elif data['state'] == 'want-deprovision': print('Server wants a deprovision') if is_provisioned: print('Deprovisioning...') code = run_external(['deprovision.sh']) if code: print('ERROR: deprovision.sh failed with exit code %d' % code, file=sys.stderr) send('deprovision-failed') return is_provisioned = False else: print('Already deprovisioned, nothing to do') send('is-deprovisioned') elif data['state'] == 'update-expiration': print('Updating expiration timestamp') with open(os.environ['EXPIRATION_TIMESTAMP'], 'w') as f: f.write(str(int(data['expiration']))) def send(state, **kwargs): kwargs['state'] = state print('Sending %r to server' % kwargs) c.send(kwargs, namespace='/device') c.connect('https://localhost:5000', headers=auth_hdr) c.wait() sys.exit(error)
class Database: def __init__(self, logger: Logger, config: Config, uri="sqlite:///data/crypto_trading.db", isTest=False): self.logger = logger self.config = config self.engine = create_engine(uri) self.session_factory = scoped_session(sessionmaker(bind=self.engine)) self.socketio_client = Client() self.isTest = isTest def socketio_connect(self): if self.isTest: return False if self.socketio_client.connected and self.socketio_client.namespaces: return True try: if not self.socketio_client.connected: self.socketio_client.connect("http://api:5123", namespaces=["/backend"]) while not self.socketio_client.connected or not self.socketio_client.namespaces: time.sleep(0.1) return True except SocketIOConnectionError: return False @contextmanager def db_session(self): """ Creates a context with an open SQLAlchemy session. """ session: Session = self.session_factory() yield session session.commit() session.close() def set_coins(self, symbols: List[str]): session: Session # Add coins to the database and set them as enabled or not with self.db_session() as session: # For all the coins in the database, if the symbol no longer appears # in the config file, set the coin as disabled coins: List[Coin] = session.query(Coin).all() for coin in coins: if coin.symbol not in symbols: coin.enabled = False # For all the symbols in the config file, add them to the database # if they don't exist for symbol in symbols: coin = next((coin for coin in coins if coin.symbol == symbol), None) if coin is None: session.add(Coin(symbol)) else: coin.enabled = True # For all the combinations of coins in the database, add a pair to the database with self.db_session() as session: coins: List[Coin] = session.query(Coin).filter(Coin.enabled).all() for from_coin in coins: for to_coin in coins: if from_coin != to_coin: pair = session.query(Pair).filter( Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() if pair is None: session.add(Pair(from_coin, to_coin)) def get_coins(self, only_enabled=True) -> List[Coin]: session: Session with self.db_session() as session: if only_enabled: coins = session.query(Coin).filter(Coin.enabled).all() else: coins = session.query(Coin).all() session.expunge_all() return coins def get_coin(self, coin: Union[Coin, str]) -> Coin: if isinstance(coin, Coin): return coin session: Session with self.db_session() as session: coin = session.query(Coin).get(coin) session.expunge(coin) return coin def set_current_coin(self, coin: Union[Coin, str]): coin = self.get_coin(coin) session: Session with self.db_session() as session: if isinstance(coin, Coin): coin = session.merge(coin) cc = CurrentCoin(coin) session.add(cc) self.send_update(cc) def get_current_coin(self) -> Optional[Coin]: session: Session with self.db_session() as session: current_coin = session.query(CurrentCoin).order_by( CurrentCoin.datetime.desc()).first() if current_coin is None: return None coin = current_coin.coin session.expunge(coin) return coin def get_pair(self, from_coin: Union[Coin, str], to_coin: Union[Coin, str]): from_coin = self.get_coin(from_coin) to_coin = self.get_coin(to_coin) session: Session with self.db_session() as session: pair: Pair = session.query(Pair).filter( Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() session.expunge(pair) return pair def get_pairs_from(self, from_coin: Union[Coin, str], only_enabled=True) -> List[Pair]: from_coin = self.get_coin(from_coin) session: Session with self.db_session() as session: pairs = session.query(Pair).filter(Pair.from_coin == from_coin) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def get_pairs(self, only_enabled=True) -> List[Pair]: session: Session with self.db_session() as session: pairs = session.query(Pair) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def batch_log_scout(self, logs: List[LogScout]): session: Session with self.db_session() as session: dt = datetime.now() session.execute( insert(ScoutHistory), [{ "pair_id": ls.pair.id, "target_ratio": ls.target_ratio, "current_coin_price": ls.coin_price, "other_coin_price": ls.optional_coin_price, "datetime": dt, } for ls in logs], ) def log_scout( self, pair: Pair, target_ratio: float, current_coin_price: float, other_coin_price: float, ): session: Session with self.db_session() as session: pair = session.merge(pair) sh = ScoutHistory(pair, target_ratio, current_coin_price, other_coin_price) session.add(sh) self.send_update(sh) def prune_scout_history(self): time_diff = datetime.now() - timedelta( hours=self.config.SCOUT_HISTORY_PRUNE_TIME) session: Session with self.db_session() as session: session.query(ScoutHistory).filter( ScoutHistory.datetime < time_diff).delete() def prune_value_history(self): session: Session with self.db_session() as session: session.query(CoinValue).delete() def create_database(self): Base.metadata.create_all(self.engine) def start_trade_log(self, from_coin: Coin, to_coin: Coin, selling: bool): return TradeLog(self, from_coin, to_coin, selling) def send_update(self, model): if not self.socketio_connect(): return self.socketio_client.emit( "update", { "table": model.__tablename__, "data": model.info() }, namespace="/backend", ) def migrate_old_state(self): """ For migrating from old dotfile format to SQL db. This method should be removed in the future. """ if os.path.isfile(".current_coin"): with open(".current_coin") as f: coin = f.read().strip() self.logger.info( f".current_coin file found, loading current coin {coin}") self.set_current_coin(coin) os.rename(".current_coin", ".current_coin.old") self.logger.info( ".current_coin renamed to .current_coin.old - You can now delete this file" ) if os.path.isfile(".current_coin_table"): with open(".current_coin_table") as f: self.logger.info( ".current_coin_table file found, loading into database") table: dict = json.load(f) session: Session with self.db_session() as session: for from_coin, to_coin_dict in table.items(): for to_coin, ratio in to_coin_dict.items(): if from_coin == to_coin: continue pair = session.merge( self.get_pair(from_coin, to_coin)) pair.ratio = ratio session.add(pair) os.rename(".current_coin_table", ".current_coin_table.old") self.logger.info( ".current_coin_table renamed to .current_coin_table.old - " "You can now delete this file") def batch_update_coin_values(self, cv_batch: List[CoinValue]): session: Session with self.db_session() as session: session.execute( insert(CoinValue), [{ "coin_id": cv.coin.symbol, "balance": cv.balance, "usd_price": cv.usd_price, "btc_price": cv.btc_price, "interval": cv.interval, "datetime": cv.datetime, } for cv in cv_batch], )
#!/usr/bin/env python """ [WHEN TO USE THIS FILE] [INSTRUCTIONS FOR USING THIS FILE] Project name: [MISSING] Author: Micah Parks This lives on the web at: [MISSING URL] Target environment: python 3.7 """ # Start standard library imports. # End standard library imports. # Start third party imports. # End third party imports. # Start project imports. from socketio import Client # End project imports. if __name__ == '__main__': clientObj = Client() clientObj.connect('http://localhost:5000') # for a in range(1000): clientObj.emit('flarba', {'foo': 'bar'}, namespace='/narba')
def _scenario_task(self) -> None: client = Client() client.connect(os.environ[ENV_LOAD_TEST_TARGET_URL]) client.emit("session_request") runner.run(scenario, client)
import requests import subprocess import os import json from socketio import Client as SocketClient from bs4 import BeautifulSoup import getFromPath dir_path = os.path.dirname(os.path.realpath(__file__)) player = subprocess.Popen( [os.path.join(dir_path, 'player\\youtubecli-win32-x64\\youtubecli.exe')], stdout=subprocess.PIPE, stdin=subprocess.PIPE) playerSocket = SocketClient() playerSocket.connect('http://localhost:8081') scraper = requests.Session() scraper.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36' } filters = {'video': 'EgIQAQ==', 'channel': 'EgIQAg==', 'playlist': 'EgIQAw=='} commands = ['play', 'pause', 'forward', 'rewind', 'volumeUp', 'volumeDown'] BLANK_ROW = '|' + ('-' * 3) + '|' + ('-' * 94) + '|\n' def main(): try:
def on_disconnect(self): print('on_disconnect') def get_current_price(self): tickers = pyupbit.get_tickers(fiat="KRW") while True: markets = pyupbit.get_current_price(tickers) client.emit( "send_price", dict(tickers=tickers, markets=markets, size=len(markets))) time.sleep(1) client = UpbitClientNamespace('/upbit') sio = Client() sio.register_namespace(client) sio.connect('http://localhost:3000', namespaces=['/upbit']) sio.start_background_task(client.get_current_price) print(sio.connected) print(sio.connection_namespaces) try: sio.wait() except KeyboardInterrupt as e: if sio.connected: sio.disconnect()
define("ip", default='127.0.0.1', help="Server IP to connect to, default 127.0.0.1") define("verbose", default=False, help="verbose") options.parse_command_line( final=False ) # final False is required or it activates the client logger. if options.ip != '127.0.0.1': URL = "ws://{}:{}/chat/".format(options.ip, DEFAULT_PORT) print("Using {}".format(URL)) # See options https://python-socketio.readthedocs.io/en/latest/api.html sio = Client(logger=False) sio.register_namespace(ChatNamespace('/chat')) sio.connect('http://{}:{}'.format(options.ip, DEFAULT_PORT), namespaces=['/chat']) sleep(1) # not needed # We have to id ourselve first of all sio.emit('hello', data={ "version": 2, "ip": "127.0.0.1", "port": DEFAULT_PORT }, namespace="/chat") # ask the peer active list sio.emit('get_peers', data={}, namespace="/chat") # send the peer our list
class Database: def __init__(self, logger: Logger, config: Config): self.logger = logger self.config = config self.socketio_client = Client() engine_args = {} if not config.DB_URI.startswith("sqlite"): engine_args = {"pool_size": 10, "max_overflow": 20} self.engine = create_engine(config.DB_URI, **engine_args) self.session_factory = sessionmaker(bind=self.engine) self.scoped_session_factory = scoped_session(self.session_factory) def socketio_connect(self): if not self.config.ENABLE_API: return False if self.socketio_client.connected and self.socketio_client.namespaces: return True try: if not self.socketio_client.connected: self.socketio_client.connect("http://api:5123", namespaces=["/backend"]) while not self.socketio_client.connected or not self.socketio_client.namespaces: time.sleep(0.1) return True except SocketIOConnectionError: return False @contextmanager def db_session(self): """ Creates a context with an open SQLAlchemy session. """ session: Session = self.scoped_session_factory() yield session session.commit() session.close() def set_coins(self, symbols: List[str]): session: Session # Add coins to the database and set them as enabled or not with self.db_session() as session: # For all the coins in the database, if the symbol no longer appears # in the config file, set the coin as disabled coins: List[Coin] = session.query(Coin).all() for coin in coins: if coin.symbol not in symbols: coin.enabled = False # For all the symbols in the config file, add them to the database # if they don't exist for symbol in symbols: coin = next((coin for coin in coins if coin.symbol == symbol), None) if coin is None: session.add(Coin(symbol)) else: coin.enabled = True # For all the combinations of coins in the database, add a pair to the database with self.db_session() as session: coins: List[Coin] = session.query(Coin).filter(Coin.enabled).all() for from_coin in coins: for to_coin in coins: if from_coin != to_coin: pair = session.query(Pair).filter( Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() if pair is None: session.add(Pair(from_coin, to_coin)) def get_coins(self, only_enabled=True) -> List[Coin]: session: Session with self.db_session() as session: if only_enabled: coins = session.query(Coin).filter(Coin.enabled).all() else: coins = session.query(Coin).all() session.expunge_all() return coins def get_coin(self, coin: Union[Coin, str]) -> Coin: if isinstance(coin, Coin): return coin session: Session with self.db_session() as session: coin = session.query(Coin).get(coin) session.expunge(coin) return coin def set_current_coin(self, coin: Union[Coin, str]): coin = self.get_coin(coin) session: Session with self.db_session() as session: if isinstance(coin, Coin): coin = session.merge(coin) cc = CurrentCoin(coin) session.add(cc) self.send_update(cc) def get_current_coin(self) -> Optional[Coin]: session: Session with self.db_session() as session: current_coin = session.query(CurrentCoin).order_by( CurrentCoin.datetime.desc()).first() if current_coin is None: return None coin = current_coin.coin session.expunge(coin) return coin def get_current_coin_date(self) -> Optional[datetime]: session: Session with self.db_session() as session: current_coin = session.query(CurrentCoin).order_by( CurrentCoin.datetime.desc()).first() if current_coin is None: return datetime.now() coin_date = current_coin.datetime return coin_date def get_pair(self, from_coin: Union[Coin, str], to_coin: Union[Coin, str]): from_coin = self.get_coin(from_coin) to_coin = self.get_coin(to_coin) session: Session with self.db_session() as session: pair: Pair = session.query(Pair).filter( Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() session.expunge(pair) return pair def get_pairs_from(self, from_coin: Union[Coin, str], only_enabled=True) -> List[Pair]: from_coin = self.get_coin(from_coin) session: Session with self.db_session() as session: pairs = session.query(Pair).filter(Pair.from_coin == from_coin) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def get_pairs(self, only_enabled=True) -> List[Pair]: session: Session with self.db_session() as session: pairs = session.query(Pair) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def log_scout( self, pair: Pair, target_ratio: float, current_coin_price: float, other_coin_price: float, ): session: Session with self.db_session() as session: pair = session.merge(pair) sh = ScoutHistory(pair, target_ratio, current_coin_price, other_coin_price) session.add(sh) self.send_update(sh) def prune_scout_history(self): time_diff = datetime.now() - timedelta( hours=self.config.SCOUT_HISTORY_PRUNE_TIME) session: Session with self.db_session() as session: session.query(ScoutHistory).filter( ScoutHistory.datetime < time_diff).delete() def prune_value_history(self): def _datetime_id_query(default, sqlite): dt_column = if_dialect( default=func.to_char(CoinValue.datetime, default), sqlite=func.strftime(sqlite, CoinValue.datetime), ) grouped = select(CoinValue, func.max(CoinValue.datetime), dt_column).group_by(CoinValue.coin_id, CoinValue, dt_column) return select(grouped.c.id.label("id")).select_from(grouped) def _update_query(datetime_query, interval): return (update(CoinValue).where( CoinValue.id.in_(datetime_query)).values( interval=interval).execution_options( synchronize_session="fetch")) hourly_update_query = _update_query( _datetime_id_query(default="HH24", sqlite="%H"), Interval.HOURLY) weekly_update_query = _update_query( _datetime_id_query(default="YYYY-WW", sqlite="%Y-%W"), Interval.WEEKLY, ) daily_update_query = _update_query( _datetime_id_query(default="YYYY-DDD", sqlite="%Y-%j"), Interval.DAILY, ) session: Session with self.db_session() as session: # Sets the first entry for each coin for each hour as 'hourly' session.execute(hourly_update_query) # Sets the first entry for each coin for each day as 'daily' session.execute(daily_update_query) # Sets the first entry for each coin for each month as 'weekly' # (Sunday is the start of the week) session.execute(weekly_update_query) # Early commit to make sure the delete statements work properly. session.commit() # The last 24 hours worth of minutely entries will be kept, so # count(coins) * 1440 entries time_diff = datetime.now() - timedelta(hours=24) session.query(CoinValue).filter( CoinValue.interval == Interval.MINUTELY, CoinValue.datetime < time_diff).delete() # The last 28 days worth of hourly entries will be kept, so count(coins) * 672 entries time_diff = datetime.now() - timedelta(days=28) session.query(CoinValue).filter( CoinValue.interval == Interval.HOURLY, CoinValue.datetime < time_diff).delete() # The last years worth of daily entries will be kept, so count(coins) * 365 entries time_diff = datetime.now() - timedelta(days=365) session.query(CoinValue).filter( CoinValue.interval == Interval.DAILY, CoinValue.datetime < time_diff).delete() # All weekly entries will be kept forever def create_database(self): Base.metadata.create_all(self.engine) def start_trade_log(self, from_coin: Coin, to_coin: Coin, selling: bool): return TradeLog(self, from_coin, to_coin, selling) def send_update(self, model): if not self.socketio_connect(): return self.socketio_client.emit( "update", { "table": model.__tablename__, "data": model.info() }, namespace="/backend", )
def test_admin_namespace_with_faulty_token(server_url: str, client: socketio.Client): with pytest.raises(socketio_exceptions.ConnectionError): client.connect(f"{server_url}?token=not-admin", namespaces=["/admin"])
class Database: def __init__(self, logger: Logger, config: Config, uri="sqlite:///data/crypto_trading.db"): self.logger = logger self.config = config self.engine = create_engine(uri) self.session_factory = scoped_session(sessionmaker(bind=self.engine)) self.socketio_client = Client() def socketio_connect(self): if self.socketio_client.connected and self.socketio_client.namespaces: return True try: if not self.socketio_client.connected: self.socketio_client.connect("http://api:5123", namespaces=["/backend"]) while not self.socketio_client.connected or not self.socketio_client.namespaces: time.sleep(0.1) return True except SocketIOConnectionError: return False @contextmanager def db_session(self): """ Creates a context with an open SQLAlchemy session. """ session: Session = self.session_factory() yield session session.commit() session.close() def set_coins(self, symbols: List[str]): session: Session # Add coins to the database and set them as enabled or not with self.db_session() as session: # For all the coins in the database, if the symbol no longer appears # in the config file, set the coin as disabled coins: List[Coin] = session.query(Coin).all() for coin in coins: if coin.symbol not in symbols: coin.enabled = False # For all the symbols in the config file, add them to the database # if they don't exist for symbol in symbols: coin = next((coin for coin in coins if coin.symbol == symbol), None) if coin is None: session.add(Coin(symbol)) else: coin.enabled = True # For all the combinations of coins in the database, add a pair to the database with self.db_session() as session: coins: List[Coin] = session.query(Coin).filter(Coin.enabled).all() for from_coin in coins: for to_coin in coins: if from_coin != to_coin: pair = session.query(Pair).filter( Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() if pair is None: session.add(Pair(from_coin, to_coin)) def get_coins(self, only_enabled=True) -> List[Coin]: session: Session with self.db_session() as session: if only_enabled: coins = session.query(Coin).filter(Coin.enabled).all() else: coins = session.query(Coin).all() session.expunge_all() return coins def get_coin(self, coin: Union[Coin, str]) -> Coin: if isinstance(coin, Coin): return coin session: Session with self.db_session() as session: coin = session.query(Coin).get(coin) session.expunge(coin) return coin def set_current_coin(self, coin: Union[Coin, str]): coin = self.get_coin(coin) session: Session with self.db_session() as session: if isinstance(coin, Coin): coin = session.merge(coin) cc = CurrentCoin(coin) session.add(cc) self.send_update(cc) def get_current_coin(self) -> Optional[Coin]: session: Session with self.db_session() as session: current_coin = session.query(CurrentCoin).order_by( CurrentCoin.datetime.desc()).first() if current_coin is None: return None coin = current_coin.coin session.expunge(coin) return coin def get_pair(self, from_coin: Union[Coin, str], to_coin: Union[Coin, str]): from_coin = self.get_coin(from_coin) to_coin = self.get_coin(to_coin) session: Session with self.db_session() as session: pair: Pair = session.query(Pair).filter( Pair.from_coin == from_coin, Pair.to_coin == to_coin).first() session.expunge(pair) return pair def get_pairs_from(self, from_coin: Union[Coin, str], only_enabled=True) -> List[Pair]: from_coin = self.get_coin(from_coin) session: Session with self.db_session() as session: pairs = session.query(Pair).filter(Pair.from_coin == from_coin) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def get_pairs(self, only_enabled=True) -> List[Pair]: session: Session with self.db_session() as session: pairs = session.query(Pair) if only_enabled: pairs = pairs.filter(Pair.enabled.is_(True)) pairs = pairs.all() session.expunge_all() return pairs def batch_log_scout(self, logs: List[LogScout]): session: Session with self.db_session() as session: dt = datetime.now() session.execute( insert(ScoutHistory), [{ "pair_id": ls.pair.id, "target_ratio": ls.target_ratio, "current_coin_price": ls.coin_price, "other_coin_price": ls.optional_coin_price, "datetime": dt, } for ls in logs], ) def log_scout( self, pair: Pair, target_ratio: float, current_coin_price: float, other_coin_price: float, ): session: Session with self.db_session() as session: pair = session.merge(pair) sh = ScoutHistory(pair, target_ratio, current_coin_price, other_coin_price) session.add(sh) self.send_update(sh) def prune_scout_history(self): time_diff = datetime.now() - timedelta( hours=self.config.SCOUT_HISTORY_PRUNE_TIME) session: Session with self.db_session() as session: session.query(ScoutHistory).filter( ScoutHistory.datetime < time_diff).delete() def prune_value_history(self): def _datetime_id_query(dt_format): dt_column = func.strftime(dt_format, CoinValue.datetime) grouped = select(CoinValue, func.max(CoinValue.datetime), dt_column).group_by(CoinValue.coin_id, CoinValue, dt_column) return select(grouped.c.id.label("id")).select_from(grouped) def _update_query(datetime_query, interval): return (update(CoinValue).where( CoinValue.id.in_(datetime_query)).values( interval=interval).execution_options( synchronize_session="fetch")) # Sets the first entry for each coin for each hour as 'hourly' hourly_update_query = _update_query(_datetime_id_query("%H"), Interval.HOURLY) # Sets the first entry for each coin for each month as 'weekly' # (Sunday is the start of the week) weekly_update_query = _update_query( _datetime_id_query("%Y-%W"), Interval.WEEKLY, ) # Sets the first entry for each coin for each day as 'daily' daily_update_query = _update_query( _datetime_id_query("%Y-%j"), Interval.DAILY, ) session: Session with self.db_session() as session: session.execute(hourly_update_query) session.execute(daily_update_query) session.execute(weekly_update_query) # Early commit to make sure the delete statements work properly. session.commit() # The last 24 hours worth of minutely entries will be kept, so # count(coins) * 1440 entries time_diff = datetime.now() - timedelta(hours=24) session.query(CoinValue).filter( CoinValue.interval == Interval.MINUTELY, CoinValue.datetime < time_diff).delete() # The last 28 days worth of hourly entries will be kept, so count(coins) * 672 entries time_diff = datetime.now() - timedelta(days=28) session.query(CoinValue).filter( CoinValue.interval == Interval.HOURLY, CoinValue.datetime < time_diff).delete() # The last years worth of daily entries will be kept, so count(coins) * 365 entries time_diff = datetime.now() - timedelta(days=365) session.query(CoinValue).filter( CoinValue.interval == Interval.DAILY, CoinValue.datetime < time_diff).delete() # All weekly entries will be kept forever def create_database(self): Base.metadata.create_all(self.engine) def start_trade_log(self, from_coin: Coin, to_coin: Coin, selling: bool): return TradeLog(self, from_coin, to_coin, selling) def send_update(self, model): if not self.socketio_connect(): return self.socketio_client.emit( "update", { "table": model.__tablename__, "data": model.info() }, namespace="/backend", ) def migrate_old_state(self): """ For migrating from old dotfile format to SQL db. This method should be removed in the future. """ if os.path.isfile(".current_coin"): with open(".current_coin") as f: coin = f.read().strip() self.logger.info( f".current_coin file found, loading current coin {coin}") self.set_current_coin(coin) os.rename(".current_coin", ".current_coin.old") self.logger.info( ".current_coin renamed to .current_coin.old - You can now delete this file" ) if os.path.isfile(".current_coin_table"): with open(".current_coin_table") as f: self.logger.info( ".current_coin_table file found, loading into database") table: dict = json.load(f) session: Session with self.db_session() as session: for from_coin, to_coin_dict in table.items(): for to_coin, ratio in to_coin_dict.items(): if from_coin == to_coin: continue pair = session.merge( self.get_pair(from_coin, to_coin)) pair.ratio = ratio session.add(pair) os.rename(".current_coin_table", ".current_coin_table.old") self.logger.info( ".current_coin_table renamed to .current_coin_table.old - " "You can now delete this file") def batch_update_coin_values(self, cv_batch: List[CoinValue]): session: Session with self.db_session() as session: session.execute( insert(CoinValue), [{ "coin_id": cv.coin.symbol, "balance": cv.balance, "usd_price": cv.usd_price, "btc_price": cv.btc_price, "interval": cv.interval, "datetime": cv.datetime, } for cv in cv_batch], )
def test_automatic_mock_event_emission( server_url_fixture: str, mock_client_wait_timeout: float, mock_client_wait_interval: float, client: socketio.Client, request: pytest.FixtureRequest, ): server_url: str = request.getfixturevalue(server_url_fixture) new_message_event = "new message" new_message_mock_ack = Mock() @client.on(new_message_event) def _new_message_handler(data): jsonschema.validate(data, { "username": { "type": "string" }, "message": { "type": "string" } }) # Assert that message is of sentence format: assert data["message"].endswith(".") assert " " in data["message"] # Assert that username is a first name: assert data["username"].istitle() new_message_mock_ack(new_message_event) typing_event = "typing" typing_mock_ack = Mock() @client.on(typing_event) def _typing_handler(data): jsonschema.validate(data, {"username": {"type": "string"}}) # Assert that username is a first name: assert data["username"].istitle() typing_mock_ack(typing_event) user_joined_event = "user joined" user_joined_mock_ack = Mock() @client.on(user_joined_event) def _user_joined_handler(data): jsonschema.validate(data, { "username": { "type": "string" }, "numUsers": { "type": "integer" } }) # Assert that username is a first name: assert data["username"].istitle() user_joined_mock_ack(user_joined_event) client.connect(server_url, wait_timeout=mock_client_wait_timeout) # Wait for all messages to arrive: client.sleep(mock_client_wait_interval) new_message_mock_ack.assert_called_with(new_message_event) typing_mock_ack.assert_called_with(typing_event) user_joined_mock_ack.assert_called_with(user_joined_event)
continue parts = command_str.split(' ') command_name = parts[0] if command_name == 'list-room': sio.emit('list_room', callback=on_list_room_result) elif command_name == 'join-room': room_name = parts[-1] sio.emit('join_room', data=room_name, callback=on_status) elif command_name == 'leave-room': sio.emit('leave_room', callback=on_status) elif command_name == 'ready': sio.emit('ready', callback=on_status) elif command_name == 'quit' or command_name == 'exit': break else: sio.emit('command', data=command_str, callback=on_status) if __name__ == '__main__': parser = ArgumentParser() parser.add_argument('username', type=str) args = parser.parse_args() url = f'http://{HOST}:{PORT}' sid = sio.connect(url, auth={'username': args.username}) sio.start_background_task(cli, args.username) sio.wait()