summaryrefslogtreecommitdiff
path: root/mscp/mscp.py
blob: da2fcf5a46c9d67ae04a35b362ea7691fec2601c (plain)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

_retry_import_pymscp = False

try:
    import pymscp
except ImportError:
    _retry_import_pymscp = True

if _retry_import_pymscp:
    """
    libmscp.so is not installed on system library paths. So retry to
    import libmscp.so installed on the mscp python module directory.
    """
    import os
    import ctypes
    mscp_dir = os.path.dirname(__file__)
    ctypes.cdll.LoadLibrary("{}/libmscp.so".format(mscp_dir))
    import pymscp


# inherit static values from pymscp
LOCAL2REMOTE    = pymscp.LOCAL2REMOTE
REMOTE2LOCAL    = pymscp.REMOTE2LOCAL
SEVERITY_NONE   = pymscp.SEVERITY_NONE
SEVERITY_ERR    = pymscp.SEVERITY_ERR
SEVERITY_WARN   = pymscp.SEVERITY_WARN
SEVERITY_NOTICE = pymscp.SEVERITY_NOTICE
SEVERITY_INFO   = pymscp.SEVERITY_INFO
SEVERITY_DEBUG  = pymscp.SEVERITY_DEBUG

_STATE_INIT      = 0
_STATE_CONNECTED = 1
_STATE_PREPARED  = 2
_STATE_RUNNING   = 3
_STATE_STOPPED   = 4
_STATE_JOINED    = 5
_STATE_CLEANED   = 6
_STATE_RELEASED  = 7

_state_str = {
    _STATE_INIT:      "init",
    _STATE_CONNECTED: "connected",
    _STATE_PREPARED:  "prepared",
    _STATE_RUNNING:   "running",
    _STATE_STOPPED:   "stopped",
    _STATE_JOINED:    "joined",
    _STATE_CLEANED:   "cleaned",
    _STATE_RELEASED:  "released",
}


class mscp:
    def __init__(self, remote: str, direction: int, **kwargs):
        """
        See src/pymscp.c:wrap_mscp_init() to determine keyword arguments.
        """
        self.remote = remote
        self.direction = direction
        kwargs["remote"] = remote
        kwargs["direction"] = direction
        self.m = pymscp.mscp_init(**kwargs)

        self.src_paths = []
        self.dst_path = None
        self.state = _STATE_INIT

    def __str__(self):
        return "mscp:{}:{}".format(self.remote, self._state2str())

    def __repr__(self):
        return "<{}>".format(str(self))

    def __del__(self):

        if not hasattr(self, "state"):
            return # this instance failed on mscp_init

        if self.state == _STATE_RUNNING:
            self.stop()
        if self.state == _STATE_STOPPED:
            self.join()

        self.cleanup()
        self.release()

    def _state2str(self):
        return _state_str[self.state]


    def connect(self):
        if not (self.state == _STATE_INIT or state.state == _STATE_CLEANED):
            raise RuntimeError("invalid mscp state: {}".format(self._state2str()))
        pymscp.mscp_connect(m = self.m)
        self.state = _STATE_CONNECTED

    def add_src_path(self, src_path: str):
        self.src_paths.append(src_path)
        pymscp.mscp_add_src_path(m = self.m, src_path = src_path)

    def set_dst_path(self, dst_path: str):
        self.dst_path = dst_path
        pymscp.mscp_set_dst_path(m = self.m, dst_path = dst_path);

    def prepare(self):
        if self.state != _STATE_CONNECTED:
            raise RuntimeError("invalid mscp state: {}".format(self._state2str()))
        if not self.src_paths:
            raise RuntimeError("src path list is empty")
        if not self.dst_path:
            raise RuntimeError("dst path is not set")

        pymscp.mscp_prepare(m = self.m)
        self.state = _STATE_PREPARED

    def start(self):
        if self.state != _STATE_PREPARED:
            raise RuntimeError("invalid mscp state: {}".format(self._state2str()))

        pymscp.mscp_start(m = self.m)
        self.state = _STATE_RUNNING

    def stop(self):
        if self.state != _STATE_RUNNING:
            raise RuntimeError("invalid mscp state: {}".format(self._state2str()))
        pymscp.mscp_stop(m = self.m)
        self.state = _STATE_STOPPED

    def join(self):
        if not (self.state == _STATE_RUNNING or self.state == _STATE_STOPPED):
            raise RuntimeError("invalid mscp state: {}".format(self._state2str()))
        pymscp.mscp_join(m = self.m)
        self.state = _STATE_JOINED

    def stats(self):
        return pymscp.mscp_get_stats(m = self.m)

    def cleanup(self):
        if self.state == _STATE_RUNNING:
            raise RuntimeError("invalid mscp state: {}".format(self._state2str()))
        pymscp.mscp_cleanup(m = self.m)
        self.state = _STATE_CLEANED

    def release(self):
        if self.state != _STATE_CLEANED:
            raise RuntimeError("invalid mscp state: {}".format(self._state2str()))
        pymscp.mscp_free(m = self.m)
        self.state = _STATE_RELEASED

    # Simple interface: mscp.copy(src, dst)
    def copy(self, src, dst, nonblock = False):
        if self.state < _STATE_CONNECTED:
            self.connect()

        if type(src) == list:
            for path in src:
                self.add_src_path(path)
        elif type(src) == str:
            self.add_src_path(src)
        else:
            raise ValueError("src must be str of list: '{}'".format(src))

        self.set_dst_path(dst)
        
        self.prepare()
        self.start()
        if nonblock:
            return

        self.join()
        self.cleanup()