twisted实现的Redis服务器

来源:互联网 发布:抱抱软件安全吗 编辑:程序博客网 时间:2024/05/04 11:56
  1. -*- coding: utf--*-

  2. from twisted.internet import reactor

  3. from twisted.internet.protocol import ServerFactory

  4. from twisted.protocols.basic import LineReceiver

  5. import fnmatch

  6. import shlex

  7. import time



  8. class Error(Exception): pass

  9. class WrongNumberArgumentsError(Error): pass

  10. class WrongValueTypeError(Error): pass



  11. class RObj:

  12.     __slots__ = 'type', 'expireAt', 'value' 



  13.     type = 'string'

  14.     expireAt = None



  15.     def __init__(self, value):

  16.         self.value = value



  17. class RedisServerProtocol(LineReceiver):

  18.     def __init__(self):

  19.         self.argc = 0 # 参数个数

  20.         self.argl = 0 # 参数长度

  21.         self.argv = [] # 参数数组



  22.     def connectionMade(self):

  23.         self.SELECT(['', '0'])



  24.     def dataReceived(self, data):

  25.         return LineReceiver.dataReceived(self, data)



  26.     def rawDataReceived(self, data):

  27.         self.argv.append(data[:self.argl])

  28.         self.argc -= 1

  29.         if not self.argc:

  30.             self.process(self.argv)

  31.             self.argv = []

  32.         self.setLineMode(data[self.argl+2:])



  33.     def lineReceived(self, line):

  34.         if self.argc:

  35.             self.argl = int(line[1:])

  36.             self.setRawMode()

  37.             return

  38.         if line[0] == '*':

  39.             self.argc = int(line[1:])

  40.             if self.argv:

  41.                 self.sendLine('-ERR: %r' % self.argv)

  42.             return



  43.         self.process(shlex.split(line))



  44.     def process(self, argv):

  45.         command = argv[0].upper()



  46.         handler = getattr(self, command, self.todo)



  47.         try:

  48.             handler(argv)

  49.         except WrongNumberArgumentsError:

  50.             self.sendError("wrong number of arguments for %r command" % command)

  51.         except WrongValueTypeError:

  52.             self.sendError('Operation against a key holding the wrong kind of value')

  53.         except Exception, e:

  54.             import pdb;pdb.set_trace()

  55.             self.sendLine('-ERR %r' % e)



  56.     def todo(self, argv):

  57.         print 'TODO', self.argv

  58.         self.sendOK()



  59.     def sendOK(self):

  60.         self.sendLine('+OK')



  61.     def SELECT(self, argv):

  62.         self.db = self.factory.db[int(argv[1])]



  63.     def PING(self, argv):

  64.         self.sendLine('+PONG')



  65.     def SET(self, argv):

  66.         if len(argv) != 3: raise WrongNumberArgumentsError



  67.         self.db[argv[1]] = RObj(argv[2])

  68.         self.sendOK()



  69.     def SETNX(self, argv):

  70.         if len(argv) != 3: raise WrongNumberArgumentsError



  71.         key = argv[1]

  72.         if key in self.db:

  73.             self.sendInteger(0)

  74.             return



  75.         self.db[argv[1]] = RObj(argv[2])

  76.         self.sendOK()



  77.     def MSET(self, argv):

  78.         if len(argv) % 2 == 0: raise WrongNumberArgumentsError



  79.         for i in xrange(1, len(argv), 2):

  80.             self.db[argv[i]] = RObj(argv[i+1])

  81.         self.sendOK()



  82.     def EXISTS(self, argv):

  83.         if len(argv) != 2: raise WrongNumberArgumentsError



  84.         key = argv[1]

  85.         self.expireCheck(key)



  86.         if key in self.db:

  87.             self.sendInteger(1)

  88.         else:

  89.             self.sendInteger(0)



  90.     def GET(self, argv):

  91.         if len(argv) != 2: raise WrongNumberArgumentsError



  92.         key = argv[1]

  93.         self.expireCheck(key)



  94.         robj = self.db.get(key)

  95.         if robj and robj.type != 'string': raise WrongValueTypeError



  96.         self.sendBulk(robj and robj.value)



  97.     def MGET(self, argv):

  98.         if len(argv) < 2: raise WrongNumberArgumentsError



  99.         keys = argv[1:]

  100.         map(self.expireCheck, keys)



  101.         robjs = [self.db.get(key) for key in keys]

  102.         values = [o.value if o and o.type == 'string' else None for o in robjs]



  103.         self.sendBulks(values)



  104.     def DEL(self, argv):

  105.         if len(argv) < 2: raise WrongNumberArgumentsError



  106.         keys = argv[1:]

  107.         map(self.expireCheck, keys)



  108.         count = 0

  109.         for key in keys:

  110.             if key in self.db:

  111.                 del self.db[key]

  112.                 count += 1



  113.         self.sendInteger(count)



  114.     def DELEQ(self, argv):

  115.         '''DELEQ key value

  116.         

  117.         Delete a key only if value is matched.

  118.         Used only for strings.

  119.         '''

  120.         if len(argv) != 3: raise WrongNumberArgumentsError



  121.         key = argv[1]

  122.         self.expireCheck(key)



  123.         robj = self.db.get(key)



  124.         if robj and robj.value == argv[2]:

  125.             del self.db[key]

  126.             self.sendInteger(1)

  127.         else:

  128.             self.sendInteger(0)



  129.     def KEYS(self, argv):

  130.         if len(argv) != 2: raise WrongNumberArgumentsError



  131.         keys = fnmatch.filter(self.db.keys(), argv[1])

  132.         map(self.expireCheck, keys)

  133.         keys = fnmatch.filter(self.db.keys(), argv[1])



  134.         self.sendBulks(keys)



  135.     def _INCRBY(self, key, increment):

  136.         self.expireCheck(key)



  137.         robj = self.db.setdefault(key, RObj('0'))



  138.         if robj.type != 'string': raise WrongValueTypeError



  139.         try:

  140.             value = int(robj.value) + increment

  141.         except ValueError:

  142.             self.sendError('value is not an integer or out of range')

  143.             return



  144.         robj.value = str(value)

  145.         self.sendInteger(value)



  146.     def INCR(self, argv):

  147.         if len(argv) != 2: raise WrongNumberArgumentsError



  148.         self._INCRBY(argv[1], 1)



  149.     def INCRBY(self, argv):

  150.         if len(argv) != 3: raise WrongNumberArgumentsError



  151.         self._INCRBY(argv[1], int(argv[2]))



  152.     def DECR(self, argv):

  153.         if len(argv) != 2: raise WrongNumberArgumentsError



  154.         self._INCRBY(argv[1], -1)



  155.     def DECRBY(self, argv):

  156.         if len(argv) != 3: raise WrongNumberArgumentsError



  157.         self._INCRBY(argv[1], -int(argv[2]))



  158.     def _EXPIREAT(self, key, expireAt):

  159.         robj = self.db.get(key)

  160.         if robj:

  161.             robj.expireAt = expireAt

  162.             self.sendInteger(1)

  163.         else:

  164.             self.sendInteger(0)



  165.     def EXPIRE(self, argv):

  166.         if len(argv) != 3: raise WrongNumberArgumentsError



  167.         self._EXPIREAT(argv[1], time.time() + float(argv[2]))



  168.     def EXPIREAT(self, argv):

  169.         if len(argv) != 3: raise WrongNumberArgumentsError



  170.         self._EXPIREAT(argv[1], float(argv[2]))



  171.     def _EXPIREATEQ(self, key, value, expireAt):

  172.         robj = self.db.get(key)

  173.         if robj and robj.value == value:

  174.             robj.expireAt = expireAt

  175.             self.sendInteger(1)

  176.         else:

  177.             self.sendInteger(0)



  178.     def EXPIREEQ(self, argv):

  179.         '''EXPIREEQ key value seconds

  180.         

  181.         Set a key's time to live in seconds only if value is matched.

  182.         Used only for strings.

  183.         '''

  184.         if len(argv) != 4: raise WrongNumberArgumentsError



  185.         self._EXPIREATEQ(argv[1], argv[2], time.time() + float(argv[3]))



  186.     def EXPIREATEQ(self, argv):

  187.         '''EXPIREEQ key value seconds

  188.         

  189.         Set the expiration for a key as a UNIX timestamp only if value is matched.

  190.         Used only for strings.

  191.         '''

  192.         if len(argv) != 4: raise WrongNumberArgumentsError



  193.         self._EXPIREATEQ(argv[1], argv[2], float(argv[3]))



  194.     def TTL(self, argv):

  195.         if len(argv) != 2: raise WrongNumberArgumentsError



  196.         robj = self.db.get(argv[1])

  197.         if robj and robj.expireAt:

  198.             self.sendInteger(robj.expireAt - time.time())

  199.         else:

  200.             self.sendInteger(-1)



  201.     def expireCheck(self, key):

  202.         robj = self.db.get(key)

  203.         if robj and robj.expireAt:

  204.             if time.time() > robj.expireAt:

  205.                 del self.db[key]



  206.     def sendInteger(self, i):

  207.         self.sendLine(':%d' % i)



  208.     def sendBulk(self, bulk):

  209.         if bulk is None:

  210.             self.sendLine('$-1')

  211.             return

  212.         self.sendLine('$%d' % len(bulk))

  213.         self.sendLine(bulk)



  214.     def sendBulks(self, bulks):

  215.         self.sendLine('*%d' % len(bulks))

  216.         map(self.sendBulk, bulks)



  217.     def sendError(self, message):

  218.         self.sendLine('-ERR %s
原创粉丝点击