|
| 1 | +#!/usr/bin/python |
| 2 | + |
| 3 | +import os, sys, getopt, daemon, time, datetime, signal, pwd, getpass, pickle |
| 4 | +import json, requests |
| 5 | + |
| 6 | +version = "0.1.0" |
| 7 | +api_url = "https://api.bitfinex.com/v1/trades/btcusd?timestamp=%d" |
| 8 | +cfg = { 'poll':60, 'log':sys.argv[0]+'.json', 'pid':sys.argv[0]+'.pid' } |
| 9 | + |
| 10 | +def main(): |
| 11 | + if not 'last' in cfg: |
| 12 | + resetlog() |
| 13 | + if cfg['debug']: |
| 14 | + try: |
| 15 | + run() |
| 16 | + except KeyboardInterrupt: |
| 17 | + sys.exit(1) |
| 18 | + else: |
| 19 | + with daemon.DaemonContext(working_directory='.', stdout=open(sys.argv[0]+'.log','a'), stderr=open(sys.argv[0]+'.log','a'), |
| 20 | + signal_map={signal.SIGTERM:sigterm}): |
| 21 | + run() |
| 22 | + |
| 23 | +def run(): |
| 24 | + print logts(), "Started pid:", os.getpid() |
| 25 | + with file(cfg['pid'],'w') as f: f.write(str(os.getpid())) |
| 26 | + sys.stdout.flush() |
| 27 | + while 1: |
| 28 | + update() |
| 29 | + sys.stdout.flush() |
| 30 | + time.sleep(cfg['poll']) |
| 31 | + |
| 32 | +def update(): |
| 33 | + try: |
| 34 | + r = requests.get(api_url % cfg['last']['timestamp']) |
| 35 | + if r.status_code == requests.codes.ok: |
| 36 | + data = r.json() |
| 37 | + if data[0]: |
| 38 | + with open(cfg['log'], "r+") as f: |
| 39 | + f.seek (-1, os.SEEK_END) |
| 40 | + if cfg['last']['tid'] > 0: |
| 41 | + f.write(',') |
| 42 | + for trade in data[::-1]: |
| 43 | + if trade['tid'] > cfg['last']['tid']: |
| 44 | + f.write(json.dumps(trade)) |
| 45 | + f.write(',') |
| 46 | + f.seek (-1, os.SEEK_END) |
| 47 | + f.write(']') |
| 48 | + cfg['last'] = data[0] |
| 49 | + savecfg() |
| 50 | + print logts(), "Updated tid:", cfg['last']['tid'] |
| 51 | + except requests.exceptions.ConnectionError: |
| 52 | + pass |
| 53 | + |
| 54 | +def loadcfg(): |
| 55 | + global cfg |
| 56 | + try: |
| 57 | + with open(sys.argv[0]+'.cfg') as f: |
| 58 | + cfg = pickle.load(f) |
| 59 | + except IOError: |
| 60 | + print logts(),'No cfg file.\n', |
| 61 | + finally: |
| 62 | + cfg['debug'] = False |
| 63 | + options() |
| 64 | + |
| 65 | +def savecfg(): |
| 66 | + try: |
| 67 | + with open(sys.argv[0]+'.cfg', 'w') as f: |
| 68 | + pickle.dump(cfg, f) |
| 69 | + except IOError: |
| 70 | + print logts(),'Cannot save cfg file' |
| 71 | + |
| 72 | +def options(): |
| 73 | + try: |
| 74 | + opts,args = getopt.getopt(sys.argv[1:], "hvrp:u:l:i:s", |
| 75 | + ["help", "version", "debug", "reset", "poll=", "user=", "log=", "pid=", "defaults" ]) |
| 76 | + except getopt.GetoptError: |
| 77 | + usage() |
| 78 | + for opt,arg in opts: |
| 79 | + if opt in ("-h", "--help"): |
| 80 | + usage() |
| 81 | + elif opt in ("-v", "--version"): |
| 82 | + sys.exit('Version: '+version) |
| 83 | + elif opt in ("-p", "--poll"): |
| 84 | + cfg['poll'] = int(arg) |
| 85 | + elif opt in ("-u", "--user"): |
| 86 | + cfg['user'] = arg |
| 87 | + elif opt in ("-l", "--log"): |
| 88 | + cfg['log'] = arg |
| 89 | + elif opt in ("-i", "--pid"): |
| 90 | + cfg['pid'] = arg |
| 91 | + elif opt in ("-r", "--reset"): |
| 92 | + resetlog() |
| 93 | + elif opt in ("-s", "--defaults"): |
| 94 | + savecfg() |
| 95 | + print "%s updated" % (sys.argv[0]+'.cfg') |
| 96 | + sys.exit() |
| 97 | + elif opt in ("--debug"): |
| 98 | + cfg['debug'] = True |
| 99 | + |
| 100 | +def usage(): |
| 101 | + print """Command options are:\n-h,--help\tShow this help info\n-v,--version\tShow version info\n-s,--defaults\tUpdate cfg and exit\n |
| 102 | +Cfg file is %s.cfg\nThese options get saved in cfg file as default.\n-r,--reset\tReset last trade id to 0, truncate log file\n |
| 103 | +-p,--poll\tPoll interval in seconds\n-u,--user\tRun as user\n-l,--log\tSet log file path |
| 104 | +-i,--pid\tSet pid file path""" % sys.argv[0] |
| 105 | + sys.exit(1) |
| 106 | + |
| 107 | +def sigterm(signum, frame): |
| 108 | + print "%s SIGTERM - Shutting down" % logts() |
| 109 | + os.unlink(cfg['pid']) |
| 110 | + sys.exit(2) |
| 111 | + |
| 112 | +def logts(): |
| 113 | + return datetime.datetime.now().strftime('%d-%m-%Y %H:%M:%S') |
| 114 | + |
| 115 | +def resetlog(): |
| 116 | + cfg['last'] = { 'timestamp':0, 'tid':0 } |
| 117 | + savecfg() |
| 118 | + with open(cfg['log'], "w") as f: |
| 119 | + f.write("[]") |
| 120 | + |
| 121 | +if __name__ == '__main__': |
| 122 | + loadcfg() |
| 123 | + if 'user' in cfg: |
| 124 | + print logts(),"Running as:",cfg['user'] |
| 125 | + uid = pwd.getpwnam(cfg['user']).pw_uid |
| 126 | + os.setgid(uid) |
| 127 | + os.setuid(uid) |
| 128 | + |
| 129 | + main() |
| 130 | + |
0 commit comments