Skip to content
This repository has been archived by the owner on Sep 27, 2023. It is now read-only.

Commit

Permalink
Add server subcommand and gldserver module (#1292)
Browse files Browse the repository at this point in the history
* (#1277) Added additional check and errors for non-SPCT transformers that are connected to triplex_node objects, or have an "S" phase. (#1281) (#37)

Migration of fix from gridlabd issue 1432

Co-authored-by: Frank Tuffner <francis.tuffner@pnnl.gov>

* Add server python module

* Update Makefile.mk

* Fix naming conflict.

* Fix resource warning (one of two)

* Update server.cpp

* Update object.cpp

* Update gridlabd-server

* Update gldserver.py

* Update gldserver.py

* Update gridlabd-server

* Update Makefile.am

* Update gridlabd-server

* Update regulator.cpp

* Update server.cpp

* Update gldserver.py

---------

Co-authored-by: Frank Tuffner <francis.tuffner@pnnl.gov>
  • Loading branch information
dchassin and ftuffner authored May 31, 2023
1 parent d809db3 commit 8a478e2
Show file tree
Hide file tree
Showing 9 changed files with 695 additions and 14 deletions.
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ $(PYENV): requirements.txt
@python$(PYVER)-config --prefix 1>/dev/null || ( echo "ERROR [Makefile]: python$(PYVER)-dev is not installed" > /dev/stderr ; false )
@echo "Processing python requirements..."
@mkdir -p $(PYBIN) $(PYLIB) $(PYINC)
@(deactivate >/dev/null || true ; $(SYSPYTHON) -m venv $(PYENV))
@(deactivate 1>/dev/null 2>&1 || true ; $(SYSPYTHON) -m venv $(PYENV))
@$(ENVPYTHON) --version 1>/dev/null || ( echo "ERROR [Makefile]: $(ENVPYTHON) is not found" > /dev/stderr ; false )
@$(ENVPYTHON) -m pip install --upgrade pip
@$(ENVPYTHON) -m pip install pandas==2.0.0
Expand Down
4 changes: 2 additions & 2 deletions source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,8 +740,8 @@ int ppolls(struct s_pipes *pipes, FILE* input_stream, FILE* output_stream, FILE
if ( polldata[0].revents&POLLNVAL )
{
// fprintf(stderr,"poll() pipe 0 invalid\n"); fflush(stderr);
output_error("GldMain::subcommand(command='%s'): input pipe invalid", pipes->child_command);
has_error = true;
output_warning("GldMain::subcommand(command='%s'): input pipe invalid", pipes->child_command);
// has_error = true;
break;
}
if ( polldata[1].revents&POLLNVAL )
Expand Down
10 changes: 5 additions & 5 deletions source/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2461,27 +2461,27 @@ int object_property_getsize(OBJECT *obj, PROPERTY *prop)
// dynamic size
PROPERTYSPEC *spec = property_getspec(prop->ptype);
int len = spec->csize;
IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s','type':'%s'}): prop->width = %d", object_name(obj), prop->name, property_getspec(prop->ptype)->name, len);
// IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s','type':'%s'}): prop->width = %d", object_name(obj), prop->name, property_getspec(prop->ptype)->name, len);
if ( len == PSZ_DYNAMIC )
{
len = property_write(prop,(char*)(obj+1)+(int64_t)(prop->addr),NULL,0);
IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = PSZ_DYNAMIC => len = %d", object_name(obj), prop->name, len);
// IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = PSZ_DYNAMIC => len = %d", object_name(obj), prop->name, len);
}
else if ( len == PSZ_AUTO )
{
// TODO: support general calls to underlying class implementing the property
std::string *str = (std::string*)(char*)(obj+1)+(int64_t)(prop->addr);
len = str->size()+1;
IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = PSZ_AUTO => len = %d", object_name(obj), prop->name, len);
// IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = PSZ_AUTO => len = %d", object_name(obj), prop->name, len);
}
if ( len < 0 )
{
IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = %d => len = 0", object_name(obj), prop->name, len);
// IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = %d => len = 0", object_name(obj), prop->name, len);
len = 0;
}
else
{
IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = %d", object_name(obj), prop->name, len);
// IN_MYCONTEXT output_debug("object_property_getsize(OBJECT *obj={'name':'%s'}, PROPERTY *prop={'name':'%s'}) -> len = %d", object_name(obj), prop->name, len);
}

return len;
Expand Down
42 changes: 36 additions & 6 deletions source/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1124,17 +1124,15 @@ int http_find_request(HTTPCNX *http,char *uri)
return 0;
http_format(http,"[\n");
obj = find_first(list);
while ( 1 )
while ( obj )
{
if ( obj->name == NULL )
http_format(http,"\t{\"name\" : \"%s:%d\"}",obj->oclass->name,obj->id);
else
http_format(http,"\t{\"name\" : \"%s\"}",obj->name);
obj = find_next(list,obj);
if ( obj!=NULL )
if ( obj != NULL )
http_format(http,",\n\t");
else
break;
}
http_format(http,"\n\t]\n");
http_type(http,"text/json");
Expand Down Expand Up @@ -1207,6 +1205,37 @@ int http_read_request(HTTPCNX *http, char *uri)
return 1;
}

/** Process a utility operation
* @returns non-zero on success, 0 on failure (errno set)
**/

int http_util_request(HTTPCNX *http, char *uri)
{
char token[64], value[1024];
if ( sscanf(uri,"%[^/]/%[^\n]",token,value) < 2 )
{
return 1;
}
if ( strcmp(token,"convert_to_timestamp") == 0 )
{
http_type(http,"text/html");
http_decode(value);
http_format(http,"%lld",convert_to_timestamp(value));
return 1;
}
else if ( strcmp(token,"convert_from_timestamp") == 0 )
{
http_type(http,"text/html");
char buffer[64];
http_format(http,"%s",convert_from_timestamp(atol(value),buffer,sizeof(buffer)-1)>0?buffer:"INVALID");
return 1;
}
else
{
http_format(http,"uri '%s/%s' is not valid",token,value);
return 9;
}
}
/** Process an incoming GUI request
@returns non-zero on success, 0 on failure (errno set)
**/
Expand Down Expand Up @@ -2023,9 +2052,10 @@ void *http_response(void *ptr)
{"/octave/", http_run_octave, HTTP_OK, HTTP_NOTFOUND},
{"/kml/", http_kml_request, HTTP_OK, HTTP_NOTFOUND},
{"/json/", http_json_request, HTTP_OK, HTTP_NOTFOUND},
{"/find/", http_find_request, HTTP_OK, HTTP_NOTFOUND},
{"/find/", http_find_request, HTTP_OK, HTTP_NOTFOUND},
{"/modify/", http_modify_request, HTTP_OK, HTTP_NOTFOUND},
{"/read/", http_read_request, HTTP_OK, HTTP_NOTFOUND},
{"/read/", http_read_request, HTTP_OK, HTTP_NOTFOUND},
{"/util/", http_util_request, HTTP_OK, HTTP_NOTFOUND},
};
size_t n;
for ( n=0 ; n<sizeof(map)/sizeof(map[0]) ; n++ )
Expand Down
1 change: 1 addition & 0 deletions subcommands/Makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ bin_SCRIPTS += subcommands/gridlabd-plot
bin_SCRIPTS += subcommands/gridlabd-python
bin_SCRIPTS += subcommands/gridlabd-require
bin_SCRIPTS += subcommands/gridlabd-requirements
bin_SCRIPTS += subcommands/gridlabd-server
bin_SCRIPTS += subcommands/gridlabd-template
bin_SCRIPTS += subcommands/gridlabd-timezone
bin_SCRIPTS += subcommands/gridlabd-trace
Expand Down
227 changes: 227 additions & 0 deletions subcommands/gridlabd-server
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
#!/bin/bash
## GridLAB-D server control
##
## Syntax: gridlabd server COMMAND
##
## Commands:
##
## start [-p|--port PORT] [-d|--detach] OPTIONS
##
## stop|halt|shutdown|kill PORT|all
##
## list [PORT|all]
##
## log PORT
##
## status [-c|--continuous] [PORT|all]
##
## The `gridlabd server` commands controls a server in the background. This is
## contrast to the `gridlabd --server` command which does not detach the
## process from the current process after it is launched.
##
## All servers are identified by their port number. The default port number is
## 6267 and incremented automatically is already in use. The maximum number
## of server that can be started automatically is 10.
##
## The `start` command requires the GridLAB-D command line options to be
## provided.
##
## The `stop`, `halt`, `shutdown`, and `kill` commands correspond to the
## GridLAB-D server control commands. See [[GLM/Server]] for details.
##
## The `list` command outputs a list of active servers. The `status` command
## outputs the status of active servers.
##
## The server status can be one of the following:
##
## INIT initialization in progress
## RUNNING simulation running
## PAUSED simulation paused
## DONE simulation done
## LOCKED simulation locked for concurrency
## NOREPLY simulation server not responding to control commands
##
## See also:
##
## [[GLM/Server]]
##

E_OK=0
E_FAILED=1
E_INVALID=2
E_MISSING=3
E_NOTFOUND=4
E_SYNTAX=9

TIMEOUT=10
MAXPORTS=10
LOGFILE=/tmp/gridlabd-server

function error ()
{
RC=$1
shift 1
echo "ERROR [gridlabd-server]: $*" > /dev/stderr
exit $RC
}

function getport ()
{
if [ $# -eq 0 ]; then
PORT=6267
while [ ! -z "$(curl -s http://localhost:$PORT/raw/mainloop_state 2>/dev/null)" ]; do
PORT=$(($PORT+1))
done
echo $PORT
else
echo $(($1+6266))
fi
}

function getstatus()
{
for P in $(list $*); do
echo $P $(curl -s http://localhost:$P/raw/mainloop_state 2>/dev/null || echo "NOREPLY")
done

}

function waitport ()
{
for P in $(list $*); do
T=0
while [ ! -z "$(curl -s http://localhost:$P/raw/mainloop_state 2>/dev/null)" ]; do
sleep 1
T=$(($T+1))
if [ $T -gt $TIMEOUT ]; then
error E_FAILED "wait on port $P timeout"
fi
done
done
}

function list ()
{
if [ $# -gt 0 ]; then
for P in $*; do
curl -s http://localhost:$P/raw/mainloop_state >/dev/null && echo $P
done
else
P=0
while [ $P -lt $MAXPORTS ]; do
PORT=$(($P+6267))
curl -s http://localhost:$PORT/raw/mainloop_state >/dev/null && echo $PORT
P=$(($P+1))
done
fi
}

# catch no args
if [ $# -eq 0 ]; then
grep '^## ' $0 | cut -c4- | grep '^Syntax: ' > /dev/stderr
exit $E_SYNTAX
fi

# process args
case $1 in
help | --help | -h )
grep '^## ' $0 | cut -c4-
;;
start )
shift 1
while [ -z "$OK" ]; do
case $1 in
-p | --port )
PORT=$2
shift 2
;;
-d | --detach )
DETACH=yes
shift 1
;;
-l | --logfile )
LOG=$2
shift 2
;;
* )
OK=yes
;;
esac
done
if [ -z "$PORT" ]; then
PORT=$(getport)
echo $PORT
fi
if [ -z "$LOG" ]; then
LOG=$LOGFILE-$PORT.log
elif [ "$LOG" = "-" ]; then
LOG=/dev/stderr
fi
rm -f $LOG
gridlabd --server -D server_portnum=$PORT $* 1>$LOG 2>&1 &
sleep 1
if [ ! -z "$!" ] ; then
if [ ! -z "$DETACH" ]; then
disown %1
fi
else
error $E_FAILED "unable to start server for port $PORT"
fi
;;
stop | halt | shutdown | kill )
if [ -z "$2" ]; then
error $E_MISSING "missing port number"
elif [ "$2" = "all" ]; then
PORTLIST=$(list)
else
PORTLIST=$*
fi
for PORT in $PORTLIST; do
curl -s http://localhost:$PORT/control/$1
done
waitport $PORTLIST
;;
list )
shift 1
list $*
;;
log )
shift 1
if [ $# -eq 0 ]; then
error $E_MISSING "missing port number"
elif [ ! -f $LOGFILE-$1.log ]; then
error $E_NOTFOUND "no log found for port $1"
fi
echo 'INFO [gridlabd-server]: created '$(stat -f %SB -t "%Y-%m-%d %H:%M:%S %Z" $LOGFILE-$1.log)
cat $LOGFILE-$1.log
if [ -z "$(getstatus $1)" ]; then
echo 'INFO [gridlabd-server]: stopped '$(stat -f %Sm -t "%Y-%m-%d %H:%M:%S %Z" $LOGFILE-$1.log)
else
echo 'INFO [gridlabd-server]: updated '$(stat -f %Sm -t "%Y-%m-%d %H:%M:%S %Z" $LOGFILE-$1.log)
fi
;;
status )
shift 1
if [ "$1" = "-c" -o "$1" = "--continuous" ]; then
shift 1
while [ true ]; do
clear
echo "Server Last update Status Options"
echo "------ ------------------- ---------- --------------------"
for P in $(list $*); do
printf '%6.6s %19.19s %10.10s %s\n' "$P" "$(stat -f %Sm -t "%Y-%m-%d %H:%M:%S" $LOGFILE-$P.log)" "$(curl -s http://localhost:$P/raw/mainloop_state 2>/dev/null || echo 'NOREPLY')" "$(curl -s http://localhost:$P/raw/command_line 2>/dev/null | cut -f5- -d' ')"
done
echo ""
echo "Press Ctrl-C to quit"
sleep 1
done
else
getstatus $*
fi
;;
* )
error $E_INVALID "'$1' is an invalid gridlabd-server command"
;;
esac
exit $E_OK

1 change: 1 addition & 0 deletions tools/Makefile.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dist_pkgdata_DATA += tools/market_model.py
dist_pkgdata_DATA += tools/meteostat_weather.py
dist_pkgdata_DATA += tools/metar2glm.py
dist_pkgdata_DATA += tools/read_dlp.py
dist_pkgdata_DATA += tools/gldserver.py
dist_pkgdata_DATA += tools/noaa_forecast.py
dist_pkgdata_DATA += tools/nsrdb_weather.py
dist_pkgdata_DATA += tools/ucar_weather.py
Expand Down
Loading

0 comments on commit 8a478e2

Please sign in to comment.