mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-19 21:27:57 +00:00
Migrate and refactor more interfaces from batphone
This commit is contained in:
parent
42200c2bcb
commit
46ef40cf23
@ -128,6 +128,8 @@ static int outv_growbuf(struct cli_context *context, size_t needed)
|
|||||||
|
|
||||||
static int put_blob(struct cli_context *context, jbyte *value, jsize length){
|
static int put_blob(struct cli_context *context, jbyte *value, jsize length){
|
||||||
jbyteArray arr = NULL;
|
jbyteArray arr = NULL;
|
||||||
|
if (context->jni_exception)
|
||||||
|
return -1;
|
||||||
if (value && length>0){
|
if (value && length>0){
|
||||||
arr = (*context->jni_env)->NewByteArray(context->jni_env, length);
|
arr = (*context->jni_env)->NewByteArray(context->jni_env, length);
|
||||||
if (arr == NULL || (*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
if (arr == NULL || (*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
@ -143,7 +145,7 @@ static int put_blob(struct cli_context *context, jbyte *value, jsize length){
|
|||||||
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, putBlob, arr);
|
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, putBlob, arr);
|
||||||
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
context->jni_exception = 1;
|
context->jni_exception = 1;
|
||||||
return WHY("Exception thrown from CallVoidMethod()");
|
return WHY("Exception thrown from CallVoidMethod(putBlob)");
|
||||||
}
|
}
|
||||||
if (arr)
|
if (arr)
|
||||||
(*context->jni_env)->DeleteLocalRef(context->jni_env, arr);
|
(*context->jni_env)->DeleteLocalRef(context->jni_env, arr);
|
||||||
@ -287,6 +289,7 @@ int parseCommandLine(struct cli_context *context, const char *argv0, int argc, c
|
|||||||
// Load configuration so that log messages can get out.
|
// Load configuration so that log messages can get out.
|
||||||
cf_reload_permissive();
|
cf_reload_permissive();
|
||||||
NOWHENCE(HINTF("Run \"%s help\" for more information.", argv0 ? argv0 : "servald"));
|
NOWHENCE(HINTF("Run \"%s help\" for more information.", argv0 ? argv0 : "servald"));
|
||||||
|
result =-1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Load configuration so that log error messages can get out.
|
// Load configuration so that log error messages can get out.
|
||||||
@ -389,10 +392,13 @@ void cli_columns(struct cli_context *context, int columns, const char *names[])
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_JNI_H
|
#ifdef HAVE_JNI_H
|
||||||
if (context && context->jni_env) {
|
if (context && context->jni_env) {
|
||||||
|
if (context->jni_exception)
|
||||||
|
return;
|
||||||
|
|
||||||
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, startResultSet, columns);
|
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, startResultSet, columns);
|
||||||
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
context->jni_exception = 1;
|
context->jni_exception = 1;
|
||||||
WHY("Exception thrown from CallVoidMethod()");
|
WHY("Exception thrown from CallVoidMethod(startResultSet)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int i;
|
int i;
|
||||||
@ -405,6 +411,11 @@ void cli_columns(struct cli_context *context, int columns, const char *names[])
|
|||||||
}
|
}
|
||||||
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, setColumnName, i, str);
|
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, setColumnName, i, str);
|
||||||
(*context->jni_env)->DeleteLocalRef(context->jni_env, str);
|
(*context->jni_env)->DeleteLocalRef(context->jni_env, str);
|
||||||
|
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
|
context->jni_exception = 1;
|
||||||
|
WHY("Exception thrown from CallVoidMethod(setColumnName)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -425,6 +436,8 @@ void cli_field_name(struct cli_context *context, const char *name, const char *d
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_JNI_H
|
#ifdef HAVE_JNI_H
|
||||||
if (context && context->jni_env) {
|
if (context && context->jni_env) {
|
||||||
|
if (context->jni_exception)
|
||||||
|
return;
|
||||||
jstring str = (jstring)(*context->jni_env)->NewStringUTF(context->jni_env, name);
|
jstring str = (jstring)(*context->jni_env)->NewStringUTF(context->jni_env, name);
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
context->jni_exception = 1;
|
context->jni_exception = 1;
|
||||||
@ -433,6 +446,11 @@ void cli_field_name(struct cli_context *context, const char *name, const char *d
|
|||||||
}
|
}
|
||||||
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, setColumnName, -1, str);
|
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, setColumnName, -1, str);
|
||||||
(*context->jni_env)->DeleteLocalRef(context->jni_env, str);
|
(*context->jni_env)->DeleteLocalRef(context->jni_env, str);
|
||||||
|
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
|
context->jni_exception = 1;
|
||||||
|
WHY("Exception thrown from CallVoidMethod(setColumnName)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -443,7 +461,13 @@ void cli_field_name(struct cli_context *context, const char *name, const char *d
|
|||||||
void cli_put_long(struct cli_context *context, int64_t value, const char *delim){
|
void cli_put_long(struct cli_context *context, int64_t value, const char *delim){
|
||||||
#ifdef HAVE_JNI_H
|
#ifdef HAVE_JNI_H
|
||||||
if (context && context->jni_env) {
|
if (context && context->jni_env) {
|
||||||
|
if (context->jni_exception)
|
||||||
|
return;
|
||||||
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, putLong, value);
|
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, putLong, value);
|
||||||
|
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
|
context->jni_exception = 1;
|
||||||
|
WHY("Exception thrown from CallVoidMethod(putLong)");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -454,6 +478,8 @@ void cli_put_long(struct cli_context *context, int64_t value, const char *delim)
|
|||||||
void cli_put_string(struct cli_context *context, const char *value, const char *delim){
|
void cli_put_string(struct cli_context *context, const char *value, const char *delim){
|
||||||
#ifdef HAVE_JNI_H
|
#ifdef HAVE_JNI_H
|
||||||
if (context && context->jni_env) {
|
if (context && context->jni_env) {
|
||||||
|
if (context->jni_exception)
|
||||||
|
return;
|
||||||
jstring str = NULL;
|
jstring str = NULL;
|
||||||
if (value){
|
if (value){
|
||||||
str = (jstring)(*context->jni_env)->NewStringUTF(context->jni_env, value);
|
str = (jstring)(*context->jni_env)->NewStringUTF(context->jni_env, value);
|
||||||
@ -465,6 +491,10 @@ void cli_put_string(struct cli_context *context, const char *value, const char *
|
|||||||
}
|
}
|
||||||
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, putString, str);
|
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, putString, str);
|
||||||
(*context->jni_env)->DeleteLocalRef(context->jni_env, str);
|
(*context->jni_env)->DeleteLocalRef(context->jni_env, str);
|
||||||
|
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
|
context->jni_exception = 1;
|
||||||
|
WHY("Exception thrown from CallVoidMethod(putLong)");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -488,12 +518,14 @@ void cli_put_hexvalue(struct cli_context *context, const unsigned char *value, i
|
|||||||
void cli_row_count(struct cli_context *context, int rows){
|
void cli_row_count(struct cli_context *context, int rows){
|
||||||
#ifdef HAVE_JNI_H
|
#ifdef HAVE_JNI_H
|
||||||
if (context && context->jni_env) {
|
if (context && context->jni_env) {
|
||||||
|
if (context->jni_exception)
|
||||||
|
return;
|
||||||
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, totalRowCount, rows);
|
(*context->jni_env)->CallVoidMethod(context->jni_env, context->jniResults, totalRowCount, rows);
|
||||||
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
if ((*context->jni_env)->ExceptionOccurred(context->jni_env)) {
|
||||||
context->jni_exception = 1;
|
context->jni_exception = 1;
|
||||||
WHY("Exception thrown from CallVoidMethod()");
|
WHY("Exception thrown from CallVoidMethod()");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -713,6 +745,14 @@ int app_dna_lookup(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
time_ms_t now;
|
time_ms_t now;
|
||||||
int interval=125;
|
int interval=125;
|
||||||
|
|
||||||
|
const char *names[]={
|
||||||
|
"uri",
|
||||||
|
"did",
|
||||||
|
"name"
|
||||||
|
};
|
||||||
|
cli_columns(context, 3, names);
|
||||||
|
size_t rowcount = 0;
|
||||||
|
|
||||||
while (timeout > (now = gettime_ms())){
|
while (timeout > (now = gettime_ms())){
|
||||||
if ((last_tx+interval)<now){
|
if ((last_tx+interval)<now){
|
||||||
lookup_send_request(mdp_sockfd, &srcsid, port, NULL, did);
|
lookup_send_request(mdp_sockfd, &srcsid, port, NULL, did);
|
||||||
@ -750,6 +790,7 @@ int app_dna_lookup(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
cli_put_string(context, uri, ":");
|
cli_put_string(context, uri, ":");
|
||||||
cli_put_string(context, did, ":");
|
cli_put_string(context, did, ":");
|
||||||
cli_put_string(context, name, "\n");
|
cli_put_string(context, name, "\n");
|
||||||
|
rowcount++;
|
||||||
|
|
||||||
if (one_reply){
|
if (one_reply){
|
||||||
timeout=now;
|
timeout=now;
|
||||||
@ -775,6 +816,7 @@ int app_dna_lookup(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
overlay_mdp_client_close(mdp_sockfd);
|
overlay_mdp_client_close(mdp_sockfd);
|
||||||
|
cli_row_count(context, rowcount);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2102,6 +2144,15 @@ int app_keyring_list(const struct cli_parsed *parsed, struct cli_context *contex
|
|||||||
keyring_file *k = keyring_open_instance_cli(parsed);
|
keyring_file *k = keyring_open_instance_cli(parsed);
|
||||||
if (!k)
|
if (!k)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
const char *names[]={
|
||||||
|
"sid",
|
||||||
|
"did",
|
||||||
|
"name"
|
||||||
|
};
|
||||||
|
cli_columns(context, 3, names);
|
||||||
|
size_t rowcount = 0;
|
||||||
|
|
||||||
unsigned cn, in;
|
unsigned cn, in;
|
||||||
for (cn = 0; cn < k->context_count; ++cn)
|
for (cn = 0; cn < k->context_count; ++cn)
|
||||||
for (in = 0; in < k->contexts[cn]->identity_count; ++in) {
|
for (in = 0; in < k->contexts[cn]->identity_count; ++in) {
|
||||||
@ -2113,9 +2164,11 @@ int app_keyring_list(const struct cli_parsed *parsed, struct cli_context *contex
|
|||||||
cli_put_string(context, alloca_tohex_sid_t(*sidp), ":");
|
cli_put_string(context, alloca_tohex_sid_t(*sidp), ":");
|
||||||
cli_put_string(context, did, ":");
|
cli_put_string(context, did, ":");
|
||||||
cli_put_string(context, name, "\n");
|
cli_put_string(context, name, "\n");
|
||||||
|
rowcount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyring_free(k);
|
keyring_free(k);
|
||||||
|
cli_row_count(context, rowcount);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2397,6 +2450,12 @@ int app_id_list(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *names[]={
|
||||||
|
"sid"
|
||||||
|
};
|
||||||
|
cli_columns(context, 1, names);
|
||||||
|
size_t rowcount=0;
|
||||||
|
|
||||||
time_ms_t timeout=gettime_ms()+500;
|
time_ms_t timeout=gettime_ms()+500;
|
||||||
while(1){
|
while(1){
|
||||||
struct mdp_header rev_header;
|
struct mdp_header rev_header;
|
||||||
@ -2410,8 +2469,8 @@ int app_id_list(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (len>=SID_SIZE){
|
if (len>=SID_SIZE){
|
||||||
|
rowcount++;
|
||||||
sid_t *id = (sid_t*)response_payload;
|
sid_t *id = (sid_t*)response_payload;
|
||||||
cli_field_name(context, "sid", ":");
|
|
||||||
cli_put_hexvalue(context, id->binary, sizeof(sid_t), "\n");
|
cli_put_hexvalue(context, id->binary, sizeof(sid_t), "\n");
|
||||||
// TODO receive and decode other details about this identity
|
// TODO receive and decode other details about this identity
|
||||||
}
|
}
|
||||||
@ -2421,7 +2480,7 @@ int app_id_list(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cli_row_count(context, rowcount);
|
||||||
end:
|
end:
|
||||||
mdp_close(mdp_sock);
|
mdp_close(mdp_sock);
|
||||||
return ret;
|
return ret;
|
||||||
@ -2436,8 +2495,7 @@ int app_id_self(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
overlay_mdp_frame a;
|
overlay_mdp_frame a;
|
||||||
bzero(&a, sizeof(overlay_mdp_frame));
|
bzero(&a, sizeof(overlay_mdp_frame));
|
||||||
int result;
|
int result;
|
||||||
int count=0;
|
|
||||||
|
|
||||||
a.packetTypeAndFlags=MDP_GETADDRS;
|
a.packetTypeAndFlags=MDP_GETADDRS;
|
||||||
const char *arg = parsed->labelc ? parsed->labelv[0].text : "";
|
const char *arg = parsed->labelc ? parsed->labelv[0].text : "";
|
||||||
if (!strcasecmp(arg,"self"))
|
if (!strcasecmp(arg,"self"))
|
||||||
@ -2453,6 +2511,12 @@ int app_id_self(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
if ((mdp_sockfd = overlay_mdp_client_socket()) < 0)
|
if ((mdp_sockfd = overlay_mdp_client_socket()) < 0)
|
||||||
return WHY("Cannot create MDP socket");
|
return WHY("Cannot create MDP socket");
|
||||||
|
|
||||||
|
const char *names[]={
|
||||||
|
"sid"
|
||||||
|
};
|
||||||
|
cli_columns(context, 1, names);
|
||||||
|
size_t rowcount=0;
|
||||||
|
|
||||||
do{
|
do{
|
||||||
result=overlay_mdp_send(mdp_sockfd, &a, MDP_AWAITREPLY, 5000);
|
result=overlay_mdp_send(mdp_sockfd, &a, MDP_AWAITREPLY, 5000);
|
||||||
if (result) {
|
if (result) {
|
||||||
@ -2470,15 +2534,14 @@ int app_id_self(const struct cli_parsed *parsed, struct cli_context *context)
|
|||||||
}
|
}
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for(i=0;i<a.addrlist.frame_sid_count;i++) {
|
for(i=0;i<a.addrlist.frame_sid_count;i++) {
|
||||||
count++;
|
rowcount++;
|
||||||
cli_printf(context, "%s", alloca_tohex_sid_t(a.addrlist.sids[i]));
|
cli_put_string(context, alloca_tohex_sid_t(a.addrlist.sids[i]), "\n");
|
||||||
cli_delim(context, "\n");
|
|
||||||
}
|
}
|
||||||
/* get ready to ask for next block of SIDs */
|
/* get ready to ask for next block of SIDs */
|
||||||
a.packetTypeAndFlags=MDP_GETADDRS;
|
a.packetTypeAndFlags=MDP_GETADDRS;
|
||||||
a.addrlist.first_sid=a.addrlist.last_sid+1;
|
a.addrlist.first_sid=a.addrlist.last_sid+1;
|
||||||
}while(a.addrlist.frame_sid_count==MDP_MAX_SID_REQUEST);
|
}while(a.addrlist.frame_sid_count==MDP_MAX_SID_REQUEST);
|
||||||
|
cli_row_count(context, rowcount);
|
||||||
overlay_mdp_client_close(mdp_sockfd);
|
overlay_mdp_client_close(mdp_sockfd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2705,6 +2768,7 @@ int app_route_print(const struct cli_parsed *parsed, struct cli_context *context
|
|||||||
"Next hop"
|
"Next hop"
|
||||||
};
|
};
|
||||||
cli_columns(context, 4, names);
|
cli_columns(context, 4, names);
|
||||||
|
size_t rowcount=0;
|
||||||
|
|
||||||
while(overlay_mdp_client_poll(mdp_sockfd, 200)){
|
while(overlay_mdp_client_poll(mdp_sockfd, 200)){
|
||||||
overlay_mdp_frame rx;
|
overlay_mdp_frame rx;
|
||||||
@ -2743,9 +2807,11 @@ int app_route_print(const struct cli_parsed *parsed, struct cli_context *context
|
|||||||
cli_put_string(context, strbuf_str(b), ":");
|
cli_put_string(context, strbuf_str(b), ":");
|
||||||
cli_put_string(context, p->interface_name, ":");
|
cli_put_string(context, p->interface_name, ":");
|
||||||
cli_put_string(context, alloca_tohex_sid_t(p->neighbour), "\n");
|
cli_put_string(context, alloca_tohex_sid_t(p->neighbour), "\n");
|
||||||
|
rowcount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
overlay_mdp_client_close(mdp_sockfd);
|
overlay_mdp_client_close(mdp_sockfd);
|
||||||
|
cli_row_count(context, rowcount);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,10 @@ public abstract class AbstractId {
|
|||||||
return hashCode;
|
return hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void toByteBuffer(ByteBuffer buff){
|
||||||
|
buff.put(this.binary);
|
||||||
|
}
|
||||||
|
|
||||||
public String toHex(int offset, int len) {
|
public String toHex(int offset, int len) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = offset; i < offset + len && i < binary.length; i++) {
|
for (int i = offset; i < offset + len && i < binary.length; i++) {
|
||||||
|
@ -20,29 +20,7 @@
|
|||||||
|
|
||||||
package org.servalproject.servaldna;
|
package org.servalproject.servaldna;
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates an internal (coding) error in the JNI interface to servald. Typically encountered when
|
|
||||||
* unpacking the outv strings returned by a servald operation, and indicates that the C code in
|
|
||||||
* servald that constructs the outv array is not consistent with the Java code that unpacks the outv
|
|
||||||
* strings.
|
|
||||||
*/
|
|
||||||
public class ServalDInterfaceError extends Error
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public ServalDInterfaceError(String message, ServalDResult result) {
|
public interface AsyncResult<T> {
|
||||||
super(message + ": " + result);
|
public void result(T nextResult);
|
||||||
}
|
|
||||||
|
|
||||||
public ServalDInterfaceError(String message, ServalDResult result, Throwable cause) {
|
|
||||||
super(message + ": " + result, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServalDInterfaceError(ServalDResult result, Throwable cause) {
|
|
||||||
super("" + result, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServalDInterfaceError(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
56
java/org/servalproject/servaldna/JniResult.java
Normal file
56
java/org/servalproject/servaldna/JniResult.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package org.servalproject.servaldna;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by jeremy on 18/02/14.
|
||||||
|
*/
|
||||||
|
public class JniResult implements IJniResults{
|
||||||
|
protected String columnName=null;
|
||||||
|
protected String command[];
|
||||||
|
protected int result;
|
||||||
|
|
||||||
|
void setCommand(String command[]){
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
void setResult(int result) throws ServalDFailureException {
|
||||||
|
this.result = result;
|
||||||
|
if (result == ServalDCommand.STATUS_ERROR)
|
||||||
|
throw new ServalDFailureException("Command \"" + ServalDCommand.toString(command)+"\" returned an error");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getResult(){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startResultSet(int columns) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColumnName(int column, String name) {
|
||||||
|
columnName=name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBlob(byte[] value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putDouble(double value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void totalRowCount(int rows) {
|
||||||
|
}
|
||||||
|
}
|
75
java/org/servalproject/servaldna/JniResultList.java
Normal file
75
java/org/servalproject/servaldna/JniResultList.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package org.servalproject.servaldna;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by jeremy on 18/02/14.
|
||||||
|
*/
|
||||||
|
public abstract class JniResultList<T extends JniResult> implements IJniResults {
|
||||||
|
private String names[];
|
||||||
|
private int column =-1;
|
||||||
|
private int columns = -1;
|
||||||
|
private T currentRow;
|
||||||
|
private AsyncResult<T> results;
|
||||||
|
|
||||||
|
public JniResultList(AsyncResult<T> results){
|
||||||
|
this.results = results;
|
||||||
|
}
|
||||||
|
public abstract T create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startResultSet(int columns) {
|
||||||
|
names = new String[columns];
|
||||||
|
this.columns = columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColumnName(int column, String name) {
|
||||||
|
names[column]=name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareCol(){
|
||||||
|
column++;
|
||||||
|
if (column==0)
|
||||||
|
currentRow = create();
|
||||||
|
currentRow.columnName = names[column];
|
||||||
|
}
|
||||||
|
private void endCol(){
|
||||||
|
if (column+1>=columns){
|
||||||
|
if (currentRow!=null)
|
||||||
|
results.result(currentRow);
|
||||||
|
currentRow=null;
|
||||||
|
column=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
prepareCol();
|
||||||
|
currentRow.putString(value);
|
||||||
|
endCol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBlob(byte[] value) {
|
||||||
|
prepareCol();
|
||||||
|
currentRow.putBlob(value);
|
||||||
|
endCol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
prepareCol();
|
||||||
|
currentRow.putLong(value);
|
||||||
|
endCol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putDouble(double value) {
|
||||||
|
prepareCol();
|
||||||
|
currentRow.putDouble(value);
|
||||||
|
endCol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void totalRowCount(int rows) {
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
package org.servalproject.servaldna;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class JniResultsList extends AbstractJniResults implements IJniResults {
|
|
||||||
final List<byte[]> list;
|
|
||||||
private byte[] empty = new byte[0];
|
|
||||||
public JniResultsList(List<byte[]> list) {
|
|
||||||
this.list = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putBlob(byte[] value) {
|
|
||||||
list.add(value == null ? empty : value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -20,7 +20,11 @@
|
|||||||
|
|
||||||
package org.servalproject.servaldna;
|
package org.servalproject.servaldna;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class ServalDCommand
|
public class ServalDCommand
|
||||||
{
|
{
|
||||||
@ -32,6 +36,28 @@ public class ServalDCommand
|
|||||||
System.loadLibrary("serval");
|
System.loadLibrary("serval");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final int STATUS_ERROR = 255;
|
||||||
|
|
||||||
|
public static String toString(String[] values) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
sb.append(' ');
|
||||||
|
sb.append(values[i]);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// copies the semantics of serval-dna's confParseBoolean
|
||||||
|
private static boolean parseBoolean(String value, boolean defaultValue) {
|
||||||
|
if (value == null || "".equals(value))
|
||||||
|
return defaultValue;
|
||||||
|
return "off".compareToIgnoreCase(value) != 0
|
||||||
|
&& "no".compareToIgnoreCase(value) != 0
|
||||||
|
&& "false".compareToIgnoreCase(value) != 0
|
||||||
|
&& "0".compareToIgnoreCase(value) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Low-level JNI entry point into servald command line.
|
* Low-level JNI entry point into servald command line.
|
||||||
*
|
*
|
||||||
@ -39,8 +65,7 @@ public class ServalDCommand
|
|||||||
* @param args The words to pass on the command line (ie, argv[1]...argv[n])
|
* @param args The words to pass on the command line (ie, argv[1]...argv[n])
|
||||||
* @return The servald exit status code (normally 0 indicates success)
|
* @return The servald exit status code (normally 0 indicates success)
|
||||||
*/
|
*/
|
||||||
private static native int rawCommand(IJniResults results, String[] args)
|
private static native int rawCommand(IJniResults results, String[] args);
|
||||||
throws ServalDInterfaceError;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common entry point into servald command line.
|
* Common entry point into servald command line.
|
||||||
@ -54,39 +79,577 @@ public class ServalDCommand
|
|||||||
* @return The servald exit status code (normally0 indicates success)
|
* @return The servald exit status code (normally0 indicates success)
|
||||||
*/
|
*/
|
||||||
public static synchronized int command(final IJniResults callback, String... args)
|
public static synchronized int command(final IJniResults callback, String... args)
|
||||||
throws ServalDInterfaceError
|
throws ServalDFailureException {
|
||||||
|
int ret = ServalDCommand.rawCommand(callback, args);
|
||||||
|
if (ret == STATUS_ERROR)
|
||||||
|
throw new ServalDFailureException("Command \"" + toString(args)+"\" returned an error");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized JniResult command(String... args)
|
||||||
|
throws ServalDFailureException {
|
||||||
|
JniResult result = new JniResult();
|
||||||
|
result.setCommand(args);
|
||||||
|
result.setResult(ServalDCommand.rawCommand(result, args));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Status extends JniResult{
|
||||||
|
public int pid;
|
||||||
|
public int tries;
|
||||||
|
public String instancePath;
|
||||||
|
public String status;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
if (columnName.equals("instancepath"))
|
||||||
|
instancePath=value;
|
||||||
|
if (columnName.equals("status"))
|
||||||
|
status=value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
if (columnName.equals("pid"))
|
||||||
|
pid = (int)value;
|
||||||
|
if (columnName.equals("tries"))
|
||||||
|
tries = (int)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Start the servald server process if it is not already running.
|
||||||
|
*
|
||||||
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
|
*/
|
||||||
|
public static Status serverStart(String execPath)
|
||||||
|
throws ServalDFailureException {
|
||||||
|
Status result = new Status();
|
||||||
|
result.setResult(command(result, "start", "exec", execPath));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Status serverStop()
|
||||||
|
throws ServalDFailureException {
|
||||||
|
Status result = new Status();
|
||||||
|
result.setResult(command(result, "stop"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Status serverStatus()
|
||||||
|
throws ServalDFailureException {
|
||||||
|
Status result = new Status();
|
||||||
|
result.setResult(command(result, "status"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class IdentityResult extends JniResult {
|
||||||
|
public String did;
|
||||||
|
public String name;
|
||||||
|
public SubscriberId subscriberId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
if (this.columnName.equals("did"))
|
||||||
|
this.did = value;
|
||||||
|
if (this.columnName.equals("name"))
|
||||||
|
this.name = value;
|
||||||
|
if (this.columnName.equals("sid"))
|
||||||
|
try {
|
||||||
|
this.subscriberId = new SubscriberId(value);
|
||||||
|
} catch (AbstractId.InvalidHexException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBlob(byte[] value) {
|
||||||
|
if (this.columnName.equals("sid"))
|
||||||
|
try {
|
||||||
|
this.subscriberId = new SubscriberId(value);
|
||||||
|
} catch (AbstractId.InvalidBinaryException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IdentityResult keyringAdd()
|
||||||
|
throws ServalDFailureException {
|
||||||
|
IdentityResult result = new IdentityResult();
|
||||||
|
command(result, "keyring", "add");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IdentityResult keyringSetDidName(SubscriberId sid, String did, String name) throws ServalDFailureException
|
||||||
{
|
{
|
||||||
return ServalDCommand.rawCommand(callback, args);
|
IdentityResult result = new IdentityResult();
|
||||||
|
command(result, "keyring","set","did", sid.toHex(), did==null?"":did, name==null?"":name);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int keyringList(final AsyncResult<IdentityResult> results) throws ServalDFailureException
|
||||||
|
{
|
||||||
|
return keyringList(new JniResultList<IdentityResult>(results) {
|
||||||
|
@Override
|
||||||
|
public IdentityResult create() {
|
||||||
|
return new IdentityResult();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int keyringList(IJniResults results) throws ServalDFailureException{
|
||||||
|
return command(results, "keyring", "list");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IdentityResult reverseLookup(final SubscriberId sid) throws ServalDFailureException {
|
||||||
|
IdentityResult result = new IdentityResult();
|
||||||
|
command(result, "reverse", "lookup", sid.toHex());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LookupResult extends JniResult {
|
||||||
|
public String did;
|
||||||
|
public String name;
|
||||||
|
public String uri;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
if (this.columnName.equals("did"))
|
||||||
|
this.did = value;
|
||||||
|
if (this.columnName.equals("name"))
|
||||||
|
this.name = value;
|
||||||
|
if (this.columnName.equals("uri"))
|
||||||
|
this.uri = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int dnaLookup(AsyncResult<LookupResult> results, String did, int timeout) throws ServalDFailureException {
|
||||||
|
return dnaLookup(new JniResultList<LookupResult>(results) {
|
||||||
|
@Override
|
||||||
|
public LookupResult create() {
|
||||||
|
return new LookupResult();
|
||||||
|
}
|
||||||
|
}, did, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int dnaLookup(IJniResults results, String did, int timeout) throws ServalDFailureException {
|
||||||
|
return command(results, "dna", "lookup", did, Integer.toString(timeout));
|
||||||
|
}
|
||||||
|
public static class ManifestResult extends JniResult{
|
||||||
|
public BundleId manifestId;
|
||||||
|
public long version;
|
||||||
|
public long fileSize;
|
||||||
|
public FileHash fileHash;
|
||||||
|
public BundleKey bundleKey;
|
||||||
|
public long date;
|
||||||
|
public int crypt;
|
||||||
|
public String service;
|
||||||
|
public String name;
|
||||||
|
public boolean readonly=true;
|
||||||
|
public byte[] manifest;
|
||||||
|
public String secret;
|
||||||
|
public SubscriberId author;
|
||||||
|
public long rowId;
|
||||||
|
public long insertTime;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
try {
|
||||||
|
if (value!="" && (columnName.equals("manifestid")||columnName.equals("id")))
|
||||||
|
manifestId = new BundleId(value);
|
||||||
|
if (value!="" && columnName.equals("filehash"))
|
||||||
|
fileHash = new FileHash(value);
|
||||||
|
if (value!="" && columnName.equals("BK"))
|
||||||
|
bundleKey = new BundleKey(value);
|
||||||
|
if (value!="" && columnName.equals(".author"))
|
||||||
|
author = new SubscriberId(value);
|
||||||
|
} catch (AbstractId.InvalidHexException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (columnName.equals("service"))
|
||||||
|
service = value;
|
||||||
|
if (columnName.equals("name"))
|
||||||
|
name = value;
|
||||||
|
if (columnName.equals("secret"))
|
||||||
|
secret = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBlob(byte[] value) {
|
||||||
|
if (columnName.equals("manifest"))
|
||||||
|
this.manifest = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
if (columnName.equals("version"))
|
||||||
|
version = value;
|
||||||
|
if (columnName.equals("filesize"))
|
||||||
|
fileSize = value;
|
||||||
|
if (columnName.equals("date"))
|
||||||
|
date = value;
|
||||||
|
if (columnName.equals("crypt"))
|
||||||
|
crypt = (int)value;
|
||||||
|
if (columnName.equals(".readonly"))
|
||||||
|
readonly = value>0;
|
||||||
|
if (columnName.equals(".fromhere"))
|
||||||
|
readonly = value==0;
|
||||||
|
if (columnName.equals(".rowid") || columnName.equals("_id"))
|
||||||
|
rowId = value;
|
||||||
|
if (columnName.equals(".inserttime"))
|
||||||
|
insertTime = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManifestResult rhizomeAddFile(File payloadPath, File manifestPath, SubscriberId author, String pin)
|
||||||
|
throws ServalDFailureException
|
||||||
|
{
|
||||||
|
|
||||||
|
List<String> args = new LinkedList<String>();
|
||||||
|
args.add("rhizome");
|
||||||
|
args.add("add");
|
||||||
|
args.add("file");
|
||||||
|
if (pin != null) {
|
||||||
|
args.add("--entry-pin");
|
||||||
|
args.add(pin);
|
||||||
|
}
|
||||||
|
args.add(author == null ? "" : author.toHex());
|
||||||
|
if (payloadPath != null)
|
||||||
|
args.add(payloadPath.getAbsolutePath());
|
||||||
|
else if (manifestPath != null)
|
||||||
|
args.add("");
|
||||||
|
if (manifestPath != null)
|
||||||
|
args.add(manifestPath.getAbsolutePath());
|
||||||
|
|
||||||
|
ManifestResult result = new ManifestResult();
|
||||||
|
result.setResult(command(result, args.toArray(new String[args.size()])));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int rhizomeList(AsyncResult<ManifestResult> result, String service, String name, SubscriberId sender, SubscriberId recipient, int offset, int numRows) throws ServalDFailureException {
|
||||||
|
return rhizomeList(new JniResultList<ManifestResult>(result) {
|
||||||
|
@Override
|
||||||
|
public ManifestResult create() {
|
||||||
|
return new ManifestResult();
|
||||||
|
}
|
||||||
|
}, service, name, sender, recipient, offset, numRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int rhizomeList(IJniResults result, String service, String name, SubscriberId sender, SubscriberId recipient, int offset, int numRows) throws ServalDFailureException {
|
||||||
|
List<String> args = new LinkedList<String>();
|
||||||
|
args.add("rhizome");
|
||||||
|
args.add("list");
|
||||||
|
args.add(service == null ? "" : service);
|
||||||
|
args.add(name == null ? "" : name);
|
||||||
|
args.add(sender == null ? "" : sender.toHex());
|
||||||
|
args.add(recipient == null ? "" : recipient.toHex());
|
||||||
|
if (offset > 0)
|
||||||
|
args.add("" + offset);
|
||||||
|
else if (numRows > 0)
|
||||||
|
args.add("0");
|
||||||
|
if (numRows > 0)
|
||||||
|
args.add("" + numRows);
|
||||||
|
return command(result, args.toArray(new String[args.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManifestResult rhizomeImportBundle(File payloadFile,
|
||||||
|
File manifestFile) throws ServalDFailureException {
|
||||||
|
ManifestResult result = new ManifestResult();
|
||||||
|
result.setResult(command(result, "rhizome", "import", "bundle",
|
||||||
|
payloadFile.getAbsolutePath(), manifestFile.getAbsolutePath()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManifestResult rhizomeExtractBundle(BundleId manifestId, File manifestFile, File payloadFile) throws ServalDFailureException{
|
||||||
|
ManifestResult result = new ManifestResult();
|
||||||
|
result.setResult(command(result, "rhizome", "extract", "bundle",
|
||||||
|
manifestId.toHex(),
|
||||||
|
manifestFile == null ? "-" : manifestFile.getAbsolutePath(),
|
||||||
|
payloadFile.getAbsolutePath()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManifestResult rhizomeExportManifest(BundleId manifestId, File manifestFile) throws ServalDFailureException{
|
||||||
|
ManifestResult result = new ManifestResult();
|
||||||
|
result.setResult(command(result, "rhizome", "export", "manifest",
|
||||||
|
manifestId.toHex(),
|
||||||
|
manifestFile == null ? "-" : manifestFile.getAbsolutePath()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManifestResult rhizomeExtractFile(BundleId manifestId, File payloadFile) throws ServalDFailureException{
|
||||||
|
ManifestResult result = new ManifestResult();
|
||||||
|
result.setResult(command(result, "rhizome", "extract", "file",
|
||||||
|
manifestId.toHex(),
|
||||||
|
payloadFile.getAbsolutePath()));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common entry point into servald command line.
|
* Push Rhizome bundles to all configured direct hosts.
|
||||||
*
|
*
|
||||||
* @param args
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
* The parameters as passed on the command line, eg: res =
|
|
||||||
* servald.command("config", "set", "debug", "peers");
|
|
||||||
* @return An object containing the servald exit status code (normally0
|
|
||||||
* indicates success) and zero or more output fields that it would
|
|
||||||
* have sent to standard output if invoked via a shell command line.
|
|
||||||
*/
|
*/
|
||||||
|
public static void rhizomeDirectPush() throws ServalDFailureException
|
||||||
public static synchronized ServalDResult command(String... args)
|
|
||||||
throws ServalDInterfaceError
|
|
||||||
{
|
{
|
||||||
LinkedList<byte[]> results = new LinkedList<byte[]>();
|
command("rhizome", "direct", "push");
|
||||||
int status = rawCommand(new JniResultsList(results), args);
|
|
||||||
return new ServalDResult(args, status, results.toArray(new byte[results.size()][]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
public static void main(String[] args)
|
* Pull Rhizome bundles from all configured direct hosts.
|
||||||
|
*
|
||||||
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
|
*/
|
||||||
|
public static void rhizomeDirectPull() throws ServalDFailureException
|
||||||
{
|
{
|
||||||
LinkedList<byte[]> outv = new LinkedList<byte[]>();
|
command("rhizome", "direct", "pull");
|
||||||
IJniResults results = new JniResultsList(outv);
|
}
|
||||||
int status = rawCommand(results, args);
|
|
||||||
for (byte[] a: outv) {
|
/**
|
||||||
System.out.println(new String(a));
|
* Sync (push and pull) Rhizome bundles from all configured direct hosts.
|
||||||
|
*
|
||||||
|
* @author Andrew Bettison <andrew@servalproject.com>
|
||||||
|
*/
|
||||||
|
public static void rhizomeDirectSync() throws ServalDFailureException
|
||||||
|
{
|
||||||
|
command("rhizome", "direct", "sync");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConfigItems extends JniResult{
|
||||||
|
public Map<String, String> values = new HashMap<String, String>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
values.put(this.columnName, value);
|
||||||
}
|
}
|
||||||
System.exit(status);
|
}
|
||||||
|
|
||||||
|
public static ConfigItems getConfig(String pattern) throws ServalDFailureException {
|
||||||
|
ConfigItems results = new ConfigItems();
|
||||||
|
results.setResult(command(results, "config", "get", pattern));
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getConfigItem(String name) throws ServalDFailureException{
|
||||||
|
Object result = getConfig(name).values.get(name);
|
||||||
|
if (result == null)
|
||||||
|
return null;
|
||||||
|
if (result instanceof byte[]){
|
||||||
|
return new String((byte[])result);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteConfig(String name) throws ServalDFailureException {
|
||||||
|
ServalDCommand.command("config", "del", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setConfigItem(String name, String value) throws ServalDFailureException {
|
||||||
|
ServalDCommand.command("config", "set", name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getConfigItemBoolean(String name, boolean defaultValue) {
|
||||||
|
try {
|
||||||
|
String value = getConfigItem(name);
|
||||||
|
return parseBoolean(value, defaultValue);
|
||||||
|
} catch (ServalDFailureException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getConfigItemInt(String name, int defaultValue) throws ServalDFailureException{
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(getConfig(name).values.get(name));
|
||||||
|
} catch (ServalDFailureException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PeerCount extends JniResult{
|
||||||
|
long count;
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
count = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int peerCount() throws ServalDFailureException {
|
||||||
|
PeerCount result = new PeerCount();
|
||||||
|
result.setResult(ServalDCommand.command(result, "peer", "count"));
|
||||||
|
return (int)result.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int idPeers(AsyncResult<IdentityResult> results) throws ServalDFailureException {
|
||||||
|
return idPeers(new JniResultList<IdentityResult>(results) {
|
||||||
|
@Override
|
||||||
|
public IdentityResult create() {
|
||||||
|
return new IdentityResult();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int idPeers(IJniResults results) throws ServalDFailureException {
|
||||||
|
return command(results, "id", "peers");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Conversation extends JniResult{
|
||||||
|
public long id;
|
||||||
|
public SubscriberId recipient;
|
||||||
|
public String read;
|
||||||
|
public long last_message;
|
||||||
|
public long read_offset;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
if (columnName.equals("read"))
|
||||||
|
this.read = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBlob(byte[] value) {
|
||||||
|
if (columnName.equals("recipient"))
|
||||||
|
try {
|
||||||
|
this.recipient = new SubscriberId(value);
|
||||||
|
} catch (AbstractId.InvalidBinaryException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
if (columnName.equals("_id"))
|
||||||
|
this.id = value;
|
||||||
|
if (columnName.equals("last_message"))
|
||||||
|
this.last_message = value;
|
||||||
|
if (columnName.equals("read_offset"))
|
||||||
|
this.read_offset = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int listConversations(AsyncResult<Conversation> result, final SubscriberId sender, int offset, int numRows) throws ServalDFailureException {
|
||||||
|
return listConversations(new JniResultList<Conversation>(result) {
|
||||||
|
@Override
|
||||||
|
public Conversation create() {
|
||||||
|
return new Conversation();
|
||||||
|
}
|
||||||
|
}, sender, offset, numRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int listConversations(IJniResults callback, final SubscriberId sender, int offset, int numRows) throws ServalDFailureException {
|
||||||
|
return command(callback, "meshms", "list", "conversations",
|
||||||
|
sender.toHex(), ""+offset, ""+numRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Message extends JniResult{
|
||||||
|
public long id;
|
||||||
|
public long offset;
|
||||||
|
public String type;
|
||||||
|
public String message;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
if (columnName.equals("type"))
|
||||||
|
this.type = value;
|
||||||
|
if (columnName.equals("message"))
|
||||||
|
this.message = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
if (columnName.equals("_id"))
|
||||||
|
this.id = value;
|
||||||
|
if (columnName.equals("offset"))
|
||||||
|
this.offset = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int listMessages(AsyncResult<Message> result, final SubscriberId sender, final SubscriberId recipient) throws ServalDFailureException {
|
||||||
|
return listMessages(new JniResultList<Message>(result) {
|
||||||
|
@Override
|
||||||
|
public Message create() {
|
||||||
|
return new Message();
|
||||||
|
}
|
||||||
|
}, sender, recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int listMessages(IJniResults callback, final SubscriberId sender, final SubscriberId recipient) throws ServalDFailureException {
|
||||||
|
return ServalDCommand.command(callback, "meshms", "list", "messages",
|
||||||
|
sender.toHex(), recipient.toHex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendMessage(final SubscriberId sender, final SubscriberId recipient, String message) throws ServalDFailureException {
|
||||||
|
command("meshms", "send", "message",
|
||||||
|
sender.toHex(), recipient.toHex(),
|
||||||
|
message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readMessage(final SubscriberId sender, final SubscriberId recipient) throws ServalDFailureException {
|
||||||
|
command("meshms", "read", "messages",
|
||||||
|
sender.toHex(), recipient.toHex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readMessage(final SubscriberId sender, final SubscriberId recipient, long offset) throws ServalDFailureException {
|
||||||
|
command("meshms", "read", "messages",
|
||||||
|
sender.toHex(), recipient.toHex(),
|
||||||
|
"" + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int printCommand(final String fieldDelim, final String rowDelim, String... args){
|
||||||
|
return rawCommand(new IJniResults() {
|
||||||
|
int columns =-1;
|
||||||
|
int column =-1;
|
||||||
|
@Override
|
||||||
|
public void startResultSet(int columns) {
|
||||||
|
this.columns=columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColumnName(int column, String name) {
|
||||||
|
System.out.print(name + fieldDelim);
|
||||||
|
if (column>=0 && column+1==columns)
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void eol(){
|
||||||
|
if (columns==-1 || ++column==columns){
|
||||||
|
System.out.print(rowDelim);
|
||||||
|
column=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putString(String value) {
|
||||||
|
System.out.print(value);
|
||||||
|
eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putBlob(byte[] value) {
|
||||||
|
System.out.print(new String(value));
|
||||||
|
eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putLong(long value) {
|
||||||
|
System.out.print(value);
|
||||||
|
eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putDouble(double value) {
|
||||||
|
System.out.print(value);
|
||||||
|
eol();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void totalRowCount(int rows) {
|
||||||
|
}
|
||||||
|
}, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String... args)
|
||||||
|
{
|
||||||
|
System.exit(printCommand(":","\n",args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
package org.servalproject.servaldna;
|
package org.servalproject.servaldna;
|
||||||
|
|
||||||
import org.servalproject.servaldna.ServalDResult;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when a request to a servald JNI method fails. This typically means that the returned
|
* Thrown when a request to a servald JNI method fails. This typically means that the returned
|
||||||
* status is non-zero, or some other result was returned that indicated the operation failed.
|
* status is non-zero, or some other result was returned that indicated the operation failed.
|
||||||
@ -32,10 +30,6 @@ public class ServalDFailureException extends Exception
|
|||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public ServalDFailureException(String message, ServalDResult result) {
|
|
||||||
super(message + " for command: " + result.getCommandString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServalDFailureException(String message) {
|
public ServalDFailureException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
@ -1,217 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (C) 2011 The Serval Project
|
|
||||||
*
|
|
||||||
* This file is part of Serval Software (http://www.servalproject.org)
|
|
||||||
*
|
|
||||||
* Serval Software is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This source code is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this source code; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.servalproject.servaldna;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/** Represents the result of invoking servald via the JNI command-line interface. The 'args'
|
|
||||||
* attribute contains a copy of the arguments that were passed to the call that produced this
|
|
||||||
* result, to facilitate diagnosis of failures and errors. The results of a call are an integer
|
|
||||||
* 'status' value (normally the process exit status) and a list of strings in 'outv', called "output
|
|
||||||
* fields". These strings must be interpreted depending on the operation that produced them.
|
|
||||||
*
|
|
||||||
* Many operations return information about their outcome as a sequence of key-value pairs of
|
|
||||||
* fields. The getField() method and variants offer an order-independent means to query these
|
|
||||||
* fields by key and optionally enforce a type on the value. If the operation produces output
|
|
||||||
* that is not in the key-value structure, then the caller simply avoids using these methods,
|
|
||||||
* and accesses the 'outv' array directly.
|
|
||||||
*
|
|
||||||
* @author Andrew Bettison <andrew@servalproject.com>
|
|
||||||
*/
|
|
||||||
public class ServalDResult
|
|
||||||
{
|
|
||||||
public static final int STATUS_ERROR = 255;
|
|
||||||
|
|
||||||
public final String[] args;
|
|
||||||
public final int status;
|
|
||||||
public final byte[][] outv;
|
|
||||||
private HashMap<String,byte[]> keyValue;
|
|
||||||
|
|
||||||
public ServalDResult(String[] args, int status, byte[][] outv) {
|
|
||||||
this.args = args;
|
|
||||||
this.status = status;
|
|
||||||
this.outv = outv;
|
|
||||||
this.keyValue = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServalDResult(ServalDResult orig) {
|
|
||||||
this.args = orig.args;
|
|
||||||
this.status = orig.status;
|
|
||||||
this.outv = orig.outv;
|
|
||||||
this.keyValue = orig.keyValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCommandString() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = 0; i < this.args.length; i++) {
|
|
||||||
if (i > 0)
|
|
||||||
sb.append(' ');
|
|
||||||
sb.append(args[i]);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
String[] outvstr = new String[this.outv.length];
|
|
||||||
for (int i = 0; i != this.outv.length; ++i)
|
|
||||||
outvstr[i] = new String(this.outv[i]);
|
|
||||||
return this.getClass().getName() + "(args=" + Arrays.deepToString(this.args) + ", status=" + this.status + ", outv=" + Arrays.deepToString(outvstr) + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void failIfStatusError() throws ServalDFailureException {
|
|
||||||
if (this.status == STATUS_ERROR)
|
|
||||||
throw new ServalDFailureException("error exit status", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void failIfStatusNonzero() throws ServalDFailureException {
|
|
||||||
if (this.status != 0)
|
|
||||||
throw new ServalDFailureException("non-zero exit status", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void makeKeyValueMap() {
|
|
||||||
if (this.keyValue == null) {
|
|
||||||
if (this.outv.length % 2 != 0)
|
|
||||||
throw new ServalDInterfaceError("odd number of fields", this);
|
|
||||||
this.keyValue = new HashMap<String,byte[]>();
|
|
||||||
for (int i = 0; i != this.outv.length; i += 2)
|
|
||||||
this.keyValue.put(new String(this.outv[i]), this.outv[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String,byte[]> getKeyValueMap() {
|
|
||||||
makeKeyValueMap();
|
|
||||||
return new HashMap<String,byte[]>(this.keyValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected byte[] getFieldOrNull(String fieldName) {
|
|
||||||
makeKeyValueMap();
|
|
||||||
if (!this.keyValue.containsKey(fieldName))
|
|
||||||
return null;
|
|
||||||
return this.keyValue.get(fieldName);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected byte[] getField(String fieldName) throws ServalDInterfaceError {
|
|
||||||
byte[] value = getFieldOrNull(fieldName);
|
|
||||||
if (value == null)
|
|
||||||
throw new ServalDInterfaceError("missing '" + fieldName + "' field", this);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getFieldByteArray(String fieldName, byte[] defaultValue) {
|
|
||||||
byte[] value = getFieldOrNull(fieldName);
|
|
||||||
if (value == null)
|
|
||||||
return defaultValue;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFieldString(String fieldName, String defaultValue) {
|
|
||||||
byte[] value = getFieldOrNull(fieldName);
|
|
||||||
if (value == null)
|
|
||||||
return defaultValue;
|
|
||||||
return new String(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFieldString(String fieldName) throws ServalDInterfaceError {
|
|
||||||
return new String(getField(fieldName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFieldStringNonEmptyOrNull(String fieldName) throws ServalDInterfaceError {
|
|
||||||
String value = getFieldString(fieldName, "");
|
|
||||||
return value.length() == 0 ? null : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getFieldLong(String fieldName) throws ServalDInterfaceError {
|
|
||||||
String value = getFieldString(fieldName);
|
|
||||||
try {
|
|
||||||
return Long.valueOf(value);
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not of type long", this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFieldInt(String fieldName) throws ServalDInterfaceError {
|
|
||||||
String value = getFieldString(fieldName);
|
|
||||||
try {
|
|
||||||
return Integer.valueOf(value);
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not of type int", this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getFieldBoolean(String fieldName) throws ServalDInterfaceError {
|
|
||||||
String value = getFieldString(fieldName);
|
|
||||||
try {
|
|
||||||
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("on"))
|
|
||||||
return true;
|
|
||||||
if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("no") || value.equalsIgnoreCase("off"))
|
|
||||||
return false;
|
|
||||||
return Integer.parseInt(value) != 0;
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not of type boolean", this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SubscriberId getFieldSubscriberId(String fieldName, SubscriberId defaultValue) throws ServalDInterfaceError {
|
|
||||||
byte[] value = getFieldOrNull(fieldName);
|
|
||||||
if (value == null)
|
|
||||||
return defaultValue;
|
|
||||||
String str = new String(value);
|
|
||||||
try {
|
|
||||||
return new SubscriberId(str);
|
|
||||||
}
|
|
||||||
catch (AbstractId.InvalidHexException e) {
|
|
||||||
throw new ServalDInterfaceError("field " + fieldName + "='" + str + "' is not a Bundle ID: " + e.getMessage(), this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SubscriberId getFieldSubscriberId(String fieldName) throws ServalDInterfaceError {
|
|
||||||
SubscriberId value = getFieldSubscriberId(fieldName, null);
|
|
||||||
if (value == null)
|
|
||||||
throw new ServalDInterfaceError("missing '" + fieldName + "' field", this);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BundleId getFieldBundleId(String fieldName) throws ServalDInterfaceError {
|
|
||||||
String value = getFieldString(fieldName);
|
|
||||||
try {
|
|
||||||
return new BundleId(value);
|
|
||||||
}
|
|
||||||
catch (BundleId.InvalidHexException e) {
|
|
||||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not a Bundle ID: " + e.getMessage(), this, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileHash getFieldFileHash(String fieldName) throws ServalDInterfaceError {
|
|
||||||
String value = getFieldString(fieldName);
|
|
||||||
try {
|
|
||||||
return new FileHash(value);
|
|
||||||
}
|
|
||||||
catch (BundleId.InvalidHexException e) {
|
|
||||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not a file hash: " + e.getMessage(), this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -59,6 +59,7 @@ public class SubscriberId extends AbstractId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static SubscriberId broadcastSid;
|
public static SubscriberId broadcastSid;
|
||||||
|
public static SubscriberId ANY;
|
||||||
static {
|
static {
|
||||||
byte buff[] = new byte[BINARY_SIZE];
|
byte buff[] = new byte[BINARY_SIZE];
|
||||||
for (int i = 0; i < BINARY_SIZE; i++)
|
for (int i = 0; i < BINARY_SIZE; i++)
|
||||||
@ -68,5 +69,14 @@ public class SubscriberId extends AbstractId {
|
|||||||
} catch (InvalidBinaryException e) {
|
} catch (InvalidBinaryException e) {
|
||||||
// TODO log error?
|
// TODO log error?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buff = new byte[BINARY_SIZE];
|
||||||
|
for (int i = 0; i < BINARY_SIZE; i++)
|
||||||
|
buff[i] = (byte) 0x00;
|
||||||
|
try {
|
||||||
|
ANY = new SubscriberId(buff);
|
||||||
|
} catch (InvalidBinaryException e) {
|
||||||
|
// TODO log error?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
package org.servalproject.test;
|
package org.servalproject.test;
|
||||||
|
|
||||||
import org.servalproject.servaldna.ServalDCommand;
|
import org.servalproject.servaldna.ServalDCommand;
|
||||||
import org.servalproject.servaldna.ServalDResult;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
class ServalDTests
|
class ServalDTests
|
||||||
{
|
{
|
||||||
public static void main(String[] args)
|
public static void main(String... args)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i != args.length; ++i)
|
for (int i = 0; i != args.length; ++i)
|
||||||
@ -22,14 +21,8 @@ class ServalDTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
while(repeatCount>0){
|
while(repeatCount>0){
|
||||||
ServalDResult result = ServalDCommand.command(args);
|
ServalDCommand.printCommand(""," ",args);
|
||||||
System.out.print(result.status);
|
System.out.println();
|
||||||
for (byte[] a: result.outv) {
|
|
||||||
System.out.print(":");
|
|
||||||
System.out.print(new String(a));
|
|
||||||
}
|
|
||||||
System.out.println("");
|
|
||||||
|
|
||||||
repeatCount--;
|
repeatCount--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
SERVAL_SOURCES = \
|
SERVAL_SOURCES = \
|
||||||
|
$(SERVAL_BASE)sqlite-amalgamation-3070900/sqlite3.c \
|
||||||
$(SERVAL_BASE)cli.c \
|
$(SERVAL_BASE)cli.c \
|
||||||
$(SERVAL_BASE)commandline.c \
|
$(SERVAL_BASE)commandline.c \
|
||||||
$(SERVAL_BASE)conf.c \
|
$(SERVAL_BASE)conf.c \
|
||||||
@ -70,7 +71,6 @@ SERVAL_SOURCES = \
|
|||||||
$(SERVAL_BASE)sha2.c \
|
$(SERVAL_BASE)sha2.c \
|
||||||
$(SERVAL_BASE)sighandlers.c \
|
$(SERVAL_BASE)sighandlers.c \
|
||||||
$(SERVAL_BASE)slip.c \
|
$(SERVAL_BASE)slip.c \
|
||||||
$(SERVAL_BASE)sqlite-amalgamation-3070900/sqlite3.c \
|
|
||||||
$(SERVAL_BASE)srandomdev.c \
|
$(SERVAL_BASE)srandomdev.c \
|
||||||
$(SERVAL_BASE)str.c \
|
$(SERVAL_BASE)str.c \
|
||||||
$(SERVAL_BASE)strbuf.c \
|
$(SERVAL_BASE)strbuf.c \
|
||||||
|
52
testdefs.sh
52
testdefs.sh
@ -78,6 +78,57 @@ extract_stdout_keyvalue() {
|
|||||||
assert --message="stdout of ($executed) contains valid '$_label:' line" --stdout extract_stdout_keyvalue_optional "$@"
|
assert --message="stdout of ($executed) contains valid '$_label:' line" --stdout extract_stdout_keyvalue_optional "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Parse the standard result set output produced by the immediately preceding command
|
||||||
|
# command into the following shell variables:
|
||||||
|
# NCOLS the number of columns
|
||||||
|
# NROWS the number of data rows (not counting headers)
|
||||||
|
# HEADER[c] the C-th header label, 0 <= C <= NCOLS-1
|
||||||
|
# <label>[R] where <label> is a header label with all non-alphanumerics
|
||||||
|
# replaced by underscore '_' and all alphas converted to upper case, eg,
|
||||||
|
# .author -> _AUTHOR, is the value of that column in the R-th row, 0 <=
|
||||||
|
# R < NROWS
|
||||||
|
#
|
||||||
|
# Warning: overwrites existing shell variables. Names of overwritten shell
|
||||||
|
# variables are derived directly from the output of the command, so cannot be
|
||||||
|
# controlled. If a prefix is supplied, all variables are prefixed with that.
|
||||||
|
unpack_stdout_list() {
|
||||||
|
local prefix="$1"
|
||||||
|
{
|
||||||
|
local n
|
||||||
|
read n
|
||||||
|
eval ${prefix}NCOLS=\"\$n\"
|
||||||
|
declare -a ${prefix}HEADER
|
||||||
|
local -a header
|
||||||
|
local oIFS="$IFS"
|
||||||
|
IFS=:
|
||||||
|
read -r -a header
|
||||||
|
IFS="$oIFS"
|
||||||
|
eval ${prefix}HEADER="(\"\${header[@]}\")"
|
||||||
|
local hdr
|
||||||
|
local -a colvars=()
|
||||||
|
for hdr in "${header[@]}"; do
|
||||||
|
hdr="${hdr//[^A-Za-z0-9_]/_}"
|
||||||
|
# hdr="${hdr^^*}" would do in Bash-4.0 and later
|
||||||
|
hdr="$(echo "$hdr" | sed -e 's/.*/\U&/')"
|
||||||
|
colvars+=("$hdr")
|
||||||
|
done
|
||||||
|
local -a row
|
||||||
|
IFS=:
|
||||||
|
local i=0
|
||||||
|
while eval read -r -a row; do
|
||||||
|
local j=0
|
||||||
|
local val
|
||||||
|
for val in "${row[@]}"; do
|
||||||
|
eval ${prefix}${colvars[$j]}[$i]=\"\$val\"
|
||||||
|
let ++j
|
||||||
|
done
|
||||||
|
let ++i
|
||||||
|
done
|
||||||
|
IFS="$oIFS"
|
||||||
|
eval ${prefix}NROWS=$i
|
||||||
|
} < <(replayStdout)
|
||||||
|
}
|
||||||
|
|
||||||
# Utility function for creating servald fixtures:
|
# Utility function for creating servald fixtures:
|
||||||
# - set $servald variable (executable under test)
|
# - set $servald variable (executable under test)
|
||||||
# - set the current instance to be "Z"
|
# - set the current instance to be "Z"
|
||||||
@ -641,7 +692,6 @@ create_identities() {
|
|||||||
done
|
done
|
||||||
done
|
done
|
||||||
executeOk_servald keyring list "${servald_options[@]}"
|
executeOk_servald keyring list "${servald_options[@]}"
|
||||||
assertStdoutLineCount '==' $N
|
|
||||||
for ((i = 1; i <= N; ++i)); do
|
for ((i = 1; i <= N; ++i)); do
|
||||||
local sidvar=SID$instance_name$i
|
local sidvar=SID$instance_name$i
|
||||||
local didvar=DID$instance_name$i
|
local didvar=DID$instance_name$i
|
||||||
|
@ -78,63 +78,6 @@ assert_rhizome_list() {
|
|||||||
rhizome_list_file_count=$(( $(replayStdout | wc -l) - 2 ))
|
rhizome_list_file_count=$(( $(replayStdout | wc -l) - 2 ))
|
||||||
}
|
}
|
||||||
|
|
||||||
# Parse the standard output produced by the immediately preceding "rhizome list"
|
|
||||||
# command into the following shell variables:
|
|
||||||
# NCOLS the number of columns
|
|
||||||
# NROWS the number of data rows (not counting headers)
|
|
||||||
# HEADER[c] the C-th header label, 0 <= C <= NCOLS-1
|
|
||||||
# <label>[R] where <label> is a header label with all non-alphanumerics
|
|
||||||
# replaced by underscore '_' and all alphas converted to upper case, eg,
|
|
||||||
# .author -> _AUTHOR, is the value of that column in the R-th row, 0 <=
|
|
||||||
# R < NROWS
|
|
||||||
#
|
|
||||||
# Warning: overwrites existing shell variables. Names of overwritten shell
|
|
||||||
# variables are derived directly from the output of rhizome list, so cannot be
|
|
||||||
# controlled. If a prefix is supplied, all variables are prefixed with that.
|
|
||||||
rhizome_list_unpack() {
|
|
||||||
local prefix="$1"
|
|
||||||
{
|
|
||||||
local n
|
|
||||||
read n
|
|
||||||
eval ${prefix}NCOLS=\"\$n\"
|
|
||||||
declare -a ${prefix}HEADER
|
|
||||||
local -a header
|
|
||||||
local oIFS="$IFS"
|
|
||||||
IFS=:
|
|
||||||
read -r -a header
|
|
||||||
IFS="$oIFS"
|
|
||||||
eval ${prefix}HEADER="(\"\${header[@]}\")"
|
|
||||||
local hdr
|
|
||||||
local -a colvars=()
|
|
||||||
for hdr in "${header[@]}"; do
|
|
||||||
case "$hdr" in
|
|
||||||
id)
|
|
||||||
hdr=BID;;
|
|
||||||
*)
|
|
||||||
hdr="${hdr//[^A-Za-z0-9_]/_}"
|
|
||||||
# hdr="${hdr^^*}" would do in Bash-4.0 and later
|
|
||||||
hdr="$(echo "$hdr" | sed -e 's/.*/\U&/')"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
colvars+=("$hdr")
|
|
||||||
done
|
|
||||||
local -a row
|
|
||||||
IFS=:
|
|
||||||
local i=0
|
|
||||||
while eval read -r -a row; do
|
|
||||||
local j=0
|
|
||||||
local val
|
|
||||||
for val in "${row[@]}"; do
|
|
||||||
eval ${prefix}${colvars[$j]}[$i]=\"\$val\"
|
|
||||||
let ++j
|
|
||||||
done
|
|
||||||
let ++i
|
|
||||||
done
|
|
||||||
IFS="$oIFS"
|
|
||||||
eval ${prefix}NROWS=$i
|
|
||||||
} < "$TFWSTDOUT"
|
|
||||||
}
|
|
||||||
|
|
||||||
rhizome_list_dump() {
|
rhizome_list_dump() {
|
||||||
local ncols
|
local ncols
|
||||||
local -a headers
|
local -a headers
|
||||||
|
@ -80,10 +80,10 @@ test_publish() {
|
|||||||
stop_servald_server +D
|
stop_servald_server +D
|
||||||
set_instance +A
|
set_instance +A
|
||||||
executeOk_servald dna lookup "$DIDB"
|
executeOk_servald dna lookup "$DIDB"
|
||||||
assertStdoutLineCount '==' 1
|
assertStdoutLineCount '==' 3
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
||||||
executeOk_servald dna lookup "$DIDC"
|
executeOk_servald dna lookup "$DIDC"
|
||||||
assertStdoutLineCount '==' 2
|
assertStdoutLineCount '==' 4
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDC/local/$DIDC:$DIDC:$NAMEC\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDC/local/$DIDC:$DIDC:$NAMEC\$"
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDD/local/$DIDD:$DIDD:$NAMED\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDD/local/$DIDD:$DIDD:$NAMED\$"
|
||||||
assert_status_all_servald_servers running
|
assert_status_all_servald_servers running
|
||||||
@ -147,13 +147,13 @@ test_routing() {
|
|||||||
executeOk_servald route print
|
executeOk_servald route print
|
||||||
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
|
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
|
||||||
executeOk_servald dna lookup "$DIDC"
|
executeOk_servald dna lookup "$DIDC"
|
||||||
assertStdoutLineCount '==' 1
|
assertStdoutLineCount '==' 3
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDC/local/$DIDC:$DIDC:$NAMEC\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDC/local/$DIDC:$DIDC:$NAMEC\$"
|
||||||
set_instance +C
|
set_instance +C
|
||||||
executeOk_servald route print
|
executeOk_servald route print
|
||||||
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
|
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
|
||||||
executeOk_servald dna lookup "$DIDB"
|
executeOk_servald dna lookup "$DIDB"
|
||||||
assertStdoutLineCount '==' 1
|
assertStdoutLineCount '==' 3
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
||||||
executeOk_servald mdp ping $SIDB 3
|
executeOk_servald mdp ping $SIDB 3
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
|
@ -258,150 +258,157 @@ EOF
|
|||||||
}
|
}
|
||||||
test_ExecArgs() {
|
test_ExecArgs() {
|
||||||
executeOk_servald dna lookup 12345
|
executeOk_servald dna lookup 12345
|
||||||
assertStdoutIs -e "uri:dumb:12345:Hello, World!\n"
|
assertStdoutLineCount '==' 3
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^uri:dumb:12345:Hello, World!\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplyOk1="DNA helper returns one valid reply"
|
doc_ReplyOk1="DNA helper returns one valid reply"
|
||||||
test_ReplyOk1() {
|
test_ReplyOk1() {
|
||||||
executeOk_servald dna lookup 00001
|
executeOk_servald dna lookup 00001
|
||||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
assertStdoutLineCount '==' 3
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplyOk2="DNA helper returns two valid replies"
|
doc_ReplyOk2="DNA helper returns two valid replies"
|
||||||
test_ReplyOk2() {
|
test_ReplyOk2() {
|
||||||
executeOk_servald dna lookup 00002
|
executeOk_servald dna lookup 00002
|
||||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00002:Joe A. Bloggs\nsip://$SID_JOE_B@10.1.1.1:00002:Joe B. Bloggs\n"
|
assertStdoutLineCount '==' 4
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_A@10.1.1.1:00002:Joe A. Bloggs\$"
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_B@10.1.1.1:00002:Joe B. Bloggs\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplyOk3="DNA helper returns three valid replies"
|
doc_ReplyOk3="DNA helper returns three valid replies"
|
||||||
test_ReplyOk3() {
|
test_ReplyOk3() {
|
||||||
executeOk_servald dna lookup 00003
|
executeOk_servald dna lookup 00003
|
||||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00003:Joe A. Bloggs\nsip://$SID_JOE_B@10.1.1.1:00003:Joe B. Bloggs\nsip://$SID_JOE_C@10.1.1.1:00003:Joe C. Bloggs\n"
|
assertStdoutLineCount '==' 5
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_A@10.1.1.1:00003:Joe A. Bloggs\$"
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_B@10.1.1.1:00003:Joe B. Bloggs\$"
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_C@10.1.1.1:00003:Joe C. Bloggs\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_UriEmpty="DNA helper returns empty URI"
|
doc_UriEmpty="DNA helper returns empty URI"
|
||||||
test_UriEmpty() {
|
test_UriEmpty() {
|
||||||
executeOk_servald dna lookup 00004
|
executeOk_servald dna lookup 00004
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty URI'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty URI'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_UriInvalid1="DNA helper returns invalid URI, missing scheme"
|
doc_UriInvalid1="DNA helper returns invalid URI, missing scheme"
|
||||||
test_UriInvalid1() {
|
test_UriInvalid1() {
|
||||||
executeOk_servald dna lookup 000051
|
executeOk_servald dna lookup 000051
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*Bluebottle.*invalid URI'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*Bluebottle.*invalid URI'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_UriInvalid2="DNA helper returns invalid URI, invalid char"
|
doc_UriInvalid2="DNA helper returns invalid URI, invalid char"
|
||||||
test_UriInvalid2() {
|
test_UriInvalid2() {
|
||||||
executeOk_servald dna lookup 000052
|
executeOk_servald dna lookup 000052
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*sip://Sea goon.*invalid URI'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*sip://Sea goon.*invalid URI'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_UriInvalid3="DNA helper returns invalid URI, empty hierarchical part"
|
doc_UriInvalid3="DNA helper returns invalid URI, empty hierarchical part"
|
||||||
test_UriInvalid3() {
|
test_UriInvalid3() {
|
||||||
executeOk_servald dna lookup 000053
|
executeOk_servald dna lookup 000053
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*sip:.*invalid URI'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*sip:.*invalid URI'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_TokenMismatch="DNA helper returns mismatched token"
|
doc_TokenMismatch="DNA helper returns mismatched token"
|
||||||
test_TokenMismatch() {
|
test_TokenMismatch() {
|
||||||
executeOk_servald dna lookup 000061
|
executeOk_servald dna lookup 000061
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*mismatched token'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*mismatched token'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_TokenEmpty="DNA helper returns empty token"
|
doc_TokenEmpty="DNA helper returns empty token"
|
||||||
test_TokenEmpty() {
|
test_TokenEmpty() {
|
||||||
executeOk_servald dna lookup 000062
|
executeOk_servald dna lookup 000062
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty token'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty token'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_TokenInvalid="DNA helper returns invalid token"
|
doc_TokenInvalid="DNA helper returns invalid token"
|
||||||
test_TokenInvalid() {
|
test_TokenInvalid() {
|
||||||
executeOk_servald dna lookup 000063
|
executeOk_servald dna lookup 000063
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid token'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid token'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_TokenInvalidLong="DNA helper returns invalid token, too long"
|
doc_TokenInvalidLong="DNA helper returns invalid token, too long"
|
||||||
test_TokenInvalidLong() {
|
test_TokenInvalidLong() {
|
||||||
executeOk_servald dna lookup 000064
|
executeOk_servald dna lookup 000064
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_TokenInvalidShort="DNA helper returns invalid token, too short"
|
doc_TokenInvalidShort="DNA helper returns invalid token, too short"
|
||||||
test_TokenInvalidShort() {
|
test_TokenInvalidShort() {
|
||||||
executeOk_servald dna lookup 000065
|
executeOk_servald dna lookup 000065
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid token'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid token'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_DidMismatch="DNA helper returns mismatched DID"
|
doc_DidMismatch="DNA helper returns mismatched DID"
|
||||||
test_DidMismatch() {
|
test_DidMismatch() {
|
||||||
executeOk_servald dna lookup 000071
|
executeOk_servald dna lookup 000071
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*mismatched DID'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*mismatched DID'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_DidEmpty="DNA helper returns empty DID"
|
doc_DidEmpty="DNA helper returns empty DID"
|
||||||
test_DidEmpty() {
|
test_DidEmpty() {
|
||||||
executeOk_servald dna lookup 000072
|
executeOk_servald dna lookup 000072
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty DID'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty DID'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_DidInvalid="DNA helper returns invalid DID"
|
doc_DidInvalid="DNA helper returns invalid DID"
|
||||||
test_DidInvalid() {
|
test_DidInvalid() {
|
||||||
executeOk_servald dna lookup 000073
|
executeOk_servald dna lookup 000073
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid DID'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid DID'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_DidInvalidLong="DNA helper returns invalid DID, too long"
|
doc_DidInvalidLong="DNA helper returns invalid DID, too long"
|
||||||
test_DidInvalidLong() {
|
test_DidInvalidLong() {
|
||||||
executeOk_servald dna lookup 000074
|
executeOk_servald dna lookup 000074
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_DidInvalidShort="DNA helper returns invalid DID, too short"
|
doc_DidInvalidShort="DNA helper returns invalid DID, too short"
|
||||||
test_DidInvalidShort() {
|
test_DidInvalidShort() {
|
||||||
executeOk_servald dna lookup 000075
|
executeOk_servald dna lookup 000075
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid DID'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid DID'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplyInvalidMissingDelim="DNA helper returns invalid reply, missing delimiter"
|
doc_ReplyInvalidMissingDelim="DNA helper returns invalid reply, missing delimiter"
|
||||||
test_ReplyInvalidMissingDelim() {
|
test_ReplyInvalidMissingDelim() {
|
||||||
executeOk_servald dna lookup 000081
|
executeOk_servald dna lookup 000081
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplyInvalidLongName="DNA helper returns invalid reply, name too long"
|
doc_ReplyInvalidLongName="DNA helper returns invalid reply, name too long"
|
||||||
test_ReplyInvalidLongName() {
|
test_ReplyInvalidLongName() {
|
||||||
executeOk_servald dna lookup 000082
|
executeOk_servald dna lookup 000082
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplyInvalidEmpty="DNA helper returns invalid reply, empty line"
|
doc_ReplyInvalidEmpty="DNA helper returns invalid reply, empty line"
|
||||||
test_ReplyInvalidEmpty() {
|
test_ReplyInvalidEmpty() {
|
||||||
executeOk_servald dna lookup 000083
|
executeOk_servald dna lookup 000083
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply .\\n. invalid'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply .\\n. invalid'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplyInvalidMissingNewline="DNA helper returns invalid reply, missing newline"
|
doc_ReplyInvalidMissingNewline="DNA helper returns invalid reply, missing newline"
|
||||||
test_ReplyInvalidMissingNewline() {
|
test_ReplyInvalidMissingNewline() {
|
||||||
executeOk_servald dna lookup 000084
|
executeOk_servald dna lookup 000084
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*spurious'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*spurious'
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply timeout'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply timeout'
|
||||||
}
|
}
|
||||||
@ -409,30 +416,34 @@ test_ReplyInvalidMissingNewline() {
|
|||||||
doc_HelperTimeout="DNA helper process takes too long to reply and is restarted"
|
doc_HelperTimeout="DNA helper process takes too long to reply and is restarted"
|
||||||
test_HelperTimeout() {
|
test_HelperTimeout() {
|
||||||
executeOk_servald dna lookup 00009
|
executeOk_servald dna lookup 00009
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply timeout'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply timeout'
|
||||||
assertGrep "$LOGA" 'INFO:.*DNAHELPER.*process.*terminated by signal 15'
|
assertGrep "$LOGA" 'INFO:.*DNAHELPER.*process.*terminated by signal 15'
|
||||||
executeOk_servald dna lookup 00001
|
executeOk_servald dna lookup 00001
|
||||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
assertStdoutLineCount '==' 3
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_ReplySpurious="DNA helper spurious output after DONE is ignored"
|
doc_ReplySpurious="DNA helper spurious output after DONE is ignored"
|
||||||
test_ReplySpurious() {
|
test_ReplySpurious() {
|
||||||
executeOk_servald dna lookup 00010
|
executeOk_servald dna lookup 00010
|
||||||
assertStdoutIs -e "sip://$SID_JOE_E@10.1.1.1:00010:Joe E. Bloggs\n"
|
assertStdoutLineCount '==' 3
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_E@10.1.1.1:00010:Joe E. Bloggs\$"
|
||||||
assertGrep "$LOGA" 'WARN:.*DNAHELPER.*spurious output'
|
assertGrep "$LOGA" 'WARN:.*DNAHELPER.*spurious output'
|
||||||
executeOk_servald dna lookup 00001
|
executeOk_servald dna lookup 00001
|
||||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
assertStdoutLineCount '==' 3
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_HelperDies="DNA helper process dies unexpectedly and is restarted"
|
doc_HelperDies="DNA helper process dies unexpectedly and is restarted"
|
||||||
test_HelperDies() {
|
test_HelperDies() {
|
||||||
executeOk_servald dna lookup 00011
|
executeOk_servald dna lookup 00011
|
||||||
assertStdoutIs ""
|
assertStdoutLineCount '==' 2
|
||||||
assertGrep "$LOGA" 'INFO:.*DNAHELPER.*process.*exited normally with status 42'
|
assertGrep "$LOGA" 'INFO:.*DNAHELPER.*process.*exited normally with status 42'
|
||||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*goodbye cruel world\\n'
|
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*goodbye cruel world\\n'
|
||||||
executeOk_servald dna lookup 00001
|
executeOk_servald dna lookup 00001
|
||||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
assertStdoutLineCount '==' 3
|
||||||
|
assertStdoutGrep --stdout --matches=1 "^sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
runTests "$@"
|
runTests "$@"
|
||||||
|
@ -54,7 +54,7 @@ set_server_vars() {
|
|||||||
doc_LookupWildcard="Lookup by wildcard"
|
doc_LookupWildcard="Lookup by wildcard"
|
||||||
test_LookupWildcard() {
|
test_LookupWildcard() {
|
||||||
executeOk_servald dna lookup "*"
|
executeOk_servald dna lookup "*"
|
||||||
assertStdoutLineCount '==' 2
|
assertStdoutLineCount '==' 4
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ test_LookupWildcard() {
|
|||||||
doc_LookupEmpty="Lookup by empty string"
|
doc_LookupEmpty="Lookup by empty string"
|
||||||
test_LookupEmpty() {
|
test_LookupEmpty() {
|
||||||
executeOk_servald dna lookup ""
|
executeOk_servald dna lookup ""
|
||||||
assertStdoutLineCount '==' 2
|
assertStdoutLineCount '==' 4
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
||||||
}
|
}
|
||||||
@ -70,20 +70,20 @@ test_LookupEmpty() {
|
|||||||
doc_LookupNonExistent="Lookup non-existent phone number"
|
doc_LookupNonExistent="Lookup non-existent phone number"
|
||||||
test_LookupNonExistent() {
|
test_LookupNonExistent() {
|
||||||
executeOk_servald dna lookup "5551234"
|
executeOk_servald dna lookup "5551234"
|
||||||
assertStdoutLineCount '==' 0
|
assertStdoutLineCount '==' 2
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_LookupLocal="Lookup local phone number"
|
doc_LookupLocal="Lookup local phone number"
|
||||||
test_LookupLocal() {
|
test_LookupLocal() {
|
||||||
executeOk_servald dna lookup "$DIDA"
|
executeOk_servald dna lookup "$DIDA"
|
||||||
assertStdoutLineCount '==' 1
|
assertStdoutLineCount '==' 3
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDA/local/$DIDA:$DIDA:$NAMEA\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_LookupRemote="Lookup remote phone number"
|
doc_LookupRemote="Lookup remote phone number"
|
||||||
test_LookupRemote() {
|
test_LookupRemote() {
|
||||||
executeOk_servald dna lookup "$DIDB"
|
executeOk_servald dna lookup "$DIDB"
|
||||||
assertStdoutLineCount '==' 1
|
assertStdoutLineCount '==' 3
|
||||||
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
assertStdoutGrep --matches=1 "^sid://$SIDB/local/$DIDB:$DIDB:$NAMEB\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ setup_MultiLookupHelperThree() {
|
|||||||
}
|
}
|
||||||
test_MultiLookupHelperThree() {
|
test_MultiLookupHelperThree() {
|
||||||
executeOk_servald dna lookup 00003
|
executeOk_servald dna lookup 00003
|
||||||
assertStdoutLineCount '==' 3
|
assertStdoutLineCount '==' 5
|
||||||
assertStdoutGrep --matches=1 "uri:A1:00003:Name One$"
|
assertStdoutGrep --matches=1 "uri:A1:00003:Name One$"
|
||||||
assertStdoutGrep --matches=1 "uri:B1:00003:Name Three$"
|
assertStdoutGrep --matches=1 "uri:B1:00003:Name Three$"
|
||||||
assertStdoutGrep --matches=1 "uri:C1:00003:Name Six$"
|
assertStdoutGrep --matches=1 "uri:C1:00003:Name Six$"
|
||||||
@ -147,7 +147,7 @@ setup_MultiLookupHelperTwo() {
|
|||||||
}
|
}
|
||||||
test_MultiLookupHelperTwo() {
|
test_MultiLookupHelperTwo() {
|
||||||
executeOk_servald dna lookup 00002
|
executeOk_servald dna lookup 00002
|
||||||
assertStdoutLineCount '==' 2
|
assertStdoutLineCount '==' 4
|
||||||
assertStdoutGrep --matches=1 "uri:A2:00002:Name Two\$"
|
assertStdoutGrep --matches=1 "uri:A2:00002:Name Two\$"
|
||||||
assertStdoutGrep --matches=1 "uri:B2:00002:Name Four\$"
|
assertStdoutGrep --matches=1 "uri:B2:00002:Name Four\$"
|
||||||
}
|
}
|
||||||
@ -158,7 +158,7 @@ setup_MultiLookupHelperOne() {
|
|||||||
}
|
}
|
||||||
test_MultiLookupHelperOne() {
|
test_MultiLookupHelperOne() {
|
||||||
executeOk_servald dna lookup 00001
|
executeOk_servald dna lookup 00001
|
||||||
assertStdoutLineCount '==' 1
|
assertStdoutLineCount '==' 3
|
||||||
assertStdoutGrep --matches=1 "uri:B3:00001:Name Five\$"
|
assertStdoutGrep --matches=1 "uri:B3:00001:Name Five\$"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ doc_Repeat="Serval JNI repeated calls in same process"
|
|||||||
test_Repeat() {
|
test_Repeat() {
|
||||||
executeOk --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.test.ServalDTests repeat 50 'echo' 'Hello,' 'world!'
|
executeOk --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.test.ServalDTests repeat 50 'echo' 'Hello,' 'world!'
|
||||||
assertStdoutLineCount '==' 50
|
assertStdoutLineCount '==' 50
|
||||||
assertStdoutGrep --matches=50 '^0:Hello,:world!$'
|
assertStdoutGrep --matches=50 '^Hello, world! $'
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_NullArg="Serval JNI null arguments throw exception"
|
doc_NullArg="Serval JNI null arguments throw exception"
|
||||||
|
@ -47,7 +47,8 @@ setup_instances() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_keyring_list() {
|
assert_keyring_list() {
|
||||||
assertStdoutLineCount --stdout --stderr '==' $1
|
unpack_stdout_list X
|
||||||
|
assert --stdout --stderr [ $XNROWS -eq $1 ]
|
||||||
assertStdoutGrep --stderr --matches=$1 "^[0-9a-fA-F]\{64\}:[0-9*#+]*:.*\$"
|
assertStdoutGrep --stderr --matches=$1 "^[0-9a-fA-F]\{64\}:[0-9*#+]*:.*\$"
|
||||||
tfw_cat --stdout
|
tfw_cat --stdout
|
||||||
}
|
}
|
||||||
@ -198,8 +199,9 @@ setup_KeyringPinServer() {
|
|||||||
test_KeyringPinServer() {
|
test_KeyringPinServer() {
|
||||||
start_servald_server --keyring-pin=yellow
|
start_servald_server --keyring-pin=yellow
|
||||||
executeOk_servald id self
|
executeOk_servald id self
|
||||||
assertStdoutLineCount == 1
|
unpack_stdout_list X
|
||||||
assertStdoutGrep --fixed-strings "$SIDA"
|
assert --stdout --stderr [ $XNROWS -eq 1 ]
|
||||||
|
assert --stdout --stderr [ ${XSID[0]} = $SIDA ]
|
||||||
}
|
}
|
||||||
finally_KeyringPinServer() {
|
finally_KeyringPinServer() {
|
||||||
stop_servald_server
|
stop_servald_server
|
||||||
@ -216,8 +218,9 @@ setup_EntryPinServer() {
|
|||||||
test_EntryPinServer() {
|
test_EntryPinServer() {
|
||||||
start_servald_server --entry-pin=yodel
|
start_servald_server --entry-pin=yodel
|
||||||
executeOk_servald id self
|
executeOk_servald id self
|
||||||
assertStdoutLineCount == 1
|
unpack_stdout_list X
|
||||||
assertStdoutGrep --fixed-strings "$SIDA"
|
assert --stdout --stderr [ $XNROWS -eq 1 ]
|
||||||
|
assert --stdout --stderr [ ${XSID[0]} = $SIDA ]
|
||||||
}
|
}
|
||||||
finally_EntryPinServer() {
|
finally_EntryPinServer() {
|
||||||
stop_servald_server
|
stop_servald_server
|
||||||
@ -234,8 +237,9 @@ setup_KeyringEntryPinServer() {
|
|||||||
test_KeyringEntryPinServer() {
|
test_KeyringEntryPinServer() {
|
||||||
start_servald_server --keyring-pin=yellow --entry-pin=yodel
|
start_servald_server --keyring-pin=yellow --entry-pin=yodel
|
||||||
executeOk_servald id self
|
executeOk_servald id self
|
||||||
assertStdoutLineCount == 1
|
unpack_stdout_list X
|
||||||
assertStdoutGrep --fixed-strings "$SIDA"
|
assert --stdout --stderr [ $XNROWS -eq 1 ]
|
||||||
|
assert --stdout --stderr [ ${XSID[0]} = $SIDA ]
|
||||||
}
|
}
|
||||||
finally_KeyringKeyringPinServer() {
|
finally_KeyringKeyringPinServer() {
|
||||||
stop_servald_server
|
stop_servald_server
|
||||||
@ -259,32 +263,32 @@ setup_KeyringEntryPinServer() {
|
|||||||
}
|
}
|
||||||
test_KeyringEntryPinServer() {
|
test_KeyringEntryPinServer() {
|
||||||
executeOk_servald id self
|
executeOk_servald id self
|
||||||
assertStdoutLineCount == 1
|
assertStdoutLineCount == 3
|
||||||
assertStdoutGrep --fixed-strings "$SIDA"
|
assertStdoutGrep --matches=1 --fixed-strings "$SIDA"
|
||||||
executeOk_servald id enter pin 'one'
|
executeOk_servald id enter pin 'one'
|
||||||
executeOk_servald id list
|
executeOk_servald id list
|
||||||
assertStdoutLineCount == 2
|
assertStdoutLineCount == 4
|
||||||
assertStdoutGrep --fixed-strings "sid:$SIDA"
|
assertStdoutGrep --matches=1 --fixed-strings "$SIDA"
|
||||||
assertStdoutGrep --fixed-strings "sid:$ONE"
|
assertStdoutGrep --matches=1 --fixed-strings "$ONE"
|
||||||
executeOk_servald id enter pin 'two'
|
executeOk_servald id enter pin 'two'
|
||||||
executeOk_servald id list
|
executeOk_servald id list
|
||||||
assertStdoutLineCount == 4
|
assertStdoutLineCount == 6
|
||||||
assertStdoutGrep --fixed-strings "sid:$SIDA"
|
assertStdoutGrep --matches=1 --fixed-strings "$SIDA"
|
||||||
assertStdoutGrep --fixed-strings "sid:$ONE"
|
assertStdoutGrep --matches=1 --fixed-strings "$ONE"
|
||||||
assertStdoutGrep --fixed-strings "sid:$TWOA"
|
assertStdoutGrep --matches=1 --fixed-strings "$TWOA"
|
||||||
assertStdoutGrep --fixed-strings "sid:$TWOB"
|
assertStdoutGrep --matches=1 --fixed-strings "$TWOB"
|
||||||
executeOk_servald id relinquish pin 'one'
|
executeOk_servald id relinquish pin 'one'
|
||||||
executeOk_servald id list
|
executeOk_servald id list
|
||||||
assertStdoutLineCount == 3
|
assertStdoutLineCount == 5
|
||||||
assertStdoutGrep --fixed-strings "sid:$SIDA"
|
assertStdoutGrep --matches=1 --fixed-strings "$SIDA"
|
||||||
assertStdoutGrep --fixed-strings "sid:$TWOA"
|
assertStdoutGrep --matches=1 --fixed-strings "$TWOA"
|
||||||
assertStdoutGrep --fixed-strings "sid:$TWOB"
|
assertStdoutGrep --matches=1 --fixed-strings "$TWOB"
|
||||||
executeOk_servald id relinquish sid "$TWOB"
|
executeOk_servald id relinquish sid "$TWOB"
|
||||||
tfw_cat --stderr
|
tfw_cat --stderr
|
||||||
executeOk_servald id list
|
executeOk_servald id list
|
||||||
assertStdoutLineCount == 2
|
assertStdoutLineCount == 4
|
||||||
assertStdoutGrep --fixed-strings "sid:$SIDA"
|
assertStdoutGrep --matches=1 --fixed-strings "$SIDA"
|
||||||
assertStdoutGrep --fixed-strings "sid:$TWOA"
|
assertStdoutGrep --matches=1 --fixed-strings "$TWOA"
|
||||||
}
|
}
|
||||||
teardown_KeyringEntryPinServer() {
|
teardown_KeyringEntryPinServer() {
|
||||||
teardown_servald
|
teardown_servald
|
||||||
@ -306,17 +310,17 @@ setup_ListTags() {
|
|||||||
}
|
}
|
||||||
test_ListTags() {
|
test_ListTags() {
|
||||||
executeOk_servald id list
|
executeOk_servald id list
|
||||||
assertStdoutLineCount == 3
|
assertStdoutLineCount == 5
|
||||||
assertStdoutGrep --fixed-strings "sid:$ONE"
|
assertStdoutGrep --fixed-strings "$ONE"
|
||||||
assertStdoutGrep --fixed-strings "sid:$TWO"
|
assertStdoutGrep --fixed-strings "$TWO"
|
||||||
assertStdoutGrep --fixed-strings "sid:$THREE"
|
assertStdoutGrep --fixed-strings "$THREE"
|
||||||
executeOk_servald id list 'tag1'
|
executeOk_servald id list 'tag1'
|
||||||
assertStdoutLineCount == 2
|
assertStdoutLineCount == 4
|
||||||
assertStdoutGrep --fixed-strings "sid:$ONE"
|
assertStdoutGrep --fixed-strings "$ONE"
|
||||||
assertStdoutGrep --fixed-strings "sid:$TWO"
|
assertStdoutGrep --fixed-strings "$TWO"
|
||||||
executeOk_servald id list 'tag1' 'First Value'
|
executeOk_servald id list 'tag1' 'First Value'
|
||||||
assertStdoutLineCount == 1
|
assertStdoutLineCount == 3
|
||||||
assertStdoutGrep --fixed-strings "sid:$ONE"
|
assertStdoutGrep --fixed-strings "$ONE"
|
||||||
}
|
}
|
||||||
teardown_ListTags() {
|
teardown_ListTags() {
|
||||||
teardown_servald
|
teardown_servald
|
||||||
|
@ -100,17 +100,17 @@ check_meshms_bundles() {
|
|||||||
# Dump the MeshMS bundles to the log and check consistency
|
# Dump the MeshMS bundles to the log and check consistency
|
||||||
# The only "file" bundle should be the conversation list
|
# The only "file" bundle should be the conversation list
|
||||||
executeOk_servald rhizome list file
|
executeOk_servald rhizome list file
|
||||||
rhizome_list_unpack X
|
unpack_stdout_list X
|
||||||
assert --stdout --stderr [ $XNROWS -eq 1 ]
|
assert --stdout --stderr [ $XNROWS -eq 1 ]
|
||||||
assert --stdout --stderr [ ${XBID[0]} = $CONV_BID ]
|
assert --stdout --stderr [ ${XID[0]} = $CONV_BID ]
|
||||||
executeOk_servald rhizome extract bundle $CONV_BID manifest.conv payload.conv $CONV_SECRET
|
executeOk_servald rhizome extract bundle $CONV_BID manifest.conv payload.conv $CONV_SECRET
|
||||||
tfw_cat -v manifest.conv --hexdump payload.conv
|
tfw_cat -v manifest.conv --hexdump payload.conv
|
||||||
# The only "MeshMS2" bundles should be the two ply bundles
|
# The only "MeshMS2" bundles should be the two ply bundles
|
||||||
executeOk_servald rhizome list MeshMS2
|
executeOk_servald rhizome list MeshMS2
|
||||||
rhizome_list_unpack X
|
unpack_stdout_list X
|
||||||
assert --stdout [ $XNROWS -eq 2 ]
|
assert --stdout [ $XNROWS -eq 2 ]
|
||||||
local bid
|
local bid
|
||||||
for bid in ${XBID[*]}; do
|
for bid in ${XID[*]}; do
|
||||||
executeOk_servald rhizome extract bundle $bid manifest.$bid payload.$bid
|
executeOk_servald rhizome extract bundle $bid manifest.$bid payload.$bid
|
||||||
tfw_cat -v manifest.$bid --hexdump payload.$bid
|
tfw_cat -v manifest.$bid --hexdump payload.$bid
|
||||||
done
|
done
|
||||||
|
Loading…
Reference in New Issue
Block a user