├── .gitignore
├── requirements.txt
├── pysproto
├── __init__.py
├── compat.h
├── msvcint.h
├── sproto.h
├── sproto.py
├── sprotodump.py
├── sprotoparser.py
├── core.pyx
└── sproto.c
├── README.md
├── setup.py
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | dist
3 | MANIFEST
4 |
5 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | setuptools>=20
2 | Cython>=0.24
3 |
--------------------------------------------------------------------------------
/pysproto/__init__.py:
--------------------------------------------------------------------------------
1 | from .sproto import SprotoRpc
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pysproto
2 | python binding for cloudwu‘s sproto with rpc support
3 |
4 | make it one python egg
5 | installation:
6 |
7 | 0. sudo pip install -r requirements.txt
8 | 1. python setup.py build
9 | 2. python setup.py install
10 |
11 | or pip
12 |
13 | sudo pip install 'setuptools>=20' 'cython>=0.24' git+git://github.com/bttscut/pysproto.git#egg=pysproto
14 |
15 | - sproto.h, sproto.c, msvcint.h copied from https://github.com/cloudwu/sproto
16 | - sprotoparser.py copied from https://github.com/tzngit/python_sproto_parser
17 |
18 | contact me if any problem.
19 |
--------------------------------------------------------------------------------
/pysproto/compat.h:
--------------------------------------------------------------------------------
1 | #include "Python.h"
2 |
3 | typedef void (*capsule_dest)(PyObject *);
4 | typedef void (*cobj_dest)(void *);
5 |
6 | #if PY_MAJOR_VERSION != 2
7 | #error "need python 2.*"
8 | #elif PY_MINOR_VERSION > 6
9 | #define CAP_NEW PyCapsule_New
10 | #define DEST_FUNC_TYPE capsule_dest
11 | #define CAP_GET_POINTER PyCapsule_GetPointer
12 | #else
13 | #define CAP_NEW(a,b,c) PyCObject_FromVoidPtr(a,c)
14 | #define DEST_FUNC_TYPE cobj_dest
15 | #define CAP_GET_POINTER(a,b) PyCObject_AsVoidPtr(a)
16 | #endif
17 |
18 | PyObject* make_capsule(void *p, const char *name, capsule_dest dest) {
19 | return CAP_NEW(p, name, (DEST_FUNC_TYPE)dest);
20 | }
21 | void* get_pointer(PyObject *cap, const char *name) {
22 | return CAP_GET_POINTER(cap, name);
23 | }
24 |
--------------------------------------------------------------------------------
/pysproto/msvcint.h:
--------------------------------------------------------------------------------
1 | #ifndef msvc_int_h
2 | #define msvc_int_h
3 |
4 | #ifdef _MSC_VER
5 | # define inline __inline
6 | # ifndef _MSC_STDINT_H_
7 | # if (_MSC_VER < 1300)
8 | typedef signed char int8_t;
9 | typedef signed short int16_t;
10 | typedef signed int int32_t;
11 | typedef unsigned char uint8_t;
12 | typedef unsigned short uint16_t;
13 | typedef unsigned int uint32_t;
14 | # else
15 | typedef signed __int8 int8_t;
16 | typedef signed __int16 int16_t;
17 | typedef signed __int32 int32_t;
18 | typedef unsigned __int8 uint8_t;
19 | typedef unsigned __int16 uint16_t;
20 | typedef unsigned __int32 uint32_t;
21 | # endif
22 | typedef signed __int64 int64_t;
23 | typedef unsigned __int64 uint64_t;
24 | # endif
25 |
26 | #else
27 |
28 | #include
29 |
30 | #endif
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, Extension
2 |
3 | # core = Extension('pysproto.core',
4 | # sources = ["pysproto/python_sproto.c", "pysproto/sproto.c"],
5 | # extra_compile_args = ["-g3", "-O0"],
6 | # )
7 | from Cython.Build import cythonize
8 | ext = Extension("pysproto.core",
9 | sources = ["pysproto/core.pyx", "pysproto/sproto.c"],
10 | # extra_compile_args = ["-g3", "-O0"],
11 | )
12 | core = cythonize(ext)
13 |
14 | setup(
15 | name = "pysproto",
16 | version = '0.6',
17 | packages = ["pysproto"],
18 | description = "python binding for cloudwu's sproto",
19 | author = "bttscut",
20 | license = "MIT",
21 | url="http://github.com/bttscut/pysproto",
22 | keywords=["sproto", "python"],
23 | # py_modules = ["sproto.py"],
24 | ext_modules = core,
25 | )
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 codingnow.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | Copyright (c) 2016 bttsuct
16 |
17 | Permission is hereby granted, free of charge, to any person obtaining a copy
18 | of this software and associated documentation files (the "Software"), to deal
19 | in the Software without restriction, including without limitation the rights
20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 | copies of the Software, and to permit persons to whom the Software is
22 | furnished to do so, subject to the following conditions:
23 |
24 | The above copyright notice and this permission notice shall be included in all
25 | copies or substantial portions of the Software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 | SOFTWARE.
34 |
--------------------------------------------------------------------------------
/pysproto/sproto.h:
--------------------------------------------------------------------------------
1 | #ifndef sproto_h
2 | #define sproto_h
3 |
4 | #include
5 |
6 | struct sproto;
7 | struct sproto_type;
8 |
9 | #define SPROTO_REQUEST 0
10 | #define SPROTO_RESPONSE 1
11 |
12 | // type (sproto_arg.type)
13 | #define SPROTO_TINTEGER 0
14 | #define SPROTO_TBOOLEAN 1
15 | #define SPROTO_TSTRING 2
16 | #define SPROTO_TSTRUCT 3
17 |
18 | // sub type of string (sproto_arg.extra)
19 | #define SPROTO_TSTRING_STRING 0
20 | #define SPROTO_TSTRING_BINARY 1
21 |
22 | #define SPROTO_CB_ERROR -1
23 | #define SPROTO_CB_NIL -2
24 | #define SPROTO_CB_NOARRAY -3
25 |
26 | struct sproto * sproto_create(const void * proto, size_t sz);
27 | void sproto_release(struct sproto *);
28 |
29 | int sproto_prototag(const struct sproto *, const char * name);
30 | const char * sproto_protoname(const struct sproto *, int proto);
31 | // SPROTO_REQUEST(0) : request, SPROTO_RESPONSE(1): response
32 | struct sproto_type * sproto_protoquery(const struct sproto *, int proto, int what);
33 | int sproto_protoresponse(const struct sproto *, int proto);
34 |
35 | struct sproto_type * sproto_type(const struct sproto *, const char * type_name);
36 |
37 | int sproto_pack(const void * src, int srcsz, void * buffer, int bufsz);
38 | int sproto_unpack(const void * src, int srcsz, void * buffer, int bufsz);
39 |
40 | struct sproto_arg {
41 | void *ud;
42 | const char *tagname;
43 | int tagid;
44 | int type;
45 | struct sproto_type *subtype;
46 | void *value;
47 | int length;
48 | int index; // array base 1
49 | int mainindex; // for map
50 | int extra; // SPROTO_TINTEGER: decimal ; SPROTO_TSTRING 0:utf8 string 1:binary
51 | };
52 |
53 | typedef int (*sproto_callback)(const struct sproto_arg *args);
54 |
55 | int sproto_decode(const struct sproto_type *, const void * data, int size, sproto_callback cb, void *ud);
56 | int sproto_encode(const struct sproto_type *, void * buffer, int size, sproto_callback cb, void *ud);
57 |
58 | // for debug use
59 | void sproto_dump(struct sproto *);
60 | const char * sproto_name(struct sproto_type *);
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/pysproto/sproto.py:
--------------------------------------------------------------------------------
1 | from . import core
2 |
3 | __all__ = ["SprotoRpc"]
4 |
5 | class SprotoObj(object):
6 | def __init__(self, chunk):
7 | self.sp = core.newproto(chunk)
8 | self.st = {}
9 | self.proto = {}
10 |
11 | def query_type(self, tagname):
12 | if not tagname in self.st:
13 | self.st[tagname] = core.query_type(self.sp, tagname)
14 | return self.st[tagname]
15 |
16 | def protocol(self, protoname):
17 | # print "protocol", protoname
18 | if not protoname in self.proto:
19 | self.proto[protoname] = core.protocol(self.sp, protoname)
20 | return self.proto[protoname]
21 |
22 | def encode(self, st, data):
23 | # print "encode", data
24 | return core.encode(st, data)
25 |
26 | def decode(self, st, chunk):
27 | # print "decode"
28 | return core.decode(st, chunk)
29 |
30 | def pack(self, chunk):
31 | return core.pack(chunk)
32 |
33 | def unpack(self, chunk):
34 | return core.unpack(chunk)
35 |
36 | class SprotoRpc(object):
37 | def __init__(self, protobin, packagename):
38 | self._sp = SprotoObj(protobin)
39 | self._package = self._sp.query_type(packagename)
40 | self._session = {}
41 |
42 | def _gen_response_f(self, resp, session):
43 | def f(args, ud):
44 | header = self._sp.encode(self._package, {"type":0, "session":session, "ud":ud})
45 | content = self._sp.encode(resp, args)
46 | return self._sp.pack(header+content)
47 | return f
48 |
49 | def dispatch(self, data):
50 | sp = self._sp
51 | data = sp.unpack(data)
52 | header,size = sp.decode(self._package, data)
53 | content = data[size:]
54 | if header.get("type", 0):
55 | # request
56 | protoname, req, resp = sp.protocol(header["type"])
57 | result,_ = sp.decode(req, content) if req else (None, 0)
58 | ret = {"type":"REQUEST", "proto": protoname, "msg":result, "session":None}
59 | session = header.get("session")
60 | if session:
61 | ret["response"] = self._gen_response_f(resp, session)
62 | else:
63 | # response
64 | session = header["session"]
65 | if not session in self._session:
66 | raise ValueError("unknown session", session)
67 | response = self._session[session]
68 | del self._session[session]
69 | ret = {"type":"RESPONSE", "session":session, "msg":None}
70 | ret["msg"], _ = sp.decode(response, content)
71 | ret["header"] = header
72 | return ret
73 |
74 | def request(self, protoname, args = None, session = 0, ud = None):
75 | sp = self._sp
76 | tag, req, resp = sp.protocol(protoname)
77 | header = sp.encode(self._package, {"type":tag, "session":session, "ud":ud})
78 | if session and not resp:
79 | raise ValueError("proto no response")
80 | if session:
81 | self._session[session] = resp
82 | content = sp.encode(req, args) if req else ""
83 | return sp.pack(header + content)
84 |
--------------------------------------------------------------------------------
/pysproto/sprotodump.py:
--------------------------------------------------------------------------------
1 | #coding:utf-8
2 | import sprotoparser
3 | import struct
4 | import sys, argparse, os, codecs
5 |
6 | def packbytes(s):
7 | s = str(s)
8 | return struct.pack("(-1)
61 |
62 | cdef struct encode_ud:
63 | PyObject *data
64 | int deep
65 |
66 | cdef int _encode(const sproto_arg *args) except *:
67 | cdef encode_ud *self = args.ud
68 | # todo check deep
69 | data =