| … | … | @@ -7,9 +7,6 @@ DECLARE_GUILE_CONFIG_TARGET(SCM_CONFIG "opencog cs-config" "OPENCOG_TEST") |
| 7 | 7 | |
| 8 | 8 | ADD_SUBDIRECTORY (network) |
| 9 | 9 | ADD_SUBDIRECTORY (cogserver) |
| 10 | IF(HAVE_CYTHON) | |
| 11 | ADD_SUBDIRECTORY (cython) | |
| 12 | ENDIF(HAVE_CYTHON) | |
| 13 | 10 | |
| 14 | 11 | WRITE_GUILE_CONFIG(${GUILE_BIN_DIR}/opencog/cs-config.scm SCM_CONFIG TRUE) |
| 15 | 12 |
| … | … | @@ -5,6 +5,7 @@ ADD_SUBDIRECTORY (atoms) |
| 5 | 5 | ADD_SUBDIRECTORY (scm) |
| 6 | 6 | ADD_SUBDIRECTORY (modules) |
| 7 | 7 | ADD_SUBDIRECTORY (shell) |
| 8 | ADD_SUBDIRECTORY (python) | |
| 8 | 9 | |
| 9 | 10 | IF (HAVE_MCP) |
| 10 | 11 | ADD_SUBDIRECTORY (mcp-docs) |
| … | … | @@ -0,0 +1,8 @@ |
| 1 | # | |
| 2 | # Install pure Python cogserver module | |
| 3 | # | |
| 4 | INSTALL(FILES | |
| 5 | __init__.py | |
| 6 | cogserver.py | |
| 7 | DESTINATION "${PYTHON_DEST}" | |
| 8 | ) |
| … | … | @@ -0,0 +1,18 @@ |
| 1 | from pkgutil import extend_path | |
| 2 | __path__ = extend_path(__path__, __name__) | |
| 3 | ||
| 4 | # Import and expose cogserver functions | |
| 5 | try: | |
| 6 | from .cogserver import ( | |
| 7 | start_cogserver, | |
| 8 | stop_cogserver, | |
| 9 | is_cogserver_running, | |
| 10 | ) | |
| 11 | __all__ = [ | |
| 12 | 'start_cogserver', | |
| 13 | 'stop_cogserver', | |
| 14 | 'is_cogserver_running', | |
| 15 | ] | |
| 16 | except ImportError: | |
| 17 | # Module not fully installed yet | |
| 18 | pass |
| … | … | @@ -0,0 +1,101 @@ |
| 1 | # | |
| 2 | # cogserver.py | |
| 3 | # | |
| 4 | # Pure Python wrapper for starting/stopping the CogServer. | |
| 5 | # This module provides a convenient Python API for controlling | |
| 6 | # the CogServer network server. | |
| 7 | # | |
| 8 | ||
| 9 | from opencog.type_constructors import get_thread_atomspace, FloatValue, VoidValue, Predicate | |
| 10 | from opencog.atomspace import types | |
| 11 | ||
| 12 | # Global server state | |
| 13 | _server_handle = None | |
| 14 | _server_running = False | |
| 15 | ||
| 16 | def start_cogserver(console_port=17001, web_port=18080, mcp_port=18888, | |
| 17 | enable_console=True, enable_web=True, enable_mcp=True, | |
| 18 | name="cogserver"): | |
| 19 | """Start the CogServer with the specified configuration. | |
| 20 | ||
| 21 | Args: | |
| 22 | console_port (int, optional): Port for telnet console server. Default: 17001 | |
| 23 | web_port (int, optional): Port for web server. Default: 18080 | |
| 24 | mcp_port (int, optional): Port for MCP server. Default: 18888 | |
| 25 | enable_console (bool, optional): Enable telnet console server. Default: True | |
| 26 | enable_web (bool, optional): Enable web server. Default: True | |
| 27 | enable_mcp (bool, optional): Enable MCP server. Default: True | |
| 28 | name (str, optional): Name for the CogServerNode. Default: "cogserver" | |
| 29 | ||
| 30 | Returns: | |
| 31 | bool: True if server started successfully, False otherwise. | |
| 32 | ||
| 33 | Raises: | |
| 34 | RuntimeError: If server is already running. | |
| 35 | ValueError: If invalid ports are specified. | |
| 36 | """ | |
| 37 | global _server_handle, _server_running | |
| 38 | ||
| 39 | if _server_running: | |
| 40 | raise RuntimeError("CogServer is already running") | |
| 41 | ||
| 42 | # Validate ports | |
| 43 | for port, pname in [(console_port, "console"), (web_port, "web"), (mcp_port, "mcp")]: | |
| 44 | if not (1 <= port <= 65535): | |
| 45 | raise ValueError(f"Invalid {pname} port: {port}. Must be between 1 and 65535") | |
| 46 | ||
| 47 | # Get the thread atomspace and add the CogServerNode to it | |
| 48 | atomspace = get_thread_atomspace() | |
| 49 | _server_handle = atomspace.add_node(types.CogServerNode, name) | |
| 50 | ||
| 51 | # Set non-default port values (0 disables a server) | |
| 52 | effective_console = console_port if enable_console else 0 | |
| 53 | effective_web = web_port if enable_web else 0 | |
| 54 | effective_mcp = mcp_port if enable_mcp else 0 | |
| 55 | ||
| 56 | if effective_console != 17001: | |
| 57 | key = Predicate("*-telnet-port-*") | |
| 58 | atomspace.set_value(_server_handle, key, FloatValue(float(effective_console))) | |
| 59 | if effective_web != 18080: | |
| 60 | key = Predicate("*-web-port-*") | |
| 61 | atomspace.set_value(_server_handle, key, FloatValue(float(effective_web))) | |
| 62 | if effective_mcp != 18888: | |
| 63 | key = Predicate("*-mcp-port-*") | |
| 64 | atomspace.set_value(_server_handle, key, FloatValue(float(effective_mcp))) | |
| 65 | ||
| 66 | # Start all servers (this also starts the server thread) | |
| 67 | atomspace.set_value(_server_handle, Predicate("*-start-*"), VoidValue()) | |
| 68 | ||
| 69 | # Mark as initialized | |
| 70 | _server_running = True | |
| 71 | ||
| 72 | return True | |
| 73 | ||
| 74 | def stop_cogserver(): | |
| 75 | """Stop the running CogServer. | |
| 76 | ||
| 77 | Returns: | |
| 78 | bool: True if server was stopped, False if server was not running. | |
| 79 | """ | |
| 80 | global _server_handle, _server_running | |
| 81 | ||
| 82 | if not _server_running or _server_handle is None: | |
| 83 | return False | |
| 84 | ||
| 85 | # Stop the server | |
| 86 | atomspace = get_thread_atomspace() | |
| 87 | atomspace.set_value(_server_handle, Predicate("*-stop-*"), VoidValue()) | |
| 88 | ||
| 89 | _server_handle = None | |
| 90 | _server_running = False | |
| 91 | ||
| 92 | return True | |
| 93 | ||
| 94 | def is_cogserver_running(): | |
| 95 | """Check if the CogServer is currently running. | |
| 96 | ||
| 97 | Returns: | |
| 98 | bool: True if server is running, False otherwise. | |
| 99 | """ | |
| 100 | global _server_running | |
| 101 | return _server_running |
| … | … | @@ -1,6 +0,0 @@ |
| 1 | # | |
| 2 | ADD_SUBDIRECTORY (opencog) | |
| 3 | ||
| 4 | # module init | |
| 5 | file(MAKE_DIRECTORY opencog) | |
| 6 | file(COPY opencog/__init__.py DESTINATION opencog) |
| … | … | @@ -1,45 +0,0 @@ |
| 1 | CogServerNode Python Interface | |
| 2 | ------------------------------ | |
| 3 | ||
| 4 | The Python interface provides a very thin convenience wrapper around | |
| 5 | the CogServerNode. Users are encouraged to use the CogServerNode | |
| 6 | directly, instead of using this wrapper. | |
| 7 | ||
| 8 | ```python | |
| 9 | from opencog.atomspace import AtomSpace | |
| 10 | from opencog.cogserver import start_cogserver, stop_cogserver | |
| 11 | ||
| 12 | # Option 1: Start with default AtomSpace | |
| 13 | start_cogserver() | |
| 14 | ||
| 15 | # Option 2: Start with custom AtomSpace | |
| 16 | my_atomspace = AtomSpace() | |
| 17 | start_cogserver(atomspace=my_atomspace) | |
| 18 | ||
| 19 | # Option 3: Start with custom ports | |
| 20 | start_cogserver( | |
| 21 | console_port=17001, # Telnet console port | |
| 22 | web_port=18080, # Web interface port | |
| 23 | mcp_port=18888, # MCP server port | |
| 24 | enable_console=True, # Enable telnet console | |
| 25 | enable_web=False, # Disable web interface | |
| 26 | enable_mcp=False # Disable MCP server | |
| 27 | ) | |
| 28 | ||
| 29 | # Stop the server when done | |
| 30 | stop_cogserver() | |
| 31 | ``` | |
| 32 | ||
| 33 | ## Available Functions ## | |
| 34 | ||
| 35 | The `opencog.cogserver` module provides: | |
| 36 | ||
| 37 | * `start_cogserver(atomspace=None, console_port=17001, web_port=18080, mcp_port=18888, enable_console=True, enable_web=False, enable_mcp=False)` - Start the CogServer | |
| 38 | * `stop_cogserver()` - Stop the running CogServer | |
| 39 | * `is_cogserver_running()` - Check if server is running | |
| 40 | ||
| 41 | ## Tutorial ## | |
| 42 | ||
| 43 | The OpenCog wiki contains the Python tutorial: | |
| 44 | ||
| 45 | http://wiki.opencog.org/w/Python |
| … | … | @@ -1,53 +0,0 @@ |
| 1 | ||
| 2 | # Need to use -fno-strict-aliasing when compiling cython code, in order | |
| 3 | # to avoid nasty compiler warnings about aliasing. Cython explicitly | |
| 4 | # performs aliasing, in order to emulate python object inheritance. | |
| 5 | # See, for example, | |
| 6 | # https://groups.google.com/forum/#!topic/cython-users/JV1-KvIUeIg | |
| 7 | # | |
| 8 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing") | |
| 9 | ||
| 10 | INCLUDE_DIRECTORIES( | |
| 11 | ${ATOMSPACE_INCLUDE_DIR} | |
| 12 | ${Python3_INCLUDE_DIRS} | |
| 13 | ${CMAKE_CURRENT_SOURCE_DIR} | |
| 14 | ${CMAKE_CURRENT_BINARY_DIR} | |
| 15 | ) | |
| 16 | ||
| 17 | SET(CYTHON_FLAGS "-3" "-f" "-I" "${ATOMSPACE_INCLUDE_DIR}/opencog/cython") | |
| 18 | ||
| 19 | # Use this as a guide: | |
| 20 | # https://github.com/OpenKinect/libfreenect/blob/master/wrappers/python/CMakeLists.txt | |
| 21 | ||
| 22 | ############################ cogserver ######################### | |
| 23 | CYTHON_ADD_MODULE_PYX(cogserver | |
| 24 | "${ATOMSPACE_INCLUDE_DIR}/opencog/cython/opencog/atomspace.pxd" | |
| 25 | ) | |
| 26 | ||
| 27 | list(APPEND ADDITIONAL_MAKE_CLEAN_FILES "cogserver.cpp") | |
| 28 | ||
| 29 | # opencog.cogserver Python bindings | |
| 30 | ADD_LIBRARY(cogserver_cython SHARED | |
| 31 | cogserver.cpp | |
| 32 | ) | |
| 33 | ||
| 34 | TARGET_LINK_LIBRARIES(cogserver_cython | |
| 35 | server | |
| 36 | servernode | |
| 37 | ${ATOMSPACE_LIBRARIES} | |
| 38 | ${COGUTIL_LIBRARY} | |
| 39 | ${Python3_LIBRARIES} | |
| 40 | ) | |
| 41 | ||
| 42 | SET_TARGET_PROPERTIES(cogserver_cython PROPERTIES | |
| 43 | PREFIX "" | |
| 44 | OUTPUT_NAME cogserver) | |
| 45 | ||
| 46 | INSTALL (TARGETS cogserver_cython | |
| 47 | DESTINATION "${PYTHON_DEST}") | |
| 48 | ||
| 49 | INSTALL (FILES __init__.py | |
| 50 | DESTINATION "${PYTHON_DEST}") | |
| 51 | ||
| 52 | INSTALL (FILES cogserver.pxd | |
| 53 | DESTINATION "${CMAKE_INSTALL_PREFIX}/include/opencog/cython/opencog") |
| … | … | @@ -1,20 +0,0 @@ |
| 1 | from pkgutil import extend_path | |
| 2 | __path__ = extend_path(__path__, __name__) | |
| 3 | ||
| 4 | # Import and expose cogserver functions | |
| 5 | try: | |
| 6 | from .cogserver import ( | |
| 7 | start_cogserver, | |
| 8 | stop_cogserver, | |
| 9 | is_cogserver_running, | |
| 10 | get_server_atomspace | |
| 11 | ) | |
| 12 | __all__ = [ | |
| 13 | 'start_cogserver', | |
| 14 | 'stop_cogserver', | |
| 15 | 'is_cogserver_running', | |
| 16 | 'get_server_atomspace' | |
| 17 | ] | |
| 18 | except ImportError: | |
| 19 | # Module not built yet | |
| 20 | pass |
| … | … | @@ -1,11 +0,0 @@ |
| 1 | # CogServer extern declarations | |
| 2 | from libcpp.string cimport string | |
| 3 | from libcpp.memory cimport shared_ptr | |
| 4 | from opencog.atomspace cimport cAtomSpacePtr, cHandle, cAtom | |
| 5 | ||
| 6 | cdef extern from "opencog/cogserver/atoms/CogServerNode.h" namespace "opencog": | |
| 7 | cdef cppclass cCogServerNode "opencog::CogServerNode": | |
| 8 | cAtomSpacePtr getAtomSpace() | |
| 9 | ||
| 10 | ctypedef shared_ptr[cCogServerNode] cCogServerNodePtr "opencog::CogServerNodePtr" | |
| 11 | cCogServerNodePtr CogServerNodeCast(const cHandle&) |
| … | … | @@ -1,107 +0,0 @@ |
| 1 | # distutils: language = c++ | |
| 2 | # cython: language_level=3 | |
| 3 | ||
| 4 | from opencog.cogserver cimport cCogServerNode, cCogServerNodePtr, CogServerNodeCast | |
| 5 | from opencog.atomspace cimport cHandle, Atom, handle_cast | |
| 6 | from opencog.type_constructors import get_thread_atomspace, FloatValue, VoidValue, Predicate | |
| 7 | from opencog.atomspace import types | |
| 8 | from cython.operator cimport dereference as deref | |
| 9 | from libcpp.string cimport string | |
| 10 | ||
| 11 | # Global server state | |
| 12 | cdef cCogServerNodePtr _server_ptr | |
| 13 | _server_handle = None # Keep Python reference to prevent GC | |
| 14 | _server_running = False | |
| 15 | ||
| 16 | def start_cogserver(console_port=17001, web_port=18080, mcp_port=18888, | |
| 17 | enable_console=True, enable_web=True, enable_mcp=True, | |
| 18 | name="cogserver"): | |
| 19 | """Start the CogServer with the specified configuration. | |
| 20 | ||
| 21 | Args: | |
| 22 | console_port (int, optional): Port for telnet console server. Default: 17001 | |
| 23 | web_port (int, optional): Port for web server. Default: 18080 | |
| 24 | mcp_port (int, optional): Port for MCP server. Default: 18888 | |
| 25 | enable_console (bool, optional): Enable telnet console server. Default: True | |
| 26 | enable_web (bool, optional): Enable web server. Default: True | |
| 27 | enable_mcp (bool, optional): Enable MCP server. Default: True | |
| 28 | name (str, optional): Name for the CogServerNode. Default: "cogserver" | |
| 29 | ||
| 30 | Returns: | |
| 31 | bool: True if server started successfully, False otherwise. | |
| 32 | ||
| 33 | Raises: | |
| 34 | RuntimeError: If server is already running. | |
| 35 | ValueError: If invalid ports are specified. | |
| 36 | """ | |
| 37 | global _server_ptr, _server_handle, _server_running | |
| 38 | ||
| 39 | if _server_running: | |
| 40 | raise RuntimeError("CogServer is already running") | |
| 41 | ||
| 42 | # Validate ports | |
| 43 | for port, pname in [(console_port, "console"), (web_port, "web"), (mcp_port, "mcp")]: | |
| 44 | if not (1 <= port <= 65535): | |
| 45 | raise ValueError(f"Invalid {pname} port: {port}. Must be between 1 and 65535") | |
| 46 | ||
| 47 | # Get the thread atomspace and add the CogServerNode to it | |
| 48 | atomspace = get_thread_atomspace() | |
| 49 | _server_handle = atomspace.add_node(types.CogServerNode, name) | |
| 50 | ||
| 51 | # Get the C++ CogServerNode pointer from the Python Atom | |
| 52 | cdef Atom atom = <Atom>_server_handle | |
| 53 | cdef cHandle chandle = handle_cast(atom.shared_ptr) | |
| 54 | _server_ptr = CogServerNodeCast(chandle) | |
| 55 | ||
| 56 | # Set non-default port values (0 disables a server) | |
| 57 | effective_console = console_port if enable_console else 0 | |
| 58 | effective_web = web_port if enable_web else 0 | |
| 59 | effective_mcp = mcp_port if enable_mcp else 0 | |
| 60 | ||
| 61 | if effective_console != 17001: | |
| 62 | key = Predicate("*-telnet-port-*") | |
| 63 | atomspace.set_value(_server_handle, key, FloatValue(float(effective_console))) | |
| 64 | if effective_web != 18080: | |
| 65 | key = Predicate("*-web-port-*") | |
| 66 | atomspace.set_value(_server_handle, key, FloatValue(float(effective_web))) | |
| 67 | if effective_mcp != 18888: | |
| 68 | key = Predicate("*-mcp-port-*") | |
| 69 | atomspace.set_value(_server_handle, key, FloatValue(float(effective_mcp))) | |
| 70 | ||
| 71 | # Start all servers (this also starts the server thread) | |
| 72 | atomspace.set_value(_server_handle, Predicate("*-start-*"), VoidValue()) | |
| 73 | ||
| 74 | # Mark as initialized | |
| 75 | _server_running = True | |
| 76 | ||
| 77 | return True | |
| 78 | ||
| 79 | def stop_cogserver(): | |
| 80 | """Stop the running CogServer. | |
| 81 | ||
| 82 | Returns: | |
| 83 | bool: True if server was stopped, False if server was not running. | |
| 84 | """ | |
| 85 | global _server_ptr, _server_handle, _server_running | |
| 86 | ||
| 87 | if not _server_running or not _server_ptr: | |
| 88 | return False | |
| 89 | ||
| 90 | # Stop the server | |
| 91 | atomspace = get_thread_atomspace() | |
| 92 | atomspace.set_value(_server_handle, Predicate("*-stop-*"), VoidValue()) | |
| 93 | ||
| 94 | _server_ptr.reset() | |
| 95 | _server_handle = None | |
| 96 | _server_running = False | |
| 97 | ||
| 98 | return True | |
| 99 | ||
| 100 | def is_cogserver_running(): | |
| 101 | """Check if the CogServer is currently running. | |
| 102 | ||
| 103 | Returns: | |
| 104 | bool: True if server is running, False otherwise. | |
| 105 | """ | |
| 106 | global _server_running | |
| 107 | return _server_running |