#!/usr/bin/python3
#-*- coding: utf-8 -*-
##############################################
# Home	: http://netkiller.github.io
# Author: Neo <netkiller@msn.com>
##############################################

try:
	import time
	import os, sys
	import hashlib
	import socket
	import logging,logging.handlers
	from optparse import OptionParser
except ImportError as err:
	print("Error: %s" %(err))

class Logpush():
	def __init__(self):
		self.line_terminators = ('\r\n', '\n', '\r')
		self.postion = False
	def errlog(self, file):
		log = None
		try:
			logging.basicConfig(
				level=logging.NOTSET,
				format='%(asctime)s %(levelname)-8s %(message)s',
				datefmt='%Y-%m-%d %H:%M:%S',
				filename=file,
				filemode='a'
			)
			log = logging.getLogger()
			handler = logging.handlers.TimedRotatingFileHandler(file, 'M', 1, 0)
			#handler.suffix = "%Y-%m-%d.%H-%M.log"
			handler.suffix = "%Y-%m-%d.log"
			log.addHandler(handler)
		except AttributeError as err:
			print("Error: %s %s" %(err, file))
			sys.exit(2)
		except FileNotFoundError as err:
			print("Error: %s %s" %(err, file))
			sys.exit(2)
		except PermissionError as err:
			print("Error: %s %s" %(err, file))
			sys.exit(2)
		return(log)
		
	def follow(self, filepath):
		self.file = open(filepath, 'rb')
		self.file.seek(0, 2)
		while 1:
			where = self.file.tell()
			line = self.file.readline()
			if line :
				print(line.decode("utf-8").strip(''), end='')
			else:
				if where < self.file.tell() :
					self.file.seek(where)
				else:
					self.file.seek(self.file.tell())
				time.sleep(1)
	def sendto(self, host, port, sleep, filepath, daemon = False, full=False):
		sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		self.log.info("connect: %s, port: %s, sleep: %s, logfile: %s, full text: %s" % (host, str(port), str(sleep), filepath, full) )
		
		m = hashlib.md5()
		m.update(filepath.encode('utf-8'))
		postion_file = '/dev/shm/'+str(port)+'-'+str(m.hexdigest())+'.pos'
		
		while True:
			if os.path.isfile(filepath):
				self.file = open(filepath, 'rb')
				size = os.stat(filepath).st_size
			else:
				time.sleep(1)
				continue
			#mtime = os.stat(filepath).st_mtime
			#ctime = os.stat(filepath).st_ctime
			#print(ctime, mtime)
			#print(os.path.getmtime(filepath))
			#self.log.info("%s: , %s, %s" % (filepath, str(ctime), str(mtime) ) )
			self.log.info("open file: %s, size: %s" % (filepath, str(size) ) )

			if full :
				self.file.seek(0, 0)
				self.log.info("full text %s %s" % (filepath, str(port)) )
			else:
				if self.postion and os.path.isfile(postion_file):
					with open(postion_file, 'r') as pos:
						postion = int(pos.readline())
					if postion :
						self.file.seek(postion)	
						self.log.info("open postion %s %s %s." % (filepath, str(port), str(postion)) )
					else:
						self.file.seek(0, os.SEEK_END)
						self.log.info("reset postion seek end %s %s" % (filepath, str(port)) )
				else:			
					self.file.seek(0, 2)
					self.log.info("seek end %s %s" % (filepath, str(port)) )
					
			while True:
				postion = self.file.tell()
				line = self.file.readline()
				if line :
					if not daemon :
						print(line.decode("utf-8").strip(''), end='')
					sock.sendto(line, (host, port))
					if self.postion :
						#if postion != self.file.tell() :
						with open(postion_file, 'w') as pos:
							pos.write(str(self.file.tell()))
							pos.close()
						self.log.info("save postion %s %s %s." % (filepath, str(port), str(postion)) )
					time.sleep(sleep)
					#self.log.info("%s: %s" % (filepath, str(where)) )
				else:
					self.file.seek(postion)					
					if not os.path.isfile(filepath):
						self.file.close()
						full = True
						self.log.warning("%s is removed." % (filepath) )
						break
					else:
						curr_size = os.stat(filepath).st_size
						if size > curr_size : 
							self.log.warning("%s: size %s, current: %s" % (filepath, str(size), str(curr_size)) )
							self.file.close()
							full = True
							break
							#continue
					time.sleep(1)
					#sock.sendto(bytes("-----\n","utf8"), (host, port))
					#time.sleep(sleep)

	def stdin(self, host, port, sleep, daemon = False,):
		sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		line = ' '
		while line:
			line = sys.stdin.readline()
			if not daemon :
				print(line, end='')
			sock.sendto(bytes(line,"utf8"), (host, port))
			#time.sleep(sleep)
		
	def usage(self):
		print("\n  Homepage: https://www.netkiller.cn\tAuthor: Neo <netkiller@msn.com>")				
	def main(self):
		try:
			parser = OptionParser(usage='usage: %prog [options] filename')
			parser.add_option('-H', '--host', dest='host', default='', metavar='localhost', type='str', help='push log to remote host')
			parser.add_option('-p', '--port', dest='port', default=1214, metavar='1214', type='int',  help='port')
			parser.add_option('', '--sleep', dest='sleep', default=0.05, metavar='0.05', type='float',
						  help='with -s, sleep  for  approximately S  seconds between iterations')
			parser.add_option('-d','--daemon', dest='daemon', default=False, action='store_true', help='run as daemon')						  
			parser.add_option('-f', '--full', dest='full', default=False, action='store_true', help='Full text')
			parser.add_option('', '--stdin', dest='stdin', default=False, action='store_true', help='cat file | prog ...')
			parser.add_option('-e', '--errlog', dest='errlog', default='/tmp/rlog.log', metavar='/tmp/rlog.log', type='string',help='error log')
			parser.add_option('', '--postion', dest='postion', default=False, action='store_true', help='save postion of log file')
			
			(options, args) = parser.parse_args()

			self.log = self.errlog(options.errlog)
			
			if not (len(args) == 1) :
				if options.stdin :
					self.stdin(options.host, options.port, options.sleep, options.daemon)
				else:
					parser.print_help()
					self.usage()
					sys.exit(1)
			else:
				if options.host and options.port:
					if options.daemon:
						pid = os.fork()
						if pid > 0:
							sys.exit(0)
					self.postion = options.postion
					self.sendto(options.host, options.port, options.sleep, args[0], options.daemon, options.full)
				else:
					self.follow(args[0])

		except Exception as err:
			print("Error: %s %s" %(err, ''))
			sys.exit(1)
		
if __name__ == '__main__':
	try:
		log = Logpush()
		log.main()
	except KeyboardInterrupt:
		print ("Crtl+C Pressed. Shutting down.")