mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Compare commits
84 Commits
sl-eurecom
...
setparam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51ce2fb17f | ||
|
|
4ca7dafb64 | ||
|
|
a3b05f0bd6 | ||
|
|
61dab4c7fd | ||
|
|
afb85855a9 | ||
|
|
eb68baaaa6 | ||
|
|
b4e0280228 | ||
|
|
16fc6028f9 | ||
|
|
2051e652fb | ||
|
|
6dc9440bd1 | ||
|
|
51f2a75bac | ||
|
|
1fadb0c11e | ||
|
|
9d2b747586 | ||
|
|
12099a910e | ||
|
|
9cca19e2b4 | ||
|
|
698e7fee1f | ||
|
|
857094e95c | ||
|
|
39a8aa3455 | ||
|
|
291533dd71 | ||
|
|
e18753db6e | ||
|
|
4cfa385ae0 | ||
|
|
2761d013d7 | ||
|
|
b112ed2c6b | ||
|
|
abb59447b3 | ||
|
|
e3d38b5cbe | ||
|
|
3b282d7fb9 | ||
|
|
80bf03581d | ||
|
|
86f36e8098 | ||
|
|
273ce8cb49 | ||
|
|
93126750ea | ||
|
|
7a7b2ff48a | ||
|
|
dac3bc1af5 | ||
|
|
32e49924b0 | ||
|
|
b203d4aebc | ||
|
|
dfa7579857 | ||
|
|
f2af6c26fa | ||
|
|
c4cf67f04b | ||
|
|
9dbcab30c8 | ||
|
|
24e878148e | ||
|
|
8d74ea3809 | ||
|
|
a3ac83a1bf | ||
|
|
5ef05129e1 | ||
|
|
8de026f86e | ||
|
|
3127898899 | ||
|
|
3c6b21e9c0 | ||
|
|
2afae81592 | ||
|
|
fa03569f1f | ||
|
|
108d9a965e | ||
|
|
6686076f06 | ||
|
|
afdbca2a48 | ||
|
|
a3b64c4a7e | ||
|
|
564bcde637 | ||
|
|
2027d77b18 | ||
|
|
28f1035e27 | ||
|
|
6e3f09a35d | ||
|
|
9ca2d78f2e | ||
|
|
14321bfe6f | ||
|
|
1fee616d62 | ||
|
|
1eb79272a1 | ||
|
|
79b8586432 | ||
|
|
9301d8a7f0 | ||
|
|
8ad4c7b75c | ||
|
|
36e1715f18 | ||
|
|
310245ef78 | ||
|
|
64e33694ef | ||
|
|
8c355a08a7 | ||
|
|
b575a95144 | ||
|
|
c239d99f1c | ||
|
|
fc3319c9dc | ||
|
|
f1e87cab8f | ||
|
|
e5a96b5d01 | ||
|
|
77b4022bbf | ||
|
|
d007295a34 | ||
|
|
6bcd3006b0 | ||
|
|
7acc5e967b | ||
|
|
426b99211d | ||
|
|
c7b2c19f0c | ||
|
|
317559806a | ||
|
|
51362d9c6c | ||
|
|
8ead6ae767 | ||
|
|
6e915cd64e | ||
|
|
190f90e35d | ||
|
|
7f19b9453e | ||
|
|
5861a7019b |
30
.vscode/launch.json
vendored
30
.vscode/launch.json
vendored
@@ -10,7 +10,8 @@
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/cmake_targets/ran_build/build/lte-softmodem",
|
||||
"args": [
|
||||
"-O", "../ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf",
|
||||
"-O",
|
||||
"../ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf",
|
||||
"--noS1"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
@@ -26,6 +27,31 @@
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Launch Chrome (4200 ng serve)",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:4200",
|
||||
"webRoot": "${workspaceFolder}/common/utils/websrv/frontend"
|
||||
},
|
||||
{
|
||||
"name": "Launch Chrome (localhost)",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost",
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"sourceMapPathOverrides": {
|
||||
"webpack:/*": "${webRoot}/*",
|
||||
"/./*": "${webRoot}/*",
|
||||
"/src/*": "${webRoot}/*",
|
||||
"/*": "*",
|
||||
"/./~/*": "${webRoot}/node_modules/*"
|
||||
},
|
||||
"trace": true,
|
||||
"runtimeArgs": [
|
||||
"--remote-debugging-port=9222"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3178,3 +3178,4 @@ ADD_CUSTOM_TARGET(oarf
|
||||
)
|
||||
|
||||
include (${OPENAIR_DIR}/common/utils/telnetsrv/telnetsrv_CMakeLists.txt)
|
||||
include (${OPENAIR_DIR}/common/utils/websrv/websrv_CMakeLists.txt)
|
||||
|
||||
@@ -57,7 +57,7 @@ CMAKE_BUILD_TYPE="RelWithDebInfo"
|
||||
CMAKE_CMD="$CMAKE"
|
||||
BUILD_ECLIPSE=0
|
||||
NR="False"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope"
|
||||
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope websrv"
|
||||
RU=0
|
||||
trap handle_ctrl_c INT
|
||||
|
||||
|
||||
@@ -88,6 +88,8 @@ int processoption(paramdef_t *cfgoptions, char *value) {
|
||||
config_check_valptr(cfgoptions, cfgoptions->strptr, strlen(tmpval)+1);
|
||||
sprintf(*(cfgoptions->strptr), "%s",tmpval);
|
||||
} else {
|
||||
AssertFatal( ( strlen(*(cfgoptions->strptr)) < cfgoptions->numelt), "[CONFIG] Error: %s too long, %s value cannot exceed %i bytes\n",
|
||||
cfgoptions->optname,tmpval, cfgoptions->numelt) ;
|
||||
sprintf( (char *)(cfgoptions->strptr), "%s",tmpval);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,10 +88,21 @@ int load_config_sharedlib(configmodule_interface_t *cfgptr) {
|
||||
st = -1;
|
||||
}
|
||||
|
||||
if ( cfgptr->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
sprintf (fname,"config_%s_set",cfgptr->cfgmode);
|
||||
cfgptr->set = dlsym(lib_handle,fname);
|
||||
|
||||
if (cfgptr->set == NULL ) {
|
||||
printf("[CONFIG] %s %d no function %s for config mode %s\n",
|
||||
__FILE__, __LINE__,fname, cfgptr->cfgmode);
|
||||
st = -1;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf (fname,"config_%s_end",cfgptr->cfgmode);
|
||||
cfgptr->end = dlsym(lib_handle,fname);
|
||||
|
||||
if (cfgptr->getlist == NULL ) {
|
||||
if (cfgptr->end == NULL ) {
|
||||
printf("[CONFIG] %s %d no function %s for config mode %s\n",
|
||||
__FILE__, __LINE__,fname, cfgptr->cfgmode);
|
||||
}
|
||||
@@ -186,6 +197,7 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
uint32_t initflags)
|
||||
{
|
||||
char *cfgparam=NULL;
|
||||
|
||||
char *modeparams=NULL;
|
||||
char *cfgmode=NULL;
|
||||
char *strtokctx=NULL;
|
||||
@@ -193,7 +205,8 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
uint32_t tmpflags=0;
|
||||
int i;
|
||||
int OoptIdx=-1;
|
||||
|
||||
int OWoptIdx=-1;
|
||||
|
||||
printf("CMDLINE: ");
|
||||
for (int i=0; i<argc; i++)
|
||||
printf("\"%s\" ", argv[i]);
|
||||
@@ -208,7 +221,11 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
cfgparam = argv[i+1];
|
||||
OoptIdx=i;
|
||||
}
|
||||
|
||||
|
||||
char *OWopt = strstr(argv[i],"OW");
|
||||
if ( OWopt == argv[i]+2) {
|
||||
OWoptIdx=i;
|
||||
}
|
||||
if ( strstr(argv[i], "help_config") != NULL ) {
|
||||
config_printhelp(Config_Params,CONFIG_PARAMLENGTH(Config_Params),CONFIG_SECTIONNAME);
|
||||
exit(0);
|
||||
@@ -258,6 +275,11 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
/* argv[0] is the exec name, always Ok */
|
||||
cfgptr->argv_info[0] |= CONFIG_CMDLINEOPT_PROCESSED;
|
||||
|
||||
/* When reuested _(_--OW or rtflag is 5), a file with config parameters, as defined after all processing, will be created */
|
||||
if (OWoptIdx >= 0) {
|
||||
cfgptr->argv_info[OWoptIdx] |= CONFIG_CMDLINEOPT_PROCESSED;
|
||||
cfgptr->rtflags |= CONFIG_SAVERUNCFG ;
|
||||
}
|
||||
/* when OoptIdx is >0, -O option has been detected at position OoptIdx
|
||||
* we must memorize arv[OoptIdx is Ok */
|
||||
if (OoptIdx >= 0) {
|
||||
@@ -294,14 +316,18 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
printf("%s ",cfgptr->cfgP[i]);
|
||||
}
|
||||
|
||||
printf(", debug flags: 0x%08x\n",cfgptr->rtflags);
|
||||
|
||||
if (cfgptr->rtflags & CONFIG_PRINTPARAMS) {
|
||||
cfgptr->status = malloc(sizeof(configmodule_status_t));
|
||||
}
|
||||
if (strstr(cfgparam,CONFIG_CMDLINEONLY) == NULL) {
|
||||
i=load_config_sharedlib(cfgptr);
|
||||
|
||||
if (i == 0) {
|
||||
printf("[CONFIG] config module %s loaded\n",cfgmode);
|
||||
Config_Params[CONFIGPARAM_DEBUGFLAGS_IDX].uptr=&(cfgptr->rtflags);
|
||||
int idx = config_paramidx_fromname(Config_Params, CONFIG_PARAMLENGTH(Config_Params), CONFIGP_DEBUGFLAGS);
|
||||
Config_Params[idx].uptr=&(cfgptr->rtflags);
|
||||
idx = config_paramidx_fromname(Config_Params, CONFIG_PARAMLENGTH(Config_Params), CONFIGP_TMPDIR);
|
||||
Config_Params[idx].strptr=&(cfgptr->tmpdir);
|
||||
config_get(Config_Params,CONFIG_PARAMLENGTH(Config_Params), CONFIG_SECTIONNAME );
|
||||
} else {
|
||||
fprintf(stderr,"[CONFIG] %s %d config module \"%s\" couldn't be loaded\n", __FILE__, __LINE__,cfgmode);
|
||||
@@ -313,7 +339,10 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
cfgptr->getlist = config_cmdlineonly_getlist;
|
||||
cfgptr->end = (configmodule_endfunc_t)nooptfunc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
printf("[CONFIG] debug flags: 0x%08x\n",cfgptr->rtflags);
|
||||
|
||||
if (modeparams != NULL) free(modeparams);
|
||||
|
||||
if (cfgmode != NULL) free(cfgmode);
|
||||
@@ -330,6 +359,14 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
/* free memory allocated when reading parameters */
|
||||
/* config module could be initialized again after this call */
|
||||
void end_configmodule(void) {
|
||||
if ( cfgptr->status && (cfgptr->rtflags & CONFIG_SAVERUNCFG)) {
|
||||
printf_params("[CONFIG] Runtime params creation status: %i null values, %i errors, %i empty list or array, %i successfull \n",
|
||||
cfgptr->status->num_err_nullvalue,
|
||||
cfgptr->status->num_err_write,
|
||||
cfgptr->status->emptyla,
|
||||
cfgptr->status->num_write);
|
||||
|
||||
}
|
||||
if (cfgptr != NULL) {
|
||||
if (cfgptr->end != NULL) {
|
||||
printf ("[CONFIG] calling config module end function...\n");
|
||||
@@ -355,7 +392,7 @@ void end_configmodule(void) {
|
||||
void free_configmodule(void) {
|
||||
if (cfgptr != NULL) {
|
||||
end_configmodule();
|
||||
|
||||
if( cfgptr->status != NULL) free(cfgptr->status);
|
||||
if( cfgptr->cfgmode != NULL) free(cfgptr->cfgmode);
|
||||
|
||||
printf ("[CONFIG] free %i config parameter pointers\n",cfgptr->num_cfgP);
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#define CONFIG_DEBUGPTR (1<<1) // print memory allocation/free debug messages
|
||||
#define CONFIG_DEBUGCMDLINE (1<<2) // print command line processing messages
|
||||
#define CONFIG_NOABORTONCHKF (1<<4) // disable abort execution when parameter checking function fails
|
||||
#define CONFIG_SAVERUNCFG (1<<5) // create config file with running values, as after cfg file + command line processing
|
||||
#define CONFIG_NOEXITONHELP (1<<19) // do not exit after printing help
|
||||
#define CONFIG_HELP (1<<20) // print help message
|
||||
#define CONFIG_ABORT (1<<21) // config failed,abort execution
|
||||
@@ -61,7 +62,23 @@
|
||||
typedef int(*configmodule_initfunc_t)(char *cfgP[],int numP);
|
||||
typedef int(*configmodule_getfunc_t)(paramdef_t *,int numparams, char *prefix);
|
||||
typedef int(*configmodule_getlistfunc_t)(paramlist_def_t *, paramdef_t *,int numparams, char *prefix);
|
||||
typedef int(*configmodule_setfunc_t)(paramdef_t *cfgoptions, int numoptions, char *prefix );
|
||||
typedef void(*configmodule_endfunc_t)(void);
|
||||
typedef struct configmodule_status {
|
||||
int num_paramgroups;
|
||||
char ** paramgroups_names;
|
||||
int num_err_nullvalue;
|
||||
int emptyla;
|
||||
union {
|
||||
int num_err_read;
|
||||
int num_err_write;
|
||||
};
|
||||
union {
|
||||
int num_read;
|
||||
int num_write;
|
||||
} ;
|
||||
}configmodule_status_t;
|
||||
|
||||
typedef struct configmodule_interface {
|
||||
int argc;
|
||||
char **argv;
|
||||
@@ -72,11 +89,14 @@ typedef struct configmodule_interface {
|
||||
configmodule_initfunc_t init;
|
||||
configmodule_getfunc_t get;
|
||||
configmodule_getlistfunc_t getlist;
|
||||
configmodule_setfunc_t set;
|
||||
configmodule_endfunc_t end;
|
||||
uint32_t numptrs;
|
||||
uint32_t rtflags;
|
||||
char *ptrs[CONFIG_MAX_ALLOCATEDPTRS];
|
||||
bool ptrsAllocated[CONFIG_MAX_ALLOCATEDPTRS];
|
||||
char *tmpdir;
|
||||
configmodule_status_t *status; // allocated in debug mode only
|
||||
} configmodule_interface_t;
|
||||
|
||||
#ifdef CONFIG_LOADCONFIG_MAIN
|
||||
@@ -89,16 +109,19 @@ static char config_helpstr [] = "\n lte-softmodem -O [config mode]<:dbgl[debugfl
|
||||
incp parameter can be used to define the include path used for config files (@include directive)\n \
|
||||
defaults is set to the path of the main config file.\n";
|
||||
|
||||
#define CONFIG_SECTIONNAME "config"
|
||||
#define CONFIGPARAM_DEBUGFLAGS_IDX 0
|
||||
#define CONFIG_HELP_TMPDIR "<Repository to create temporary file>"
|
||||
|
||||
#define CONFIG_SECTIONNAME "config"
|
||||
#define CONFIGP_DEBUGFLAGS "debugflags"
|
||||
#define CONFIGP_TMPDIR "tmpdir"
|
||||
|
||||
static paramdef_t Config_Params[] = {
|
||||
/*-----------------------------------------------------------------------------------------------------------------------*/
|
||||
/* config parameters for config module */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-----------------------------------------------------------------------------------------------------------------------*/
|
||||
{"debugflags", config_helpstr, 0, uptr:NULL, defintval:0, TYPE_MASK, 0},
|
||||
/*--------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* config parameters for config module */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*--------------------------------------------------------------------------------------------------------------------------*/
|
||||
{CONFIGP_DEBUGFLAGS, config_helpstr, 0, uptr:NULL, defintval:0, TYPE_MASK, 0},
|
||||
{CONFIGP_TMPDIR, CONFIG_HELP_TMPDIR,PARAMFLAG_NOFREE, strptr:NULL, defstrval:"/tmp" ,TYPE_STRING, 0},
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#define PARAMFLAG_NOFREE (1 << 3) // don't free parameter in end function
|
||||
#define PARAMFLAG_BOOL (1 << 4) // integer param can be 0 or 1
|
||||
#define PARAMFLAG_CMDLINE_NOPREFIXENABLED (1 << 5) // on the command line, allow a parameter to be specified without the prefix
|
||||
#define PARAMFLAG_CMDLINEONLY (1 << 6) // this parameter cannot be specified in config file
|
||||
|
||||
/* Flags used by config modules to return info to calling modules and/or to for internal usage*/
|
||||
#define PARAMFLAG_MALLOCINCONFIG (1 << 15) // parameter allocated in config module
|
||||
|
||||
@@ -237,6 +237,9 @@ int config_get(paramdef_t *params, int numparams, char *prefix) {
|
||||
|
||||
if (ret >= 0) {
|
||||
config_process_cmdline(params, numparams, prefix);
|
||||
if ( cfgif->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
config_get_if()->set(params, numparams, prefix);
|
||||
}
|
||||
config_execcheck(params, numparams, prefix);
|
||||
}
|
||||
|
||||
@@ -271,9 +274,11 @@ int config_getlist(paramlist_def_t *ParamList, paramdef_t *params, int numparams
|
||||
char cfgpath[MAX_OPTNAME_SIZE*2 + 6]; /* prefix.listname.[listindex] */
|
||||
|
||||
for (int i = 0; i < ParamList->numelt; ++i) {
|
||||
// TODO config_process_cmdline?
|
||||
sprintf(cfgpath, "%s.[%i]", newprefix, i);
|
||||
config_process_cmdline(ParamList->paramarray[i],numparams,cfgpath);
|
||||
if ( config_get_if()->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
config_get_if()->set(ParamList->paramarray[i], numparams,cfgpath );
|
||||
}
|
||||
config_execcheck(ParamList->paramarray[i], numparams, cfgpath);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,11 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "config_libconfig.h"
|
||||
#include "config_libconfig_private.h"
|
||||
@@ -87,8 +90,222 @@ int read_intarray(paramdef_t *cfgoptions,config_setting_t *setting, char *cfgpat
|
||||
|
||||
return cfgoptions->numelt;
|
||||
}
|
||||
int config_libconfig_setparams(paramdef_t *cfgoptions, int numoptions, config_setting_t * asetting, char * prefix) {
|
||||
int status;
|
||||
int errors=0;
|
||||
int notused=0;
|
||||
int emptyla=0;
|
||||
#define LIBCONFIG_NOTUSED_PARAMS "Not used? (NULL value ptr)"
|
||||
char *secprefix=(prefix==NULL)?"":prefix;
|
||||
|
||||
for(int i=0; i<numoptions; i++) {
|
||||
if (cfgoptions[i].paramflags & PARAMFLAG_CMDLINEONLY) {
|
||||
continue;
|
||||
printf_params("[LIBCONFIG] setting %s.%s skipped (command line only) \n",secprefix,cfgoptions[i].optname);
|
||||
}
|
||||
status=CONFIG_FALSE;
|
||||
config_setting_t * psetting;
|
||||
char *spath=malloc(((prefix==NULL)?0:strlen(prefix))+strlen(cfgoptions[i].optname)+10);
|
||||
sprintf(spath,"%s%s%s",secprefix, (prefix==NULL)?"":".", cfgoptions[i].optname);
|
||||
psetting = config_lookup(&(libconfig_privdata.runtcfg),spath);
|
||||
free(spath);
|
||||
if (psetting != NULL) {
|
||||
printf_params("[LIBCONFIG] setting %s.%s already created \n",secprefix,cfgoptions[i].optname);
|
||||
continue;
|
||||
}
|
||||
switch(cfgoptions[i].type) {
|
||||
case TYPE_STRING:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_STRING);
|
||||
if (psetting!= NULL) {
|
||||
char *value;
|
||||
if (cfgoptions[i].strptr == NULL) {
|
||||
notused++;
|
||||
value=LIBCONFIG_NOTUSED_PARAMS;
|
||||
} else {
|
||||
if (cfgoptions[i].numelt == 0 ) {
|
||||
value = *(cfgoptions[i].strptr);
|
||||
} else {
|
||||
value = (char *)(cfgoptions[i].strptr);
|
||||
}
|
||||
}
|
||||
status=config_setting_set_string(psetting, value);
|
||||
}
|
||||
break;
|
||||
case TYPE_STRINGLIST:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_LIST);
|
||||
if (psetting!= NULL)
|
||||
{
|
||||
if(cfgoptions[i].numelt <= 0) {
|
||||
emptyla++;
|
||||
printf_params("[LIBCONFIG], no element in list %s\n",cfgoptions[i].optname);
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
for (int j=0; j<cfgoptions[i].numelt ; j++) {
|
||||
config_setting_t *elemsetting=config_setting_set_string_elem(psetting, -1,cfgoptions[i].strptr[j] );
|
||||
if (elemsetting == NULL) {
|
||||
fprintf(stderr,"[LIBCONFIG] Error: Creating list %s element %i value %s\n",cfgoptions[i].optname,j,cfgoptions[i].strptr[j]);
|
||||
break;
|
||||
} else
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_UINT8:
|
||||
case TYPE_INT8:
|
||||
case TYPE_UINT16:
|
||||
case TYPE_INT16:
|
||||
case TYPE_UINT32:
|
||||
case TYPE_INT32:
|
||||
case TYPE_MASK:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_INT);
|
||||
if (psetting!= NULL)
|
||||
status=config_setting_set_int(psetting, (int)*(cfgoptions[i].iptr) );
|
||||
break;
|
||||
|
||||
case TYPE_UINT64:
|
||||
case TYPE_INT64:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_INT64);
|
||||
if (psetting!= NULL)
|
||||
status=config_setting_set_int64(psetting, (int64_t)*(cfgoptions[i].i64ptr) );
|
||||
break;
|
||||
|
||||
case TYPE_UINTARRAY:
|
||||
case TYPE_INTARRAY:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_ARRAY);
|
||||
if (psetting!= NULL) {
|
||||
if(cfgoptions[i].numelt <= 0) {
|
||||
emptyla++;
|
||||
printf_params("[LIBCONFIG], no element in array %s.%s\n",secprefix,cfgoptions[i].optname);
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
for (int j=0; j<cfgoptions[i].numelt ; j++) {
|
||||
config_setting_t *elemsetting=config_setting_set_int_elem(psetting, -1,(int)(cfgoptions[i].iptr[j]) );
|
||||
if (elemsetting == NULL) {
|
||||
fprintf(stderr,"[LIBCONFIG] Error: Creating array %s.%s, at index %i value %i\n",secprefix,cfgoptions[i].optname,j,(int)(cfgoptions[i].iptr[j]));
|
||||
break;
|
||||
} else
|
||||
status=CONFIG_TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_DOUBLE:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_FLOAT);
|
||||
if (psetting!= NULL)
|
||||
status=config_setting_set_float(psetting, (double)*(cfgoptions[i].dblptr) );
|
||||
break;
|
||||
|
||||
case TYPE_IPV4ADDR:
|
||||
psetting =config_setting_add(asetting,cfgoptions[i].optname,CONFIG_TYPE_STRING);
|
||||
if (psetting!= NULL) {
|
||||
char ipstr[INET_ADDRSTRLEN];
|
||||
if (inet_ntop(AF_INET, cfgoptions[i].uptr, ipstr, INET_ADDRSTRLEN) == NULL) {
|
||||
notused++;
|
||||
sprintf(ipstr,"undef");
|
||||
} else {
|
||||
status=config_setting_set_string(psetting, ipstr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LIST:
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,"[LIBCONFIG] %s.%s type %i not supported\n",secprefix,cfgoptions[i].optname ,cfgoptions[i].type);
|
||||
status=CONFIG_FALSE;
|
||||
break;
|
||||
} /* switch on param type */
|
||||
if (status != CONFIG_TRUE) {
|
||||
errors++;
|
||||
fprintf(stderr,"[LIBCONFIG] Error creating setting %i: %s.%s type %i\n",i,secprefix,cfgoptions[i].optname ,cfgoptions[i].type);
|
||||
}
|
||||
}
|
||||
printf_params("[LIBCONFIG], in group \"%s\" %i settings \n",secprefix,numoptions);
|
||||
if (notused > 0)
|
||||
printf_params("[LIBCONFIG], ..... %i settings with NULL value pointer\n",notused);
|
||||
if (errors >0)
|
||||
fprintf(stderr,"[LIBCONFIG] .....%i settings creation errors \n",errors);
|
||||
if (emptyla >0)
|
||||
fprintf(stderr,"[LIBCONFIG] .....%i empty lists or arrays settings \n",emptyla);
|
||||
|
||||
if ( cfgptr->status ) {
|
||||
cfgptr->status->num_err_nullvalue += notused;
|
||||
cfgptr->status->num_err_write += errors;
|
||||
cfgptr->status->num_write += numoptions;
|
||||
cfgptr->status->emptyla += emptyla;
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
int config_libconfig_set(paramdef_t *cfgoptions, int numoptions, char *prefix ) {
|
||||
char *tokctx1=NULL;
|
||||
int listidx=-1;
|
||||
char *prefixbck=NULL;
|
||||
char *prefix_elem1=NULL;
|
||||
config_setting_t * asetting = config_root_setting (&(libconfig_privdata.runtcfg));
|
||||
if (prefix != NULL) {
|
||||
prefixbck=strdup(prefix);
|
||||
prefix_elem1 = strtok_r(prefixbck, ".", &tokctx1);
|
||||
}
|
||||
printf_params("[LIBCONFIG], processing prefix %s\n",(prefix==NULL)?"NULL":prefix);
|
||||
|
||||
/* parse the prefix , possibly creating groups, lists and list elements */
|
||||
while (prefix_elem1 != NULL) {
|
||||
int n1=strlen(prefix_elem1);
|
||||
char *prefix_elem2 = prefix_elem1+n1+1 ;
|
||||
printf_params("[LIBCONFIG], processing elem1 %s elem2 %s\n",prefix_elem1,prefix_elem2);
|
||||
/* prefix (the path to the parameter name) may contain groups and elements from a list, which are specified with [] */
|
||||
if (prefix_elem2[0] != '[') { // not a list
|
||||
|
||||
config_setting_t *tmpset = config_setting_lookup(asetting,prefix_elem1);
|
||||
if (tmpset == NULL)
|
||||
asetting = config_setting_add (asetting, prefix_elem1, CONFIG_TYPE_GROUP);
|
||||
else
|
||||
asetting = tmpset;
|
||||
printf_params("[LIBCONFIG], creating or looking for group %s: %s\n",prefix_elem1,(asetting==NULL)?"NOK":"OK");
|
||||
} else { // a list
|
||||
listidx=(int)strtol(prefix_elem2+1,NULL,10);
|
||||
if (errno == EINVAL || errno == ERANGE) {
|
||||
printf_params("[LIBCONFIG], Error %s looking for list index in %s \n",strerror(errno), prefix_elem2);
|
||||
break;
|
||||
}
|
||||
config_setting_t *tmpset = config_setting_lookup(asetting,prefix_elem1);
|
||||
if (tmpset == NULL)
|
||||
asetting = config_setting_add (asetting, prefix_elem1, CONFIG_TYPE_LIST);
|
||||
else
|
||||
asetting = tmpset;
|
||||
printf_params("[LIBCONFIG], creating or looking for list %s: %s\n",prefix_elem1,(asetting==NULL)?"NOK":"OK");
|
||||
if (asetting != NULL) {
|
||||
tmpset = config_setting_get_elem (asetting, listidx);
|
||||
if (tmpset == NULL)
|
||||
asetting = config_setting_add (asetting, NULL, CONFIG_TYPE_GROUP);
|
||||
else
|
||||
asetting = tmpset;
|
||||
printf_params("[LIBCONFIG], creating or looking for list element %i: %s\n",listidx,(asetting==NULL)?"NOK":"OK");
|
||||
}
|
||||
prefix_elem1 = strtok_r(NULL, ".", &tokctx1); //skip the [x] elements we already took care of it
|
||||
if (prefix_elem1 == NULL) {
|
||||
fprintf(stderr, "[LICONFIG] End of parsing %s \n",prefix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (asetting == NULL) {
|
||||
fprintf(stderr,"[LIBCONFIG] Error creating setting %s %s %i\n",prefix_elem1,prefix_elem2,listidx);
|
||||
}
|
||||
prefix_elem1 = strtok_r(NULL, ".", &tokctx1);
|
||||
}
|
||||
free(prefixbck);
|
||||
if (asetting != NULL) {
|
||||
config_libconfig_setparams(cfgoptions, numoptions,asetting,prefix);
|
||||
printf_params("[LIBCONFIG] %i settings added in group %s\n",numoptions,(prefix==NULL)?"":prefix);
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr,"[LIBCONFIG] Error parsing %s params, skipped...\n",(prefix==NULL)?"":prefix);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int config_libconfig_get(paramdef_t *cfgoptions,int numoptions, char *prefix ) {
|
||||
@@ -376,6 +593,12 @@ int config_libconfig_init(char *cfgP[], int numP) {
|
||||
free(tmppath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* possibly init a libconfig struct for saving really used params */
|
||||
if( cfgptr->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
config_init ( &(libconfig_privdata.runtcfg));
|
||||
// config_set_options (&(libconfig_privdata.runtcfg), CONFIG_OPTION_ALLOW_OVERRIDES, CONFIG_TRUE);
|
||||
}
|
||||
free(tmppath);
|
||||
return 0;
|
||||
}
|
||||
@@ -383,7 +606,25 @@ int config_libconfig_init(char *cfgP[], int numP) {
|
||||
|
||||
void config_libconfig_end(void ) {
|
||||
config_destroy(&(libconfig_privdata.cfg));
|
||||
|
||||
if( cfgptr->rtflags & CONFIG_SAVERUNCFG ) {
|
||||
char *fname=strdup(libconfig_privdata.configfile);
|
||||
int newcfgflen = strlen( libconfig_privdata.configfile) + strlen(cfgptr->tmpdir) + 20;
|
||||
char *newcfgf = malloc( newcfgflen);
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
snprintf (newcfgf,newcfgflen, "%s/%s-run%d_%02d_%02d_%02d%02d",cfgptr->tmpdir,basename(fname),
|
||||
tm.tm_year + 1900,tm.tm_mon + 1,tm.tm_mday, tm.tm_hour, tm.tm_min);
|
||||
if ( config_write_file (&(libconfig_privdata.runtcfg) , newcfgf) != CONFIG_TRUE) {
|
||||
fprintf(stderr,"[LIBCONFIG] %s %d file %s - line %d: %s\n",__FILE__, __LINE__,
|
||||
newcfgf, config_error_line(&(libconfig_privdata.runtcfg)),
|
||||
config_error_text(&(libconfig_privdata.runtcfg)));
|
||||
} else {
|
||||
printf("[LIBCONFIG] file %s created successfully\n", newcfgf);
|
||||
}
|
||||
config_destroy(&(libconfig_privdata.runtcfg));
|
||||
free(fname);
|
||||
free(newcfgf);
|
||||
}
|
||||
if ( libconfig_privdata.configfile != NULL ) {
|
||||
free(libconfig_privdata.configfile);
|
||||
libconfig_privdata.configfile=NULL;
|
||||
|
||||
@@ -40,12 +40,11 @@ extern "C"
|
||||
|
||||
#include "common/config/config_paramdesc.h"
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct libconfig_privatedata {
|
||||
char *configfile;
|
||||
config_t cfg;
|
||||
config_t runtcfg;
|
||||
} libconfig_privatedata_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -302,8 +302,8 @@ void log_getconfig(log_t *g_log)
|
||||
|
||||
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_PREDEF_COMPONENTS; i++) {
|
||||
if(g_log->log_component[i].name == NULL) {
|
||||
g_log->log_component[i].name = malloc(16);
|
||||
sprintf((char *)g_log->log_component[i].name,"comp%i?",i);
|
||||
g_log->log_component[i].name = calloc(1,16);
|
||||
snprintf((char *)g_log->log_component[i].name,15,"undefcomp%i",i);
|
||||
logparams_logfile[i].paramflags = PARAMFLAG_DONOTREAD;
|
||||
logparams_level[i].paramflags = PARAMFLAG_DONOTREAD;
|
||||
}
|
||||
|
||||
@@ -90,25 +90,28 @@ int get_phybsize(void) {
|
||||
};
|
||||
int add_telnetcmd(char *modulename,telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd );
|
||||
int setoutput(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
int wsetoutput(char *buff, int debug, telnet_printfunc_t prnt, ... );
|
||||
int setparam(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
int wsetparam(char *buff, int debug, telnet_printfunc_t prnt, ... );
|
||||
int history_cmd(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
|
||||
|
||||
telnetshell_vardef_t telnet_vardef[] = {
|
||||
{"debug",TELNET_VARTYPE_INT32,&telnetparams.telnetdbg},
|
||||
{"prio",TELNET_VARTYPE_INT32,&telnetparams.priority},
|
||||
{"loopc",TELNET_VARTYPE_INT32,&telnetparams.loopcount},
|
||||
{"loopd",TELNET_VARTYPE_INT32,&telnetparams.loopdelay},
|
||||
{"phypb",TELNET_VARTYPE_INT32,&telnetparams.phyprntbuff_size},
|
||||
{"hsize",TELNET_VARTYPE_INT32,&telnetparams.histsize},
|
||||
{"hfile",TELNET_VARTYPE_STRING,&telnetparams.histfile},
|
||||
{"",0,NULL}
|
||||
{"debug",TELNET_VARTYPE_INT32,0,&telnetparams.telnetdbg},
|
||||
{"prio",TELNET_VARTYPE_INT32,0,&telnetparams.priority},
|
||||
{"loopc",TELNET_VARTYPE_INT32,0,&telnetparams.loopcount},
|
||||
{"loopd",TELNET_VARTYPE_INT32,0,&telnetparams.loopdelay},
|
||||
{"phypb",TELNET_VARTYPE_INT32,0,&telnetparams.phyprntbuff_size},
|
||||
{"hsize",TELNET_VARTYPE_INT32,0,&telnetparams.histsize},
|
||||
{"hfile",TELNET_VARTYPE_STRING,TELNET_CHECKVAL_RDONLY,&telnetparams.histfile},
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
|
||||
telnetshell_cmddef_t telnet_cmdarray[] = {
|
||||
{"redirlog","[here,file,off]",setoutput},
|
||||
{"param","[prio]",setparam},
|
||||
{"history","[list,reset]",history_cmd},
|
||||
{"","",NULL},
|
||||
{"redirlog","[here,file,off]",setoutput,{wsetoutput},0,NULL},
|
||||
{"param","[prio]",setparam,{wsetparam},0,NULL},
|
||||
{"history","[list,reset]",history_cmd,{NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
|
||||
@@ -245,6 +248,11 @@ void redirstd(char *newfname,telnet_printfunc_t prnt ) {
|
||||
prnt("ERROR: stderr redir to %s error %s",strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int wsetoutput(char *buffer, int debug, telnet_printfunc_t prnt, ... ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
char cmds[TELNET_MAX_MSGLENGTH/TELNET_CMD_MAXSIZE][TELNET_CMD_MAXSIZE];
|
||||
char *logfname;
|
||||
@@ -281,6 +289,10 @@ int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
return CMDSTATUS_FOUND;
|
||||
} /* setoutput */
|
||||
|
||||
int wsetparam(char *buff, int debug, telnet_printfunc_t prnt, ...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setparam(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
char cmds[TELNET_MAX_MSGLENGTH/TELNET_CMD_MAXSIZE][TELNET_CMD_MAXSIZE];
|
||||
memset(cmds,0,sizeof(cmds));
|
||||
@@ -344,6 +356,98 @@ int history_cmd(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
/*
|
||||
generic commands available for all modules loaded by the server
|
||||
*/
|
||||
char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex) {
|
||||
char *val;
|
||||
switch(var[varindex].vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
val=malloc(64);
|
||||
snprintf(val,64,"%i",*(int32_t *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT64:
|
||||
val=malloc(128);
|
||||
snprintf(val,128,"%lli",(long long)*(int64_t *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
val=malloc(16);
|
||||
snprintf(val,16,"%hi",*(short *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
val=malloc(16);
|
||||
snprintf(val,16,"%i",(int)(*(int8_t *)(var[varindex].varvalptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
val=malloc(64);
|
||||
snprintf(val,64,"%u",*(unsigned int *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
val=malloc(32);
|
||||
snprintf(val,32,"%g\n",*(double *)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
val = strdup(*(char **)(var[varindex].varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
val=malloc(64);
|
||||
snprintf(val,64,"ERR:var %i unknown type",varindex);
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
int telnet_setvarvalue(telnetshell_vardef_t *var,char *strval, telnet_printfunc_t prnt ) {
|
||||
int st=0;
|
||||
switch(var->vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
*(int *)(var->varvalptr) = (int)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%i\n",*(int *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
*(short *)(var->varvalptr) = (short)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%hi\n",*(short *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
*(char *)(var->varvalptr) = (char)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%i\n",*(int *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
*(unsigned int *)(var->varvalptr) = (unsigned int)strtol(strval,NULL,0);
|
||||
if (prnt != NULL)
|
||||
prnt("%u\n",*(unsigned int *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
*(double *)(var->varvalptr) = strtod(strval,NULL);
|
||||
if (prnt != NULL)
|
||||
prnt("%g\n",*(double *)(var->varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
sprintf(*(char **)(var->varvalptr),"%s", strval);
|
||||
if (prnt != NULL)
|
||||
prnt("\"%s\"\n",*(char **)(var->varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (prnt != NULL)
|
||||
prnt("unknown type\n");
|
||||
st=-1;
|
||||
break;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
int setgetvar(int moduleindex,char getorset,char *params) {
|
||||
int n,i;
|
||||
@@ -357,81 +461,15 @@ int setgetvar(int moduleindex,char getorset,char *params) {
|
||||
if (n > 0 && (getorset == 'g' || getorset == 'G')) {
|
||||
client_printf("%s, %s = ", telnetparams.CmdParsers[moduleindex].module,
|
||||
telnetparams.CmdParsers[moduleindex].var[i].varname );
|
||||
|
||||
switch(telnetparams.CmdParsers[moduleindex].var[i].vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
client_printf("%i\n",*(int32_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT64:
|
||||
client_printf("%lli\n",*(int64_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
client_printf("%i\n",(int)(*(int8_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
client_printf("unknown type\n");
|
||||
break;
|
||||
}
|
||||
char *strval=telnet_getvarvalue(telnetparams.CmdParsers[moduleindex].var, i);
|
||||
client_printf("%s\n",strval);
|
||||
free(strval);
|
||||
}
|
||||
|
||||
if (n > 1 && (getorset == 's' || getorset == 'S')) {
|
||||
client_printf("%s, %s set to \n", telnetparams.CmdParsers[moduleindex].module,
|
||||
telnetparams.CmdParsers[moduleindex].var[i].varname);
|
||||
telnet_setvarvalue(&(telnetparams.CmdParsers[moduleindex].var[i]),varval, client_printf);
|
||||
|
||||
switch(telnetparams.CmdParsers[moduleindex].var[i].vartype) {
|
||||
case TELNET_VARTYPE_INT32:
|
||||
*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (int)strtol(varval,NULL,0);
|
||||
client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT16:
|
||||
*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (short)strtol(varval,NULL,0);
|
||||
client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_INT8:
|
||||
*(char *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (char)strtol(varval,NULL,0);
|
||||
client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_UINT:
|
||||
*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (unsigned int)strtol(varval,NULL,0);
|
||||
client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = strtod(varval,NULL);
|
||||
client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
case TELNET_VARTYPE_STRING:
|
||||
sprintf(*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr),"%s", varval);
|
||||
client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
client_printf("unknown type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,6 +512,8 @@ int process_command(char *buf) {
|
||||
}
|
||||
|
||||
for(j=0; telnetparams.CmdParsers[i].cmd[j].cmdfunc != NULL ; j++) {
|
||||
if ( telnetparams.CmdParsers[i].cmd[j].cmdflags & TELNETSRV_CMDFLAG_WEBSRVONLY )
|
||||
continue;
|
||||
client_printf(" %s %s %s\n",
|
||||
telnetparams.CmdParsers[i].module,telnetparams.CmdParsers[i].cmd[j].cmdname,
|
||||
telnetparams.CmdParsers[i].cmd[j].helpstr);
|
||||
@@ -489,7 +529,7 @@ int process_command(char *buf) {
|
||||
j = sscanf(buf,"%19s %19s %m[^\t\n]",modulename,cmd,&cmdb);
|
||||
|
||||
if (telnetparams.telnetdbg > 0)
|
||||
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n",j,modulename,cmd,cmdb);
|
||||
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n",j,modulename,cmd,(cmdb==NULL)?"":cmdb);
|
||||
|
||||
for (i=0; j>=2 && telnetparams.CmdParsers[i].var != NULL && telnetparams.CmdParsers[i].cmd != NULL; i++) {
|
||||
if ( (strncasecmp(telnetparams.CmdParsers[i].module,modulename,strlen(telnetparams.CmdParsers[i].module)) == 0)) {
|
||||
@@ -504,13 +544,16 @@ int process_command(char *buf) {
|
||||
} else {
|
||||
for (k=0 ; telnetparams.CmdParsers[i].cmd[k].cmdfunc != NULL ; k++) {
|
||||
if (strncasecmp(cmd, telnetparams.CmdParsers[i].cmd[k].cmdname,sizeof(telnetparams.CmdParsers[i].cmd[k].cmdname)) == 0) {
|
||||
if (telnetparams.CmdParsers[i].cmd[k].cmdflags & TELNETSRV_CMDFLAG_WEBSRVONLY)
|
||||
continue;
|
||||
if (telnetparams.CmdParsers[i].cmd[k].qptr != NULL) {
|
||||
notifiedFIFO_elt_t *msg =newNotifiedFIFO_elt(sizeof(telnetsrv_qmsg_t),0,NULL,NULL);
|
||||
telnetsrv_qmsg_t *cmddata=NotifiedFifoData(msg);
|
||||
cmddata->cmdfunc=(qcmdfunc_t)telnetparams.CmdParsers[i].cmd[k].cmdfunc;
|
||||
cmddata->prnt=client_printf;
|
||||
cmddata->debug=telnetparams.telnetdbg;
|
||||
cmddata->cmdbuff=strdup(cmdb);
|
||||
if (cmdb != NULL)
|
||||
cmddata->cmdbuff=strdup(cmdb);
|
||||
pushNotifiedFIFO(telnetparams.CmdParsers[i].cmd[k].qptr, msg);
|
||||
} else {
|
||||
telnetparams.CmdParsers[i].cmd[k].cmdfunc(cmdb, telnetparams.telnetdbg, client_printf);
|
||||
@@ -901,3 +944,7 @@ int telnetsrv_getfarray(loader_shlibfunc_t **farray) {
|
||||
(*farray)[1].fptr=(int (*)(void) )poll_telnetcmdq;
|
||||
return ( 2);
|
||||
}
|
||||
/* for webserver interface, needs access to some telnet server paramaters */
|
||||
telnetsrv_params_t *get_telnetsrv_params(void) {
|
||||
return &telnetparams;
|
||||
}
|
||||
|
||||
@@ -48,19 +48,52 @@
|
||||
#define CMDSTATUS_VARNOTFOUND 3
|
||||
#define CMDSTATUS_NOTFOUND 4
|
||||
|
||||
/* definitions to store 2 dim table, used to store command results before */
|
||||
/* displaying them either on console or web page */
|
||||
#define TELNET_MAXLINE_NUM 100
|
||||
#define TELNET_MAXCOL_NUM 5
|
||||
|
||||
typedef struct col {
|
||||
char coltitle[TELNET_CMD_MAXSIZE];
|
||||
unsigned int coltype;
|
||||
} acol_t;
|
||||
|
||||
typedef struct line {
|
||||
char *val[TELNET_MAXCOL_NUM];
|
||||
} aline_t;
|
||||
|
||||
typedef struct webdatadef {
|
||||
char tblname[TELNET_HELPSTR_SIZE];
|
||||
int numlines;
|
||||
int numcols;
|
||||
acol_t columns[TELNET_MAXCOL_NUM];
|
||||
aline_t lines[TELNET_MAXLINE_NUM];
|
||||
} webdatadef_t;
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* structure to be used when adding a module to the telnet server */
|
||||
/* This is the second parameter of the add_telnetcmd function, which can be used */
|
||||
/* to add a set of new command to the telnet server shell */
|
||||
typedef void(*telnet_printfunc_t)(const char* format, ...);
|
||||
typedef int(*cmdfunc_t)(char*, int, telnet_printfunc_t prnt);
|
||||
typedef int(*webfunc_t)(char *cmdbuff, int debug, telnet_printfunc_t prnt, ... );
|
||||
typedef int(*webfunc_getdata_t)(char *cmdbuff, int debug, void *data);
|
||||
typedef int(*qcmdfunc_t)(char*, int, telnet_printfunc_t prnt,void *arg);
|
||||
|
||||
#define TELNETSRV_CMDFLAG_PUSHINTPOOLQ (1<<0) // ask the telnet server to push the command in a thread pool queue
|
||||
#define TELNETSRV_CMDFLAG_PUSHINTPOOLQ (1<<0) // ask the telnet server to push the command in a thread pool queue
|
||||
#define TELNETSRV_CMDFLAG_GETWEBDATA (1<<1) // When called from web server, use the getdata variant of the function
|
||||
#define TELNETSRV_CMDFLAG_TELNETONLY (1<<2) // Only for telnet client connections
|
||||
#define TELNETSRV_CMDFLAG_WEBSRVONLY (1<<3) // Only for web server connections
|
||||
#define TELNETSRV_CMDFLAG_CONFEXEC (1<<4) // Ask for confirm before exec
|
||||
#define TELNETSRV_CMDFLAG_GETWEBTBLDATA (1<<8) // When called from web server, use the get table data variant of the function
|
||||
#define TELNETSRV_CMDFLAG_PRINTWEBTBLDATA (1<<9) // Print as a single column table
|
||||
typedef struct cmddef {
|
||||
char cmdname[TELNET_CMD_MAXSIZE];
|
||||
char helpstr[TELNET_HELPSTR_SIZE];
|
||||
cmdfunc_t cmdfunc;
|
||||
cmdfunc_t cmdfunc;
|
||||
union {
|
||||
webfunc_t webfunc;
|
||||
webfunc_getdata_t webfunc_getdata;
|
||||
};
|
||||
unsigned int cmdflags;
|
||||
void *qptr;
|
||||
} telnetshell_cmddef_t;
|
||||
@@ -78,6 +111,8 @@ typedef struct telnetsrv_qmsg {
|
||||
/*structure to be used when adding a module to the telnet server */
|
||||
/* This is the first parameter of the add_telnetcmd function, which can be used */
|
||||
/* to add a set of new variables which can be got/set from the telnet server shell */
|
||||
/* var type: bits 0-3, type value (1 to 15)
|
||||
* type modifier, bits 4-31 */
|
||||
#define TELNET_VARTYPE_INT32 1
|
||||
#define TELNET_VARTYPE_INT16 2
|
||||
#define TELNET_VARTYPE_INT64 3
|
||||
@@ -85,10 +120,15 @@ typedef struct telnetsrv_qmsg {
|
||||
#define TELNET_VARTYPE_DOUBLE 5
|
||||
#define TELNET_VARTYPE_INT8 6
|
||||
#define TELNET_VARTYPE_UINT 7
|
||||
|
||||
#define TELNET_CHECKVAL_RDONLY 16
|
||||
#define TELNET_CHECKVAL_BOOL 32
|
||||
typedef struct variabledef {
|
||||
char varname[TELNET_CMD_MAXSIZE];
|
||||
char vartype;
|
||||
char checkval;
|
||||
void *varvalptr;
|
||||
|
||||
} telnetshell_vardef_t;
|
||||
|
||||
|
||||
@@ -155,4 +195,9 @@ void set_sched(pthread_t tid, int pid,int priority);
|
||||
void set_affinity(pthread_t tid, int pid, int coreid);
|
||||
extern int get_phybsize(void);
|
||||
#endif
|
||||
#ifdef WEBSERVERCODE
|
||||
extern telnetsrv_params_t *get_telnetsrv_params(void);
|
||||
extern char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex);
|
||||
extern int telnet_setvarvalue(telnetshell_vardef_t *var,char *strval, telnet_printfunc_t prnt ) ;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -30,6 +30,6 @@ endforeach()
|
||||
|
||||
install(TARGETS telnetsrv DESTINATION bin)
|
||||
|
||||
if (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build")
|
||||
install(TARGETS telnetsrv DESTINATION ${OPENAIR_BUILD_DIR}/ran_build/build)
|
||||
endif (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build")
|
||||
if (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
install(TARGETS telnetsrv DESTINATION ${OPENAIR_CMAKE}/ran_build/build)
|
||||
endif (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
|
||||
@@ -110,9 +110,8 @@ int dump_phyvars(char *buf, int debug, telnet_printfunc_t prnt) {
|
||||
|
||||
|
||||
telnetshell_cmddef_t phy_cmdarray[] = {
|
||||
{"disp","[phycnt,uedump,uestat UE<x>]", dump_phyvars},
|
||||
|
||||
{"","",NULL},
|
||||
{"disp","[phycnt,uedump,uestat UE<x>]", dump_phyvars,{NULL},0,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -42,24 +42,29 @@
|
||||
|
||||
int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
telnetshell_cmddef_t loader_cmdarray[] = {
|
||||
{"show","[params,modules]",loader_show_cmd},
|
||||
{"","",NULL},
|
||||
{"show","[params,modules]",loader_show_cmd,{(webfunc_t)loader_show_cmd},0,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (buff == NULL) {
|
||||
prnt("ERROR wrong loader SHOW command...\n");
|
||||
return 0;
|
||||
}
|
||||
if (debug > 0)
|
||||
prnt( "loader_show_cmd received %s\n",buff);
|
||||
|
||||
|
||||
if (strcasestr(buff,"params") != NULL) {
|
||||
prnt( "loader parameters:\n");
|
||||
prnt( " Main executable build version: \"%s\"\n", loader_data.mainexec_buildversion);
|
||||
prnt( " Default shared lib path: \"%s\"\n", loader_data.shlibpath);
|
||||
prnt( " Max number of shared lib : %i\n", loader_data.maxshlibs);
|
||||
}
|
||||
else if (strcasestr(buff,"modules") != NULL) {
|
||||
else if (strcasestr(buff,"modules") != NULL || buff[0]==0 || strcasestr(buff,"show") != NULL) {
|
||||
prnt( "%i shared lib have been dynamicaly loaded by the oai loader\n", loader_data.numshlibs);
|
||||
for (int i=0 ; i<loader_data.numshlibs ; i++) {
|
||||
prnt( " Module %i: %s\n", i,loader_data.shlibs[i].name);
|
||||
|
||||
@@ -39,11 +39,11 @@
|
||||
|
||||
|
||||
telnetshell_vardef_t loader_globalvardef[] = {
|
||||
{"mainversion",TELNET_VARTYPE_STRING,&(loader_data.mainexec_buildversion)},
|
||||
{"defpath",TELNET_VARTYPE_STRING,&(loader_data.shlibpath)},
|
||||
{"maxshlibs",TELNET_VARTYPE_INT32,&(loader_data.maxshlibs)},
|
||||
{"numshlibs",TELNET_VARTYPE_INT32,&(loader_data.numshlibs)},
|
||||
{"",0,NULL}
|
||||
{"mainversion",TELNET_VARTYPE_STRING,TELNET_CHECKVAL_RDONLY, &(loader_data.mainexec_buildversion)},
|
||||
{"defpath",TELNET_VARTYPE_STRING,TELNET_CHECKVAL_RDONLY,&(loader_data.shlibpath)},
|
||||
{"maxshlibs",TELNET_VARTYPE_INT32,TELNET_CHECKVAL_RDONLY,&(loader_data.maxshlibs)},
|
||||
{"numshlibs",TELNET_VARTYPE_INT32,TELNET_CHECKVAL_RDONLY,&(loader_data.numshlibs)},
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
telnetshell_vardef_t *loader_modulesvardef;
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ telnetshell_cmddef_t measur_cmdarray[] = {
|
||||
};
|
||||
|
||||
telnetshell_vardef_t measur_vardef[] = {
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
/* function to be implemented in any telnetsrv_xxx_measurements.c sources
|
||||
to allow common measurment code to access measurments data */
|
||||
|
||||
@@ -53,7 +53,7 @@ telnetshell_vardef_t phy_vardef[] = {
|
||||
//{"txshift",TELNET_VARTYPE_INT32,NULL},
|
||||
//{"rachemin",TELNET_VARTYPE_INT32,NULL},
|
||||
//{"rachdmax",TELNET_VARTYPE_INT32,NULL},
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
@@ -139,7 +139,9 @@ char toksep[2];
|
||||
prnt("%s\n",prntline);
|
||||
} /*decode_procstat */
|
||||
|
||||
void read_statfile(char *fname,int debug, telnet_printfunc_t prnt)
|
||||
|
||||
|
||||
void read_statfile(char *fname,int debug, telnet_printfunc_t prnt, void *data)
|
||||
{
|
||||
FILE *procfile;
|
||||
char arecord[1024];
|
||||
@@ -169,9 +171,9 @@ struct dirent *entry;
|
||||
|
||||
|
||||
|
||||
prnt(" id name state USRmod KRNmod prio nice vsize proc pol \n\n");
|
||||
prnt("\n id name state USRmod KRNmod prio nice vsize proc pol \n\n");
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/stat", getpid());
|
||||
read_statfile(aname,debug,prnt);
|
||||
read_statfile(aname,debug,prnt,NULL);
|
||||
prnt("\n");
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task", getpid());
|
||||
proc_dir = opendir(aname);
|
||||
@@ -183,18 +185,86 @@ struct dirent *entry;
|
||||
|
||||
while ((entry = readdir(proc_dir)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task/%.*s/stat", getpid(),(int)(sizeof(aname)-24),entry->d_name);
|
||||
read_statfile(aname,debug,prnt);
|
||||
if(entry->d_name[0] != '.')
|
||||
{
|
||||
snprintf(aname, sizeof(aname), "/proc/%d/task/%.*s/stat", getpid(),(int)(sizeof(aname)-24),entry->d_name);
|
||||
read_statfile(aname,debug,prnt,NULL);
|
||||
}
|
||||
} /* while entry != NULL */
|
||||
closedir(proc_dir);
|
||||
} /* print_threads */
|
||||
|
||||
int proccmd_websrv_getdata(char *cmdbuff, int debug, void *data) {
|
||||
|
||||
if (strcasestr(cmdbuff,"loglvl") != NULL) {
|
||||
webdatadef_t *logsdata = ( webdatadef_t *) data;
|
||||
logsdata->numcols=4;
|
||||
logsdata->numlines=0;
|
||||
snprintf(logsdata->columns[0].coltitle,TELNET_CMD_MAXSIZE,"component");
|
||||
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
|
||||
snprintf(logsdata->columns[1].coltitle,TELNET_CMD_MAXSIZE,"level");
|
||||
logsdata->columns[1].coltype = TELNET_VARTYPE_STRING;
|
||||
snprintf(logsdata->columns[2].coltitle,TELNET_CMD_MAXSIZE,"enabled");
|
||||
logsdata->columns[2].coltype = TELNET_CHECKVAL_BOOL;
|
||||
snprintf(logsdata->columns[3].coltitle,TELNET_CMD_MAXSIZE,"output");
|
||||
logsdata->columns[3].coltype = TELNET_VARTYPE_STRING;
|
||||
|
||||
|
||||
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
|
||||
if (g_log->log_component[i].name != NULL) {
|
||||
logsdata->numlines++;
|
||||
logsdata->lines[i].val[0]= (char *)(g_log->log_component[i].name);
|
||||
|
||||
logsdata->lines[i].val[1]=map_int_to_str(log_level_names,(g_log->log_component[i].level>=0)?g_log->log_component[i].level:g_log->log_component[i].savedlevel);
|
||||
logsdata->lines[i].val[2]=(g_log->log_component[i].level>=0)?"true":"false";
|
||||
logsdata->lines[i].val[3]=(g_log->log_component[i].filelog>0)?g_log->log_component[i].filelog_name:"stdout";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strcasestr(cmdbuff,"dbgopt") != NULL) {
|
||||
webdatadef_t *logsdata = ( webdatadef_t *) data;
|
||||
logsdata->numcols=3;
|
||||
logsdata->numlines=0;
|
||||
snprintf(logsdata->columns[0].coltitle,TELNET_CMD_MAXSIZE,"module");
|
||||
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
|
||||
snprintf(logsdata->columns[1].coltitle,TELNET_CMD_MAXSIZE,"debug");
|
||||
logsdata->columns[1].coltype = TELNET_CHECKVAL_BOOL;
|
||||
snprintf(logsdata->columns[2].coltitle,TELNET_CMD_MAXSIZE,"dump");
|
||||
logsdata->columns[2].coltype = TELNET_CHECKVAL_BOOL;
|
||||
|
||||
for (int i=0; log_maskmap[i].name != NULL ; i++) {
|
||||
logsdata->numlines++;
|
||||
logsdata->lines[i].val[0]= log_maskmap[i].name;
|
||||
logsdata->lines[i].val[1]= (g_log->debug_mask & log_maskmap[i].value)?"true":"false";
|
||||
logsdata->lines[i].val[2]=(g_log->dump_mask & log_maskmap[i].value)?"true":"false";
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasestr(cmdbuff,"logopt") != NULL) {
|
||||
webdatadef_t *logsdata = ( webdatadef_t *) data;
|
||||
logsdata->numcols=2;
|
||||
logsdata->numlines=0;
|
||||
snprintf(logsdata->columns[0].coltitle,TELNET_CMD_MAXSIZE,"option");
|
||||
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
|
||||
snprintf(logsdata->columns[1].coltitle,TELNET_CMD_MAXSIZE,"enabled");
|
||||
logsdata->columns[1].coltype = TELNET_CHECKVAL_BOOL;
|
||||
|
||||
for (int i=0; log_options[i].name != NULL; i++) {
|
||||
logsdata->numlines++;
|
||||
logsdata->lines[i].val[0]=log_options[i].name;
|
||||
logsdata->lines[i].val[1]=(g_log->flag & log_options[i].value)?"true":"false";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
|
||||
if (buf == NULL) {
|
||||
prnt("ERROR wrong softmodem SHOW command...\n");
|
||||
return 0;
|
||||
}
|
||||
if (debug > 0)
|
||||
prnt(" proccmd_show received %s\n",buf);
|
||||
if (strcasestr(buf,"thread") != NULL) {
|
||||
@@ -270,6 +340,10 @@ int bv1,bv2;
|
||||
int res;
|
||||
char sv1[64];
|
||||
|
||||
if (buf == NULL) {
|
||||
prnt("ERROR wrong thread command...\n");
|
||||
return 0;
|
||||
}
|
||||
bv1=0;
|
||||
bv2=0;
|
||||
sv1[0]=0;
|
||||
@@ -284,7 +358,7 @@ char sv1[64];
|
||||
prnt(" proccmd_thread: %i params = %i,%s,%i\n",res,bv1,sv1,bv2);
|
||||
if(res != 3)
|
||||
{
|
||||
prnt("softmodem thread needs 3 params, %i received\n",res);
|
||||
print_threads(buf, debug, prnt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -307,7 +381,7 @@ int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (debug > 0)
|
||||
prnt("process module received %s\n",buf);
|
||||
|
||||
end_configmodule();
|
||||
exit_fun("telnet server received exit command\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,9 @@ extern int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_thread(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt);
|
||||
extern int proccmd_websrv_getdata(char *cmdbuff, int debug, void *data);
|
||||
telnetshell_vardef_t proc_vardef[] = {
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
#define PROCCMD_LOG_HELP_STRING " log sub commands: \n\
|
||||
show: display current log configuration \n\
|
||||
@@ -73,10 +74,14 @@ telnetshell_vardef_t proc_vardef[] = {
|
||||
|
||||
|
||||
telnetshell_cmddef_t proc_cmdarray[] = {
|
||||
{"show","loglvl|thread|config", proccmd_show},
|
||||
{"log","(enter help for details)", proccmd_log},
|
||||
{"thread","(enter help for details)", proccmd_thread},
|
||||
{"exit","", proccmd_exit},
|
||||
{"show","loglvl|thread|config", proccmd_show,{(webfunc_t)proccmd_websrv_getdata},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"log","(enter help for details)", proccmd_log, {NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"show loglvl","", proccmd_log,{(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_GETWEBTBLDATA,NULL},
|
||||
{"show logopt","", proccmd_log,{(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_GETWEBTBLDATA,NULL},
|
||||
{"show dbgopt","", proccmd_log,{(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_GETWEBTBLDATA,NULL},
|
||||
{"show config","", proccmd_show,{(webfunc_t)proccmd_show}, TELNETSRV_CMDFLAG_WEBSRVONLY,NULL},
|
||||
{"show thread","", proccmd_thread,{(webfunc_t)proccmd_show},TELNETSRV_CMDFLAG_WEBSRVONLY|TELNETSRV_CMDFLAG_PRINTWEBTBLDATA,NULL},
|
||||
{"exit","", proccmd_exit,{NULL},TELNETSRV_CMDFLAG_CONFEXEC,NULL},
|
||||
{"","",NULL},
|
||||
};
|
||||
#else
|
||||
|
||||
7
common/utils/websrv/DOC/websrv.md
Normal file
7
common/utils/websrv/DOC/websrv.md
Normal file
@@ -0,0 +1,7 @@
|
||||
The oai embedded telnet server is an optional monitoring and debugging tool. It provides a simple Command Line Interface to the oai softmem. New commands can easily be added by developers to the telnet server.
|
||||
|
||||
* [Using the telnet server](telnetusage.md)
|
||||
* [Adding commands to the oai telnet server](telnetaddcmd.md)
|
||||
* [telnet server architecture ](telnetarch.md)
|
||||
|
||||
[oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home)
|
||||
31
common/utils/websrv/DOC/websrvarch.md
Normal file
31
common/utils/websrv/DOC/websrvarch.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# telnet server principles
|
||||
|
||||
The oai telnet server is implemented in shared libraries to be loaded by the [oai shared library loader](loader). `libtelnetsrv.so ` contains the code common to all oai softmodem executables, where `libtelnetsrv_<app>.so` contains the code specific to the executable identified by `app`.
|
||||
|
||||
| `<app>` | executable |
|
||||
| :-----: | :---------------: |
|
||||
| enb | `lte-softmodem` |
|
||||
| gnb | `nr-softmodem` |
|
||||
| 4Gue | `lte-uesoftmodem` |
|
||||
| 5Gue | `nr-uesoftmodem` |
|
||||
|
||||
The implementation includes a `telnetsrv_autoinit` function which is automatically called at load time, starts the telnet server and registers a first set of commands, which are delivered with the server (telnet, softmodem, loader). it also uses the `get_softmodem_function` call to retrieve the running executable id and possibly loads the corresponding `libtelnetsrv_<app>.so`library.
|
||||
|
||||
Currently the telnet server only supports one user connection. The same dedicated thread is used to wait for a user connection and process the input received from this connection.
|
||||
|
||||
The telnet server provides an API which can be used by any oai component to add new CLI commands to the server. A pre-defined command can be used to get or set a list of variables.
|
||||
|
||||
|
||||
|
||||
# telnet server source files
|
||||
|
||||
telnet server source files are located in [common/utils/telnetsrv](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv)
|
||||
|
||||
1. [telnetsrv.c](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.c) contains the telnet server implementation, including the implementation of the `telnet` CLI command. This implementation is compatible with all softmodem executables and is in charge of loading any additional `libtelnetsrv_<app> .so` containing code specific to the running executables.
|
||||
1. [telnetsrv.h](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop/common/utils/telnetsrv/telnetsrv.h) is the telnet server include file containing both private and public data type definitions. It also contains API prototypes for functions that are used to register a new command in the server.
|
||||
1. `telnetsrv_<XXX\>.c`: implementation of \<XXX\> CLI command which are delivered with the telnet server and are common to all softmodem executables.
|
||||
1. `telnetsrv_<XXX\>.h`: include file for the implementation of XXX CLI command. Usually included only in the corresponding `.c`file
|
||||
1. `telnetsrv_<app>_<XXX>.c`: implementation of \<XXX\> CLI command specific to the executable identified by \<app\>.These sources are used to create `libtelnetsrv_<app>.so` at build time.
|
||||
1. [telnetsrv_CMakeLists.txt](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/common/utils/telnetsrv/telnetsrv_CMakeLists.txt): CMakelists file containing the cmake instructions to build the telnet server. this file is included in the [global oai CMakelists](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/cmake_targets/CMakeLists.txt).
|
||||
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
40
common/utils/websrv/DOC/websrvuse.md
Normal file
40
common/utils/websrv/DOC/websrvuse.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# starting the softmodem with the telnet server
|
||||
By default the embedded telnet server, which is implemented in a shared library, is not built. It can be built after compiling the softmodem executable using the `build_oai` script:
|
||||
|
||||
```bash
|
||||
cd \<oai repository\>/openairinterface5g
|
||||
source oaienv
|
||||
cd cmake_targets
|
||||
./build_oai --build-lib telnetsrv
|
||||
```
|
||||
|
||||
This will create the `libtelnetsrv.so` and `libtelnetsrv_<app> file in the `targets/bin` and `cmake_targets/ran_build/build` sub directories of the oai repository. <app> can be "enb", "gnb", "4GUE" or "5GUE", each library containing functions specific to a given executable.
|
||||
|
||||
When starting the softmodem, you must specify the **_\-\-telnetsrv_** option to load and start the telnet server. The telnet server is loaded via the [oai shared library loader](loader).
|
||||
|
||||
# using the Command Line Interface
|
||||
By default the telnet server listen on all the ip addresses configured on the system and on port 9090. This behavior can be changed using the `listenaddr` and `listenport` parameters.
|
||||
The telnet server includes a basic help, listing available commands and some commands also provide a specific detailed help sub-command.
|
||||
Below are examples of telnet sessions:
|
||||
|
||||
* [getting help](telnethelp.md)
|
||||
* [using the history](telnethist.md)
|
||||
* [using the get and set commands](telnetgetset.md)
|
||||
* [using the loop command](telnetloop.md)
|
||||
* [loader command](telnetloader.md)
|
||||
* [log command](telnetlog.md)
|
||||
* [measur command](telnetmeasur.md)
|
||||
|
||||
# telnet server parameters
|
||||
The telnet server is using the [oai configuration module](Config/Rtusage). Telnet parameters must be specified in the `telnetsrv` section. Some parameters can be modified via the telnet telnet server command, as specified in the last column of the following table.
|
||||
|
||||
| name | type | default | description | dynamic |
|
||||
|:---:|:---:|:---:|:----|:----:|
|
||||
| `listenaddr` | `ipV4 address, ascii format` | "0.0.0.0" | local address the server is listening on| N |
|
||||
| `listenport` | `integer` | 9090 | port number the server is listening on | N |
|
||||
| `loopcount` | `integer` | 10 | number of iterations for the loop command | Y |
|
||||
| `loopdelay` | `integer` | 5000 | delay (in ms) between 2 loop command iterations | Y |
|
||||
| `histfile` | `character string` | "oaitelnet.history" | file used for command history persistency | Y |
|
||||
| `histfsize` | `integer` | 50 | maximum number of commands saved in the history | Y |
|
||||
|
||||
[oai telnet server home](telnetsrv.md)
|
||||
17
common/utils/websrv/frontend/.browserslistrc
Normal file
17
common/utils/websrv/frontend/.browserslistrc
Normal file
@@ -0,0 +1,17 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
||||
16
common/utils/websrv/frontend/.editorconfig
Normal file
16
common/utils/websrv/frontend/.editorconfig
Normal file
@@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
50
common/utils/websrv/frontend/.eslintrc.json
Normal file
50
common/utils/websrv/frontend/.eslintrc.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"projects/**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"common/utils/websrv/frontend/tsconfig.json"
|
||||
],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "app",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "app",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
49
common/utils/websrv/frontend/.gitignore
vendored
Normal file
49
common/utils/websrv/frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/artifacts
|
||||
/builds
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
speed-measure-plugin*.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
config.toml
|
||||
31
common/utils/websrv/frontend/.gitlab-ci.yml
Normal file
31
common/utils/websrv/frontend/.gitlab-ci.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
stages:
|
||||
- install
|
||||
- build
|
||||
|
||||
variables:
|
||||
TRION_CLI_VERSION: 12.2.4
|
||||
|
||||
#
|
||||
#jobs
|
||||
#
|
||||
|
||||
install:
|
||||
stage: install
|
||||
image: trion/ng-cli:${TRION_CLI_VERSION}
|
||||
script:
|
||||
- npm ci
|
||||
only:
|
||||
changes:
|
||||
- package-lock.json
|
||||
|
||||
build:
|
||||
stage: build
|
||||
extends: .install
|
||||
image: trion/ng-cli-karma:${TRION_CLI_VERSION}
|
||||
script:
|
||||
- npm run lint
|
||||
- npm run build
|
||||
artifacts:
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- dist/softmodem-ngx
|
||||
1
common/utils/websrv/frontend/README.md
Normal file
1
common/utils/websrv/frontend/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# SoftModemNgx
|
||||
107
common/utils/websrv/frontend/angular.json
Normal file
107
common/utils/websrv/frontend/angular.json
Normal file
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"cli": {
|
||||
"analytics": false,
|
||||
"defaultCollection": "@angular-eslint/schematics"
|
||||
},
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"softmodemngx": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/softmodem-ngx",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/purple-green.css",
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"allowedCommonJsDependencies": [
|
||||
"@firebase/auth",
|
||||
"firebase"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "2mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "softmodemngx:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "softmodemngx:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "softmodemngx:build"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "softmodemngx"
|
||||
}
|
||||
40
common/utils/websrv/frontend/e2e/protractor-ci.conf.js
Normal file
40
common/utils/websrv/frontend/e2e/protractor-ci.conf.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions: {
|
||||
args: ['--headless', '--no-sandbox']
|
||||
}
|
||||
},
|
||||
directConnect: true,
|
||||
SELENIUM_PROMISE_MANAGER: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function () { }
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({
|
||||
spec: {
|
||||
displayStacktrace: StacktraceOption.PRETTY
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
37
common/utils/websrv/frontend/e2e/protractor.conf.js
Normal file
37
common/utils/websrv/frontend/e2e/protractor.conf.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
SELENIUM_PROMISE_MANAGER: false,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function () { }
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({
|
||||
spec: {
|
||||
displayStacktrace: StacktraceOption.PRETTY
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
23
common/utils/websrv/frontend/e2e/src/app.e2e-spec.ts
Normal file
23
common/utils/websrv/frontend/e2e/src/app.e2e-spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { browser, logging } from 'protractor';
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
// it('should display welcome message', async () => {
|
||||
// await page.navigateTo();
|
||||
// expect(await page.getTitleText()).toEqual('example app is running!');
|
||||
// });
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
||||
11
common/utils/websrv/frontend/e2e/src/app.po.ts
Normal file
11
common/utils/websrv/frontend/e2e/src/app.po.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
async navigateTo(): Promise<unknown> {
|
||||
return browser.get(browser.baseUrl);
|
||||
}
|
||||
|
||||
async getTitleText(): Promise<string> {
|
||||
return element(by.css('app-root .content span')).getText();
|
||||
}
|
||||
}
|
||||
10
common/utils/websrv/frontend/e2e/tsconfig.json
Normal file
10
common/utils/websrv/frontend/e2e/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"types": ["jasmine", "node"]
|
||||
}
|
||||
}
|
||||
31289
common/utils/websrv/frontend/package-lock.json
generated
Normal file
31289
common/utils/websrv/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
62
common/utils/websrv/frontend/package.json
Normal file
62
common/utils/websrv/frontend/package.json
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "softmodemngx",
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"lint": "ng lint",
|
||||
"build": "ng build",
|
||||
"dev": "ng serve --configuration=development",
|
||||
"prod": "ng serve --configuration=production"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.2.4",
|
||||
"@angular/cdk": "~12.2.4",
|
||||
"@angular/common": "~12.2.4",
|
||||
"@angular/compiler": "~12.2.4",
|
||||
"@angular/core": "~12.2.4",
|
||||
"@angular/flex-layout": "^12.0.0-beta.34",
|
||||
"@angular/forms": "~12.2.4",
|
||||
"@angular/material": "^12.2.4",
|
||||
"@angular/platform-browser": "~12.2.4",
|
||||
"@angular/platform-browser-dynamic": "~12.2.4",
|
||||
"@angular/router": "~12.2.4",
|
||||
"moment": "^2.29.1",
|
||||
"rxjs": "^6.6.6",
|
||||
"tslib": "^2.0.0",
|
||||
"zone.js": "^0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/architect": "^0.1200.0",
|
||||
"@angular-devkit/build-angular": "~12.2.4",
|
||||
"@angular-eslint/builder": "12.1.0",
|
||||
"@angular-eslint/eslint-plugin": "12.1.0",
|
||||
"@angular-eslint/eslint-plugin-template": "12.1.0",
|
||||
"@angular-eslint/schematics": "12.5.0",
|
||||
"@angular-eslint/template-parser": "12.1.0",
|
||||
"@angular/cli": "~12.2.4",
|
||||
"@angular/compiler-cli": "~12.2.4",
|
||||
"@angular/language-service": "^12.2.4",
|
||||
"@types/node": "^12.20.23",
|
||||
"@typescript-eslint/eslint-plugin": "4.23.0",
|
||||
"@typescript-eslint/parser": "4.23.0",
|
||||
"eslint": "^7.26.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"fuzzy": "^0.1.3",
|
||||
"husky": "^5.1.3",
|
||||
"inquirer": "^6.2.2",
|
||||
"inquirer-autocomplete-prompt": "^1.0.1",
|
||||
"jasmine-core": "~3.7.1",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"open": "^7.0.3",
|
||||
"ts-node": "^8.10.2",
|
||||
"tslint-angular": "^3.0.3",
|
||||
"typescript": "~4.2.4"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged && ng lint && ng test",
|
||||
"pre-push": "ng build --aot true"
|
||||
}
|
||||
}
|
||||
}
|
||||
85
common/utils/websrv/frontend/src/app/api/commands.api.ts
Normal file
85
common/utils/websrv/frontend/src/app/api/commands.api.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { Param, ParamFC } from '../controls/param.control';
|
||||
|
||||
|
||||
export interface IVariable {
|
||||
name: string;
|
||||
value: string;
|
||||
type: IArgType;
|
||||
modifiable: boolean; //set command ?
|
||||
}
|
||||
|
||||
export enum ILogLvl {
|
||||
error = "error",
|
||||
warn = "warn",
|
||||
analysis = "analysis",
|
||||
info = "info",
|
||||
debug = "debug",
|
||||
trace = "trace"
|
||||
}
|
||||
|
||||
export enum ILogOutput {
|
||||
stdout = "stdout",
|
||||
telnet = "telnet",
|
||||
web = "web",
|
||||
file = "/tmp/<component>.log",
|
||||
}
|
||||
|
||||
export enum IArgType {
|
||||
boolean = "boolean",
|
||||
list = "list",
|
||||
range = "range",
|
||||
number = "number",
|
||||
string = "string"
|
||||
}
|
||||
|
||||
export interface ICommand {
|
||||
name: string;
|
||||
confirm?: string;
|
||||
}
|
||||
|
||||
|
||||
export interface IColumn { //should use IVariable ?
|
||||
name: string;
|
||||
type: IArgType;
|
||||
modifiable: boolean; //set command ?
|
||||
}
|
||||
|
||||
export type IRow = string[]
|
||||
export interface ITable {
|
||||
columns: IColumn[];
|
||||
rows: IRow[];
|
||||
}
|
||||
export interface IResp {
|
||||
display: string[],
|
||||
table?: ITable
|
||||
}
|
||||
|
||||
const route = '/oaisoftmodem';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class CommandsApi {
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
|
||||
public readVariables$ = (moduleName?: string) => this.httpClient.get<IVariable[]>(environment.backend + route + '/' + (moduleName ? ('/' + moduleName) : "") + '/variables/');
|
||||
|
||||
public readCommands$ = (moduleName?: string) => this.httpClient.get<ICommand[]>(environment.backend + route + '/' + (moduleName ? ('/' + moduleName) : "") + '/commands/');
|
||||
|
||||
public runCommand$ = (command: ICommand, moduleName: string) => this.httpClient.post<IResp>(environment.backend + route + '/' + moduleName + '/commands/', command);
|
||||
|
||||
public setVariable$ = (variable: IVariable, moduleName?: string) => this.httpClient.post<IResp>(environment.backend + route + (moduleName ? ('/' + moduleName) : "") + '/variables/', variable);
|
||||
|
||||
public setParam$ = (param: Param) => this.httpClient.post<IResp>(environment.backend + route + '/' + param.moduleName + '/set',
|
||||
{
|
||||
cmdName: param.cmdName,
|
||||
colName: param.col.name,
|
||||
rawIndex: param.rawIndex,
|
||||
value: param.value
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
15
common/utils/websrv/frontend/src/app/app-routing.module.ts
Normal file
15
common/utils/websrv/frontend/src/app/app-routing.module.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { CommandsComponent } from './components/commands/commands.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/commands', pathMatch: 'full' },
|
||||
{ path: 'commands', component: CommandsComponent },
|
||||
{ path: '**', redirectTo: '' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
1
common/utils/websrv/frontend/src/app/app.component.html
Normal file
1
common/utils/websrv/frontend/src/app/app.component.html
Normal file
@@ -0,0 +1 @@
|
||||
<app-commands></app-commands>
|
||||
10
common/utils/websrv/frontend/src/app/app.component.ts
Normal file
10
common/utils/websrv/frontend/src/app/app.component.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css'],
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'softmodem-ngx';
|
||||
}
|
||||
78
common/utils/websrv/frontend/src/app/app.module.ts
Normal file
78
common/utils/websrv/frontend/src/app/app.module.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ClipboardModule } from '@angular/cdk/clipboard/';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatNativeDateModule } from '@angular/material/core';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { CommandsApi } from './api/commands.api';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { CommandsComponent } from './components/commands/commands.component';
|
||||
import { ConfirmDialogComponent } from './components/confirm/confirm.component';
|
||||
import { ErrorDialogComponent } from './components/error-dialog/error-dialog.component';
|
||||
import { InterceptorProviders } from './interceptors/interceptors';
|
||||
import { LoadingService } from './services/loading.service';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ErrorDialogComponent,
|
||||
CommandsComponent,
|
||||
ConfirmDialogComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
ReactiveFormsModule,
|
||||
// MatChipsModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatButtonModule,
|
||||
FlexLayoutModule,
|
||||
MatToolbarModule,
|
||||
// MatListModule,
|
||||
MatTableModule,
|
||||
MatSelectModule,
|
||||
MatDialogModule,
|
||||
MatSnackBarModule,
|
||||
MatSlideToggleModule,
|
||||
MatGridListModule,
|
||||
MatCardModule,
|
||||
// MatMenuModule,
|
||||
],
|
||||
providers: [
|
||||
// services
|
||||
LoadingService,
|
||||
// api
|
||||
CommandsApi,
|
||||
// interceptors
|
||||
InterceptorProviders,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
entryComponents: [ErrorDialogComponent],
|
||||
})
|
||||
export class AppModule { }
|
||||
@@ -0,0 +1,34 @@
|
||||
mat-form-field {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: green;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.ng-invalid .status {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.dashboard-card {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
}
|
||||
|
||||
.more-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.dashboard-card-content {
|
||||
text-align: start;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<div class="grid-container">
|
||||
<mat-grid-list cols="2" rowHeight="200px">
|
||||
<mat-grid-tile [colspan]="1" [rowspan]="2">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Softmodem variables</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div *ngIf="vars$ | async as vars">
|
||||
<div *ngFor="let variable of vars">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ variable.nameFC.value }}</mat-label>
|
||||
<input input matInput [formControl]="variable.valueFC" />
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="primary" [disabled]="!variable.modifiableFC.value"
|
||||
(click)="onVarSubmit(variable)">
|
||||
set
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<mat-grid-tile [colspan]="1" [rowspan]="2">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Softmodem commands</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div *ngIf="modules$ | async as modules" fxLaypout="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Module</mat-label>
|
||||
<mat-select (selectionChange)="onModuleSelect($event.value)">
|
||||
<mat-option *ngFor="let module of modules" [value]="module"> {{ module.nameFC.value }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div *ngIf="modulecmds$ | async as cmds">
|
||||
<div *ngIf="cmds.length">
|
||||
<div *ngFor="let cmd of cmds" fxLayoutGap="10px" fxLayoutAlign="start start">
|
||||
<button mat-raised-button color="primary" (click)="onCmdSubmit(cmd)"> {{cmd.nameFC.value}} </button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<mat-grid-tile *ngIf="modulevars$ | async as modulevars" [colspan]="1" [rowspan]="6">
|
||||
<mat-card *ngIf="modulevars.length" class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ selectedModule!.nameFC.value }} variables</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
<div *ngFor="let variable of modulevars">
|
||||
<mat-form-field>
|
||||
<mat-label>{{ variable.nameFC.value }}</mat-label>
|
||||
<input input matInput [formControl]="variable.valueFC" />
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="primary" [disabled]="!variable.modifiableFC.value"
|
||||
(click)="onModuleVarsubmit(variable)">
|
||||
set
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
<mat-grid-tile *ngIf="selectedCmd" [colspan]="1" [rowspan]="10">
|
||||
<mat-card class="dashboard-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ selectedModule!.nameFC.value }} {{ selectedCmd.name }} </mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="dashboard-card-content">
|
||||
|
||||
<mat-table mat-table [dataSource]="rows$" multiTemplateDataRows class="mat-elevation-z8">
|
||||
|
||||
<!-- For anyone who has set the multiTemplateDataRows property of mat-table to true,
|
||||
you can't use index. Instead you have use either dataIndex or renderIndex.
|
||||
See https://github.com/angular/material2/issues/12793 -->
|
||||
|
||||
|
||||
<div *ngFor="let col of columns; index as colIndex" matColumnDef="{{col.name}}">
|
||||
<mat-header-cell *matHeaderCellDef>
|
||||
<div>
|
||||
<h4>{{ col.name }}</h4>
|
||||
</div>
|
||||
</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row; dataIndex as rowIndex">
|
||||
|
||||
<div *ngIf="col.type === IOptionType.boolean; then toggle else default"> </div>
|
||||
<!-- <button mat-raised-button color="primary" (click)="onParamSubmit(row)"> set </button> -->
|
||||
|
||||
<ng-template #toggle>
|
||||
<mat-slide-toggle [formControl]="row[colIndex]" [checked]="row[colIndex].value"
|
||||
[disabled]="!col.modifiable" (change)="onParamSubmit(row)">
|
||||
</mat-slide-toggle>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #default>
|
||||
<mat-form-field>
|
||||
<input matInput [formControl]="row[colIndex]" [disabled]="!col.modifiable" />
|
||||
</mat-form-field>
|
||||
</ng-template>
|
||||
|
||||
</mat-cell>
|
||||
</div>
|
||||
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let row; columns: displayedColumns" (keydown.enter)="onParamSubmit(row)"></mat-row>
|
||||
|
||||
</mat-table>
|
||||
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
|
||||
</mat-grid-list>
|
||||
</div>
|
||||
@@ -0,0 +1,121 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { of } from 'rxjs/internal/observable/of';
|
||||
import { map } from 'rxjs/internal/operators/map';
|
||||
import { mergeMap } from 'rxjs/internal/operators/mergeMap';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { CommandsApi, IArgType, IColumn, ICommand } from 'src/app/api/commands.api';
|
||||
import { CmdCtrl } from 'src/app/controls/cmd.control';
|
||||
import { Param, ParamFC } from 'src/app/controls/param.control';
|
||||
import { VarCtrl } from 'src/app/controls/var.control';
|
||||
import { DialogService } from 'src/app/services/dialog.service';
|
||||
import { LoadingService } from 'src/app/services/loading.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-commands',
|
||||
templateUrl: './commands.component.html',
|
||||
styleUrls: ['./commands.component.css'],
|
||||
})
|
||||
export class CommandsComponent {
|
||||
|
||||
IOptionType = IArgType;
|
||||
|
||||
vars$: Observable<VarCtrl[]>
|
||||
modules$: Observable<CmdCtrl[]>
|
||||
selectedModule?: CmdCtrl
|
||||
selectedCmd?: ICommand
|
||||
|
||||
modulevars$?: Observable<VarCtrl[]>
|
||||
modulecmds$?: Observable<CmdCtrl[]>
|
||||
|
||||
//table columns
|
||||
displayedColumns: string[] = []
|
||||
rows$: Observable<ParamFC[][]> = new Observable<ParamFC[][]>()
|
||||
columns: IColumn[] = []
|
||||
|
||||
constructor(
|
||||
public commandsApi: CommandsApi,
|
||||
public loadingService: LoadingService,
|
||||
public dialogService: DialogService
|
||||
) {
|
||||
this.vars$ = this.commandsApi.readVariables$().pipe(
|
||||
map((vars) => vars.map(ivar => new VarCtrl(ivar)))
|
||||
);
|
||||
|
||||
this.modules$ = this.commandsApi.readCommands$().pipe(
|
||||
map((cmds) => cmds.map(icmd => new CmdCtrl(icmd)))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
onModuleSelect(control: CmdCtrl) {
|
||||
|
||||
this.selectedModule = control
|
||||
|
||||
this.modulecmds$ = this.commandsApi.readCommands$(`${control.nameFC.value}`).pipe(
|
||||
map(icmds => icmds.map(icmd => new CmdCtrl(icmd)))
|
||||
)
|
||||
|
||||
this.modulevars$ = this.commandsApi.readVariables$(`${control.nameFC.value}`).pipe(
|
||||
map(ivars => ivars.map(ivar => new VarCtrl(ivar))),
|
||||
)
|
||||
}
|
||||
|
||||
onVarSubmit(control: VarCtrl) {
|
||||
this.commandsApi.setVariable$(control.api()).subscribe();
|
||||
}
|
||||
|
||||
onModuleVarsubmit(control: VarCtrl) {
|
||||
this.commandsApi.setVariable$(control.api(), `${this.selectedModule!.nameFC.value}`)
|
||||
.pipe(
|
||||
map(resp => this.dialogService.openRespDialog(resp))
|
||||
).subscribe();
|
||||
}
|
||||
|
||||
onCmdSubmit(control: CmdCtrl) {
|
||||
this.selectedCmd = control.api()
|
||||
|
||||
const obs = control.confirm
|
||||
? this.dialogService.openConfirmDialog(control.confirm).pipe(
|
||||
filter(confirmed => confirmed)
|
||||
)
|
||||
: of(null)
|
||||
|
||||
this.rows$ = obs.pipe(
|
||||
mergeMap(() => this.commandsApi.runCommand$(control.api(), `${this.selectedModule!.nameFC.value}`)),
|
||||
mergeMap(resp => {
|
||||
if (resp.display[0]) return this.dialogService.openRespDialog(resp, 'cmd ' + control.nameFC.value + ' response:')
|
||||
else return of(resp)
|
||||
}),
|
||||
map(resp => {
|
||||
this.columns = resp.table!.columns
|
||||
this.displayedColumns = this.columns.map(col => col.name)
|
||||
|
||||
let rows = [];
|
||||
|
||||
for (let i = 0; i < resp.table!.rows.length; i++) {
|
||||
let row: Param[] = []
|
||||
|
||||
for (let j = 0; j < this.columns.length; j++) {
|
||||
row[j] = new Param(
|
||||
resp.table!.rows[i][j],
|
||||
this.columns[j],
|
||||
j,
|
||||
this.selectedModule!.nameFC.value,
|
||||
this.selectedCmd!.name
|
||||
)
|
||||
}
|
||||
rows[i] = row.map(param => new ParamFC(param))
|
||||
}
|
||||
return rows
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
onParamSubmit(row: ParamFC[]) {
|
||||
row.map(paramFC => this.commandsApi.setParam$(paramFC.api()).subscribe());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<h3>{{ data.title }}</h3>
|
||||
<div fxLayoutGap="10px" mat-dialog-actions fxLayout="row" fxLayoutAlign="center start">
|
||||
<button mat-button [mat-dialog-close]="true" cdkFocusInitial>Ok</button>
|
||||
<button mat-button (click)="onNoClick()">Cancel</button>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-confirm',
|
||||
templateUrl: './confirm.component.html',
|
||||
styleUrls: ['./confirm.component.css']
|
||||
})
|
||||
export class ConfirmDialogComponent {
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<void>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<div fxLayout="column" fxLayoutAlign="center center">
|
||||
<h3>{{ data.title }}</h3>
|
||||
<pre [innerHTML]="data.body"></pre>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-error-dialog',
|
||||
templateUrl: './error-dialog.component.html',
|
||||
styleUrls: ['./error-dialog.component.css'],
|
||||
})
|
||||
export class ErrorDialogComponent {
|
||||
JSON = JSON
|
||||
title = 'Angular-Interceptor';
|
||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
}
|
||||
}
|
||||
36
common/utils/websrv/frontend/src/app/controls/cmd.control.ts
Normal file
36
common/utils/websrv/frontend/src/app/controls/cmd.control.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { ICommand } from '../api/commands.api';
|
||||
|
||||
const enum CmdFCN {
|
||||
name = 'name',
|
||||
confirm = 'confirm'
|
||||
}
|
||||
|
||||
export class CmdCtrl extends FormGroup {
|
||||
|
||||
confirm?: string
|
||||
|
||||
constructor(cmd: ICommand) {
|
||||
super({});
|
||||
|
||||
this.addControl(CmdFCN.name, new FormControl(cmd.name));
|
||||
this.confirm = cmd.confirm
|
||||
}
|
||||
|
||||
api() {
|
||||
const doc: ICommand = {
|
||||
name: this.nameFC.value
|
||||
};
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
get nameFC() {
|
||||
return this.get(CmdFCN.name) as FormControl;
|
||||
}
|
||||
|
||||
set nameFC(fc: FormControl) {
|
||||
this.setControl(CmdFCN.name, fc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { IArgType, IColumn } from '../api/commands.api';
|
||||
|
||||
export class Param {
|
||||
|
||||
constructor(
|
||||
public value: string,
|
||||
public col: IColumn,
|
||||
public rawIndex: number,
|
||||
public moduleName: string,
|
||||
public cmdName: string) { }
|
||||
}
|
||||
|
||||
export class ParamFC extends FormControl {
|
||||
|
||||
constructor(public param: Param) {
|
||||
super(param.value);
|
||||
}
|
||||
|
||||
api() {
|
||||
this.param.value = this.value
|
||||
return this.param
|
||||
}
|
||||
}
|
||||
|
||||
67
common/utils/websrv/frontend/src/app/controls/var.control.ts
Normal file
67
common/utils/websrv/frontend/src/app/controls/var.control.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { IVariable } from '../api/commands.api';
|
||||
|
||||
|
||||
const enum VariablesFCN {
|
||||
name = 'name',
|
||||
value = "value",
|
||||
type = "type",
|
||||
modifiable = "modifiable"
|
||||
}
|
||||
|
||||
|
||||
export class VarCtrl extends FormGroup {
|
||||
|
||||
constructor(ivar: IVariable) {
|
||||
super({});
|
||||
|
||||
this.addControl(VariablesFCN.name, new FormControl(ivar.name));
|
||||
this.addControl(VariablesFCN.value, new FormControl(ivar.value));
|
||||
this.addControl(VariablesFCN.type, new FormControl(ivar.type));
|
||||
this.addControl(VariablesFCN.modifiable, new FormControl(ivar.modifiable));
|
||||
}
|
||||
|
||||
api() {
|
||||
const doc: IVariable = {
|
||||
name: this.nameFC.value,
|
||||
value: String(this.valueFC.value), //FIXME
|
||||
type: this.typeFC.value,
|
||||
modifiable: this.modifiableFC.value
|
||||
};
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
get nameFC() {
|
||||
return this.get(VariablesFCN.name) as FormControl;
|
||||
}
|
||||
|
||||
set nameFC(control: FormControl) {
|
||||
this.setControl(VariablesFCN.name, control);
|
||||
}
|
||||
|
||||
get valueFC() {
|
||||
return this.get(VariablesFCN.value) as FormControl;
|
||||
}
|
||||
|
||||
set valueFC(control: FormControl) {
|
||||
this.setControl(VariablesFCN.value, control);
|
||||
}
|
||||
|
||||
get typeFC() {
|
||||
return this.get(VariablesFCN.type) as FormControl;
|
||||
}
|
||||
|
||||
set typeFC(control: FormControl) {
|
||||
this.setControl(VariablesFCN.type, control);
|
||||
}
|
||||
|
||||
get modifiableFC() {
|
||||
return this.get(VariablesFCN.modifiable) as FormControl;
|
||||
}
|
||||
|
||||
set modifiableFC(control: FormControl) {
|
||||
this.setControl(VariablesFCN.modifiable, control);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
import { DialogService as DialogService } from '../services/dialog.service';
|
||||
|
||||
@Injectable()
|
||||
export class ErrorInterceptor implements HttpInterceptor {
|
||||
constructor(public dialogService: DialogService) { }
|
||||
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler) {
|
||||
return next.handle(request).pipe(
|
||||
// tap((event: HttpEvent<any>) => {
|
||||
// if (event instanceof HttpResponse) {
|
||||
// switch (event.status) {
|
||||
// case 200:
|
||||
// case 201:
|
||||
// this.log(GREEN, request.method + ' ' + event.status + ' Success');
|
||||
// this.dialogService.openSnackBar(request.method + ' ' + event.status + ' Success');
|
||||
// break;
|
||||
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // return throwError(event.body);
|
||||
// }
|
||||
// }),
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
switch (error.status) {
|
||||
case 400:
|
||||
case 403:
|
||||
case 501:
|
||||
case 500:
|
||||
this.log(YELLOW, request.method + ' ' + error.status + ' Error: ' + error.error);
|
||||
this.dialogService.openErrorDialog(error);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return throwError(error.error);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private log = (color: string, txt: string) => console.log(color, '[API] ' + txt);
|
||||
}
|
||||
|
||||
const RED = '\x1b[31m%s\x1b[0m';
|
||||
const GREEN = '\x1b[32m%s\x1b[0m';
|
||||
const YELLOW = '\x1b[33m%s\x1b[0m';
|
||||
const MAGENTA = '\x1b[35m%s\x1b[0m';
|
||||
const CYAN = '\x1b[36m%s%s\x1b[0m';
|
||||
@@ -0,0 +1,8 @@
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { ErrorInterceptor } from './error.interceptor';
|
||||
import { SpinnerInterceptor } from './spinner.interceptor';
|
||||
|
||||
export const InterceptorProviders = [
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: SpinnerInterceptor, multi: true },
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
|
||||
];
|
||||
@@ -0,0 +1,29 @@
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { LoadingService } from '../services/loading.service';
|
||||
|
||||
@Injectable()
|
||||
export class SpinnerInterceptor implements HttpInterceptor {
|
||||
activeRequests = 0;
|
||||
|
||||
constructor(private loadingService: LoadingService) { }
|
||||
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler) {
|
||||
if (this.activeRequests === 0) {
|
||||
this.loadingService.startLoading();
|
||||
}
|
||||
|
||||
this.activeRequests++;
|
||||
|
||||
return next.handle(request).pipe(
|
||||
finalize(() => {
|
||||
this.activeRequests--;
|
||||
if (this.activeRequests === 0) {
|
||||
this.loadingService.stopLoading();
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { of } from 'rxjs/internal/observable/of';
|
||||
import { tap } from 'rxjs/internal/operators/tap';
|
||||
import { IResp } from '../api/commands.api';
|
||||
import { ConfirmDialogComponent } from '../components/confirm/confirm.component';
|
||||
import { ErrorDialogComponent } from '../components/error-dialog/error-dialog.component';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DialogService {
|
||||
public isDialogOpen = false;
|
||||
|
||||
constructor(
|
||||
private _dialog: MatDialog,
|
||||
private _snackBar: MatSnackBar,
|
||||
) { }
|
||||
|
||||
openErrorDialog(error: HttpErrorResponse): Observable<any> {
|
||||
if (this.isDialogOpen) {
|
||||
return of(undefined);
|
||||
}
|
||||
|
||||
this.isDialogOpen = true;
|
||||
|
||||
return this._dialog.open(ErrorDialogComponent, {
|
||||
width: '900px',
|
||||
data: {
|
||||
title: error.status + ' Error',
|
||||
body: error.error,
|
||||
},
|
||||
}).afterClosed()
|
||||
.pipe(tap(() => this.isDialogOpen = false));
|
||||
}
|
||||
|
||||
openRespDialog(resp: IResp, title?: string): Observable<IResp> {
|
||||
if (this.isDialogOpen || !resp.display.length) {
|
||||
return of(resp);
|
||||
}
|
||||
|
||||
this.isDialogOpen = true;
|
||||
|
||||
const dialogRef = this._dialog.open(ErrorDialogComponent, {
|
||||
width: '900px',
|
||||
height: '80%',
|
||||
data: {
|
||||
title: title,
|
||||
body: resp.display!.join("</p><p>")
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((_) => {
|
||||
console.log('The dialog was closed');
|
||||
this.isDialogOpen = false;
|
||||
});
|
||||
|
||||
return of(resp)
|
||||
}
|
||||
|
||||
openSnackBar(title: string): void {
|
||||
this._snackBar.open(title, undefined, {
|
||||
duration: 500,
|
||||
horizontalPosition: 'center',
|
||||
verticalPosition: 'bottom',
|
||||
});
|
||||
}
|
||||
|
||||
openConfirmDialog(question: string) {
|
||||
if (this.isDialogOpen) {
|
||||
return of(undefined);
|
||||
}
|
||||
|
||||
this.isDialogOpen = true;
|
||||
|
||||
return this._dialog.open(ConfirmDialogComponent, {
|
||||
width: '300px',
|
||||
data: { title: question }
|
||||
})
|
||||
.afterClosed()
|
||||
.pipe(tap(() => this.isDialogOpen = false));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class LoadingService {
|
||||
isLoading$ = new Subject<boolean>();
|
||||
|
||||
constructor() { }
|
||||
|
||||
startLoading() {
|
||||
this.isLoading$.next(true);
|
||||
}
|
||||
|
||||
stopLoading() {
|
||||
this.isLoading$.next(false);
|
||||
}
|
||||
}
|
||||
0
common/utils/websrv/frontend/src/assets/.gitkeep
Normal file
0
common/utils/websrv/frontend/src/assets/.gitkeep
Normal file
@@ -0,0 +1,8 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: true,
|
||||
backend: 'http://localhost:8090' //FIXME
|
||||
};
|
||||
19
common/utils/websrv/frontend/src/environments/environment.ts
Normal file
19
common/utils/websrv/frontend/src/environments/environment.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
backend: 'http://192.168.1.67:8090'
|
||||
// backend: 'http://10.133.10.152:8090'
|
||||
// backend: 'http://10.130.163.206:8090'
|
||||
};
|
||||
|
||||
/*
|
||||
* For easier debugging in development mode, you can import the following file
|
||||
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||
*
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
BIN
common/utils/websrv/frontend/src/favicon.ico
Normal file
BIN
common/utils/websrv/frontend/src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
18
common/utils/websrv/frontend/src/index.html
Normal file
18
common/utils/websrv/frontend/src/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>SoftmodemNgx</title>
|
||||
<base href="/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body class="mat-typography">
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
13
common/utils/websrv/frontend/src/main.ts
Normal file
13
common/utils/websrv/frontend/src/main.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule)
|
||||
.catch((err) => console.error(err));
|
||||
65
common/utils/websrv/frontend/src/polyfills.ts
Normal file
65
common/utils/websrv/frontend/src/polyfills.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/**
|
||||
* IE11 requires the following for NgClass support on SVG elements
|
||||
*/
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
||||
10
common/utils/websrv/frontend/src/styles.css
Normal file
10
common/utils/websrv/frontend/src/styles.css
Normal file
@@ -0,0 +1,10 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Roboto, 'Helvetica Neue', sans-serif;
|
||||
}
|
||||
23
common/utils/websrv/frontend/src/test.ts
Normal file
23
common/utils/websrv/frontend/src/test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp,
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
10
common/utils/websrv/frontend/tsconfig.app.json
Normal file
10
common/utils/websrv/frontend/tsconfig.app.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": ["src/main.ts", "src/polyfills.ts"],
|
||||
"include": ["src/**/*.d.ts"]
|
||||
}
|
||||
30
common/utils/websrv/frontend/tsconfig.json
Normal file
30
common/utils/websrv/frontend/tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
10
common/utils/websrv/frontend/tsconfig.spec.json
Normal file
10
common/utils/websrv/frontend/tsconfig.spec.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": ["jasmine"]
|
||||
},
|
||||
"files": ["src/test.ts", "src/polyfills.ts"],
|
||||
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
|
||||
}
|
||||
805
common/utils/websrv/websrv.c
Normal file
805
common/utils/websrv/websrv.c
Normal file
@@ -0,0 +1,805 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file common/utils/websrv/websrv.c
|
||||
* \brief: implementation of web API
|
||||
* \author Francois TABURET
|
||||
* \date 2022
|
||||
* \version 0.1
|
||||
* \company NOKIA BellLabs France
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
#include <libgen.h>
|
||||
#include <jansson.h>
|
||||
#include <ulfius.h>
|
||||
#include "common/config/config_userapi.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/websrv/websrv.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#define WEBSERVERCODE
|
||||
#include "common/utils/telnetsrv/telnetsrv.h"
|
||||
|
||||
|
||||
static websrv_params_t websrvparams;
|
||||
static websrv_printf_t websrv_printf_buff;
|
||||
paramdef_t websrvoptions[] = {
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* configuration parameters for telnet utility */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
{"listenaddr", "<listen ip address>\n", 0, uptr:&websrvparams.listenaddr, defstrval:"0.0.0.0", TYPE_IPV4ADDR, 0 },
|
||||
{"listenport", "<local port>\n", 0, uptr:&(websrvparams.listenport), defuintval:8090, TYPE_UINT, 0 },
|
||||
{"priority", "<scheduling policy (0-99)\n", 0, iptr:&websrvparams.priority, defuintval:0, TYPE_INT, 0 },
|
||||
{"debug", "<debug level>\n", 0, uptr:&websrvparams.dbglvl, defuintval:0, TYPE_UINT, 0 },
|
||||
{"url", "<server url>\n", 0, strptr:&websrvparams.url, defstrval:"index.html", TYPE_STRING, 0 },
|
||||
{"cert", "<cert file>\n", 0, strptr:&websrvparams.certfile, defstrval:NULL, TYPE_STRING, 0 },
|
||||
{"key", "<key file>\n", 0, strptr:&websrvparams.keyfile, defstrval:NULL, TYPE_STRING, 0 },
|
||||
};
|
||||
int websrv_add_endpoint( char **http_method, int num_method, const char * url_prefix,const char * url_format,
|
||||
int (* callback_function[])(const struct _u_request * request,
|
||||
struct _u_response * response,
|
||||
void * user_data),
|
||||
void * user_data) ;
|
||||
|
||||
void register_module_endpoints(cmdparser_t *module) ;
|
||||
|
||||
void websrv_printjson(char * label, json_t *jsonobj){
|
||||
char *jstr = json_dumps(jsonobj,0);
|
||||
LOG_I(UTIL,"[websrv] %s:%s\n", label, (jstr==NULL)?"??\n":jstr);
|
||||
free(jstr);
|
||||
}
|
||||
void websrv_gettbldata_response(struct _u_response * response,webdatadef_t * wdata) ;
|
||||
/*-----------------------------------*/
|
||||
/* build a json body in a response */
|
||||
void websrv_jbody( struct _u_response * response, json_t *jbody) {
|
||||
websrv_printjson( (char *)__FUNCTION__ , jbody);
|
||||
int us=ulfius_add_header_to_response(response,"content-type" ,"application/json");
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 500, "Internal server error (ulfius_add_header_to_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set response header type ulfius error %d \n",us);
|
||||
}
|
||||
us=ulfius_set_json_body_response(response, 200, jbody);
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 500, "Internal server error (ulfius_set_json_body_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set body response ulfius error %d \n",us);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/* format a json string array in a response body */
|
||||
int websrv_string_response(char *astring, struct _u_response * response, int httpstatus) {
|
||||
json_t *jstr = json_array();
|
||||
char *tokctx;
|
||||
char *aline=strtok_r(astring,"\n",&tokctx);
|
||||
while(aline != NULL) {
|
||||
json_t *jline=json_string(aline);
|
||||
json_array_append_new(jstr,jline);
|
||||
aline=strtok_r(NULL,"\n",&tokctx);
|
||||
}
|
||||
json_t *jbody = json_pack("{s:o}","display",jstr);
|
||||
websrv_jbody(response,jbody);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
void websrv_printf_start(struct _u_response * response, int buffsize ) {
|
||||
pthread_mutex_lock(&(websrv_printf_buff.mutex));
|
||||
websrv_printf_buff.buff = malloc(buffsize);
|
||||
websrv_printf_buff.buffptr = websrv_printf_buff.buff;
|
||||
websrv_printf_buff.buffsize = buffsize;
|
||||
websrv_printf_buff.response = response;
|
||||
}
|
||||
|
||||
void websrv_printf_atpos( int pos, const char *message, ...) {
|
||||
va_list va_args;
|
||||
va_start(va_args, message);
|
||||
|
||||
websrv_printf_buff.buffptr = websrv_printf_buff.buff + pos + vsnprintf( websrv_printf_buff.buff + pos, websrv_printf_buff.buffsize - pos -1,message, va_args );
|
||||
|
||||
va_end(va_args);
|
||||
return ;
|
||||
}
|
||||
|
||||
void websrv_printf( const char *message, ...) {
|
||||
va_list va_args;
|
||||
va_start(va_args, message);
|
||||
websrv_printf_buff.buffptr += vsnprintf( websrv_printf_buff.buffptr,
|
||||
websrv_printf_buff.buffsize - (websrv_printf_buff.buffptr - websrv_printf_buff.buff) - 1,message, va_args );
|
||||
|
||||
va_end(va_args);
|
||||
return ;
|
||||
}
|
||||
|
||||
void websrv_printf_end(int httpstatus ) {
|
||||
if (httpstatus >= 200 && httpstatus < 300) {
|
||||
LOG_I(UTIL,"[websrv] %s\n",websrv_printf_buff.buff);
|
||||
websrv_string_response(websrv_printf_buff.buff, websrv_printf_buff.response, httpstatus) ;
|
||||
} else {
|
||||
LOG_W(UTIL,"[websrv] %s\n",websrv_printf_buff.buff);
|
||||
ulfius_set_binary_body_response(websrv_printf_buff.response,httpstatus , websrv_printf_buff.buff,websrv_printf_buff.buffptr - websrv_printf_buff.buff);
|
||||
}
|
||||
|
||||
free(websrv_printf_buff.buff);
|
||||
websrv_printf_buff.buff=NULL;
|
||||
pthread_mutex_unlock(&(websrv_printf_buff.mutex));
|
||||
|
||||
}
|
||||
|
||||
/* buid a response via a webdatadef_t structure containing one string column */
|
||||
void websrv_printf_tbl_end(int httpstatus ) {
|
||||
webdatadef_t pdata;
|
||||
char *tokctx;
|
||||
|
||||
pdata.numcols=1;
|
||||
pdata.numlines=0;
|
||||
pdata.columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
|
||||
pdata.columns[0].coltitle[0]=0;
|
||||
for ( char *alineptr=strtok_r(websrv_printf_buff.buff,"\n",&tokctx); alineptr != NULL ; alineptr=strtok_r(NULL,"\n",&tokctx) ) {
|
||||
pdata.lines[pdata.numlines].val[0]=alineptr;
|
||||
pdata.numlines++;
|
||||
}
|
||||
websrv_gettbldata_response(websrv_printf_buff.response,&pdata);
|
||||
free(websrv_printf_buff.buff);
|
||||
websrv_printf_buff.buff=NULL;
|
||||
pthread_mutex_unlock(&(websrv_printf_buff.mutex));
|
||||
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------------------------------*/
|
||||
/* format a json response from a result table returned from a call to a telnet server command */
|
||||
void websrv_getdata_response(struct _u_response * response,webdatadef_t * wdata) {
|
||||
json_t *jdata = json_array();
|
||||
|
||||
for (int i=0; i<wdata->numlines ; i++) {
|
||||
json_t *kv=json_object();
|
||||
for (int j=0; j<wdata->numcols; j++) {
|
||||
json_t *jval;
|
||||
if(wdata->columns[j].coltype & TELNET_CHECKVAL_BOOL)
|
||||
jval=json_boolean(wdata->lines[i].val[j]);
|
||||
else if (wdata->columns[j].coltype & TELNET_VARTYPE_STRING)
|
||||
jval=json_string(wdata->lines[i].val[j]);
|
||||
// else if (wdata->columns[j].coltype == TELNET_VARTYPE_DOUBLE)
|
||||
// jval=json_real((double)(wdata->lines[i].val[j]));
|
||||
else
|
||||
jval=json_integer((long)(wdata->lines[i].val[j]));
|
||||
json_object_set_new(kv, wdata->columns[j].coltitle, jval);
|
||||
}
|
||||
json_array_append_new(jdata,kv);
|
||||
}
|
||||
json_t *jbody=json_pack("{s:[o],s:o}","display",json_null(),"logs",jdata);
|
||||
websrv_jbody(response,jbody);
|
||||
}
|
||||
/*--------------------------------------------------------------------------------------------------*/
|
||||
/* format a json response from a result table returned from a call to a telnet server command */
|
||||
void websrv_gettbldata_response(struct _u_response * response,webdatadef_t * wdata) {
|
||||
json_t *jcols = json_array();
|
||||
json_t *jdata = json_array();
|
||||
char *coltype;
|
||||
for (int i=0; i<wdata->numcols; i++) {
|
||||
if(wdata->columns[i].coltype & TELNET_CHECKVAL_BOOL)
|
||||
coltype="boolean";
|
||||
else if (wdata->columns[i].coltype & TELNET_VARTYPE_STRING)
|
||||
coltype="string";
|
||||
else
|
||||
coltype="number";
|
||||
json_t *acol=json_pack("{s:s,s:s,s:b}","name",wdata->columns[i].coltitle,"type",coltype,
|
||||
"modifiable",( wdata->columns[i].coltype & TELNET_CHECKVAL_RDONLY)?0:1 );
|
||||
json_array_append_new(jcols,acol);
|
||||
}
|
||||
for (int i=0; i<wdata->numlines ; i++) {
|
||||
json_t *jval;
|
||||
json_t *jline=json_array();
|
||||
for (int j=0; j<wdata->numcols; j++) {
|
||||
if(wdata->columns[j].coltype & TELNET_CHECKVAL_BOOL)
|
||||
jval=json_string(wdata->lines[i].val[j]);
|
||||
else if (wdata->columns[j].coltype & TELNET_VARTYPE_STRING)
|
||||
jval=json_string(wdata->lines[i].val[j]);
|
||||
// else if (wdata->columns[j].coltype == TELNET_VARTYPE_DOUBLE)
|
||||
// jval=json_real((double)(wdata->lines[i].val[j]));
|
||||
else
|
||||
jval=json_integer((long)(wdata->lines[i].val[j]));
|
||||
json_array_append_new(jline,jval);
|
||||
}
|
||||
json_array_append_new(jdata,jline);
|
||||
}
|
||||
json_t *jbody=json_pack("{s:[],s:{s:o,s:o}}","display","table","columns",jcols,"rows",jdata);
|
||||
websrv_jbody(response,jbody);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------------------*/
|
||||
/* callbacks and utility functions to stream a file */
|
||||
char * websrv_read_file(const char * filename) {
|
||||
char * buffer = NULL;
|
||||
long length;
|
||||
FILE * f = fopen (filename, "rb");
|
||||
if (f != NULL) {
|
||||
fseek (f, 0, SEEK_END);
|
||||
length = ftell (f);
|
||||
fseek (f, 0, SEEK_SET);
|
||||
buffer = malloc (length + 1);
|
||||
if (buffer != NULL) {
|
||||
int rlen = fread (buffer, 1, length, f);
|
||||
if (rlen !=length) {
|
||||
free(buffer);
|
||||
LOG_E(UTIL,"[websrv] couldn't read %s_\n",filename);
|
||||
return NULL;
|
||||
}
|
||||
buffer[length] = '\0';
|
||||
}
|
||||
fclose (f);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
/* callbacks to send static streams */
|
||||
static ssize_t callback_stream(void * cls, uint64_t pos, char * buf, size_t max) {
|
||||
if (cls != NULL) {
|
||||
return fread (buf, sizeof(char), max, (FILE *)cls);
|
||||
} else {
|
||||
return U_STREAM_END;
|
||||
}
|
||||
}
|
||||
|
||||
static void callback_stream_free(void * cls) {
|
||||
if (cls != NULL) {
|
||||
fclose((FILE *)cls);
|
||||
}
|
||||
}
|
||||
|
||||
FILE *websrv_getfile(char *filename, struct _u_response * response) {
|
||||
FILE *f = fopen (filename, "rb");
|
||||
int length;
|
||||
|
||||
if (f) {
|
||||
fseek (f, 0, SEEK_END);
|
||||
length = ftell (f);
|
||||
fseek (f, 0, SEEK_SET);
|
||||
LOG_I(UTIL,"[websrv] sending %d bytes from %s\n", length, filename);
|
||||
} else {
|
||||
LOG_E(UTIL,"[websrv] couldn't open %s\n",filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *content_type="text/html";
|
||||
size_t nl = strlen(filename);
|
||||
if ( nl >= 3 && !strcmp(filename + nl - 3, "css"))
|
||||
content_type="text/css";
|
||||
|
||||
int ust=ulfius_add_header_to_response(response,"content-type" ,content_type);
|
||||
if (ust != U_OK){
|
||||
ulfius_set_string_body_response(response, 501, "Internal server error (ulfius_add_header_to_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set response header type ulfius error %d \n",ust);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ust=ulfius_set_stream_response(response, 200, callback_stream, callback_stream_free, length, 1024, f);
|
||||
if(ust != U_OK) {
|
||||
LOG_E(UTIL,"[websrv] ulfius_set_stream_response error %d\n",ust);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
|
||||
}
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* callback processing main ((initial) url (<address>/<websrvparams.url> */
|
||||
int websrv_callback_get_mainurl(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
LOG_I(UTIL,"[websrv] Requested file is: %s\n",request->http_url);
|
||||
|
||||
FILE *f = websrv_getfile(websrvparams.url,response) ;
|
||||
if (f == NULL)
|
||||
return U_CALLBACK_ERROR;
|
||||
return U_CALLBACK_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
/* default callback tries to find a file in the web server repo (path exctracted from <websrvparams.url>) and if found streams it */
|
||||
int websrv_callback_default (const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
LOG_I(UTIL,"[websrv] Requested file is: %s %s\n",request->http_verb,request->http_url);
|
||||
if (request->map_post_body != NULL)
|
||||
for (int i=0; i<u_map_count(request->map_post_body) ; i++)
|
||||
LOG_I(UTIL,"[websrv] POST parameter %i %s : %s\n",i,u_map_enum_keys(request->map_post_body)[i], u_map_enum_values(request->map_post_body)[i] );
|
||||
char *tmpurl = strdup(websrvparams.url);
|
||||
char *srvdir = dirname(tmpurl);
|
||||
if (srvdir==NULL) {
|
||||
LOG_E(UTIL,"[websrv] Cannot extract dir name from %s requested file is %s\n",websrvparams.url,request->http_url);
|
||||
return U_CALLBACK_ERROR;
|
||||
}
|
||||
char *fpath = malloc( strlen(request->http_url)+strlen(srvdir)+2);
|
||||
sprintf(fpath,"%s/%s",srvdir, request->http_url);
|
||||
FILE *f = websrv_getfile(fpath,response) ;
|
||||
free(fpath);
|
||||
free(tmpurl);
|
||||
if (f == NULL)
|
||||
return U_CALLBACK_ERROR;
|
||||
return U_CALLBACK_CONTINUE;
|
||||
}
|
||||
/* callback processing url (<address>/oaisoftmodem/:module/variables or <address>/oaisoftmodem/:module/commands) */
|
||||
int websrv_callback_newmodule(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
LOG_I(UTIL,"[websrv] callback_newmodule received %s %s\n",request->http_verb,request->http_url);
|
||||
if (user_data == NULL) {
|
||||
ulfius_set_string_body_response(response, 500, "Cannot access oai softmodem data");
|
||||
LOG_E(UTIL,"[websrv] callback_newmodule: user-data is NULL");
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
telnetsrv_params_t *telnetparams = (telnetsrv_params_t *)user_data;
|
||||
for (int i=0; i<u_map_count(request->map_url) ; i++) {
|
||||
LOG_I(UTIL,"[websrv] url element %i %s : %s\n",i,u_map_enum_keys(request->map_url)[i], u_map_enum_values(request->map_url)[i] );
|
||||
if ( strcmp(u_map_enum_keys(request->map_url)[i],"module") == 0) {
|
||||
for (int j=0; telnetparams->CmdParsers[j].cmd != NULL; j++) {
|
||||
/* found the module in the telnet server module array, it was likely not registered at init time */
|
||||
if (strcmp(telnetparams->CmdParsers[j].module, u_map_enum_values(request->map_url)[i]) == 0) {
|
||||
register_module_endpoints( &(telnetparams->CmdParsers[j]) );
|
||||
return U_CALLBACK_CONTINUE;
|
||||
}
|
||||
} /* for j */
|
||||
}
|
||||
} /* for i */
|
||||
ulfius_set_string_body_response(response, 500, "Request for an unknown module");
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
|
||||
/* callback processing url (<address>/oaisoftmodem/module/variables or <address>/oaisoftmodem/module/commands), options method */
|
||||
int websrv_callback_okset_softmodem_cmdvar(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
LOG_I(UTIL,"[websrv] : callback_okset_softmodem_cmdvar received %s %s\n",request->http_verb,request->http_url);
|
||||
for (int i=0; i<u_map_count(request->map_header) ; i++)
|
||||
LOG_I(UTIL,"[websrv] header variable %i %s : %s\n",i,u_map_enum_keys(request->map_header)[i], u_map_enum_values(request->map_header)[i] );
|
||||
int us=ulfius_add_header_to_response(response,"Access-Control-Request-Method" ,"POST");
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 501, "Internal server error (ulfius_add_header_to_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set response header type ulfius error %d \n",us);
|
||||
}
|
||||
us=ulfius_add_header_to_response(response,"Access-Control-Allow-Headers", "content-type");
|
||||
us=ulfius_set_empty_body_response(response, 200);
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 501, "Internal server error (ulfius_set_empty_body_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set empty body response ulfius error %d \n",us);
|
||||
}
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
int websrv_callback_set_softmodemvar(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
LOG_I(UTIL,"[websrv] : callback_set_softmodemvar received %s %s\n",request->http_verb,request->http_url);
|
||||
websrv_printf_start(response,256);
|
||||
json_error_t jserr;
|
||||
json_t* jsbody = ulfius_get_json_body_request (request, &jserr);
|
||||
int httpstatus=404;
|
||||
if (jsbody == NULL) {
|
||||
websrv_printf("cannot find json body in %s %s\n",request->http_url, jserr.text );
|
||||
httpstatus=400;
|
||||
} else {
|
||||
websrv_printjson("callback_set_softmodemvar: ",jsbody);
|
||||
if (user_data == NULL) {
|
||||
httpstatus=500;
|
||||
websrv_printf("%s: NULL user data",request->http_url);
|
||||
} else {
|
||||
cmdparser_t * modulestruct = (cmdparser_t *)user_data;
|
||||
json_t *J=json_object_get(jsbody, "name");
|
||||
const char *vname=json_string_value(J);
|
||||
for ( telnetshell_vardef_t *var = modulestruct->var; var->varvalptr!= NULL ;var++) {
|
||||
if (strncmp(var->varname,vname,TELNET_CMD_MAXSIZE) == 0){
|
||||
J=json_object_get(jsbody, "value");
|
||||
if(J!=NULL) {
|
||||
if (json_is_string(J)) {
|
||||
const char *vval=json_string_value(J);
|
||||
websrv_printf("var %s set to ",var->varname);
|
||||
int st=telnet_setvarvalue(var,(char *)vval, websrv_printf );
|
||||
if (st>=0) {
|
||||
httpstatus=200;
|
||||
} else {
|
||||
httpstatus=500;
|
||||
}
|
||||
} else if (json_is_integer(J)) {
|
||||
json_int_t i = json_integer_value(J);
|
||||
switch(var->vartype) {
|
||||
case TELNET_VARTYPE_INT64:
|
||||
*(int64_t *)var->varvalptr=(int64_t)i;
|
||||
break;
|
||||
case TELNET_VARTYPE_INT32:
|
||||
*(int32_t *)var->varvalptr=(int32_t)i;
|
||||
break;
|
||||
case TELNET_VARTYPE_INT16:
|
||||
*(int16_t *)var->varvalptr=(int16_t)i;
|
||||
break;
|
||||
case TELNET_VARTYPE_INT8:
|
||||
*(int8_t *)var->varvalptr=(int8_t)i;
|
||||
break;
|
||||
case TELNET_VARTYPE_UINT:
|
||||
*(unsigned int *)var->varvalptr=(unsigned int)i;
|
||||
break;
|
||||
default:
|
||||
httpstatus=500;
|
||||
websrv_printf(" Cannot set var %s, integer type mismatch\n",vname );
|
||||
break;
|
||||
}
|
||||
} else if (json_is_real(J)) {
|
||||
double lf = json_real_value(J);
|
||||
if(var->vartype==TELNET_VARTYPE_DOUBLE) {
|
||||
*(double *)var->varvalptr = lf;
|
||||
httpstatus=200;
|
||||
websrv_printf(" Var %s, set to %g\n",vname, *(double *)var->varvalptr );
|
||||
} else {
|
||||
httpstatus=500;
|
||||
websrv_printf(" Cannot set var %s, real type mismatch\n",vname );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
httpstatus=500;
|
||||
websrv_printf("Cannot set var %s, json object is NULL\n",vname );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}//for
|
||||
}//user_data
|
||||
} //sbody
|
||||
websrv_printf_end(httpstatus);
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
/* callback processing module url (<address>/oaisoftmodem/module/commands), post method */
|
||||
int websrv_processwebfunc(struct _u_response * response, cmdparser_t * modulestruct ,telnetshell_cmddef_t *cmd) {
|
||||
LOG_I(UTIL,"[websrv] : executing command %s %s\n",modulestruct->module,cmd->cmdname);
|
||||
|
||||
if ( cmd->cmdflags & TELNETSRV_CMDFLAG_GETWEBDATA ) {
|
||||
webdatadef_t wdata;
|
||||
memset(&wdata,0,sizeof(wdata));
|
||||
cmd->webfunc_getdata(cmd->cmdname,websrvparams.dbglvl,(webdatadef_t *)&wdata);
|
||||
websrv_getdata_response(response,&wdata);
|
||||
} else if (cmd->cmdflags & TELNETSRV_CMDFLAG_GETWEBTBLDATA) {
|
||||
webdatadef_t wdata;
|
||||
memset(&wdata,0,sizeof(wdata));
|
||||
cmd->webfunc_getdata(cmd->cmdname,websrvparams.dbglvl,(webdatadef_t *)&wdata);
|
||||
websrv_gettbldata_response(response,&wdata);
|
||||
} else {
|
||||
websrv_printf_start(response,16384);
|
||||
char *sptr=index(cmd->cmdname,' ');
|
||||
cmd->cmdfunc((sptr==NULL)?cmd->cmdname:sptr,websrvparams.dbglvl,websrv_printf);
|
||||
if (cmd->cmdflags & TELNETSRV_CMDFLAG_PRINTWEBTBLDATA)
|
||||
websrv_printf_tbl_end(200);
|
||||
else
|
||||
websrv_printf_end(200);
|
||||
}
|
||||
return 200;
|
||||
}
|
||||
|
||||
int websrv_callback_exec_softmodemcmd(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
LOG_I(UTIL,"[websrv] : callback_exec_softmodemcmd received %s %s\n",request->http_verb,request->http_url);
|
||||
if (user_data == NULL) {
|
||||
ulfius_set_string_body_response(response, 500, "Cannot access oai softmodem data");
|
||||
LOG_E(UTIL,"[websrv] callback_exec_softmodemcmd: user-data is NULL");
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
cmdparser_t * modulestruct = (cmdparser_t *)user_data;
|
||||
json_t* jsbody = ulfius_get_json_body_request (request, NULL);
|
||||
int httpstatus=404;
|
||||
char *msg="";
|
||||
if (jsbody == NULL) {
|
||||
msg="Unproperly formatted request body";
|
||||
httpstatus=400;
|
||||
} else {
|
||||
websrv_printjson("callback_exec_softmodemcmd: ",jsbody);
|
||||
json_t *J=json_object_get(jsbody, "name");
|
||||
const char *vname = json_string_value(J);
|
||||
if (vname == NULL ) {
|
||||
msg="No command name in request body";
|
||||
LOG_E(UTIL,"[websrv] command name not found in body\n");
|
||||
httpstatus=400;
|
||||
} else {
|
||||
httpstatus=501;
|
||||
msg="Unknown command in request body";
|
||||
for ( telnetshell_cmddef_t *cmd = modulestruct->cmd ; cmd->cmdfunc != NULL ;cmd++) {
|
||||
if ( strcmp(cmd->cmdname,vname) == 0 && (( cmd->cmdflags & TELNETSRV_CMDFLAG_TELNETONLY) == 0) ){
|
||||
httpstatus=websrv_processwebfunc(response,modulestruct,cmd);
|
||||
break;
|
||||
}
|
||||
}//for
|
||||
}
|
||||
} //sbody
|
||||
if (httpstatus >= 300)
|
||||
ulfius_set_string_body_response(response, httpstatus, msg);
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
/* callback processing module url (<address>/oaisoftmodem/module/variables), get method*/
|
||||
int websrv_callback_get_softmodemvar(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
|
||||
LOG_I(UTIL,"[websrv] : callback_get_softmodemvar received %s %s module %s\n",request->http_verb,request->http_url,
|
||||
(user_data==NULL)?"NULL":((cmdparser_t *)user_data)->module);
|
||||
if (user_data == NULL) {
|
||||
ulfius_set_string_body_response(response, 500, "No variables defined for this module");
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
cmdparser_t * modulestruct = (cmdparser_t *)user_data;
|
||||
LOG_I(UTIL,"[websrv] received %s variables request\n", modulestruct->module);
|
||||
json_t *modulevars = json_array();
|
||||
|
||||
for(int j=0; modulestruct->var[j].varvalptr != NULL ; j++) {
|
||||
char*strval=telnet_getvarvalue(modulestruct->var, j);
|
||||
int modifiable=1;
|
||||
if (modulestruct->var[j].checkval & TELNET_CHECKVAL_RDONLY)
|
||||
modifiable=0;
|
||||
json_t *oneaction;
|
||||
switch(modulestruct->var[j].vartype) {
|
||||
case TELNET_VARTYPE_DOUBLE:
|
||||
oneaction =json_pack("{s:s,s:s,s:g,s:b}","type","number","name",modulestruct->var[j].varname,"value",*(double *)(modulestruct->var[j].varvalptr),"modifiable",modifiable);
|
||||
case TELNET_VARTYPE_INT32:
|
||||
case TELNET_VARTYPE_INT16:
|
||||
case TELNET_VARTYPE_INT8:
|
||||
case TELNET_VARTYPE_UINT:
|
||||
oneaction =json_pack("{s:s,s:s,s:i,s:b}","type","number","name",modulestruct->var[j].varname,"value",(int)(*(int *)(modulestruct->var[j].varvalptr)),"modifiable",modifiable);
|
||||
break;
|
||||
case TELNET_VARTYPE_INT64:
|
||||
oneaction =json_pack("{s:s,s:s,s:lli,s:b}","type","number","name",modulestruct->var[j].varname,"value",(int64_t)(*(int64_t *)(modulestruct->var[j].varvalptr)),"modifiable",modifiable);
|
||||
break;
|
||||
case TELNET_VARTYPE_STRING:
|
||||
oneaction =json_pack("{s:s,s:s,s:s,s:b}","type","string","name",modulestruct->var[j].varname,"value",strval,"modifiable",modifiable);
|
||||
break;
|
||||
default:
|
||||
oneaction =json_pack("{s:s,s:s,s:s,s:b}","type","???","name",modulestruct->var[j].varname,"value","???","modifiable",modifiable);
|
||||
break;
|
||||
}
|
||||
if (oneaction==NULL) {
|
||||
LOG_E(UTIL,"[websrv] cannot encode oneaction %s/%s\n",modulestruct->module,modulestruct->var[j].varname);
|
||||
} else {
|
||||
websrv_printjson("oneaction",oneaction);
|
||||
}
|
||||
free(strval);
|
||||
json_array_append(modulevars , oneaction);
|
||||
}
|
||||
if (json_array_size(modulevars) == 0) {
|
||||
LOG_I(UTIL,"[websrv] no defined variables for %s\n",modulestruct->module);
|
||||
} else {
|
||||
websrv_printjson("modulevars",modulevars);
|
||||
}
|
||||
|
||||
int us=ulfius_add_header_to_response(response,"content-type" ,"application/json");
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 500, "Internal server error (ulfius_add_header_to_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set response header type ulfius error %d \n",us);
|
||||
}
|
||||
us=ulfius_set_json_body_response(response, 200, modulevars);
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 500, "Internal server error (ulfius_set_json_body_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set body response ulfius error %d \n",us);
|
||||
}
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
|
||||
/* callback processing module url (<address>/oaisoftmodem/module/commands)*/
|
||||
int websrv_callback_get_softmodemcmd(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
LOG_I(UTIL,"[websrv] : callback_get_softmodemcmd received %s %s module %s\n",request->http_verb,request->http_url,
|
||||
(user_data==NULL)?"NULL":((cmdparser_t *)user_data)->module);
|
||||
if (user_data == NULL) {
|
||||
ulfius_set_string_body_response(response, 500, "No commands defined for this module");
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
cmdparser_t *modulestruct = (cmdparser_t *)user_data;
|
||||
|
||||
LOG_I(UTIL,"[websrv] received %s commands request\n", modulestruct->module);
|
||||
json_t *modulesubcom = json_array();
|
||||
for(int j=0; modulestruct->cmd[j].cmdfunc != NULL ; j++) {
|
||||
if(strcasecmp("help",modulestruct->cmd[j].cmdname) == 0 || ( modulestruct->cmd[j].cmdflags & TELNETSRV_CMDFLAG_TELNETONLY ) ) {
|
||||
continue;
|
||||
}
|
||||
json_t *acmd;
|
||||
if (modulestruct->cmd[j].cmdflags & TELNETSRV_CMDFLAG_CONFEXEC) {
|
||||
char confstr[256];
|
||||
snprintf(confstr,sizeof(confstr),"Execute %s ?",modulestruct->cmd[j].cmdname);
|
||||
acmd =json_pack( "{s:s,s:s}", "name",modulestruct->cmd[j].cmdname,"confirm", confstr);
|
||||
} else {
|
||||
acmd =json_pack( "{s:s}", "name",modulestruct->cmd[j].cmdname);
|
||||
}
|
||||
json_array_append(modulesubcom , acmd);
|
||||
}
|
||||
if (modulesubcom==NULL) {
|
||||
LOG_E(UTIL,"[websrv] cannot encode modulesubcom response for %s\n",modulestruct->module);
|
||||
} else {
|
||||
websrv_printjson("modulesubcom",modulesubcom);
|
||||
}
|
||||
int us=ulfius_add_header_to_response(response,"content-type" ,"application/json");
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 500, "Internal server error (ulfius_add_header_to_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set response header type ulfius error %d \n",us);
|
||||
}
|
||||
us=ulfius_set_json_body_response(response, 200, modulesubcom);
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 500, "Internal server error (ulfius_set_json_body_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set body response ulfius error %d \n",us);
|
||||
}
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
|
||||
int websrv_callback_get_softmodemmodules(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
telnetsrv_params_t *telnetparams= get_telnetsrv_params();
|
||||
|
||||
json_t *cmdnames = json_array();
|
||||
for (int i=0; telnetparams->CmdParsers[i].var != NULL && telnetparams->CmdParsers[i].cmd != NULL; i++) {
|
||||
json_t *acmd =json_pack( "{s:s}", "name",telnetparams->CmdParsers[i].module);
|
||||
json_array_append(cmdnames, acmd);
|
||||
}
|
||||
|
||||
|
||||
int us=ulfius_add_header_to_response(response,"content-type" ,"application/json");
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 501, "Internal server error (ulfius_add_header_to_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set modules response header type ulfius error %d \n",us);
|
||||
}
|
||||
|
||||
us=ulfius_set_json_body_response(response, 200, cmdnames);
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 501, "Internal server error (ulfius_set_json_body_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set modules body response ulfius error %d \n",us);
|
||||
} else {
|
||||
websrv_printjson("cmdnames",cmdnames);
|
||||
}
|
||||
// ulfius_set_string_body_response(response, 200, cfgfile);
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
/* callback processing initial url (<address>/oaisoftmodem)*/
|
||||
int websrv_callback_get_softmodemstatus(const struct _u_request * request, struct _u_response * response, void * user_data) {
|
||||
char *cfgfile=CONFIG_GETCONFFILE ;
|
||||
char *execfunc=get_softmodem_function(NULL);
|
||||
char *strtype="string";
|
||||
json_t *modulevars = json_array();
|
||||
json_t *body1=json_pack("{s:s,s:s,s:s,s:b}","name","config_file", "value",cfgfile, "type",strtype,"modifiable",0);
|
||||
if (body1==NULL) {
|
||||
LOG_E(UTIL,"[websrv] cannot encode status body1 response\n");
|
||||
} else {
|
||||
websrv_printjson("status body1",body1);
|
||||
}
|
||||
|
||||
json_t *body2=json_pack("{s:s,s:s,s:s,s:b}","name","exec_function", "value",execfunc, "type", strtype, "modifiable",0);
|
||||
if (body2==NULL) {
|
||||
LOG_E(UTIL,"[websrv] cannot encode status body1 response\n");
|
||||
} else {
|
||||
websrv_printjson("status body2",body2);
|
||||
}
|
||||
|
||||
json_array_append(modulevars , body1);
|
||||
json_array_append(modulevars , body2);
|
||||
|
||||
int us=ulfius_add_header_to_response(response,"content-type" ,"application/json");
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 501, "Internal server error (ulfius_add_header_to_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set status response header type ulfius error %d \n",us);
|
||||
}
|
||||
|
||||
us=ulfius_set_json_body_response(response, 200, modulevars);
|
||||
if (us != U_OK){
|
||||
ulfius_set_string_body_response(response, 501, "Internal server error (ulfius_set_json_body_response)");
|
||||
LOG_E(UTIL,"[websrv] cannot set status body response ulfius error %d \n",us);
|
||||
}
|
||||
// ulfius_set_string_body_response(response, 200, cfgfile);
|
||||
return U_CALLBACK_COMPLETE;
|
||||
}
|
||||
|
||||
|
||||
int websrv_add_endpoint( char **http_method, int num_method, const char * url_prefix,const char * url_format,
|
||||
int (* callback_function[])(const struct _u_request * request,
|
||||
struct _u_response * response,
|
||||
void * user_data),
|
||||
void * user_data) {
|
||||
int status;
|
||||
int j=0;
|
||||
int priority = (user_data == NULL)?10:0;
|
||||
for (int i=0; i<num_method; i++) {
|
||||
status=ulfius_add_endpoint_by_val(&(websrvparams.instance),http_method[i],url_prefix,url_format,priority,callback_function[i],user_data);
|
||||
if (status != U_OK) {
|
||||
LOG_E(UTIL,"[websrv] cannot add endpoint %s %s/%s\n",http_method[i],url_prefix,url_format);
|
||||
} else {
|
||||
j++;
|
||||
LOG_I(UTIL,"[websrv] endpoint %s %s/%s added\n",http_method[i],url_prefix,url_format);
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
/* add endpoints for a module, as defined in cmdparser_t telnet server structure */
|
||||
void register_module_endpoints(cmdparser_t *module) {
|
||||
int (* callback_functions_var[3])(const struct _u_request * request,
|
||||
struct _u_response * response,
|
||||
void * user_data) ={websrv_callback_get_softmodemvar,websrv_callback_okset_softmodem_cmdvar,websrv_callback_set_softmodemvar};
|
||||
char *http_methods[3]={"GET","OPTIONS","POST"};
|
||||
|
||||
|
||||
int (* callback_functions_cmd[3])(const struct _u_request * request,
|
||||
struct _u_response * response,
|
||||
void * user_data) ={websrv_callback_get_softmodemcmd,websrv_callback_okset_softmodem_cmdvar,websrv_callback_exec_softmodemcmd};
|
||||
char prefixurl[TELNET_CMD_MAXSIZE+20];
|
||||
snprintf(prefixurl,TELNET_CMD_MAXSIZE+19,"oaisoftmodem/%s",module->module);
|
||||
LOG_I(UTIL,"[websrv] add endpoints %s/[variables or commands] \n",prefixurl);
|
||||
|
||||
websrv_add_endpoint(http_methods,3,prefixurl,"commands" ,callback_functions_cmd , module );
|
||||
websrv_add_endpoint(http_methods,3,prefixurl,"variables" ,callback_functions_var, module);
|
||||
}
|
||||
|
||||
|
||||
void* websrv_autoinit() {
|
||||
int ret;
|
||||
telnetsrv_params_t *telnetparams= get_telnetsrv_params();
|
||||
memset(&websrvparams,0,sizeof(websrvparams));
|
||||
config_get( websrvoptions,sizeof(websrvoptions)/sizeof(paramdef_t),"websrv");
|
||||
|
||||
|
||||
|
||||
if (ulfius_init_instance(&(websrvparams.instance), websrvparams.listenport, NULL, NULL) != U_OK) {
|
||||
LOG_W(UTIL, "[websrv] Error,cannot init websrv\n");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
u_map_put(websrvparams.instance.default_headers, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
// Maximum body size sent by the client is 1 Kb
|
||||
websrvparams.instance.max_post_body_size = 1024;
|
||||
|
||||
// Endpoint list declaration
|
||||
//1: load the frontend code: files contained in the websrvparams.url directory
|
||||
ulfius_add_endpoint_by_val(&(websrvparams.instance), "GET", websrvparams.url, NULL, 0, &websrv_callback_get_mainurl, NULL);
|
||||
//2: build the first page, when receiving the "oaisoftmodem" url
|
||||
// ulfius_add_endpoint_by_val(&(websrvparams.instance), "GET", "oaisoftmodem", "variables", 0, &websrv_callback_get_softmodemstatus, NULL);
|
||||
ulfius_add_endpoint_by_val(&(websrvparams.instance), "GET", "oaisoftmodem", "commands", 0, &websrv_callback_get_softmodemmodules, NULL);
|
||||
|
||||
//3 default_endpoint declaration, it tries to open the file with the url name as specified in the request.It looks for the file
|
||||
ulfius_set_default_endpoint(&(websrvparams.instance), &websrv_callback_default, NULL);
|
||||
|
||||
// endpoints
|
||||
int (* callback_functions_var[3])(const struct _u_request * request,
|
||||
struct _u_response * response,
|
||||
void * user_data) ={websrv_callback_get_softmodemstatus,websrv_callback_okset_softmodem_cmdvar,websrv_callback_set_softmodemvar};
|
||||
char *http_methods[3]={"GET","OPTIONS","POST"};
|
||||
|
||||
websrv_add_endpoint(http_methods,3,"oaisoftmodem","variables" ,callback_functions_var,NULL);
|
||||
|
||||
for (int i=0; telnetparams->CmdParsers[i].cmd != NULL; i++) {
|
||||
register_module_endpoints( &(telnetparams->CmdParsers[i]) );
|
||||
}
|
||||
ulfius_add_endpoint_by_val(&(websrvparams.instance), "GET", "oaisoftmodem", "@module/commands", 10, websrv_callback_newmodule, telnetparams);
|
||||
ulfius_add_endpoint_by_val(&(websrvparams.instance), "GET", "oaisoftmodem", "@module/variables", 10, websrv_callback_newmodule, telnetparams);
|
||||
// Start the framework
|
||||
ret=U_ERROR;
|
||||
if (websrvparams.keyfile!=NULL && websrvparams.certfile!=NULL) {
|
||||
char * key_pem = websrv_read_file(websrvparams.keyfile);
|
||||
char * cert_pem = websrv_read_file(websrvparams.certfile);
|
||||
if ( key_pem == NULL && cert_pem != NULL) {
|
||||
ret = ulfius_start_secure_framework(&(websrvparams.instance), key_pem, cert_pem);
|
||||
free(key_pem);
|
||||
free(cert_pem);
|
||||
} else {
|
||||
LOG_E(UTIL,"[websrv] Unable to load key %s and cert %s_\n",websrvparams.keyfile,websrvparams.certfile);
|
||||
}
|
||||
} else {
|
||||
ret = ulfius_start_framework(&(websrvparams.instance));
|
||||
}
|
||||
|
||||
if (ret == U_OK) {
|
||||
LOG_I(UTIL, "[websrv] Web server started on port %d", websrvparams.instance.port);
|
||||
} else {
|
||||
LOG_W(UTIL,"[websrv] Error starting web server on port %d\n",websrvparams.instance.port);
|
||||
}
|
||||
return &(websrvparams.instance);
|
||||
|
||||
}
|
||||
|
||||
void websrv_end(void *webinst) {
|
||||
ulfius_stop_framework((struct _u_instance *)webinst);
|
||||
ulfius_clean_instance((struct _u_instance *)webinst);
|
||||
return;
|
||||
}
|
||||
65
common/utils/websrv/websrv.h
Normal file
65
common/utils/websrv/websrv.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file common/utils/websrv/websrv.h
|
||||
* \brief: implementation of web API
|
||||
* \author Francois TABURET
|
||||
* \date 2022
|
||||
* \version 0.1
|
||||
* \company NOKIA BellLabs France
|
||||
* \email: francois.taburet@nokia-bell-labs.com
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#ifndef WEBSRV_H
|
||||
#define WEBSRV_H
|
||||
|
||||
#define WEBSRV_MODNAME "websrv"
|
||||
|
||||
#define WEBSRV_PORT 8090
|
||||
/* websrv_printf_t is an internal structure storing messages while processing a request */
|
||||
/* The meaage is used to fill a response body */
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex; // protect the message betwween the websrv_printf_start and websrv_print_end calls
|
||||
struct _u_response * response; // the ulfius response structure, used to send the message
|
||||
char *buff; // a buffer to store the message, allocated in websrv_printf_start, free in websrv_print_end
|
||||
int buffsize; //
|
||||
char *buffptr; // pointer to free portion of buff
|
||||
} websrv_printf_t;
|
||||
|
||||
/* websrv_params_t is an internal structure storing all the current parameters and */
|
||||
/* global variables used by the web server */
|
||||
typedef struct {
|
||||
struct _u_instance instance; // ulfius (web server) instance
|
||||
unsigned int dbglvl; // debug level of the server
|
||||
int priority; // server running priority
|
||||
unsigned int listenport; // ip port the telnet server is listening on
|
||||
unsigned int listenaddr; // ip address the telnet server is listening on
|
||||
unsigned int listenstdin; // enable command input from stdin
|
||||
char *url; // url for the main (initial) web page
|
||||
char *certfile; // cert file
|
||||
char *keyfile; // key file
|
||||
} websrv_params_t;
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
47
common/utils/websrv/websrv_CMakeLists.txt
Normal file
47
common/utils/websrv/websrv_CMakeLists.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
if ( "${OPENAIR_CMAKE}" STREQUAL "")
|
||||
message( FATAL_ERROR "oai Environment variables not set")
|
||||
endif ( "${OPENAIR_CMAKE}" STREQUAL "")
|
||||
set(WEBSRVROOT ${OPENAIR_DIR}/common/utils/websrv )
|
||||
# websrv dependencies
|
||||
#set( ULFIUS "")
|
||||
find_library(ULFIUS NAMES "libulfius.so" REQUIRED NO_CACHE)
|
||||
if ("${ULFIUS}" STREQUAL "")
|
||||
message( FATAL_ERROR "ulfius library (https://github.com/babelouest/ulfius) not found, install libulfius-dev (ubuntu) ")
|
||||
endif("${ULFIUS}" STREQUAL "")
|
||||
|
||||
#set (NPM "")
|
||||
find_program(NPM NAMES npm NO_CACHE)
|
||||
if ("${NPM}" STREQUAL "")
|
||||
message( ERROR " npm is not installed, frontend won't be built. Possibly install npm, package is available for ubuntu and fedora")
|
||||
endif("${NPM}" STREQUAL "")
|
||||
|
||||
# build the backend ( the embedded web server)
|
||||
set(WEBSRV_SOURCE
|
||||
${WEBSRVROOT}/websrv.c
|
||||
)
|
||||
add_library(websrv MODULE ${WEBSRV_SOURCE} )
|
||||
target_link_libraries(websrv PRIVATE ulfius jansson)
|
||||
|
||||
|
||||
# build the frontend ( loaded from web server by browsers)
|
||||
add_custom_target (
|
||||
websrvfront_installjsdep
|
||||
WORKING_DIRECTORY ${WEBSRVROOT}/frontend
|
||||
COMMAND npm install
|
||||
DEPENDS ${WEBSRVROOT}/frontend/package-lock.json
|
||||
)
|
||||
|
||||
add_custom_target (
|
||||
websrvfront
|
||||
WORKING_DIRECTORY ${WEBSRVROOT}/frontend
|
||||
COMMAND npm run build
|
||||
DEPENDS websrvfront_installjsdep
|
||||
)
|
||||
#install built files, required at exec time
|
||||
install(TARGETS websrv DESTINATION bin)
|
||||
if (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
add_custom_command(TARGET websrvfront
|
||||
POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${WEBSRVROOT}/frontend/dist/softmodem-ngx ${OPENAIR_CMAKE}/ran_build/build/websrv
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${WEBSRVROOT}/frontend/dist/softmodem-ngx ${OPENAIR_TARGETS}/bin/websrv
|
||||
COMMENT "Moving frontend files to:\n ${OPENAIR_CMAKE}/ran_build/build/websrv\n ${OPENAIR_TARGETS}/bin/websrv" )
|
||||
endif (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
|
||||
@@ -1494,7 +1494,8 @@ int start_rf(RU_t *ru) {
|
||||
}
|
||||
|
||||
int stop_rf(RU_t *ru) {
|
||||
ru->rfdevice.trx_end_func(&ru->rfdevice);
|
||||
if (ru->rfdevice.trx_end_func )
|
||||
ru->rfdevice.trx_end_func(&ru->rfdevice);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ void get_common_options(uint32_t execmask) {
|
||||
uint32_t online_log_messages=0;
|
||||
uint32_t glog_level=0 ;
|
||||
uint32_t start_telnetsrv = 0, start_telnetclt = 0;
|
||||
uint32_t start_websrv = 0;
|
||||
uint32_t noS1 = 0, nokrnmod = 1, nonbiot = 0;
|
||||
uint32_t rfsim = 0, basicsim = 0, do_forms = 0;
|
||||
char *logmem_filename = NULL;
|
||||
@@ -117,6 +118,10 @@ void get_common_options(uint32_t execmask) {
|
||||
set_softmodem_optmask(SOFTMODEM_TELNETCLT_BIT);
|
||||
}
|
||||
|
||||
if (start_telnetsrv) {
|
||||
load_module_shlib("websrv",NULL,0,NULL);
|
||||
}
|
||||
|
||||
if (logmem_filename != NULL && strlen(logmem_filename) > 0) {
|
||||
log_mem_filename = &logmem_filename[0];
|
||||
log_mem_flag = 1;
|
||||
@@ -197,6 +202,7 @@ void signal_handler(int sig) {
|
||||
softmodem_printresources(sig,(telnet_printfunc_t)printf);
|
||||
if (sig != SOFTMODEM_RTSIGNAL) {
|
||||
printf("Linux signal %s...\n",strsignal(sig));
|
||||
end_configmodule();
|
||||
exit_function(__FILE__, __FUNCTION__, __LINE__,"softmodem starting exit procedure\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,18 +170,20 @@ extern int usrp_tx_thread;
|
||||
#define CONFIG_HLP_FLOG "Enable online log \n"
|
||||
#define CONFIG_HLP_LOGL "Set the global log level, valid options: (4:trace, 3:debug, 2:info, 1:warn, (0:error))\n"
|
||||
#define CONFIG_HLP_TELN "Start embedded telnet server \n"
|
||||
#define CONFIG_HLP_WEB "Start embedded web server \n"
|
||||
#define CONFIG_FLOG_OPT "R"
|
||||
#define CONFIG_LOGL_OPT "g"
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* command line parameters for LOG utility */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* command line parameters for LOG utility */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define CMDLINE_LOGPARAMS_DESC { \
|
||||
{CONFIG_FLOG_OPT , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \
|
||||
{CONFIG_LOGL_OPT , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \
|
||||
{"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \
|
||||
{"log-mem", NULL, 0, strptr:(char **)&logmem_filename, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{"telnetclt", NULL, 0, uptr:&start_telnetclt, defstrval:NULL, TYPE_UINT, 0}, \
|
||||
{CONFIG_FLOG_OPT , CONFIG_HLP_FLOG, 0, uptr:&online_log_messages, defintval:1, TYPE_INT, 0}, \
|
||||
{CONFIG_LOGL_OPT , CONFIG_HLP_LOGL, 0, uptr:&glog_level, defintval:0, TYPE_UINT, 0}, \
|
||||
{"telnetsrv", CONFIG_HLP_TELN, PARAMFLAG_BOOL|PARAMFLAG_CMDLINEONLY, uptr:&start_telnetsrv, defintval:0, TYPE_UINT, 0}, \
|
||||
{"websrv", CONFIG_HLP_WEB, PARAMFLAG_BOOL|PARAMFLAG_CMDLINEONLY, uptr:&start_websrv, defintval:0, TYPE_UINT, 0}, \
|
||||
{"log-mem", NULL, 0, strptr:(char **)&logmem_filename, defstrval:NULL, TYPE_STRING, 0}, \
|
||||
{"telnetclt", NULL, 0, uptr:&start_telnetclt, defstrval:NULL, TYPE_UINT, 0}, \
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
|
||||
static int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
static telnetshell_cmddef_t coding_cmdarray[] = {
|
||||
{"mode","[sse,avx2,stdc,none]",coding_setmod_cmd},
|
||||
{"","",NULL},
|
||||
{"mode","[sse,avx2,stdc,none]",coding_setmod_cmd,{NULL},0,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
telnetshell_vardef_t coding_vardef[] = {
|
||||
{"maxiter",TELNET_VARTYPE_INT32,&max_turbo_iterations},
|
||||
{"",0,NULL}
|
||||
{"maxiter",TELNET_VARTYPE_INT32,0,&max_turbo_iterations},
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
/* PHY/defs.h contains MODE_DECODE_XXX macros, following table must match */
|
||||
static char *modedesc[] = {"none","sse","C","avx2"};
|
||||
|
||||
@@ -48,14 +48,16 @@ static int channelmod_show_cmd(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
static int channelmod_modify_cmd(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
static int channelmod_print_help(char *buff, int debug, telnet_printfunc_t prnt);
|
||||
static telnetshell_cmddef_t channelmod_cmdarray[] = {
|
||||
{"help","",channelmod_print_help},
|
||||
{"show","<predef,current>",channelmod_show_cmd},
|
||||
{"modify","<channelid> <param> <value>",channelmod_modify_cmd},
|
||||
{"","",NULL},
|
||||
{"help","",channelmod_print_help,{NULL},0,NULL},
|
||||
{"show","<predef,current>",channelmod_show_cmd,{NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"show predef","",channelmod_show_cmd,{NULL},TELNETSRV_CMDFLAG_WEBSRVONLY,NULL},
|
||||
{"show current","",channelmod_show_cmd,{NULL},TELNETSRV_CMDFLAG_WEBSRVONLY,NULL},
|
||||
{"modify","<channelid> <param> <value>",channelmod_modify_cmd,{NULL},TELNETSRV_CMDFLAG_TELNETONLY,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
static telnetshell_vardef_t channelmod_vardef[] = {
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
|
||||
static double snr_dB=25;
|
||||
@@ -1931,10 +1933,15 @@ static void display_channelmodel(channel_desc_t *cd,int debug, telnet_printfunc_
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int channelmod_show_cmd(char *buff, int debug, telnet_printfunc_t prnt) {
|
||||
char *subcmd=NULL;
|
||||
int s = sscanf(buff,"%ms\n",&subcmd);
|
||||
int s;
|
||||
if (buff == NULL) {
|
||||
subcmd = strdup(""); //enforce help display
|
||||
s=2;
|
||||
} else {
|
||||
s = sscanf(buff,"%ms\n",&subcmd);
|
||||
}
|
||||
|
||||
if (s>0) {
|
||||
if ( strcmp(subcmd,"predef") == 0) {
|
||||
|
||||
@@ -91,12 +91,12 @@
|
||||
|
||||
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
||||
static telnetshell_cmddef_t rfsimu_cmdarray[] = {
|
||||
{"setmodel","<model name> <model type>",(cmdfunc_t)rfsimu_setchanmod_cmd,TELNETSRV_CMDFLAG_PUSHINTPOOLQ},
|
||||
{"","",NULL},
|
||||
{"setmodel","<model name> <model type>",(cmdfunc_t)rfsimu_setchanmod_cmd,{NULL},TELNETSRV_CMDFLAG_PUSHINTPOOLQ,NULL},
|
||||
{"","",NULL,{NULL},0,NULL},
|
||||
};
|
||||
|
||||
static telnetshell_vardef_t rfsimu_vardef[] = {
|
||||
{"",0,NULL}
|
||||
{"",0,0,NULL}
|
||||
};
|
||||
pthread_mutex_t Sockmutex;
|
||||
|
||||
@@ -316,6 +316,15 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) {
|
||||
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg) {
|
||||
char *modelname=NULL;
|
||||
char *modeltype=NULL;
|
||||
rfsimulator_state_t *t = (rfsimulator_state_t *)arg;
|
||||
if(t->channelmod==false) {
|
||||
prnt("ERROR channel modelisation disabled...\n");
|
||||
return 0;
|
||||
}
|
||||
if (buff == NULL) {
|
||||
prnt("ERROR wrong rfsimu setchannelmod command...\n");
|
||||
return 0;
|
||||
}
|
||||
if (debug)
|
||||
prnt("rfsimu_setchanmod_cmd buffer \"%s\"\n",buff);
|
||||
int s = sscanf(buff,"%m[^ ] %ms\n",&modelname, &modeltype);
|
||||
|
||||
Reference in New Issue
Block a user