Skip to content

Commit 577c664

Browse files
Merge pull request #265 from deniskoronchik/dev
Prepare 0.4.0
2 parents 9d2dcf3 + 446b604 commit 577c664

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1160
-411
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ sc-machine.json
1616
manifest.json
1717
*.user
1818
*.*~
19+
20+
.vscode
21+
__pycache__

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ endif()
5555
# find dependencies
5656
if (${UNIX})
5757
find_package(PythonLibs 3.4 REQUIRED)
58-
message(${PYTHONLIBS_VERSION_STRING})
5958

6059
string(REPLACE "." ";" PY_VERSION_LIST ${PYTHONLIBS_VERSION_STRING})
6160
list(GET PY_VERSION_LIST 0 PY_VERSION_MAJOR)

docs/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## v0.4.0
22

3+
* Add events support in Python scripts
4+
* Improve Python scripts run
5+
* Add common libraries for a Python
6+
* Fix memory leaks in core
37
* Improve test logging
48
* Improve work with memory buffers
59
* Cleanup API

docs/python/python.md

Lines changed: 117 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,123 @@
11
# Python
22

3-
You can implement agents using python. All python modules should be implemented with specified rules.
3+
You can implement agents using **Python 3**. All python modules should be implemented with specified rules.
44

5-
1. Each module, that implement agent should be names by this rule: `a_<agentName>.py`. That allows system to
6-
know which modules could be used to run. Util modules and others should be named NOT using this rule.
5+
1. You can specify search paths of a python modules by `python.modules_path` value in a [configuration file](../other/config.md).
76

8-
2. You can specify search paths of a python modules by `python.modules_path` value in a [configuration file](../other/config.md).
7+
8+
# Usage example
9+
There are two ways to run python script:
10+
11+
- when you need run script and wait it finished, then just use this code:
12+
```cpp
13+
#include <sc-memory/cpp/python/sc_python_interp.hpp>
14+
...
15+
void doSomething()
16+
{
17+
...
18+
py::ScPythonInterpreter::RunScript("lg/tv_service.py", m_bridge);
19+
...
20+
}
21+
```
22+
Then in python you can write any code you want:
23+
```python
24+
import any_module
25+
26+
# create context (with minimal access)
27+
ctx = createScMemoryContext('context name')
28+
29+
# create node
30+
nodeAddr = ctx.CreateNode(ScType.NodeConst)
31+
...
32+
33+
# you can use any installed python libraries
34+
any_module.doSomething()
35+
```
36+
37+
- if you want to run script as a service and communicate with it, then use code:
38+
```cpp
39+
class Service
40+
{
41+
public:
42+
void Run()
43+
{
44+
// Run script in a separate thread
45+
m_workThread.reset(new std::thread([&]
46+
{
47+
// should exist my/my_script.py in python modules path
48+
py::ScPythonInterpreter::RunScript("my/my_script.py", m_bridge);
49+
}));
50+
m_workThread->detach();
51+
52+
// wait until bridge starts
53+
m_bridge->WaitInitialize();
54+
55+
// now you can use bridge
56+
ScPythonBridge::ResponsePtr res = m_bridge->DoRequest("eventName", "eventData");
57+
}
58+
59+
void Stop()
60+
{
61+
m_bridge->Close(); // close bridge
62+
m_workThread->join(); // wait until thread finished
63+
}
64+
65+
private:
66+
py::ScPythonBridgePtr m_bridge; // special bridge to communicate with python script
67+
std::unique_ptr<std::thread> m_workThread; // thread where script runs
68+
};
69+
```
70+
71+
Then in python code use common module:
72+
```python
73+
from common import ScModule
74+
75+
class MyModule(ScModule):
76+
77+
kNrelMainIdtf = 'nrel_main_idtf'
78+
kDevice = 'device'
79+
80+
def __init__(self):
81+
ScModule.__init__(self,
82+
createScMemoryContext('MyModule'), keynodes=[
83+
# there we can initialize keynodes that we need
84+
MyModule.kNrelMainIdtf,
85+
MyModule.kDevice,
86+
], cpp_bridge=cpp_bridge)
87+
# cpp_bridge - is a global variable that store CPP-Python bridge object
88+
89+
90+
def OnCppUpdate(self):
91+
super.OnCppUpdate(self)
92+
# you can overload more functions for work
93+
# see more details in sc-kpm/python/common/sc_module.py
94+
95+
def printMainIdtf(self):
96+
# template to update current volume value
97+
templ = ScTemplate()
98+
templ.TripleWithRelation(
99+
self.keynodes[self.kDevice], # get ScAddr of keynode
100+
ScType.EdgeDCommonVar,
101+
ScType.Link >> '_link',
102+
ScType.EdgeAccessVarPosPerm,
103+
self.keynodes[self.kNrelMainIdtf])
104+
105+
# self.sc_context - is a context to work with sc-memory (use just this one)
106+
searchResult = self.sc_context.HelperSearchTemplate(templ)
107+
108+
linkAddr = None
109+
if searchResult.Size() > 0:
110+
# we found old value change it
111+
linkAddr = searchResult[0]['_link']
112+
else:
113+
genResult = self.sc_context.HelperGenTemplate(templ, ScTemplateGenParams())
114+
if genResult:
115+
linkAddr = genResult['_link']
116+
117+
if linkAddr:
118+
print(self.sc_context.GetLinkContent(linkAddr))
119+
120+
```
9121

10122
# Classes
11123

@@ -306,7 +418,7 @@ for i in range(resultNum):
306418
## ScMemoryContext
307419

308420
This class implements context, that allows you to work with memory.
309-
<div class="note"><b>You shouldn't share one context between two or more threads</b></div>
421+
<div class="note"><b>DO NOT use one context in different threads</b></div>
310422
There are methods of this class:
311423

312424
- `CreateNode(type)` - create node with specified type. Where `type` is an instance of `ScType` (just **edge** types could be used). Returns `ScAddr` of created node. If returned `ScAddr` is not valid (`IsValid()`), then node wasn't created.

sc-fm/sc_fm_filesystem/sc_fm_filesystem.c

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ sc_result sc_fs_engine_addr_ref_append(const sc_fm_engine *engine, sc_addr addr,
131131
addrs_num = 1;
132132
memcpy(content, &addrs_num, sizeof(addrs_num));
133133
memcpy(content + sizeof(addrs_num), &addr, sizeof(addr));
134-
}else
134+
}
135+
else
135136
{
136137
content2 = content;
137138
(*(sc_uint32*)content)++;
@@ -195,30 +196,42 @@ sc_result sc_fs_engine_addr_ref_remove(const sc_fm_engine *engine, sc_addr addr,
195196
if (content != 0)
196197
{
197198
g_assert(content_len % sizeof(sc_addr) == 0);
198-
sc_addr *iter = (sc_addr*)content;
199+
sc_addr *begin_addr = (sc_addr*)(content + sizeof(sc_uint32));
200+
sc_addr *iter = begin_addr;
199201
sc_addr *iter_end = (sc_addr*)(content + content_len);
200202
sc_bool found = SC_FALSE;
203+
sc_uint32 *addrs_num = (sc_uint32*)content;
204+
205+
g_assert(content_len == (*addrs_num * sizeof(sc_addr) + sizeof(sc_uint32)));
201206

202207
while (iter != iter_end)
203208
{
204209
if (SC_ADDR_IS_EQUAL(*iter, addr))
205210
{
206-
if (content_len > sizeof(sc_addr))
211+
if (*addrs_num > 1)
207212
{
208213
found = SC_TRUE;
209-
content2 = g_new0(gchar, content_len - sizeof(sc_addr));
210-
if ((gchar*)iter != content)
211-
memcpy(content2, content, (gchar*)iter - content);
214+
content_len -= sizeof(sc_addr);
215+
content2 = g_new0(gchar, content_len);
216+
217+
(*addrs_num)--;
218+
219+
// write number of addrs
220+
memcpy(content2, addrs_num, sizeof(sc_uint32));
221+
222+
if (iter != begin_addr)
223+
memcpy(content2, begin_addr, (gchar*)iter - (gchar*)begin_addr);
212224

213225
iter_next = iter;
214226
++iter_next;
215227

216228
if (iter_next != iter_end)
217-
memcpy(content2, iter + 1, (gchar*)iter_end - (gchar*)iter_next);
229+
memcpy(content2, iter_next, (gchar*)iter_end - (gchar*)iter_next);
218230

219231
g_free(content);
220232
content = content2;
221-
} else
233+
}
234+
else
222235
{
223236
g_free(content);
224237
content = null_ptr;
@@ -228,16 +241,11 @@ sc_result sc_fs_engine_addr_ref_remove(const sc_fm_engine *engine, sc_addr addr,
228241
}
229242
++iter;
230243
}
231-
232-
content = g_new0(gchar, content_len + sizeof(addr));
233-
memcpy(content, content2, content_len);
234-
memcpy(content + content_len, &addr, sizeof(addr));
235-
content_len += sizeof(addr);
236-
237-
// old content doesn't need
238-
g_free(content2);
239-
} else
244+
}
245+
else
246+
{
240247
res = SC_RESULT_ERROR_NOT_FOUND;
248+
}
241249

242250
// write content to file
243251
res = SC_RESULT_OK;
@@ -247,7 +255,9 @@ sc_result sc_fs_engine_addr_ref_remove(const sc_fm_engine *engine, sc_addr addr,
247255
res = SC_RESULT_ERROR_IO;
248256
}
249257
else if (g_file_set_contents(addr_path, content, content_len, 0) != TRUE)
258+
{
250259
res = SC_RESULT_ERROR_IO;
260+
}
251261

252262
clean:
253263
{
@@ -294,7 +304,8 @@ sc_result sc_fs_engine_find(const sc_fm_engine *engine, const sc_check_sum *chec
294304
*result = 0;
295305
*result_count = 0;
296306
res = SC_RESULT_ERROR_NOT_FOUND;
297-
}else
307+
}
308+
else
298309
{
299310
*result_count = *((sc_uint32*)content);
300311
content2 = content;

0 commit comments

Comments
 (0)