aboutsummaryrefslogtreecommitdiffstats
path: root/src/py/imc/async.py
blob: fdb42c467d7e1b6d44819c77d621f789324f3c88 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import traceback
import uuid
import ssl

import tornado.stack_context
from Crypto.Hash import SHA512
from greenlet import greenlet

from imc import auth

gr_idmap = {}
ret_idmap = {}
gr_main = greenlet.getcurrent()

def switch_top():
    global gr_main

    assert greenlet.getcurrent() != gr_main

    old_idendata = auth.current_idendata
    old_contexts = tornado.stack_context._state.contexts
    auth.current_idendata = None

    try:
        result =  gr_main.switch(None)

    except Exception as err:
        traceback.print_stack()
        print(err)
        return (False,'Einternal')

    finally:
        tornado.stack_context._state.contexts = old_contexts
        auth.current_idendata = old_idendata

    return result

def caller(f):
    def wrapper(*args,**kwargs):
        global gr_main
        global gr_idmap
        global ret_idmap

        def _call(*args,**kwargs):
            ret = f(*args,**kwargs)
            retids = gr_idmap[grid]
            for retid in retids:
                del ret_idmap[retid] 

            del gr_idmap[grid]

            return (True,ret)
        
        old_idendata = auth.current_idendata
        old_contexts = tornado.stack_context._state.contexts

        try:
            gr = greenlet(_call)
            grid = id(gr)
            gr_idmap[grid] = set()

            result = gr.switch(*args,**kwargs)

            if result == None:
                return (False,None)

            if gr.dead == False:
                gr.parent = gr_main

            return result

        except TypeError as err:
            traceback.print_stack()
            print(err)
            return (False,'Eparameter')

        except Exception as err:
            traceback.print_stack()
            print(err)
            return (False,'Einternal')

        finally:
            tornado.stack_context._state.contexts = old_contexts
            auth.current_idendata = old_idendata

    return wrapper

def get_retid():
    global gr_idmap
    global ret_idmap

    gr = greenlet.getcurrent()
    grid = id(gr)
    retid = SHA512.new(uuid.uuid1().bytes + ssl.RAND_bytes(64)).hexdigest()

    gr_idmap[grid].add(retid)
    ret_idmap[retid] = gr

    return retid

def ret(retid,value = None,err = None):
    global gr_main
    global gr_idmap
    global ret_idmap

    assert greenlet.getcurrent() == gr_main

    try:
        gr = ret_idmap.pop(retid)
        gr_idmap[id(gr)].remove(retid)

    except KeyError:
        return

    old_idendata = auth.current_idendata
    old_contexts = tornado.stack_context._state.contexts

    try:
        if err == None:
            gr.switch(value)
        
        else:
            gr.throw(err)

    except Exception as err:
        traceback.print_stack()
        print(err)

    finally:
        tornado.stack_context._state.contexts = old_contexts
        auth.current_idendata = old_idendata