mirror of
https://github.com/upa/mscp.git
synced 2026-02-14 17:24:42 +08:00
add mscp and pymscp python modules.
pymscp is a C Python wrapper for libmscp functions. mscp module provides simple (?) Python API.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,3 +3,7 @@ html
|
||||
compile_commands.json
|
||||
CMakeUserPresets.json
|
||||
.*.swp
|
||||
|
||||
dist
|
||||
*.egg-info
|
||||
__pycache__
|
||||
|
||||
1
mscp/__init__.py
Normal file
1
mscp/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from mscp.mscp import *
|
||||
120
mscp/mscp.py
Normal file
120
mscp/mscp.py
Normal file
@@ -0,0 +1,120 @@
|
||||
|
||||
import pymscp
|
||||
|
||||
_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.
|
||||
"""
|
||||
kwargs["remote"] = remote
|
||||
kwargs["direction"] = direction
|
||||
self.m = pymscp.mscp_init(**kwargs)
|
||||
|
||||
self.src_paths = []
|
||||
self.dst_path = None
|
||||
self.state = _STATE_INIT
|
||||
|
||||
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(_state2str()))
|
||||
pymscp.mscp_connect(m = self.m)
|
||||
self.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_CONNCTED:
|
||||
raise RuntimeError("invalid mscp state: {}".format(_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(_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(_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(_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_JOIND:
|
||||
raise RuntimeError("invalid mscp state: {}".format(_state2str()))
|
||||
pymscp.mscp_cleanup()
|
||||
self.state = _STATE_CLEAND
|
||||
|
||||
def free(self):
|
||||
if self.state != _STATE_CLEANED:
|
||||
raise RuntimeError("invalid mscp state: {}".format(_state2str()))
|
||||
pymscp.mscp_free()
|
||||
|
||||
|
||||
# Simple interface: mscp.copy(src, dst)
|
||||
def copy(self, src, dst, nonblock = False):
|
||||
if self.state < _STATE_CONNECTED:
|
||||
self.connect()
|
||||
|
||||
if type(src) == list:
|
||||
self.src_paths += src
|
||||
elif type(src) == str:
|
||||
self.src_paths.append(src)
|
||||
else:
|
||||
raise ValueError("src must be str of list: '{}'".format(src))
|
||||
|
||||
self.dst_path = dst
|
||||
|
||||
self.prepare()
|
||||
self.start()
|
||||
if nonblock:
|
||||
return
|
||||
|
||||
self.cleanup()
|
||||
12
setup.py
12
setup.py
@@ -1,7 +1,15 @@
|
||||
from distutils.core import setup, Extension
|
||||
from setuptools import setup, Extension, find_packages
|
||||
|
||||
setup(
|
||||
name='pymscp',
|
||||
name='mscp',
|
||||
version = "0.0.1",
|
||||
description = "libmscp python binding",
|
||||
author = "Ryo Nakamura",
|
||||
author_email = "upa@haeena.net",
|
||||
url = "https://github.com/upa/mscp",
|
||||
packages = find_packages("mscp"),
|
||||
package_dir = {"": "mscp"},
|
||||
py_modules = [ "mscp" ],
|
||||
ext_modules = [
|
||||
Extension(
|
||||
'pymscp',
|
||||
|
||||
189
src/pymscp.c
189
src/pymscp.c
@@ -2,6 +2,57 @@
|
||||
#include <Python.h>
|
||||
#include <mscp.h>
|
||||
|
||||
/*
|
||||
* This is a wrapper for python binding of libmscp. setup.py builds
|
||||
* pymscp.c after libmscp was built, and setup.py installs pymscp
|
||||
* modlue and mscp python module (mscp/mscp.py), which is a warpper
|
||||
* for pymscp.
|
||||
*/
|
||||
|
||||
#define MAX_MSCP_INSTS 16
|
||||
|
||||
/* XXX: cut corners */
|
||||
struct mscp *insts[MAX_MSCP_INSTS];
|
||||
|
||||
static int add_mscp_inst(struct mscp *m)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < MAX_MSCP_INSTS; n++) {
|
||||
if (insts[n] == NULL) {
|
||||
insts[n] = m;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1; /* full of mscp instances */
|
||||
}
|
||||
|
||||
static struct mscp *get_mscp_inst(unsigned long long maddr)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < MAX_MSCP_INSTS; n++) {
|
||||
if (insts[n] == (void *)maddr)
|
||||
return insts[n];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int release_mscp_inst(struct mscp *m)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < MAX_MSCP_INSTS; n++) {
|
||||
if (insts[n] == m) {
|
||||
insts[n] = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* wrapper functions */
|
||||
|
||||
static PyObject *wrap_mscp_init(PyObject *sef, PyObject *args, PyObject *kw)
|
||||
{
|
||||
/*
|
||||
@@ -11,8 +62,10 @@ static PyObject *wrap_mscp_init(PyObject *sef, PyObject *args, PyObject *kw)
|
||||
|
||||
char *remote;
|
||||
char *keywords[] = {
|
||||
/* mscp_opts */
|
||||
"remote", /* const char * */
|
||||
"direction", /* int, MSCP_DIRECTION_L2R or MSCP_DIRECTION_R2L */
|
||||
|
||||
/* mscp_opts */
|
||||
"nr_threads", /* int */
|
||||
"nr_ahead", /* int */
|
||||
"min_chunk_sz", /* unsigned long */
|
||||
@@ -36,14 +89,16 @@ static PyObject *wrap_mscp_init(PyObject *sef, PyObject *args, PyObject *kw)
|
||||
"enable_nagle", /* bool */
|
||||
NULL,
|
||||
};
|
||||
const char *fmt = "siiikkkzii" "zzzzzzzzipp";
|
||||
char *coremask;
|
||||
char *login_name, *port, *identity, *cipher, *hmac, *compress;
|
||||
char *password, *passphrase;
|
||||
const char *fmt = "si" "|iikkkzii" "zzzzzzzzipp";
|
||||
char *coremask = NULL;
|
||||
char *login_name = NULL, *port = NULL, *identity = NULL;
|
||||
char *cipher = NULL, *hmac = NULL, *compress = NULL;
|
||||
char *password = NULL, *passphrase = NULL;
|
||||
|
||||
struct mscp_opts mo;
|
||||
struct mscp_ssh_opts so;
|
||||
struct mscp_opts mo;
|
||||
struct mscp *m;
|
||||
int direction;
|
||||
int ret;
|
||||
|
||||
memset(&mo, 0, sizeof(mo));
|
||||
@@ -51,7 +106,7 @@ static PyObject *wrap_mscp_init(PyObject *sef, PyObject *args, PyObject *kw)
|
||||
|
||||
ret = PyArg_ParseTupleAndKeywords(args, kw, fmt, keywords,
|
||||
&remote,
|
||||
&mo.direction,
|
||||
&direction,
|
||||
&mo.nr_threads,
|
||||
&mo.nr_ahead,
|
||||
&mo.min_chunk_sz,
|
||||
@@ -68,6 +123,7 @@ static PyObject *wrap_mscp_init(PyObject *sef, PyObject *args, PyObject *kw)
|
||||
&compress,
|
||||
&password,
|
||||
&passphrase,
|
||||
&so.debug_level,
|
||||
&so.no_hostkey_check,
|
||||
&so.enable_nagle);
|
||||
|
||||
@@ -75,29 +131,35 @@ static PyObject *wrap_mscp_init(PyObject *sef, PyObject *args, PyObject *kw)
|
||||
return NULL;
|
||||
|
||||
if (coremask)
|
||||
strncpy(mo.coremask, coremask, MSCP_MAX_COREMASK_STR);
|
||||
strncpy(mo.coremask, coremask, MSCP_MAX_COREMASK_STR - 1);
|
||||
if (login_name)
|
||||
strncpy(so.login_name, login_name, MSCP_SSH_MAX_LOGIN_NAME);
|
||||
strncpy(so.login_name, login_name, MSCP_SSH_MAX_LOGIN_NAME - 1);
|
||||
if (port)
|
||||
strncpy(so.port, port, MSCP_SSH_MAX_PORT_STR);
|
||||
strncpy(so.port, port, MSCP_SSH_MAX_PORT_STR - 1);
|
||||
if (identity)
|
||||
strncpy(so.identity, identity, MSCP_SSH_MAX_IDENTITY_PATH);
|
||||
strncpy(so.identity, identity, MSCP_SSH_MAX_IDENTITY_PATH - 1);
|
||||
if (cipher)
|
||||
strncpy(so.cipher, cipher, MSCP_SSH_MAX_CIPHER_STR);
|
||||
strncpy(so.cipher, cipher, MSCP_SSH_MAX_CIPHER_STR - 1);
|
||||
if (hmac)
|
||||
strncpy(so.hmac, hmac, MSCP_SSH_MAX_HMAC_STR);
|
||||
strncpy(so.hmac, hmac, MSCP_SSH_MAX_HMAC_STR - 1);
|
||||
if (compress)
|
||||
strncpy(so.compress, compress, MSCP_SSH_MAX_COMP_STR);
|
||||
strncpy(so.compress, compress, MSCP_SSH_MAX_COMP_STR - 1);
|
||||
if (password)
|
||||
strncpy(so.password, password, MSCP_SSH_MAX_PASSWORD);
|
||||
strncpy(so.password, password, MSCP_SSH_MAX_PASSWORD - 1);
|
||||
if (passphrase)
|
||||
strncpy(so.passphrase, passphrase, MSCP_SSH_MAX_PASSPHRASE);
|
||||
strncpy(so.passphrase, passphrase, MSCP_SSH_MAX_PASSPHRASE - 1);
|
||||
|
||||
|
||||
m = mscp_init(remote, &mo, &so);
|
||||
m = mscp_init(remote, direction, &mo, &so);
|
||||
if (!m)
|
||||
return NULL;
|
||||
|
||||
if (add_mscp_inst(m) < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, "too many mscp isntances");
|
||||
mscp_free(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Py_BuildValue("K", (unsigned long long)m);
|
||||
}
|
||||
|
||||
@@ -110,7 +172,12 @@ static PyObject *wrap_mscp_connect(PyObject *self, PyObject *args, PyObject *kw)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mscp_connect(m) < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
||||
return NULL;
|
||||
@@ -129,7 +196,12 @@ static PyObject *wrap_mscp_add_src_path(PyObject *self, PyObject *args, PyObject
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "Ks", keywords, &maddr, &src_path))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mscp_add_src_path(m, src_path) < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
||||
return NULL;
|
||||
@@ -148,7 +220,12 @@ static PyObject *wrap_mscp_set_dst_path(PyObject *self, PyObject *args, PyObject
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "Ks", keywords, &maddr, &dst_path))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mscp_set_dst_path(m, dst_path) < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
||||
return NULL;
|
||||
@@ -166,7 +243,12 @@ static PyObject *wrap_mscp_prepare(PyObject *self, PyObject *args, PyObject *kw)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mscp_prepare(m) < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
||||
return NULL;
|
||||
@@ -184,7 +266,12 @@ static PyObject *wrap_mscp_start(PyObject *self, PyObject *args, PyObject *kw)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mscp_start(m) < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
||||
return NULL;
|
||||
@@ -202,7 +289,12 @@ static PyObject *wrap_mscp_stop(PyObject *self, PyObject *args, PyObject *kw)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mscp_stop(m);
|
||||
|
||||
return Py_BuildValue("");
|
||||
@@ -217,7 +309,12 @@ static PyObject *wrap_mscp_join(PyObject *self, PyObject *args, PyObject *kw)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mscp_join(m) < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, mscp_get_error());
|
||||
return NULL;
|
||||
@@ -236,7 +333,12 @@ static PyObject *wrap_mscp_get_stats(PyObject *self, PyObject *args, PyObject *k
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mscp_get_stats(m, &s);
|
||||
|
||||
return Py_BuildValue("KKd", s.total, s.done, s.finished);
|
||||
@@ -251,7 +353,12 @@ static PyObject *wrap_mscp_cleanup(PyObject *self, PyObject *args, PyObject *kw)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mscp_cleanup(m);
|
||||
|
||||
return Py_BuildValue("");
|
||||
@@ -266,13 +373,19 @@ static PyObject *wrap_mscp_free(PyObject *self, PyObject *args, PyObject *kw)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "K", keywords, &maddr))
|
||||
return NULL;
|
||||
|
||||
m = (void *)maddr;
|
||||
m = get_mscp_inst(maddr);
|
||||
if (!m) {
|
||||
PyErr_Format(PyExc_RuntimeError, "invalid mscp address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
release_mscp_inst(m);
|
||||
mscp_free(m);
|
||||
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
static PyMethodDef PyMscpMethods[] = {
|
||||
static PyMethodDef pymscpMethods[] = {
|
||||
{
|
||||
"mscp_init", (PyCFunction)wrap_mscp_init,
|
||||
METH_VARARGS | METH_KEYWORDS, NULL
|
||||
@@ -317,15 +430,25 @@ static PyMethodDef PyMscpMethods[] = {
|
||||
"mscp_free", (PyCFunction)wrap_mscp_free,
|
||||
METH_VARARGS | METH_KEYWORDS, NULL
|
||||
},
|
||||
|
||||
{ NULL, NULL, 0, NULL },
|
||||
};
|
||||
|
||||
static PyModuleDef PyMscpModule = {
|
||||
PyModuleDef_HEAD_INIT, "PyMscp", NULL, -1, PyMscpMethods,
|
||||
static PyModuleDef pymscpModule = {
|
||||
PyModuleDef_HEAD_INIT, "pymscp", NULL, -1, pymscpMethods,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_PyMscp(void) {
|
||||
return PyModule_Create(&PyMscpModule);
|
||||
PyMODINIT_FUNC PyInit_pymscp(void) {
|
||||
PyObject *mod = PyModule_Create(&pymscpModule);
|
||||
|
||||
PyModule_AddIntConstant(mod, "LOCAL2REMOTE", MSCP_DIRECTION_L2R);
|
||||
PyModule_AddIntConstant(mod, "REMOTE2LOCAL", MSCP_DIRECTION_R2L);
|
||||
PyModule_AddIntConstant(mod, "SEVERITY_NONE", MSCP_SEVERITY_NONE);
|
||||
PyModule_AddIntConstant(mod, "SEVERITY_ERR", MSCP_SEVERITY_ERR);
|
||||
PyModule_AddIntConstant(mod, "SEVERITY_WARN", MSCP_SEVERITY_WARN);
|
||||
PyModule_AddIntConstant(mod, "SEVERITY_NOTICE", MSCP_SEVERITY_NOTICE);
|
||||
PyModule_AddIntConstant(mod, "SEVERITY_INFO", MSCP_SEVERITY_INFO);
|
||||
PyModule_AddIntConstant(mod, "SEVERITY_DEBUG", MSCP_SEVERITY_DEBUG);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user