diff --git a/.github/workflows/build-publish.yaml b/.github/workflows/build-publish.yaml
index db8d2f36a..1483fc143 100644
--- a/.github/workflows/build-publish.yaml
+++ b/.github/workflows/build-publish.yaml
@@ -109,6 +109,10 @@ jobs:
- name: cert-tool
directory: tools/cert-tool
file: tools/cert-tool/Dockerfile
+ - name: snippet-service
+ directory: snippet-service
+ file: .tmp/docker/snippet-service/Dockerfile
+ template-file: tools/docker/Dockerfile.in
- name: mongodb-standby-tool
directory: tools/mongodb/standby-tool
file: tools/mongodb/standby-tool/Dockerfile
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5c7139d79..79a19f626 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -34,7 +34,7 @@ jobs:
log:
level: "debug"
dumpBody: "true"
-
+
- name: test/cqldb
cmd: test
checkRace: "true"
@@ -43,7 +43,6 @@ jobs:
log:
level: "debug"
dumpBody: "true"
-
# test without check race
- name: test/norace
@@ -52,7 +51,7 @@ jobs:
log:
level: "debug"
dumpBody: "true"
-
+
- name: test/norace/cqldb
cmd: test
database: "cqldb"
@@ -85,6 +84,10 @@ jobs:
log:
level: "debug"
dumpBody: "true"
+ snippetService:
+ log:
+ level: "debug"
+ dumpBody: "true"
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
@@ -113,6 +116,7 @@ jobs:
TEST_RESOURCE_AGGREGATE_LOG_LEVEL=${{ matrix.resourceAggregate.log.level }} TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY=${{ matrix.resourceAggregate.log.dumpBody }} \
TEST_GRPC_GATEWAY_LOG_LEVEL=${{ matrix.grpcGateway.log.level }} TEST_GRPC_GATEWAY_LOG_DUMP_BODY=${{ matrix.grpcGateway.log.dumpBody }} \
TEST_IDENTITY_STORE_LOG_LEVEL=${{ matrix.identityStore.log.level }} TEST_IDENTITY_STORE_LOG_DUMP_BODY=${{ matrix.identityStore.log.dumpBody }} \
+ TEST_SNIPPET_SERVICE_LOG_LEVEL=${{ matrix.snippetService.log.level }} TEST_SNIPPET_SERVICE_LOG_DUMP_BODY=${{ matrix.snippetService.log.dumpBody }} \
TEST_DATABASE=${{ matrix.database }} \
${{ matrix.args }}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 9207a2c6c..2b6faccea 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -35,6 +35,8 @@
"TEST_GRPC_GATEWAY_LOG_DUMP_BODY": "false",
"TEST_IDENTITY_STORE_LOG_LEVEL": "info",
"TEST_IDENTITY_STORE_LOG_DUMP_BODY": "false",
+ "TEST_SNIPPET_SERVICE_LOG_LEVEL": "info",
+ "TEST_SNIPPET_SERVICE_LOG_DUMP_BODY": "false",
"TEST_DATABASE": "mongoDB",
"TEST_BRIDGE_DEVICE_CONFIG": "${workspaceFolder}/.tmp/bridge/config-test.yaml",
// "TEST_DEVICE_NAME": "bridged-device-0",
diff --git a/Makefile b/Makefile
index 612c32686..ddfe61fc2 100644
--- a/Makefile
+++ b/Makefile
@@ -31,6 +31,8 @@ TEST_GRPC_GATEWAY_LOG_LEVEL ?= info
TEST_GRPC_GATEWAY_LOG_DUMP_BODY ?= false
TEST_IDENTITY_STORE_LOG_LEVEL ?= info
TEST_IDENTITY_STORE_LOG_DUMP_BODY ?= false
+TEST_SNIPPET_SERVICE_LOG_LEVEL ?= info
+TEST_SNIPPET_SERVICE_LOG_DUMP_BODY ?= false
TEST_MEMORY_COAP_GATEWAY_NUM_DEVICES ?= 1
TEST_MEMORY_COAP_GATEWAY_NUM_RESOURCES ?= 1
TEST_MEMORY_COAP_GATEWAY_EXPECTED_RSS_IN_MB ?= 50
@@ -42,7 +44,7 @@ CERT_TOOL_SIGN_ALG ?= ECDSA-SHA256
CERT_TOOL_ELLIPTIC_CURVE ?= P256
CERT_TOOL_IMAGE = ghcr.io/plgd-dev/hub/cert-tool:vnext
-SUBDIRS := bundle certificate-authority cloud2cloud-connector cloud2cloud-gateway coap-gateway grpc-gateway resource-aggregate resource-directory http-gateway identity-store test/oauth-server tools/cert-tool
+SUBDIRS := bundle certificate-authority cloud2cloud-connector cloud2cloud-gateway coap-gateway grpc-gateway resource-aggregate resource-directory http-gateway identity-store snippet-service test/oauth-server tools/cert-tool
.PHONY: $(SUBDIRS) push proto/generate clean build test env mongo nats certificates hub-build http-gateway-www simulators
default: build
@@ -327,9 +329,9 @@ define RUN-TESTS-IN-DIRECTORY
COVERAGE_FILE=/coverage/$$(echo $(1) | sed -e "s/[\.\/]//g").coverage.txt ; \
JSON_REPORT_FILE=$(WORKING_DIRECTORY)/.tmp/report/$$(echo $(1) | sed -e "s/[\.\/]//g").report.json ; \
if [ -n "$${JSON_REPORT}" ]; then \
- $(call RUN-DOCKER, go test -timeout=45m -race -p 1 -v $(1)... -covermode=atomic -coverprofile=$${COVERAGE_FILE} -json > "$${JSON_REPORT_FILE}") \
+ $(call RUN-DOCKER, /bin/sh -c "$(2) go test -timeout=45m -race -p 1 -v $(1)... -covermode=atomic -coverprofile=$${COVERAGE_FILE} -json > $${JSON_REPORT_FILE}") \
else \
- $(call RUN-DOCKER, go test -timeout=45m -race -p 1 -v $(1)... -covermode=atomic -coverprofile=$${COVERAGE_FILE}) \
+ $(call RUN-DOCKER, /bin/sh -c "$(2) go test -timeout=45m -race -p 1 -v $(1)... -covermode=atomic -coverprofile=$${COVERAGE_FILE}") \
fi ; \
EXIT_STATUS=$$? ; \
if [ $${EXIT_STATUS} -ne 0 ]; then \
@@ -372,6 +374,7 @@ define RUN-TESTS-UDP
TEST_RESOURCE_AGGREGATE_LEVEL=$(TEST_RESOURCE_AGGREGATE_LEVEL) TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY=$(TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY) \
TEST_GRPC_GATEWAY_LOG_LEVEL=$(TEST_GRPC_GATEWAY_LOG_LEVEL) TEST_GRPC_GATEWAY_LOG_DUMP_BODY=$(TEST_GRPC_GATEWAY_LOG_DUMP_BODY) \
TEST_IDENTITY_STORE_LOG_LEVEL=$(TEST_IDENTITY_STORE_LOG_LEVEL) TEST_IDENTITY_STORE_LOG_DUMP_BODY=$(TEST_IDENTITY_STORE_LOG_DUMP_BODY) \
+ TEST_SNIPPET_SERVICE_LOG_LEVEL=$(TEST_SNIPPET_SERVICE_LOG_LEVEL) TEST_SNIPPET_SERVICE_LOG_DUMP_BODY=$(TEST_SNIPPET_SERVICE_LOG_DUMP_BODY) \
TEST_DATABASE=$(TEST_DATABASE))
$(call RUN-TESTS,iotivity-lite-dtls,./test/iotivity-lite/service,-timeout=$(TEST_TIMEOUT) $(GO_BUILD_ARG) -p 1 -v -tags=test,\
TEST_COAP_GATEWAY_UDP_ENABLED=$(TEST_COAP_GATEWAY_UDP_ENABLED) \
@@ -379,6 +382,7 @@ define RUN-TESTS-UDP
TEST_RESOURCE_AGGREGATE_LEVEL=$(TEST_RESOURCE_AGGREGATE_LEVEL) TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY=$(TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY) \
TEST_GRPC_GATEWAY_LOG_LEVEL=$(TEST_GRPC_GATEWAY_LOG_LEVEL) TEST_GRPC_GATEWAY_LOG_DUMP_BODY=$(TEST_GRPC_GATEWAY_LOG_DUMP_BODY) \
TEST_IDENTITY_STORE_LOG_LEVEL=$(TEST_IDENTITY_STORE_LOG_LEVEL) TEST_IDENTITY_STORE_LOG_DUMP_BODY=$(TEST_IDENTITY_STORE_LOG_DUMP_BODY) \
+ TEST_SNIPPET_SERVICE_LOG_LEVEL=$(TEST_SNIPPET_SERVICE_LOG_LEVEL) TEST_SNIPPET_SERVICE_LOG_DUMP_BODY=$(TEST_SNIPPET_SERVICE_LOG_DUMP_BODY) \
TEST_DATABASE=$(TEST_DATABASE))
endef
@@ -391,6 +395,7 @@ test: env hub-test
TEST_RESOURCE_AGGREGATE_LEVEL=$(TEST_RESOURCE_AGGREGATE_LEVEL) TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY=$(TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY) \
TEST_GRPC_GATEWAY_LOG_LEVEL=$(TEST_GRPC_GATEWAY_LOG_LEVEL) TEST_GRPC_GATEWAY_LOG_DUMP_BODY=$(TEST_GRPC_GATEWAY_LOG_DUMP_BODY) \
TEST_IDENTITY_STORE_LOG_LEVEL=$(TEST_IDENTITY_STORE_LOG_LEVEL) TEST_IDENTITY_STORE_LOG_DUMP_BODY=$(TEST_IDENTITY_STORE_LOG_DUMP_BODY) \
+ TEST_SNIPPET_SERVICE_LOG_LEVEL=$(TEST_SNIPPET_SERVICE_LOG_LEVEL) TEST_SNIPPET_SERVICE_LOG_DUMP_BODY=$(TEST_SNIPPET_SERVICE_LOG_DUMP_BODY) \
TEST_DATABASE=$(TEST_DATABASE))
ifeq ($(TEST_COAP_GATEWAY_UDP_ENABLED),true)
@$(call RUN-TESTS-UDP)
@@ -411,6 +416,7 @@ test/mem: env/test/mem hub-test
TEST_RESOURCE_AGGREGATE_LEVEL=$(TEST_RESOURCE_AGGREGATE_LEVEL) TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY=$(TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY) \
TEST_GRPC_GATEWAY_LOG_LEVEL=$(TEST_GRPC_GATEWAY_LOG_LEVEL) TEST_GRPC_GATEWAY_LOG_DUMP_BODY=$(TEST_GRPC_GATEWAY_LOG_DUMP_BODY) \
TEST_IDENTITY_STORE_LOG_LEVEL=$(TEST_IDENTITY_STORE_LOG_LEVEL) TEST_IDENTITY_STORE_LOG_DUMP_BODY=$(TEST_IDENTITY_STORE_LOG_DUMP_BODY)\
+ TEST_SNIPPET_SERVICE_LOG_LEVEL=$(TEST_SNIPPET_SERVICE_LOG_LEVEL) TEST_SNIPPET_SERVICE_LOG_DUMP_BODY=$(TEST_SNIPPET_SERVICE_LOG_DUMP_BODY) \
TEST_DATABASE=$(TEST_DATABASE))
.PHONY: test/mem
@@ -428,7 +434,14 @@ $(test-targets): %: env hub-test
echo "No golang files detected, directory $$TARGET_DIRECTORY skipped"; \
exit 0; \
fi ; \
- $(call RUN-TESTS-IN-DIRECTORY,$(patsubst test-%,./%/,$@))
+ $(call RUN-TESTS-IN-DIRECTORY,$(patsubst test-%,./%/,$@),\
+ TEST_COAP_GATEWAY_UDP_ENABLED=$(TEST_COAP_GATEWAY_UDP_ENABLED) \
+ TEST_COAP_GATEWAY_LOG_LEVEL=$(TEST_COAP_GATEWAY_LOG_LEVEL) TEST_COAP_GATEWAY_LOG_DUMP_BODY=$(TEST_COAP_GATEWAY_LOG_DUMP_BODY) \
+ TEST_RESOURCE_AGGREGATE_LEVEL=$(TEST_RESOURCE_AGGREGATE_LEVEL) TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY=$(TEST_RESOURCE_AGGREGATE_LOG_DUMP_BODY) \
+ TEST_GRPC_GATEWAY_LOG_LEVEL=$(TEST_GRPC_GATEWAY_LOG_LEVEL) TEST_GRPC_GATEWAY_LOG_DUMP_BODY=$(TEST_GRPC_GATEWAY_LOG_DUMP_BODY) \
+ TEST_IDENTITY_STORE_LOG_LEVEL=$(TEST_IDENTITY_STORE_LOG_LEVEL) TEST_IDENTITY_STORE_LOG_DUMP_BODY=$(TEST_IDENTITY_STORE_LOG_DUMP_BODY) \
+ TEST_SNIPPET_SERVICE_LOG_LEVEL=$(TEST_SNIPPET_SERVICE_LOG_LEVEL) TEST_SNIPPET_SERVICE_LOG_DUMP_BODY=$(TEST_SNIPPET_SERVICE_LOG_DUMP_BODY) \
+ TEST_DATABASE=$(TEST_DATABASE))
.PHONY: $(test-targets)
diff --git a/bundle/Dockerfile b/bundle/Dockerfile
index 9cc19ab46..3b9a66e7a 100644
--- a/bundle/Dockerfile
+++ b/bundle/Dockerfile
@@ -113,6 +113,13 @@ RUN go build \
-o "/go/bin/$tool" \
./
+#snippet-service
+ARG service=snippet-service
+WORKDIR $root_directory/$service
+RUN go build -ldflags "-linkmode external -extldflags -static -X github.com/plgd-dev/hub/v2/pkg/build.CommitDate=$COMMIT_DATE -X github.com/plgd-dev/hub/v2/pkg/build.CommitHash=$SHORT_COMMIT -X github.com/plgd-dev/hub/v2/pkg/build.BuildDate=$DATE -X github.com/plgd-dev/hub/v2/pkg/build.Version=$VERSION -X github.com/plgd-dev/hub/v2/pkg/build.ReleaseURL=$RELEASE_URL" \
+ -o "/go/bin/$service" \
+ ./cmd/service
+
#nats
WORKDIR $root_directory
RUN apkArch="$(apk --print-arch)"; \
@@ -178,6 +185,8 @@ COPY --from=build /go/bin/cloud2cloud-connector /usr/local/bin/cloud2cloud-conne
COPY --from=build /go/src/github.com/plgd-dev/hub/cloud2cloud-connector/config.yaml /configs/cloud2cloud-connector.yaml
COPY --from=build /go/src/github.com/plgd-dev/hub/bundle/run.sh /usr/local/bin/run.sh
COPY --from=build /go/src/github.com/plgd-dev/hub/bundle/nginx /nginx
+COPY --from=build /go/bin/snippet-service /usr/local/bin/snippet-service
+COPY --from=build /go/src/github.com/plgd-dev/hub/snippet-service/config.yaml /configs/snippet-service.yaml
# install scylla
RUN curl -sSf get.scylladb.com/server | sudo bash -s -- --scylla-version 5.2
@@ -232,6 +241,8 @@ ENV NATS_PORT=10001
ENV SCYLLA_SMP=1
ENV SCYLLA_DEVELOPER_MODE=true
ENV SCYLLA_PORT=29142
+ENV SNIPPET_SERVICE_PORT=9091
+ENV HTTP_SNIPPET_SERVICE_PORT=9092
ENV M2M_OAUTH_SERVER_PORT=9080
# OAuth
diff --git a/bundle/nginx/nginx.conf.template b/bundle/nginx/nginx.conf.template
index fbcb44c8d..312c36a9f 100644
--- a/bundle/nginx/nginx.conf.template
+++ b/bundle/nginx/nginx.conf.template
@@ -121,6 +121,20 @@ http {
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
+ location ~ ^(/snippet-service) {
+ set $upstream_snippet_service https://127.0.0.1:REPLACE_HTTP_SNIPPET_SERVICE_PORT;
+ proxy_pass $upstream_snippet_service;
+ proxy_ssl_certificate /data/certs/internal/endpoint.crt;
+ proxy_ssl_certificate_key /data/certs/internal/endpoint.key;
+ proxy_ssl_trusted_certificate /data/certs/root_ca.crt;
+ proxy_ssl_verify on;
+ set $cors_headers 'Authority,Method,Path,Scheme,Accept,Accept-Encoding,Accept-Language,Content-Type,Origin,Refer,Sec-Fetch-Dest,Sec-Fetch-Mode,Sec-Fetch-Site,Authorization,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,correlation-id';
+ include /nginx/cors.conf;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+ proxy_set_header Host $host;
+ }
location ~ ^/ {
set $upstream_http_gateway https://127.0.0.1:REPLACE_HTTP_GATEWAY_PORT;
proxy_pass $upstream_http_gateway;
diff --git a/bundle/run.sh b/bundle/run.sh
index ac423c9fa..d6d944b39 100755
--- a/bundle/run.sh
+++ b/bundle/run.sh
@@ -15,6 +15,7 @@ export NGINX_PATH="/data/nginx"
export JETSTREAM_PATH="/data/jetstream"
export CERTIFICATE_AUTHORITY_ADDRESS="localhost:${CERTIFICATE_AUTHORITY_PORT}"
+export CERTIFICATE_AUTHORITY_HTTP_ADDRESS="localhost:${HTTP_CERTIFICATE_AUTHORITY_PORT}"
export MOCK_OAUTH_SERVER_ADDRESS="localhost:${MOCK_OAUTH_SERVER_PORT}"
export RESOURCE_AGGREGATE_ADDRESS="localhost:${RESOURCE_AGGREGATE_PORT}"
export RESOURCE_DIRECTORY_ADDRESS="localhost:${RESOURCE_DIRECTORY_PORT}"
@@ -23,6 +24,8 @@ export GRPC_GATEWAY_ADDRESS="localhost:${GRPC_GATEWAY_PORT}"
export HTTP_GATEWAY_ADDRESS="localhost:${HTTP_GATEWAY_PORT}"
export CLOUD2CLOUD_GATEWAY_ADDRESS="localhost:${CLOUD2CLOUD_GATEWAY_PORT}"
export CLOUD2CLOUD_CONNECTOR_ADDRESS="localhost:${CLOUD2CLOUD_CONNECTOR_PORT}"
+export SNIPPET_SERVICE_ADDRESS="localhost:${SNIPPET_SERVICE_PORT}"
+export SNIPPET_SERVICE_HTTP_ADDRESS="localhost:${HTTP_SNIPPET_SERVICE_PORT}"
export M2M_OAUTH_SERVER_ADDRESS="localhost:${M2M_OAUTH_SERVER_PORT}"
export INTERNAL_CERT_DIR_PATH="$CERTIFICATES_PATH/internal"
@@ -484,6 +487,7 @@ if [ "${OVERRIDE_FILES}" = "true" ] || [ ! -f "${NGINX_PATH}/nginx.conf" ]; then
sed -i "s/REPLACE_CLOUD2CLOUD_GATEWAY_PORT/$CLOUD2CLOUD_GATEWAY_PORT/g" ${NGINX_PATH}/nginx.conf
sed -i "s/REPLACE_CLOUD2CLOUD_CONNECTOR_PORT/$CLOUD2CLOUD_CONNECTOR_PORT/g" ${NGINX_PATH}/nginx.conf
sed -i "s/REPLACE_HTTP_CERTIFICATE_AUTHORITY_PORT/$HTTP_CERTIFICATE_AUTHORITY_PORT/g" ${NGINX_PATH}/nginx.conf
+ sed -i "s/REPLACE_HTTP_SNIPPET_SERVICE_PORT/$HTTP_SNIPPET_SERVICE_PORT/g" ${NGINX_PATH}/nginx.conf
sed -i "s/REPLACE_M2M_OAUTH_SERVER_PORT/$M2M_OAUTH_SERVER_PORT/g" ${NGINX_PATH}/nginx.conf
fi
@@ -1009,6 +1013,7 @@ cat /configs/certificate-authority.yaml | yq e "\
.apis.grpc.authorization.http.tls.useSystemCAPool = true |
.apis.grpc.authorization.authority = \"https://${OAUTH_ENDPOINT}\" |
.apis.grpc.authorization.ownerClaim = \"${OWNER_CLAIM}\" |
+ .apis.http.address = \"${CERTIFICATE_AUTHORITY_HTTP_ADDRESS}\" |
.clients.storage.use = \"${DATABASE_USE}\" |
.clients.storage.mongoDB.uri = \"${MONGODB_URI}\" |
.clients.storage.cqlDB.hosts = [ \"${SCYLLA_HOSTNAME}\" ] |
@@ -1241,7 +1246,51 @@ while true; do
sleep 1
done
+# snippet-service
+echo "starting snippet-service"
+## configuration
+if [ "${OVERRIDE_FILES}" = "true" ] || [ ! -f "/data/snippet-service.yaml" ]; then
+cat /configs/snippet-service.yaml | yq e "\
+ .hubID = \"${HUB_ID}\" |
+ .log.level = \"${LOG_LEVEL}\" |
+ .apis.grpc.address = \"${SNIPPET_SERVICE_ADDRESS}\" |
+ .apis.grpc.authorization.audience = \"${SERVICE_OAUTH_AUDIENCE}\" |
+ .apis.grpc.authorization.http.tls.useSystemCAPool = true |
+ .apis.grpc.authorization.authority = \"https://${OAUTH_ENDPOINT}\" |
+ .apis.grpc.authorization.ownerClaim = \"${OWNER_CLAIM}\" |
+ .apis.http.address = \"${SNIPPET_SERVICE_HTTP_ADDRESS}\" |
+ .clients.storage.use = \"${DATABASE_USE}\" |
+ .clients.storage.mongoDB.uri = \"${MONGODB_URI}\" |
+ .clients.storage.cqlDB.hosts = [ \"${SCYLLA_HOSTNAME}\" ] |
+ .clients.storage.cqlDB.port = ${SCYLLA_PORT} |
+ .clients.openTelemetryCollector.grpc.enabled = ${OPEN_TELEMETRY_EXPORTER_ENABLED} |
+ .clients.openTelemetryCollector.grpc.address = \"${OPEN_TELEMETRY_EXPORTER_ADDRESS}\" |
+ .clients.openTelemetryCollector.grpc.tls.caPool = \"${OPEN_TELEMETRY_EXPORTER_CA_POOL}\" |
+ .clients.openTelemetryCollector.grpc.tls.keyFile = \"${OPEN_TELEMETRY_EXPORTER_KEY_FILE}\" |
+ .clients.openTelemetryCollector.grpc.tls.certFile = \"${OPEN_TELEMETRY_EXPORTER_CERT_FILE}\" |
+ .clients.openTelemetryCollector.grpc.tls.useSystemCAPool = true
+" - > /data/snippet-service.yaml
+fi
+snippet-service --config /data/snippet-service.yaml >$LOGS_PATH/snippet-service.log 2>&1 &
+status=$?
+snippet_service_pid=$!
+if [ $status -ne 0 ]; then
+ echo "Failed to start snippet-service: $status"
+ sync
+ cat $LOGS_PATH/snippet-service.log
+ exit $status
+fi
+# waiting for ca. Without wait, sometimes the service didn't connect.
+i=0
+while true; do
+ i=$((i+1))
+ if openssl s_client -connect ${SNIPPET_SERVICE_ADDRESS} -cert ${INTERNAL_CERT_DIR_PATH}/${GRPC_INTERNAL_CERT_NAME} -key ${INTERNAL_CERT_DIR_PATH}/${GRPC_INTERNAL_CERT_KEY_NAME} <<< "Q" 2>/dev/null > /dev/null; then
+ break
+ fi
+ echo "Try to reconnect to snippet-service(${SNIPPET_SERVICE_ADDRESS}) $i"
+ sleep 1
+done
echo "Open browser at https://${DOMAIN}"
@@ -1367,4 +1416,11 @@ while sleep 10; do
exit 1
fi
fi
+ ps aux |grep $snippet_service_pid |grep -q -v grep
+ if [ $? -ne 0 ]; then
+ echo "snippet-service has already exited."
+ sync
+ cat $LOGS_PATH/snippet-service.log
+ exit 1
+ fi
done
diff --git a/charts/plgd-hub/templates/http-gateway/_helpers.tpl b/charts/plgd-hub/templates/http-gateway/_helpers.tpl
index e8c19c261..f3e42db4b 100644
--- a/charts/plgd-hub/templates/http-gateway/_helpers.tpl
+++ b/charts/plgd-hub/templates/http-gateway/_helpers.tpl
@@ -83,6 +83,20 @@
{{- end }}
{{- end }}
+{{- define "plgd-hub.httpgateway.snippetServiceApiDomain" -}}
+ {{- $domain := "" }}
+ {{- if .Values.snippetservice }}
+ {{- if .Values.snippetservice.enabled }}
+ {{- if .Values.snippetservice.domain }}
+ {{- $domain = printf "https://%s" .Values.snippetservice.domain }}
+ {{- else }}
+ {{- $domain = printf "https://api.%s" .Values.global.domain }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- printf $domain }}
+{{- end }}
+
{{- define "plgd-hub.httpgateway.uiDomain" -}}
{{- if .Values.httpgateway.uiDomain }}
{{- printf "%s" .Values.httpgateway.uiDomain }}
diff --git a/charts/plgd-hub/templates/http-gateway/config.yaml b/charts/plgd-hub/templates/http-gateway/config.yaml
index b5daac2db..ca7a94470 100644
--- a/charts/plgd-hub/templates/http-gateway/config.yaml
+++ b/charts/plgd-hub/templates/http-gateway/config.yaml
@@ -53,6 +53,7 @@ data:
webConfiguration:
httpGatewayAddress: {{ .ui.webConfiguration.httpGatewayAddress | default ( printf "https://%s" ( include "plgd-hub.httpgateway.apiDomain" $)) | quote }}
deviceProvisioningService: {{ .ui.webConfiguration.deviceProvisioningService | default ( include "plgd-hub.httpgateway.dpsApiDomain" $) | quote }}
+ snippetService: {{ .ui.webConfiguration.snippetService | default ( include "plgd-hub.httpgateway.snippetServiceApiDomain" $) | quote }}
{{- if not $.Values.mockoauthserver.enabled }}
webOAuthClient:
authority: {{ required ".ui.webConfiguration.webOAuthClient.authority or global.authority is required" ( .ui.webConfiguration.webOAuthClient.authority | default $.Values.global.authority ) | quote }}
diff --git a/charts/plgd-hub/templates/snippet-service/_helpers.tpl b/charts/plgd-hub/templates/snippet-service/_helpers.tpl
new file mode 100644
index 000000000..0d2d07419
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/_helpers.tpl
@@ -0,0 +1,53 @@
+{{- define "plgd-hub.snippetservice.fullname" -}}
+{{- if .Values.snippetservice.fullnameOverride }}
+{{- .Values.snippetservice.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Values.snippetservice.name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s-%s" .Release.Name $name .Values.snippetservice.name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{- define "plgd-hub.snippetservice.configName" -}}
+ {{- $fullName := include "plgd-hub.snippetservice.fullname" . -}}
+ {{- printf "%s-cfg" $fullName }}
+{{- end -}}
+
+{{- define "plgd-hub.snippetservice.createServiceCertByCm" }}
+ {{- $serviceTls := .Values.snippetservice.apis.grpc.tls.certFile }}
+ {{- if $serviceTls }}
+ {{- printf "" -}}
+ {{- else }}
+ {{- printf "true" -}}
+ {{- end }}
+{{- end }}
+
+{{- define "plgd-hub.snippetservice.domain" -}}
+ {{- if .Values.snippetservice.domain }}
+ {{- printf "%s" .Values.snippetservice.domain }}
+ {{- else }}
+ {{- printf "api.%s" .Values.global.domain }}
+ {{- end }}
+{{- end }}
+
+{{- define "plgd-hub.snippetservice.serviceCertName" -}}
+ {{- $fullName := include "plgd-hub.snippetservice.fullname" . -}}
+ {{- printf "%s-crt" $fullName -}}
+{{- end }}
+
+{{- define "plgd-hub.snippetservice.domainCertName" -}}
+ {{- if .Values.snippetservice.ingress.secretName }}
+ {{- printf "%s" .Values.snippetservice.ingress.secretName -}}
+ {{- else }}
+ {{- $fullName := include "plgd-hub.snippetservice.fullname" . -}}
+ {{- printf "%s-domain-crt" $fullName -}}
+ {{- end }}
+{{- end }}
+
+{{- define "plgd-hub.snippetservice.selectorLabels" -}}
+app.kubernetes.io/name: {{ .Values.snippetservice.name }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
\ No newline at end of file
diff --git a/charts/plgd-hub/templates/snippet-service/config.yaml b/charts/plgd-hub/templates/snippet-service/config.yaml
new file mode 100644
index 000000000..384f60237
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/config.yaml
@@ -0,0 +1,112 @@
+{{- if .Values.snippetservice.enabled }}
+{{- $cert := "/certs" }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ include "plgd-hub.snippetservice.configName" . }}
+ namespace: {{ .Release.Namespace }}
+data:
+ {{ .Values.snippetservice.config.fileName }}: |
+ {{- with .Values.snippetservice }}
+ hubID: {{ required "snippetservice.hubId or global.hubId is required" ( .hubId | default $.Values.global.hubId) | quote }}
+ log:
+ level: {{ .log.level }}
+ dumpBody: {{ .log.dumpBody }}
+ encoding: {{ .log.encoding }}
+ stacktrace:
+ enabled: {{ .log.stacktrace.enabled }}
+ level: {{ .log.stacktrace.level }}
+ encoderConfig:
+ timeEncoder: {{ .log.encoderConfig.timeEncoder }}
+ apis:
+ grpc:
+ address: {{ .apis.grpc.address | default (printf "0.0.0.0:%v" .port) | quote }}
+ sendMsgSize: {{ int64 .apis.grpc.sendMsgSize | default 4194304 }}
+ recvMsgSize: {{ int64 .apis.grpc.recvMsgSize | default 4194304 }}
+ enforcementPolicy:
+ minTime: {{ .apis.grpc.enforcementPolicy.minTime }}
+ permitWithoutStream: {{ .apis.grpc.enforcementPolicy.permitWithoutStream }}
+ keepAlive:
+ # 0s - means infinity
+ maxConnectionIdle: {{ .apis.grpc.keepAlive.maxConnectionIdle }}
+ # 0s - means infinity
+ maxConnectionAge: {{ .apis.grpc.keepAlive.maxConnectionIdle }}
+ # 0s - means infinity
+ maxConnectionAgeGrace: {{ .apis.grpc.keepAlive.maxConnectionAgeGrace }}
+ time: {{ .apis.grpc.keepAlive.maxConnectionIdle }}
+ timeout: {{ .apis.grpc.keepAlive.maxConnectionIdle }}
+ tls:
+ {{- $tls := .apis.grpc.tls }}
+ {{- include "plgd-hub.certificateConfig" (list $ $tls $cert ) | indent 8 }}
+ clientCertificateRequired: {{ .apis.grpc.tls.clientCertificateRequired }}
+ authorization:
+ {{- $authorization := .apis.grpc.authorization }}
+ {{- include "plgd-hub.authorizationConfig" (list $ $authorization "snippetservice.apis.grpc.authorization" $cert ) | indent 8 }}
+ http:
+ address: {{ .apis.http.address | default (printf "0.0.0.0:%v" .httpPort) | quote }}
+ readTimeout: {{ .apis.http.readTimeout }}
+ readHeaderTimeout: {{ .apis.http.readHeaderTimeout }}
+ writeTimeout: {{ .apis.http.writeTimeout }}
+ idleTimeout: {{ .apis.http.idleTimeout }}
+ clients:
+ eventBus:
+ subscriptionID: {{ .clients.eventBus.subscriptionID | default "snippet-service" }}
+ nats:
+ url: {{ printf " " }}{{- include "plgd-hub.natsUri" (list $ .clients.eventBus.nats.url) | quote }}
+ pendingLimits:
+ msgLimit: {{ .clients.eventBus.nats.pendingLimits.msgLimit }}
+ bytesLimit: {{ printf "%v" .clients.eventBus.nats.pendingLimits.bytesLimit }}
+ tls:
+ {{- $natsTls := .clients.eventBus.nats.tls }}
+ {{- include "plgd-hub.certificateConfig" (list $ $natsTls $cert ) | indent 10 }}
+ useSystemCAPool: {{ .clients.eventBus.nats.tls.useSystemCAPool }}
+ storage:
+ use: {{ include "plgd-hub.useDatabase" (list $ . .clients.storage.use) | quote }}
+ mongoDB:
+ uri: {{ include "plgd-hub.mongoDBUri" (list $ .clients.storage.mongoDB.uri ) | quote }}
+ database: {{ .clients.storage.mongoDB.database }}
+ maxPoolSize: {{ .clients.storage.mongoDB.maxPoolSize }}
+ maxConnIdleTime: {{ .clients.storage.mongoDB.maxConnIdleTime }}
+ tls:
+ {{- $mongoDbTls := .clients.storage.mongoDB.tls }}
+ {{- include "plgd-hub.certificateConfig" (list $ $mongoDbTls $cert ) | indent 10 }}
+ useSystemCAPool: {{ .clients.storage.mongoDB.tls.useSystemCAPool }}
+ cqlDB:
+ hosts:
+ {{- include "plgd-hub.cqlDBHosts" (list $ .clients.storage.cqlDB.hosts ) | indent 8 }}
+ port: {{ .clients.storage.cqlDB.port | default 9142 }}
+ table: {{ .clients.storage.cqlDB.table | quote }}
+ numConnections: {{ .clients.storage.cqlDB.numConnections }}
+ connectTimeout: {{ .clients.storage.cqlDB.connectTimeout }}
+ useHostnameResolution: {{ .clients.storage.cqlDB.useHostnameResolution }}
+ reconnectionPolicy:
+ constant:
+ interval: {{ .clients.storage.cqlDB.reconnectionPolicy.constant.interval }}
+ maxRetries: {{ .clients.storage.cqlDB.reconnectionPolicy.constant.maxRetries }}
+ keyspace:
+ name: {{ .clients.storage.cqlDB.keyspace.name }}
+ create: {{ .clients.storage.cqlDB.keyspace.create }}
+ replication:
+ {{- toYaml .clients.storage.cqlDB.keyspace.replication | nindent 14 }}
+ tls:
+ {{- $cqlDbTls := .clients.storage.cqlDB.tls }}
+ {{- include "plgd-hub.certificateConfig" (list $ $cqlDbTls $cert ) | indent 10 }}
+ useSystemCAPool: {{ .clients.storage.cqlDB.tls.useSystemCAPool }}
+ resourceUpdater:
+ cleanUpExpiredUpdates: {{ .clients.resourceUpdater.cleanUpExpiredUpdates | quote }}
+ grpc:
+ {{- $resourceUpdater := .clients.resourceUpdater.grpc.address }}
+ address:{{ printf " " }}{{- include "plgd-hub.resourceAggregateAddress" (list $ $resourceUpdater ) | quote }}
+ sendMsgSize: {{ int64 .clients.resourceUpdater.grpc.sendMsgSize | default 4194304 }}
+ recvMsgSize: {{ int64 .clients.resourceUpdater.grpc.recvMsgSize | default 4194304 }}
+ keepAlive:
+ time: {{ .clients.resourceUpdater.grpc.keepAlive.time }}
+ timeout: {{ .clients.resourceUpdater.grpc.keepAlive.timeout }}
+ permitWithoutStream: {{ .clients.resourceUpdater.grpc.keepAlive.permitWithoutStream }}
+ tls:
+ {{- $raClientTls := .clients.resourceUpdater.grpc.tls }}
+ {{- include "plgd-hub.certificateConfig" (list $ $raClientTls $cert) | indent 10 }}
+ useSystemCAPool: {{ .clients.resourceUpdater.grpc.tls.useSystemCAPool }}
+ {{- include "plgd-hub.openTelemetryExporterConfig" (list $ $cert ) | nindent 6 }}
+ {{- end }}
+{{- end }}
diff --git a/charts/plgd-hub/templates/snippet-service/deployment.yaml b/charts/plgd-hub/templates/snippet-service/deployment.yaml
new file mode 100644
index 000000000..e433aa572
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/deployment.yaml
@@ -0,0 +1,129 @@
+{{- if .Values.snippetservice.enabled }}
+{{- $cert := "/certs" }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "plgd-hub.snippetservice.fullname" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+ {{- with .Values.snippetservice.deploymentLabels }}
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+ {{- with .Values.snippetservice.deploymentAnnotations }}
+ annotations:
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+spec:
+ replicas: {{ .Values.snippetservice.replicas }}
+ selector:
+ matchLabels:
+ {{- include "plgd-hub.snippetservice.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ {{- with .Values.snippetservice.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ {{- include "plgd-hub.snippetservice.selectorLabels" . | nindent 8 }}
+ spec:
+ {{- with .Values.snippetservice.securityContext }}
+ securityContext:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- if .Values.snippetservice.rbac.enabled }}
+ serviceAccountName: {{ .Values.snippetservice.rbac.serviceAccountName }}
+ {{- end }}
+ {{- with .Values.snippetservice.image.imagePullSecrets }}
+ imagePullSecrets:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ restartPolicy: {{ .Values.snippetservice.restartPolicy }}
+ {{- if .Values.snippetservice.initContainersTpl }}
+ initContainers:
+ {{- tpl .Values.snippetservice.initContainersTpl . | nindent 8 }}
+ {{- end }}
+ containers:
+ - name: {{ .Values.snippetservice.name }}
+ {{- with .Values.snippetservice.podSecurityContext }}
+ securityContext:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ image: {{ include "plgd-hub.image" (list . .Values.snippetservice) | quote }}
+ imagePullPolicy: {{ .Values.snippetservice.image.pullPolicy }}
+ {{- if .Values.snippetservice.command }}
+ command:
+ {{- range .Values.snippetservice.command }}
+ - {{ . | quote }}
+ {{- end }}
+ {{- end}}
+ args:
+ - "--config"
+ - {{ printf "%s/%s" .Values.snippetservice.config.mountPath .Values.snippetservice.config.fileName | quote }}
+ ports:
+ - name: grpc
+ containerPort: {{ .Values.snippetservice.port }}
+ protocol: TCP
+ - name: http
+ containerPort: {{ .Values.snippetservice.httpPort }}
+ protocol: TCP
+ {{- with .Values.snippetservice.livenessProbe }}
+ livenessProbe:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with .Values.snippetservice.readinessProbe }}
+ readinessProbe:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- with .Values.snippetservice.resources }}
+ resources:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ volumeMounts:
+ - name: {{ .Values.snippetservice.config.volume }}
+ mountPath: {{ .Values.snippetservice.config.mountPath }}
+ {{- if ( include "plgd-hub.snippetservice.createServiceCertByCm" . ) }}
+ - name: service-crt
+ mountPath: {{ $cert }}
+ {{- end }}
+ {{- if .Values.global.authorizationCAPool }}
+ - name: {{ .Values.extraAuthorizationCAPool.name }}
+ mountPath: {{ .Values.extraAuthorizationCAPool.mountPath }}
+ {{- end }}
+ {{- with .Values.snippetservice.extraVolumeMounts }}
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- if .Values.snippetservice.extraContainers }}
+ {{- include "plgd-hub.tplvalues.render" ( dict "value" .Values.snippetservice.extraContainers "context" $ ) | nindent 8 }}
+ {{- end }}
+ volumes:
+ - name: {{ .Values.resourcedirectory.config.volume }}
+ configMap:
+ name: {{ include "plgd-hub.snippetservice.configName" . }}
+ {{- if ( include "plgd-hub.snippetservice.createServiceCertByCm" . ) }}
+ - name: service-crt
+ secret:
+ secretName: {{ include "plgd-hub.snippetservice.serviceCertName" . }}
+ {{- end }}
+ {{- if .Values.global.authorizationCAPool }}
+ - name: {{ .Values.extraAuthorizationCAPool.name }}
+ secret:
+ secretName: {{ .Values.extraAuthorizationCAPool.name }}
+ {{- end }}
+ {{- with .Values.snippetservice.extraVolumes }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.snippetservice.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.snippetservice.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.snippetservice.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+{{- end }}
diff --git a/charts/plgd-hub/templates/snippet-service/domain-crt.yaml b/charts/plgd-hub/templates/snippet-service/domain-crt.yaml
new file mode 100644
index 000000000..c1d06ff62
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/domain-crt.yaml
@@ -0,0 +1,34 @@
+{{- $domainCrt := include "plgd-hub.snippetservice.domainCertName" . }}
+{{- if and $domainCrt .Values.certmanager.enabled .Values.snippetservice.enabled (not $.Values.global.enableWildCartCert ) }}
+{{- $serviceDns := include "plgd-hub.snippetservice.fullname" . }}
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: {{ $domainCrt }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+ {{- with .Values.certmanager.external.labels }}
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+ {{- with .Values.certmanager.external.annotations }}
+ annotations:
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+spec:
+ secretName: {{ $domainCrt }}
+ privateKey:
+ algorithm: {{ .Values.certmanager.external.cert.key.algorithm | default .Values.certmanager.default.cert.key.algorithm }}
+ size: {{ .Values.certmanager.external.cert.key.size | default .Values.certmanager.default.cert.key.size }}
+ usages:
+ - server auth
+ - client auth
+ dnsNames:
+ - {{ include "plgd-hub.snippetservice.domain" . | quote }}
+ duration: {{ .Values.certmanager.external.cert.duration | default .Values.certmanager.default.cert.duration }}
+ renewBefore: {{ .Values.certmanager.external.cert.renewBefore | default .Values.certmanager.default.cert.renewBefore }}
+ issuerRef:
+ name: {{ .Values.certmanager.external.issuer.name | default .Values.certmanager.default.issuer.name }}
+ kind: {{ .Values.certmanager.external.issuer.kind | default .Values.certmanager.default.issuer.kind }}
+ group: {{ .Values.certmanager.external.issuer.group | default .Values.certmanager.default.issuer.group }}
+{{- end }}
diff --git a/charts/plgd-hub/templates/snippet-service/grpc-ingress.yaml b/charts/plgd-hub/templates/snippet-service/grpc-ingress.yaml
new file mode 100644
index 000000000..12ef47117
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/grpc-ingress.yaml
@@ -0,0 +1,40 @@
+{{- if and .Values.snippetservice.enabled .Values.snippetservice.ingress.grpc.enabled }}
+{{- $fullname := include "plgd-hub.snippetservice.fullname" . }}
+{{- $port := .Values.snippetservice.port }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: {{ $fullname }}-grpc
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+ annotations:
+ {{- if .Values.snippetservice.ingress.grpc.annotations }}
+ {{- include "plgd-hub.tplvalues.render" ( dict "value" .Values.snippetservice.ingress.grpc.annotations "context" $ ) | nindent 4 }}
+ {{- end }}
+ {{- if .Values.snippetservice.ingress.grpc.customAnnotations }}
+ {{- include "plgd-hub.tplvalues.render" ( dict "value" .Values.snippetservice.ingress.grpc.customAnnotations "context" $ ) | nindent 4 }}
+ {{- end }}
+spec:
+ tls:
+ - hosts:
+ - {{ include "plgd-hub.snippetservice.domain" . | quote }}
+ {{- if $.Values.global.enableWildCartCert }}
+ secretName: {{ include "plgd-hub.wildCardCertName" . | quote }}
+ {{- else }}
+ secretName: {{ include "plgd-hub.snippetservice.domainCertName" . | quote }}
+ {{- end }}
+ rules:
+ - host: {{ include "plgd-hub.snippetservice.domain" . | quote }}
+ http:
+ paths:
+ {{- range .Values.snippetservice.ingress.grpc.paths }}
+ - path: {{ . }}
+ pathType: Prefix
+ backend:
+ service:
+ name: {{ $fullname }}-grpc
+ port:
+ number: {{ $port }}
+ {{- end }}
+{{- end }}
diff --git a/charts/plgd-hub/templates/snippet-service/grpc-service.yaml b/charts/plgd-hub/templates/snippet-service/grpc-service.yaml
new file mode 100644
index 000000000..e2d37681f
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/grpc-service.yaml
@@ -0,0 +1,25 @@
+{{- if .Values.snippetservice.enabled -}}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "plgd-hub.snippetservice.fullname" . }}-grpc
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+ {{- with .Values.snippetservice.service.grpc.labels }}
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+ {{- if .Values.snippetservice.service.grpc.annotations }}
+ annotations:
+ {{- include "plgd-hub.tplvalues.render" ( dict "value" .Values.snippetservice.service.grpc.annotations "context" $ ) | nindent 4 }}
+ {{- end }}
+spec:
+ type: {{ .Values.snippetservice.service.grpc.type | default "ClusterIP" }}
+ ports:
+ - port: {{ .Values.snippetservice.port }}
+ targetPort: {{ .Values.snippetservice.service.grpc.targetPort }}
+ protocol: {{ .Values.snippetservice.service.grpc.protocol }}
+ name: {{ .Values.snippetservice.service.grpc.name }}
+ selector:
+ {{- include "plgd-hub.snippetservice.selectorLabels" . | nindent 4 }}
+{{- end }}
\ No newline at end of file
diff --git a/charts/plgd-hub/templates/snippet-service/http-ingress.yaml b/charts/plgd-hub/templates/snippet-service/http-ingress.yaml
new file mode 100644
index 000000000..3ee3cd2b2
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/http-ingress.yaml
@@ -0,0 +1,40 @@
+{{- if and .Values.snippetservice.enabled .Values.snippetservice.ingress.http.enabled }}
+{{- $fullname := include "plgd-hub.snippetservice.fullname" . }}
+{{- $port := .Values.snippetservice.httpPort }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: {{ $fullname }}-http
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+ annotations:
+ {{- if .Values.snippetservice.ingress.http.annotations }}
+ {{- include "plgd-hub.tplvalues.render" ( dict "value" .Values.snippetservice.ingress.http.annotations "context" $ ) | nindent 4 }}
+ {{- end }}
+ {{- if .Values.snippetservice.ingress.http.customAnnotations }}
+ {{- include "plgd-hub.tplvalues.render" ( dict "value" .Values.snippetservice.ingress.http.customAnnotations "context" $ ) | nindent 4 }}
+ {{- end }}
+spec:
+ tls:
+ - hosts:
+ - {{ include "plgd-hub.snippetservice.domain" . | quote }}
+ {{- if $.Values.global.enableWildCartCert }}
+ secretName: {{ include "plgd-hub.wildCardCertName" . | quote }}
+ {{- else }}
+ secretName: {{ include "plgd-hub.snippetservice.domainCertName" . | quote }}
+ {{- end }}
+ rules:
+ - host: {{ include "plgd-hub.snippetservice.domain" . | quote }}
+ http:
+ paths:
+ {{- range .Values.snippetservice.ingress.http.paths }}
+ - path: {{ . }}
+ pathType: Prefix
+ backend:
+ service:
+ name: {{ $fullname }}-http
+ port:
+ number: {{ $port }}
+ {{- end }}
+{{- end }}
diff --git a/charts/plgd-hub/templates/snippet-service/http-service.yaml b/charts/plgd-hub/templates/snippet-service/http-service.yaml
new file mode 100644
index 000000000..1e6cf659c
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/http-service.yaml
@@ -0,0 +1,25 @@
+{{- if .Values.snippetservice.enabled -}}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "plgd-hub.snippetservice.fullname" . }}-http
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+ {{- with .Values.snippetservice.service.http.labels }}
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+ {{- if .Values.snippetservice.service.http.annotations }}
+ annotations:
+ {{- include "plgd-hub.tplvalues.render" ( dict "value" .Values.snippetservice.service.http.annotations "context" $ ) | nindent 4 }}
+ {{- end }}
+spec:
+ type: {{ .Values.snippetservice.service.http.type | default "ClusterIP" }}
+ ports:
+ - port: {{ .Values.snippetservice.httpPort }}
+ targetPort: {{ .Values.snippetservice.service.http.targetPort }}
+ protocol: {{ .Values.snippetservice.service.http.protocol }}
+ name: {{ .Values.snippetservice.service.http.name }}
+ selector:
+ {{- include "plgd-hub.snippetservice.selectorLabels" . | nindent 4 }}
+{{- end }}
\ No newline at end of file
diff --git a/charts/plgd-hub/templates/snippet-service/role.yaml b/charts/plgd-hub/templates/snippet-service/role.yaml
new file mode 100644
index 000000000..0dc01b10c
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/role.yaml
@@ -0,0 +1,3 @@
+{{- if and .Values.snippetservice.rbac.enabled .Values.snippetservice.rbac.roleBindingDefitionTpl }}
+{{- tpl .Values.snippetservice.rbac.roleBindingDefitionTpl $ }}
+{{- end }}
diff --git a/charts/plgd-hub/templates/snippet-service/service-account.yaml b/charts/plgd-hub/templates/snippet-service/service-account.yaml
new file mode 100644
index 000000000..b1a4a7081
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/service-account.yaml
@@ -0,0 +1,9 @@
+{{- if and .Values.snippetservice.rbac.enabled .Values.snippetservice.enabled }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ .Values.snippetservice.rbac.serviceAccountName }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+{{- end }}
diff --git a/charts/plgd-hub/templates/snippet-service/service-crt.yaml b/charts/plgd-hub/templates/snippet-service/service-crt.yaml
new file mode 100644
index 000000000..afce0d74b
--- /dev/null
+++ b/charts/plgd-hub/templates/snippet-service/service-crt.yaml
@@ -0,0 +1,44 @@
+{{- $createServiceCert := include "plgd-hub.snippetservice.serviceCertName" . }}
+{{- if and $createServiceCert .Values.certmanager.enabled .Values.snippetservice.enabled }}
+{{- $serviceCertName := include "plgd-hub.snippetservice.serviceCertName" . }}
+{{- $serviceDns := include "plgd-hub.snippetservice.fullname" . }}
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+ name: {{ $serviceCertName }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "plgd-hub.labels" . | nindent 4 }}
+ {{- with .Values.certmanager.internal.labels }}
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+ {{- with .Values.certmanager.internal.annotations }}
+ annotations:
+ {{- . | toYaml | nindent 4 }}
+ {{- end }}
+spec:
+ secretName: {{ $serviceCertName }}
+ privateKey:
+ algorithm: {{ .Values.certmanager.internal.cert.key.algorithm | default .Values.certmanager.default.cert.key.algorithm }}
+ size: {{ .Values.certmanager.internal.cert.key.size | default .Values.certmanager.default.cert.key.size }}
+ usages:
+ - server auth
+ - client auth
+ dnsNames:
+ - {{ printf "%s-http.%s.svc.%s" $serviceDns .Release.Namespace .Values.cluster.dns | quote }}
+ - {{ printf "%s-grpc.%s.svc.%s" $serviceDns .Release.Namespace .Values.cluster.dns | quote }}
+ - {{ printf "%s-http" $serviceDns | quote }}
+ - {{ printf "%s-grpc" $serviceDns | quote }}
+ {{- if .Values.snippetservice.service.grpc.crt.extraDnsNames }}
+ {{- toYaml .Values.snippetservice.service.grpc.crt.extraDnsNames | nindent 4}}
+ {{- end }}
+ {{- if .Values.snippetservice.service.http.crt.extraDnsNames }}
+ {{- toYaml .Values.snippetservice.service.http.crt.extraDnsNames | nindent 4}}
+ {{- end }}
+ duration: {{ .Values.certmanager.internal.cert.duration | default .Values.certmanager.default.cert.duration }}
+ renewBefore: {{ .Values.certmanager.internal.cert.renewBefore | default .Values.certmanager.default.cert.renewBefore }}
+ issuerRef:
+ name: {{ .Values.certmanager.internal.issuer.name | default .Values.certmanager.default.issuer.name }}
+ kind: {{ .Values.certmanager.internal.issuer.kind | default .Values.certmanager.default.issuer.kind }}
+ group: {{ .Values.certmanager.internal.issuer.group | default .Values.certmanager.default.issuer.group }}
+{{- end }}
diff --git a/charts/plgd-hub/values.yaml b/charts/plgd-hub/values.yaml
index fe6831bab..082f9e255 100644
--- a/charts/plgd-hub/values.yaml
+++ b/charts/plgd-hub/values.yaml
@@ -1740,6 +1740,7 @@ httpgateway:
webConfiguration:
httpGatewayAddress: ""
deviceProvisioningService: ""
+ snippetService: ""
webOAuthClient:
authority: ""
clientID: ""
@@ -2292,6 +2293,253 @@ certificateauthority:
validFrom: "now-1h"
expiresIn: "87600h"
+snippetservice:
+ # -- Enable snippet-service
+ enabled: true
+ # -- Name of component. Used in label selectors
+ name: snippet-service
+ # -- Full name to override
+ fullnameOverride:
+ # -- Number of replicas
+ replicas: 1
+ # -- Additional labels for snippet-service deployment
+ deploymentLabels: {}
+ # -- Additional annotations for snippet-service deployment
+ deploymentAnnotations: {}
+ # -- Pod security context
+ podSecurityContext: {}
+ # -- Labels for snippet-service pod
+ podLabels: {}
+ # -- Annotations for snippet-service pod
+ podAnnotations: {}
+ service:
+ grpc:
+ # -- Service type
+ type: ClusterIP
+ # -- Labels for snippet-service
+ labels: {}
+ # -- Annotations for snippet-service
+ annotations: {}
+ # -- Target port
+ targetPort: grpc
+ # -- Protocol
+ protocol: TCP
+ # -- Name
+ name: grpc
+ crt:
+ # -- Extra DNS names for service certificate
+ extraDnsNames: []
+ http:
+ # -- Service type
+ type: ClusterIP
+ # -- Labels for snippet service
+ labels: {}
+ # -- Annotations for snippet service
+ annotations: {}
+ # -- Target port
+ targetPort: http
+ # -- Protocol
+ protocol: TCP
+ # -- Name
+ name: http
+ crt:
+ # -- Extra DNS names for service certificate
+ extraDnsNames: []
+ # -- RBAC configuration
+ rbac:
+ # -- Enable RBAC
+ enabled: false
+ # -- Name of snippet service SA
+ serviceAccountName: snippet-service
+ # -- Template definition for Role/binding etc..
+ roleBindingDefitionTpl:
+ # -- Security context for pod
+ securityContext:
+ # -- Image pull secrets
+ imagePullSecrets:
+ # -- Restart policy for pod
+ restartPolicy: Always
+ # -- Init containers definition
+ initContainersTpl:
+ # -- Extra POD containers
+ extraContainers: {}
+ image:
+ # -- Image registry
+ registry: ghcr.io/
+ # -- Image repository
+ repository: plgd-dev/hub/snippet-service
+ # -- Image tag.
+ tag:
+ # -- Image pull policy
+ pullPolicy: Always
+ # -- Image pull secrets
+ imagePullSecrets:
+ # -- Liveness probe. snippet-service doesn't have any default liveness probe
+ livenessProbe:
+ # -- Readiness probe. snippet-service doesn't have aby default readiness probe
+ readinessProbe:
+ # -- Resources limit
+ resources:
+ # -- Node selector
+ nodeSelector:
+ # -- Affinity definition
+ affinity:
+ # -- Toleration definition
+ tolerations:
+ # -- Optional extra volumes
+ extraVolumes:
+ # -- Optional extra volume mounts
+ extraVolumeMounts:
+ # -- External domain for snippet-service. Default: api.{{ global.domain }}
+ domain:
+ ingress:
+ http:
+ # -- Enable ingress
+ enabled: true
+ # -- Override name of host/tls secret. If not specified, it will be generated
+ secretName:
+ # -- Pre defined map of Ingress annotation
+ annotations:
+ nginx.org/grpc-services: "{{ include \"plgd-hub.snippetservice.fullname\" . }}-http"
+ nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
+ ingress.kubernetes.io/force-ssl-redirect: "true"
+ nginx.ingress.kubernetes.io/enable-cors: "true"
+ cert-manager.io/private-key-rotation-policy: always
+ # -- Custom map of Ingress annotation
+ customAnnotations: {}
+ # -- Ingress path
+ paths:
+ - /snippet-service
+ grpc:
+ # -- Enable ingress
+ enabled: true
+ # -- Override name of host/tls secret. If not specified, it will be generated
+ secretName:
+ # -- Pre defined map of Ingress annotation
+ annotations:
+ nginx.org/grpc-services: "{{ include \"plgd-hub.snippetservice.fullname\" . }}-grpc"
+ nginx.ingress.kubernetes.io/backend-protocol: "GRPCS"
+ ingress.kubernetes.io/force-ssl-redirect: "true"
+ nginx.ingress.kubernetes.io/enable-cors: "true"
+ cert-manager.io/private-key-rotation-policy: always
+ # -- Custom map of Ingress annotation
+ customAnnotations: { }
+ # -- Paths
+ paths:
+ - /snippetservice.pb.SnippetService
+ # -- Service configuration
+ config:
+ # -- File name for config file
+ fileName: service.yaml
+ # -- Config file volume name
+ volume: config
+ # -- Mount path
+ mountPath: /config
+ # -- Service and POD port
+ port: 9100
+ httpPort: 9101
+ # -- Hub ID. Overrides the global.hubId
+ hubId:
+ # -- Log section
+ log:
+ # -- Logging enabled from level
+ level: info
+ # -- Dump grpc messages
+ dumpBody: false
+ # -- The supported values are: "json", "console"
+ encoding: json
+ stacktrace:
+ # -- Log stacktrace
+ enabled: false
+ # -- Stacktrace from level
+ level: warn
+ encoderConfig:
+ # -- Time format for logs. The supported values are: "rfc3339nano", "rfc3339"
+ timeEncoder: rfc3339nano
+ # -- For complete snippet-service configuration see [plgd/snippet-service](https://github.com/plgd-dev/hub/tree/main/snippet-service)
+ apis:
+ grpc:
+ address:
+ sendMsgSize: 4194304
+ recvMsgSize: 4194304
+ enforcementPolicy:
+ minTime: 5s
+ permitWithoutStream: true
+ keepAlive:
+ # 0s - means infinity
+ maxConnectionIdle: 0s
+ # 0s - means infinity
+ maxConnectionAge: 0s
+ # 0s - means infinity
+ maxConnectionAgeGrace: 0s
+ time: 2h
+ timeout: 20s
+ tls:
+ caPool:
+ keyFile:
+ certFile:
+ clientCertificateRequired: false
+ authorization:
+ ownerClaim:
+ authority:
+ audience:
+ http:
+ maxIdleConns: 16
+ maxConnsPerHost: 32
+ maxIdleConnsPerHost: 16
+ idleConnTimeout: "30s"
+ timeout: "10s"
+ tls:
+ caPool:
+ keyFile:
+ certFile:
+ useSystemCAPool: true
+ http:
+ address:
+ readTimeout: 8s
+ readHeaderTimeout: 4s
+ writeTimeout: 16s
+ idleTimeout: 30s
+ clients:
+ eventBus:
+ subscriptionID: snippet-service
+ nats:
+ url: ""
+ pendingLimits:
+ msgLimit: "524288"
+ bytesLimit: "67108864"
+ tls:
+ caPool:
+ keyFile:
+ certFile:
+ useSystemCAPool: false
+ storage:
+ use: mongoDB
+ mongoDB:
+ uri:
+ database: snippetService
+ maxPoolSize: 16
+ maxConnIdleTime: 4m0s
+ tls:
+ caPool:
+ keyFile:
+ certFile:
+ useSystemCAPool: false
+ resourceUpdater:
+ cleanUpExpiredUpdates: "0 * * * *"
+ grpc:
+ address: ""
+ sendMsgSize: 4194304
+ recvMsgSize: 4194304
+ keepAlive:
+ time: 10s
+ timeout: 20s
+ permitWithoutStream: true
+ tls:
+ caPool:
+ keyFile:
+ certFile:
+ useSystemCAPool: false
mockoauthserver:
oauth:
diff --git a/cloud2cloud-gateway/service/retrieveDevice.go b/cloud2cloud-gateway/service/retrieveDevice.go
index 36fde2079..7cf16ee97 100644
--- a/cloud2cloud-gateway/service/retrieveDevice.go
+++ b/cloud2cloud-gateway/service/retrieveDevice.go
@@ -10,13 +10,10 @@ import (
"github.com/gorilla/mux"
"github.com/plgd-dev/device/v2/schema"
- "github.com/plgd-dev/go-coap/v3/message"
pbGRPC "github.com/plgd-dev/hub/v2/grpc-gateway/pb"
"github.com/plgd-dev/hub/v2/pkg/log"
kitNetHttp "github.com/plgd-dev/hub/v2/pkg/net/http"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
- "github.com/plgd-dev/kit/v2/codec/cbor"
- "github.com/plgd-dev/kit/v2/codec/json"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -77,34 +74,10 @@ type Representation struct {
}
func unmarshalContent(c *commands.Content, m interface{}) error {
- switch c.GetContentType() {
- case message.AppCBOR.String(), message.AppOcfCbor.String():
- err := cbor.Decode(c.GetData(), m)
- if err != nil {
- return fmt.Errorf("cannot unmarshal resource content: %w", err)
- }
- case message.AppJSON.String():
- err := json.Decode(c.GetData(), m)
- if err != nil {
- return fmt.Errorf("cannot unmarshal resource content: %w", err)
- }
- case message.TextPlain.String():
- switch v := m.(type) {
- case *string:
- *v = string(c.GetData())
- case *[]byte:
- *v = c.GetData()
- case *interface{}:
- *v = string(c.GetData())
- default:
- return fmt.Errorf("cannot unmarshal resource content: invalid type (%T)", m)
- }
- case "":
+ if c.GetContentType() == "" {
return nil
- default:
- return fmt.Errorf("cannot unmarshal resource content: unknown content type (%v)", c.GetContentType())
}
- return nil
+ return commands.DecodeContent(c, m)
}
func (rh *RequestHandler) RetrieveResources(ctx context.Context, resourceIdFilter []*pbGRPC.ResourceIdFilter, deviceIdFilter []string) (map[string][]Representation, error) {
diff --git a/cloud2cloud-gateway/test/test.go b/cloud2cloud-gateway/test/test.go
index f9924c0e7..500dbee87 100644
--- a/cloud2cloud-gateway/test/test.go
+++ b/cloud2cloud-gateway/test/test.go
@@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"net"
+ "slices"
"sync"
"testing"
"time"
@@ -15,7 +16,6 @@ import (
"github.com/plgd-dev/hub/v2/pkg/mongodb"
"github.com/plgd-dev/hub/v2/pkg/net/http"
"github.com/plgd-dev/hub/v2/pkg/security/certManager/server"
- pkgStrings "github.com/plgd-dev/hub/v2/pkg/strings"
"github.com/plgd-dev/hub/v2/test/config"
testHttp "github.com/plgd-dev/hub/v2/test/http"
"github.com/stretchr/testify/require"
@@ -38,7 +38,7 @@ func MakeConfig(t require.TestingT) service.Config {
cfg.APIs.HTTP.Connection = config.MakeListenerConfig(config.C2C_GW_HOST)
cfg.APIs.HTTP.Connection.TLS.ClientCertificateRequired = false
- cfg.APIs.HTTP.Authorization = config.MakeAuthorizationConfig()
+ cfg.APIs.HTTP.Authorization = config.MakeValidatorConfig()
cfg.APIs.HTTP.Server = config.MakeHttpServerConfig()
cfg.Clients.Eventbus.NATS = config.MakeSubscriberConfig()
@@ -98,7 +98,7 @@ func C2CURI(uri string) string {
func GetUniqueSubscriptionID(subIDS ...string) string {
id := uuid.NewString()
for {
- if !pkgStrings.Contains(subIDS, id) {
+ if !slices.Contains(subIDS, id) {
break
}
id = uuid.NewString()
diff --git a/coap-gateway/service/clientObserveHandler.go b/coap-gateway/service/clientObserveHandler.go
index 00f8d4813..a2f265505 100644
--- a/coap-gateway/service/clientObserveHandler.go
+++ b/coap-gateway/service/clientObserveHandler.go
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
+ "slices"
"sync"
"sync/atomic"
@@ -17,7 +18,6 @@ import (
"github.com/plgd-dev/hub/v2/coap-gateway/service/message"
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
"github.com/plgd-dev/hub/v2/grpc-gateway/subscription"
- "github.com/plgd-dev/hub/v2/pkg/strings"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
"github.com/plgd-dev/hub/v2/resource-aggregate/events"
)
@@ -119,7 +119,7 @@ func (s *resourceSubscription) isDuplicateEvent(ev *events.ResourceChanged) bool
func (s *resourceSubscription) eventHandler(e *pb.Event) error {
switch {
case e.GetResourceUnpublished() != nil:
- if !strings.Contains(e.GetResourceUnpublished().GetHrefs(), s.href) {
+ if !slices.Contains(e.GetResourceUnpublished().GetHrefs(), s.href) {
return nil
}
s.cancelSubscription(coapCodes.ServiceUnavailable)
diff --git a/coap-gateway/service/clientSubscriber.go b/coap-gateway/service/clientSubscriber.go
index 28d9e8324..cc761724a 100644
--- a/coap-gateway/service/clientSubscriber.go
+++ b/coap-gateway/service/clientSubscriber.go
@@ -11,6 +11,19 @@ func (c *session) replaceDeviceSubscriber(deviceSubscriber *grpcClient.DeviceSub
return s
}
+func (c *session) getDeviceSubscriber() *grpcClient.DeviceSubscriber {
+ c.private.mutex.Lock()
+ defer c.private.mutex.Unlock()
+ return c.private.deviceSubscriber
+}
+
+func (c *session) triggerDeviceSubscriber() {
+ deviceSubscriber := c.getDeviceSubscriber()
+ if deviceSubscriber != nil {
+ deviceSubscriber.TriggerGetPendingCommands()
+ }
+}
+
// Replace the deviceSubscriber instance in the client with nil and clean up the previous instance.
func (c *session) closeDeviceSubscriber() error {
deviceSubscriber := c.replaceDeviceSubscriber(nil)
diff --git a/coap-gateway/service/observation/deviceObserver.go b/coap-gateway/service/observation/deviceObserver.go
index baaf63218..cd99da812 100644
--- a/coap-gateway/service/observation/deviceObserver.go
+++ b/coap-gateway/service/observation/deviceObserver.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net"
+ "slices"
"github.com/plgd-dev/device/v2/schema"
"github.com/plgd-dev/device/v2/schema/interfaces"
@@ -16,7 +17,6 @@ import (
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
"github.com/plgd-dev/hub/v2/pkg/log"
"github.com/plgd-dev/hub/v2/pkg/net/coap"
- pkgStrings "github.com/plgd-dev/hub/v2/pkg/strings"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
pbRD "github.com/plgd-dev/hub/v2/resource-directory/pb"
"google.golang.org/grpc"
@@ -308,7 +308,7 @@ func IsDiscoveryResourceObservable(links schema.ResourceLinks) (bool, error) {
return observable, nil
}
- return pkgStrings.Contains(res.Interfaces, observeInterface), nil
+ return slices.Contains(res.Interfaces, observeInterface), nil
}
func detectObservationType(links schema.ResourceLinks) (ObservationType, error) {
diff --git a/coap-gateway/service/resourceDirectory.go b/coap-gateway/service/resourceDirectory.go
index 61c6a8dcb..6deccec75 100644
--- a/coap-gateway/service/resourceDirectory.go
+++ b/coap-gateway/service/resourceDirectory.go
@@ -173,6 +173,8 @@ func resourceDirectoryPublishHandler(req *mux.Message, client *session) (*pool.M
if errCode, errO := observeResources(req.Context(), client, w, req.Sequence()); errO != nil {
return nil, statusErrorf(errCode, "%w", errO)
}
+ // trigger device subscriber to get pending commands for the resources that have been published
+ client.triggerDeviceSubscriber()
accept := coapconv.GetAccept(req.Options())
encode, err := coapconv.GetEncoder(accept)
diff --git a/coap-gateway/service/signIn.go b/coap-gateway/service/signIn.go
index fcf6ff884..a3b5551c0 100644
--- a/coap-gateway/service/signIn.go
+++ b/coap-gateway/service/signIn.go
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
+ "slices"
"time"
"github.com/plgd-dev/go-coap/v3/message"
@@ -14,7 +15,6 @@ import (
grpcgwClient "github.com/plgd-dev/hub/v2/grpc-gateway/client"
"github.com/plgd-dev/hub/v2/identity-store/events"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
- "github.com/plgd-dev/hub/v2/pkg/strings"
pkgTime "github.com/plgd-dev/hub/v2/pkg/time"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
"github.com/plgd-dev/kit/v2/codec/cbor"
@@ -173,7 +173,7 @@ func subscribeToDeviceEvents(client *session, owner, deviceID string) error {
if evt.GetOwner() != owner {
return
}
- if !strings.Contains(evt.GetDeviceIds(), deviceID) {
+ if !slices.Contains(evt.GetDeviceIds(), deviceID) {
return
}
client.Close()
diff --git a/coap-gateway/test/test.go b/coap-gateway/test/test.go
index fe78b1527..ad4884ff8 100644
--- a/coap-gateway/test/test.go
+++ b/coap-gateway/test/test.go
@@ -52,7 +52,7 @@ func MakeConfig(t require.TestingT) service.Config {
Config: config.MakeDeviceAuthorization(),
},
},
- Authority: config.MakeAuthorizationConfig(),
+ Authority: config.MakeValidatorConfig(),
}
cfg.Clients.IdentityStore.Connection = config.MakeGrpcClientConfig(config.IDENTITY_STORE_HOST)
cfg.Clients.ResourceAggregate.Connection = config.MakeGrpcClientConfig(config.RESOURCE_AGGREGATE_HOST)
diff --git a/dependency/googleapis b/dependency/googleapis
index 821a6ddff..7976ffadc 160000
--- a/dependency/googleapis
+++ b/dependency/googleapis
@@ -1 +1 @@
-Subproject commit 821a6ddff3ab55d2639dc2ca95a07f0e0b957a26
+Subproject commit 7976ffadc0f21ee9149708c0c97ef000e15de1eb
diff --git a/go.mod b/go.mod
index 0f0702299..4393d4499 100644
--- a/go.mod
+++ b/go.mod
@@ -21,6 +21,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0
github.com/hashicorp/go-multierror v1.1.1
+ github.com/itchyny/gojq v0.12.16
github.com/jessevdk/go-flags v1.6.1
github.com/json-iterator/go v1.1.12
github.com/jtacoma/uritemplates v1.0.0
@@ -56,6 +57,7 @@ require (
golang.org/x/net v0.26.0
golang.org/x/oauth2 v0.21.0
golang.org/x/sync v0.7.0
+ google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094
google.golang.org/grpc v1.64.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.4.0
@@ -86,6 +88,7 @@ require (
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/huandu/xstrings v1.0.0 // indirect
github.com/imdario/mergo v0.3.4 // indirect
+ github.com/itchyny/timefmt-go v0.1.6 // indirect
github.com/jhump/protoreflect v1.16.0 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
@@ -118,7 +121,6 @@ require (
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
)
diff --git a/go.sum b/go.sum
index 6e0c4a23e..0009ba293 100644
--- a/go.sum
+++ b/go.sum
@@ -143,6 +143,10 @@ github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
github.com/imdario/mergo v0.3.4 h1:mKkfHkZWD8dC7WxKx3N9WCF0Y+dLau45704YQmY6H94=
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/itchyny/gojq v0.12.16 h1:yLfgLxhIr/6sJNVmYfQjTIv0jGctu6/DgDoivmxTr7g=
+github.com/itchyny/gojq v0.12.16/go.mod h1:6abHbdC2uB9ogMS38XsErnfqJ94UlngIJGlRAIj4jTM=
+github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q=
+github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
diff --git a/grpc-gateway/client/client_test.go b/grpc-gateway/client/client_test.go
index 94555f8c9..bfb571a1d 100644
--- a/grpc-gateway/client/client_test.go
+++ b/grpc-gateway/client/client_test.go
@@ -2,13 +2,9 @@ package client_test
import (
"context"
- "crypto/tls"
- "crypto/x509"
- "testing"
"github.com/plgd-dev/device/v2/schema/device"
"github.com/plgd-dev/go-coap/v3/message"
- "github.com/plgd-dev/hub/v2/grpc-gateway/client"
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
"github.com/plgd-dev/hub/v2/pkg/net/grpc/server"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
@@ -16,7 +12,6 @@ import (
"github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
"github.com/plgd-dev/kit/v2/codec/cbor"
- "github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@@ -26,22 +21,6 @@ const (
TestManufacturer = "Test Manufacturer"
)
-func NewTestClient(t *testing.T) *client.Client {
- rootCAs := x509.NewCertPool()
- for _, c := range test.GetRootCertificateAuthorities(t) {
- rootCAs.AddCert(c)
- }
- tlsCfg := tls.Config{
- RootCAs: rootCAs,
- }
- clientConfig := client.Config{
- GatewayAddress: config.GRPC_GW_HOST,
- }
- c, err := client.NewFromConfig(&clientConfig, &tlsCfg)
- require.NoError(t, err)
- return c
-}
-
func NewGateway(addr string) (*server.Server, error) {
s, err := server.NewServer(addr)
if err != nil {
diff --git a/grpc-gateway/client/createResource_test.go b/grpc-gateway/client/createResource_test.go
index aad482a4c..745e73b7e 100644
--- a/grpc-gateway/client/createResource_test.go
+++ b/grpc-gateway/client/createResource_test.go
@@ -7,6 +7,7 @@ import (
"time"
"github.com/plgd-dev/device/v2/schema/device"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -67,7 +68,7 @@ func TestClient_CreateResource(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/deleteResource_test.go b/grpc-gateway/client/deleteResource_test.go
index 9dbc20918..3d53a7fbc 100644
--- a/grpc-gateway/client/deleteResource_test.go
+++ b/grpc-gateway/client/deleteResource_test.go
@@ -10,6 +10,7 @@ import (
"github.com/plgd-dev/device/v2/schema/resources"
"github.com/plgd-dev/hub/v2/grpc-gateway/client"
extCodes "github.com/plgd-dev/hub/v2/grpc-gateway/pb/codes"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -83,7 +84,7 @@ func TestClientDeleteResource(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
@@ -172,7 +173,7 @@ func TestClientBatchDeleteResource(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/deviceSubscriber.go b/grpc-gateway/client/deviceSubscriber.go
index 23e76688a..a59bde07f 100644
--- a/grpc-gateway/client/deviceSubscriber.go
+++ b/grpc-gateway/client/deviceSubscriber.go
@@ -266,6 +266,14 @@ func (s *DeviceSubscriber) triggerReconnect() {
}
}
+func (s *DeviceSubscriber) TriggerGetPendingCommands() {
+ select {
+ case <-s.done:
+ case s.reconnectChan <- true:
+ default:
+ }
+}
+
func (s *DeviceSubscriber) reconnect() {
for {
var wantToSetPendingCommandsHandler bool
diff --git a/grpc-gateway/client/deviceSubscriptions_test.go b/grpc-gateway/client/deviceSubscriptions_test.go
index 069fca867..ee672927b 100644
--- a/grpc-gateway/client/deviceSubscriptions_test.go
+++ b/grpc-gateway/client/deviceSubscriptions_test.go
@@ -9,6 +9,7 @@ import (
"github.com/plgd-dev/device/v2/schema/platform"
"github.com/plgd-dev/go-coap/v3/message"
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
"github.com/plgd-dev/hub/v2/pkg/fsnotify"
"github.com/plgd-dev/hub/v2/pkg/log"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
@@ -82,7 +83,7 @@ func TestObserveDeviceResourcesRetrieve(t *testing.T) {
}()
rac := raservice.NewResourceAggregateClient(raConn.GRPC())
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
errC := c.Close()
require.NoError(t, errC)
@@ -177,7 +178,7 @@ func TestObserveDeviceResourcesUpdate(t *testing.T) {
}()
rac := raservice.NewResourceAggregateClient(raConn.GRPC())
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
errC := c.Close()
require.NoError(t, errC)
@@ -306,7 +307,7 @@ func TestObserveDeviceResourcesCreateAndDelete(t *testing.T) {
}()
rac := raservice.NewResourceAggregateClient(raConn.GRPC())
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
errC := c.Close()
require.NoError(t, errC)
diff --git a/grpc-gateway/client/getDevice_test.go b/grpc-gateway/client/getDevice_test.go
index 525d5f517..28399270f 100644
--- a/grpc-gateway/client/getDevice_test.go
+++ b/grpc-gateway/client/getDevice_test.go
@@ -10,6 +10,7 @@ import (
"github.com/plgd-dev/device/v2/test/resource/types"
"github.com/plgd-dev/hub/v2/grpc-gateway/client"
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
test "github.com/plgd-dev/hub/v2/test"
@@ -92,7 +93,7 @@ func TestClient_GetDevice(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/getDevices_test.go b/grpc-gateway/client/getDevices_test.go
index e92774ab1..546bc7eb5 100644
--- a/grpc-gateway/client/getDevices_test.go
+++ b/grpc-gateway/client/getDevices_test.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/plgd-dev/hub/v2/grpc-gateway/client"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
test "github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -69,7 +70,7 @@ func TestClient_GetDevices(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/getResource_test.go b/grpc-gateway/client/getResource_test.go
index 6131789f8..2467f73ab 100644
--- a/grpc-gateway/client/getResource_test.go
+++ b/grpc-gateway/client/getResource_test.go
@@ -8,6 +8,7 @@ import (
"github.com/plgd-dev/device/v2/schema/configuration"
"github.com/plgd-dev/device/v2/schema/interfaces"
"github.com/plgd-dev/hub/v2/grpc-gateway/client"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -100,7 +101,7 @@ func TestClientGetResource(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/maintenance.go b/grpc-gateway/client/maintenance.go
index 088ee18ec..1201aa0cc 100644
--- a/grpc-gateway/client/maintenance.go
+++ b/grpc-gateway/client/maintenance.go
@@ -3,10 +3,10 @@ package client
import (
"context"
"net/http"
+ "slices"
"github.com/plgd-dev/device/v2/schema/maintenance"
"github.com/plgd-dev/hub/v2/pkg/net/grpc"
- "github.com/plgd-dev/hub/v2/pkg/strings"
"github.com/plgd-dev/hub/v2/resource-aggregate/events"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@@ -65,7 +65,7 @@ func (c *Client) updateMaintenanceResource(
}
var href string
for _, r := range v.GetResources() {
- if r.GetDeviceId() == deviceID && strings.Contains(r.GetResourceTypes(), maintenance.ResourceType) {
+ if r.GetDeviceId() == deviceID && slices.Contains(r.GetResourceTypes(), maintenance.ResourceType) {
href = r.GetHref()
break
}
diff --git a/grpc-gateway/client/maintenance_test.go b/grpc-gateway/client/maintenance_test.go
index 7256a3b0e..6ec137392 100644
--- a/grpc-gateway/client/maintenance_test.go
+++ b/grpc-gateway/client/maintenance_test.go
@@ -5,6 +5,7 @@ import (
"testing"
"time"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
test "github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -50,7 +51,7 @@ func TestClientFactoryReset(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
@@ -104,7 +105,7 @@ func TestClientReboot(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/observeDeviceResources_test.go b/grpc-gateway/client/observeDeviceResources_test.go
index 9a05ff6a8..0c29b82c7 100644
--- a/grpc-gateway/client/observeDeviceResources_test.go
+++ b/grpc-gateway/client/observeDeviceResources_test.go
@@ -6,6 +6,7 @@ import (
"testing"
"time"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/resource-aggregate/events"
test "github.com/plgd-dev/hub/v2/test"
@@ -24,7 +25,7 @@ func TestObserveDeviceResourcesPublish(t *testing.T) {
defer tearDown()
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/observeDevices_test.go b/grpc-gateway/client/observeDevices_test.go
index 6f32642a2..964bcf8cc 100644
--- a/grpc-gateway/client/observeDevices_test.go
+++ b/grpc-gateway/client/observeDevices_test.go
@@ -7,6 +7,7 @@ import (
"testing"
client "github.com/plgd-dev/hub/v2/grpc-gateway/client"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -23,7 +24,7 @@ func TestObserveDevices(t *testing.T) {
defer tearDown()
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/client/observeResource_test.go b/grpc-gateway/client/observeResource_test.go
index cdeaca197..1e7e81c4b 100644
--- a/grpc-gateway/client/observeResource_test.go
+++ b/grpc-gateway/client/observeResource_test.go
@@ -6,6 +6,7 @@ import (
"testing"
"github.com/plgd-dev/device/v2/schema/configuration"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -25,7 +26,7 @@ func TestObservingResource(t *testing.T) {
defer tearDown()
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
errC := c.Close()
require.NoError(t, errC)
diff --git a/grpc-gateway/client/updateResource_test.go b/grpc-gateway/client/updateResource_test.go
index f77e1e8f9..e2a69ae1f 100644
--- a/grpc-gateway/client/updateResource_test.go
+++ b/grpc-gateway/client/updateResource_test.go
@@ -8,6 +8,7 @@ import (
"github.com/plgd-dev/device/v2/schema/configuration"
"github.com/plgd-dev/device/v2/schema/interfaces"
"github.com/plgd-dev/hub/v2/grpc-gateway/client"
+ grpcgwTest "github.com/plgd-dev/hub/v2/grpc-gateway/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
@@ -94,7 +95,7 @@ func TestClientUpdateResource(t *testing.T) {
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
errC := c.Close()
require.NoError(t, errC)
@@ -131,7 +132,7 @@ func TestUpdateConfigurationName(t *testing.T) {
defer tearDown()
ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
- c := NewTestClient(t)
+ c := grpcgwTest.NewTestClient(t)
defer func() {
err := c.Close()
require.NoError(t, err)
diff --git a/grpc-gateway/pb/README.md b/grpc-gateway/pb/README.md
index e4b6b1c72..086a6ba58 100644
--- a/grpc-gateway/pb/README.md
+++ b/grpc-gateway/pb/README.md
@@ -223,6 +223,8 @@
| resource_id | [resourceaggregate.pb.ResourceId](#resourceaggregate-pb-ResourceId) | | |
| content | [Content](#grpcgateway-pb-Content) | | |
| time_to_live | [int64](#int64) | | command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms). |
+| force | [bool](#bool) | | if true, the command will be executed even if the resource does not exist |
+| async | [bool](#bool) | | if true, the command will finish immediately after pending event is created |
@@ -285,6 +287,8 @@
| resource_id | [resourceaggregate.pb.ResourceId](#resourceaggregate-pb-ResourceId) | | |
| time_to_live | [int64](#int64) | | command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms). |
| resource_interface | [string](#string) | | |
+| force | [bool](#bool) | | if true, the command will be executed even if the resource does not exist |
+| async | [bool](#bool) | | if true, the command will finish immediately after pending event is created |
@@ -695,6 +699,8 @@ Certain filters perform a logical "or" operation among the elements of t
| resource_interface | [string](#string) | | |
| time_to_live | [int64](#int64) | | command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms). |
| content | [Content](#grpcgateway-pb-Content) | | |
+| force | [bool](#bool) | | if true, the command will be executed even if the resource does not exist |
+| async | [bool](#bool) | | if true, the command will finish immediately after pending event is created |
@@ -905,6 +911,7 @@ Certain filters perform a logical "or" operation among the elements of t
| device_id_filter | [string](#string) | repeated | |
| type_filter | [string](#string) | repeated | |
| resource_id_filter | [ResourceIdFilter](#grpcgateway-pb-ResourceIdFilter) | repeated | New resource ID filter. For HTTP requests, use it multiple times as a query parameter like "resourceIdFilter={deviceID}{href}". |
+| include_hidden_resources | [bool](#bool) | | Get all pending commands for all resources, even if the resource is not published. |
@@ -1050,6 +1057,7 @@ UI configuration
| ----- | ---- | ----- | ----------- |
| visibility | [UIVisibility](#grpcgateway-pb-UIVisibility) | | |
| device_provisioning_service | [string](#string) | | Address to device provisioning service HTTP API in format https://host:port |
+| snippet_service | [string](#string) | | Address to snippet service HTTP API in format https://host:port |
diff --git a/grpc-gateway/pb/createResource.go b/grpc-gateway/pb/createResource.go
index 68476c13c..6de21b418 100644
--- a/grpc-gateway/pb/createResource.go
+++ b/grpc-gateway/pb/createResource.go
@@ -5,6 +5,7 @@ import (
"github.com/google/uuid"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
+ "github.com/plgd-dev/hub/v2/resource-aggregate/events"
"google.golang.org/grpc/peer"
)
@@ -35,5 +36,13 @@ func (req *CreateResourceRequest) ToRACommand(ctx context.Context) (*commands.Cr
CommandMetadata: &commands.CommandMetadata{
ConnectionId: connectionID,
},
+ Force: req.GetForce(),
}, nil
}
+
+func (x *CreateResourceResponse) SetData(data *events.ResourceCreated) {
+ if x == nil {
+ return
+ }
+ x.Data = data
+}
diff --git a/grpc-gateway/pb/deleteResource.go b/grpc-gateway/pb/deleteResource.go
index db1b5e557..a632fda2d 100644
--- a/grpc-gateway/pb/deleteResource.go
+++ b/grpc-gateway/pb/deleteResource.go
@@ -5,6 +5,7 @@ import (
"github.com/google/uuid"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
+ "github.com/plgd-dev/hub/v2/resource-aggregate/events"
"google.golang.org/grpc/peer"
)
@@ -30,5 +31,13 @@ func (req *DeleteResourceRequest) ToRACommand(ctx context.Context) (*commands.De
ConnectionId: connectionID,
},
ResourceInterface: req.GetResourceInterface(),
+ Force: req.GetForce(),
}, nil
}
+
+func (x *DeleteResourceResponse) SetData(data *events.ResourceDeleted) {
+ if x == nil {
+ return
+ }
+ x.Data = data
+}
diff --git a/grpc-gateway/pb/devices.pb.go b/grpc-gateway/pb/devices.pb.go
index 49f7d3df8..8c27f6cd0 100644
--- a/grpc-gateway/pb/devices.pb.go
+++ b/grpc-gateway/pb/devices.pb.go
@@ -781,6 +781,8 @@ type UpdateResourceRequest struct {
ResourceInterface string `protobuf:"bytes,3,opt,name=resource_interface,json=resourceInterface,proto3" json:"resource_interface,omitempty"`
TimeToLive int64 `protobuf:"varint,4,opt,name=time_to_live,json=timeToLive,proto3" json:"time_to_live,omitempty"` // command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms).
Content *Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"`
+ Force bool `protobuf:"varint,5,opt,name=force,proto3" json:"force,omitempty"` // if true, the command will be executed even if the resource does not exist
+ Async bool `protobuf:"varint,6,opt,name=async,proto3" json:"async,omitempty"` // if true, the command will finish immediately after pending event is created
}
func (x *UpdateResourceRequest) Reset() {
@@ -843,6 +845,20 @@ func (x *UpdateResourceRequest) GetContent() *Content {
return nil
}
+func (x *UpdateResourceRequest) GetForce() bool {
+ if x != nil {
+ return x.Force
+ }
+ return false
+}
+
+func (x *UpdateResourceRequest) GetAsync() bool {
+ if x != nil {
+ return x.Async
+ }
+ return false
+}
+
type UpdateResourceResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1533,6 +1549,8 @@ type DeleteResourceRequest struct {
ResourceId *commands.ResourceId `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"`
TimeToLive int64 `protobuf:"varint,2,opt,name=time_to_live,json=timeToLive,proto3" json:"time_to_live,omitempty"` // command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms).
ResourceInterface string `protobuf:"bytes,3,opt,name=resource_interface,json=resourceInterface,proto3" json:"resource_interface,omitempty"`
+ Force bool `protobuf:"varint,4,opt,name=force,proto3" json:"force,omitempty"` // if true, the command will be executed even if the resource does not exist
+ Async bool `protobuf:"varint,5,opt,name=async,proto3" json:"async,omitempty"` // if true, the command will finish immediately after pending event is created
}
func (x *DeleteResourceRequest) Reset() {
@@ -1588,6 +1606,20 @@ func (x *DeleteResourceRequest) GetResourceInterface() string {
return ""
}
+func (x *DeleteResourceRequest) GetForce() bool {
+ if x != nil {
+ return x.Force
+ }
+ return false
+}
+
+func (x *DeleteResourceRequest) GetAsync() bool {
+ if x != nil {
+ return x.Async
+ }
+ return false
+}
+
type DeleteResourceResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -1643,6 +1675,8 @@ type CreateResourceRequest struct {
ResourceId *commands.ResourceId `protobuf:"bytes,1,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"`
Content *Content `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"`
TimeToLive int64 `protobuf:"varint,3,opt,name=time_to_live,json=timeToLive,proto3" json:"time_to_live,omitempty"` // command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms).
+ Force bool `protobuf:"varint,4,opt,name=force,proto3" json:"force,omitempty"` // if true, the command will be executed even if the resource does not exist
+ Async bool `protobuf:"varint,5,opt,name=async,proto3" json:"async,omitempty"` // if true, the command will finish immediately after pending event is created
}
func (x *CreateResourceRequest) Reset() {
@@ -1698,6 +1732,20 @@ func (x *CreateResourceRequest) GetTimeToLive() int64 {
return 0
}
+func (x *CreateResourceRequest) GetForce() bool {
+ if x != nil {
+ return x.Force
+ }
+ return false
+}
+
+func (x *CreateResourceRequest) GetAsync() bool {
+ if x != nil {
+ return x.Async
+ }
+ return false
+}
+
type CreateResourceResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -2309,7 +2357,7 @@ var file_grpc_gateway_pb_devices_proto_rawDesc = []byte{
0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67,
0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
- 0x22, 0xde, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x22, 0x8a, 0x02, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
@@ -2323,341 +2371,349 @@ var file_grpc_gateway_pb_devices_proto_rawDesc = []byte{
0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62,
0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
- 0x74, 0x22, 0x53, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64,
- 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62,
- 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
- 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xa6, 0x08, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63,
- 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x67, 0x0a, 0x13,
- 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
- 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63,
- 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63,
- 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65,
- 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48,
- 0x00, 0x52, 0x12, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
- 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x67, 0x0a, 0x13, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f,
- 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
- 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45,
- 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73,
- 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63,
- 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25,
+ 0x74, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63,
+ 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x22, 0x53, 0x0a,
+ 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61,
+ 0x74, 0x61, 0x22, 0xa6, 0x08, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
+ 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x67, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61,
+ 0x74, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65,
+ 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
+ 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53,
+ 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x63,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x12, 0x67, 0x0a, 0x13, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34,
+ 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e,
+ 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74,
+ 0x73, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75,
+ 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f,
+ 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x65, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49,
+ 0x64, 0x1a, 0xce, 0x05, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5d, 0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e,
+ 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x3a,
+ 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e,
+ 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45, 0x76, 0x65, 0x6e, 0x74,
+ 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70,
+ 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x65, 0x76, 0x65, 0x6e,
+ 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63,
+ 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65,
+ 0x72, 0x12, 0x39, 0x0a, 0x17, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03,
+ 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x14, 0x68, 0x74, 0x74, 0x70, 0x52, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b,
+ 0x68, 0x72, 0x65, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28,
+ 0x09, 0x52, 0x0a, 0x68, 0x72, 0x65, 0x66, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x4e, 0x0a,
+ 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c,
+ 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63,
+ 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x10, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x82, 0x03,
+ 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x47, 0x49, 0x53,
+ 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x52, 0x45, 0x47,
+ 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x56,
+ 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50, 0x44,
+ 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45,
+ 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45,
+ 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45,
+ 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44,
+ 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55,
+ 0x4e, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17,
+ 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f,
+ 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53,
+ 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x09, 0x12,
+ 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, 0x54, 0x52,
+ 0x49, 0x45, 0x56, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0a, 0x12, 0x16,
+ 0x0a, 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, 0x54, 0x52, 0x49,
+ 0x45, 0x56, 0x45, 0x44, 0x10, 0x0b, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52,
+ 0x43, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e,
+ 0x47, 0x10, 0x0c, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f,
+ 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53,
+ 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e,
+ 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52,
+ 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x0f, 0x12, 0x14, 0x0a, 0x10,
+ 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x44,
+ 0x10, 0x10, 0x1a, 0x3d, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73,
+ 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49,
+ 0x64, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x85, 0x15, 0x0a, 0x05,
+ 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e,
+ 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x25,
0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64,
- 0x18, 0x65, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x1a, 0xce, 0x05, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
- 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5d, 0x0a, 0x0c,
- 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03,
- 0x28, 0x0e, 0x32, 0x3a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
- 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x45,
- 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x75, 0x62, 0x73,
- 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x0b,
- 0x65, 0x76, 0x65, 0x6e, 0x74, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, 0x64,
- 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18,
- 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x46,
- 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x17, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
- 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x14, 0x68, 0x74, 0x74, 0x70,
- 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72,
- 0x12, 0x1f, 0x0a, 0x0b, 0x68, 0x72, 0x65, 0x66, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18,
- 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x68, 0x72, 0x65, 0x66, 0x46, 0x69, 0x6c, 0x74, 0x65,
- 0x72, 0x12, 0x4e, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64,
- 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e,
- 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x52,
- 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52,
- 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65,
- 0x72, 0x22, 0x82, 0x03, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x0a, 0x52,
- 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x55,
- 0x4e, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01, 0x12, 0x1b, 0x0a,
- 0x17, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41,
- 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x22, 0x0a, 0x1e, 0x44, 0x45,
- 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50,
- 0x44, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x16,
- 0x0a, 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49,
- 0x53, 0x48, 0x45, 0x44, 0x10, 0x06, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52,
- 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x07,
- 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44,
- 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x12, 0x14, 0x0a,
- 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45,
- 0x44, 0x10, 0x09, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f,
- 0x52, 0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47,
- 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52,
- 0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x45, 0x44, 0x10, 0x0b, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45,
- 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x50, 0x45,
- 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0c, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55,
- 0x52, 0x43, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12, 0x1b, 0x0a,
- 0x17, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45,
- 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0e, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45,
- 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x0f,
- 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x48, 0x41,
- 0x4e, 0x47, 0x45, 0x44, 0x10, 0x10, 0x1a, 0x3d, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c,
- 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f,
- 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
- 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22,
- 0x85, 0x15, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62,
- 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
- 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72,
- 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x55, 0x0a, 0x11, 0x64, 0x65, 0x76,
- 0x69, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x03,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77,
- 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69,
- 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x10,
- 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64,
- 0x12, 0x5b, 0x0a, 0x13, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x72, 0x65, 0x67,
- 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e,
- 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45,
- 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67,
- 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63,
- 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x5d, 0x0a,
- 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73,
- 0x68, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62,
- 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x50, 0x75,
- 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x63, 0x0a, 0x14,
- 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69,
- 0x73, 0x68, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x72, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70,
- 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x55,
- 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65,
- 0x64, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x68,
- 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e,
- 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67,
- 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68,
- 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x5b, 0x0a, 0x13, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
- 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12,
- 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
- 0x65, 0x64, 0x12, 0x61, 0x0a, 0x15, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
- 0x6f, 0x6e, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28,
- 0x0b, 0x32, 0x2a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e,
- 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
- 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52,
- 0x14, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e,
- 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
- 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64,
- 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55,
- 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10,
- 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
- 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52,
- 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
- 0x12, 0x6b, 0x0a, 0x19, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74,
- 0x72, 0x69, 0x65, 0x76, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0e, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67,
- 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69,
- 0x6e, 0x67, 0x48, 0x00, 0x52, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65,
- 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x58, 0x0a,
- 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65,
- 0x76, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62,
- 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76,
- 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65,
- 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69,
- 0x6e, 0x67, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e,
- 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65,
- 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52,
- 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74,
- 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e,
- 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x48,
- 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74,
- 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63,
- 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x12, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67,
- 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
- 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61,
- 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67,
- 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x78, 0x0a,
- 0x1e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18,
- 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76,
- 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74,
- 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x1b, 0x64, 0x65, 0x76, 0x69,
- 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
- 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x65, 0x0a, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63,
- 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74,
- 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e,
- 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70,
- 0x64, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x15, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d,
- 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xba,
- 0x02, 0x0a, 0x10, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
- 0x72, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64,
- 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49,
- 0x64, 0x73, 0x12, 0x46, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61,
- 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65,
- 0x6e, 0x74, 0x69, 0x74, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76,
- 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65,
- 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x76, 0x0a, 0x16, 0x6f, 0x70,
- 0x65, 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72,
- 0x72, 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70,
- 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e,
- 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
- 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,
- 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70,
- 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69,
- 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65,
- 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
- 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
- 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xbe, 0x02, 0x0a, 0x12,
- 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
- 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73,
- 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64,
- 0x73, 0x12, 0x46, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64,
- 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65, 0x6e,
- 0x74, 0x69, 0x74, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65,
- 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e,
- 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x78, 0x0a, 0x16, 0x6f, 0x70, 0x65,
- 0x6e, 0x5f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72,
- 0x69, 0x65, 0x72, 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x55, 0x0a, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f,
+ 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70,
+ 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65,
+ 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x10, 0x64, 0x65, 0x76, 0x69,
+ 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x5b, 0x0a, 0x13,
+ 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
+ 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x72, 0x70, 0x63,
0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
- 0x72, 0x65, 0x64, 0x2e, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72,
- 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f,
- 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72,
- 0x69, 0x65, 0x72, 0x1a, 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d,
- 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79,
- 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
- 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x90, 0x02, 0x0a,
- 0x12, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73,
- 0x73, 0x65, 0x64, 0x12, 0x57, 0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61,
- 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63,
- 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
- 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73,
- 0x73, 0x65, 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
- 0x0b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0xa0, 0x01, 0x0a,
- 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4d, 0x0a, 0x04,
- 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70,
- 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e,
- 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65,
- 0x73, 0x73, 0x65, 0x64, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
- 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d,
- 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65,
- 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x28, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a,
- 0x02, 0x4f, 0x4b, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01,
- 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x1a,
- 0x2e, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43,
- 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f,
- 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42,
- 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x43, 0x0a, 0x0f, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
- 0x69, 0x7a, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61,
- 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61,
- 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x93, 0x06, 0x0a,
- 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73,
- 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x12, 0x0a,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
- 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
- 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61,
- 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c,
- 0x0a, 0x11, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x5f, 0x6e,
- 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63,
- 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
- 0x69, 0x7a, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x6d, 0x61, 0x6e, 0x75,
- 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c,
- 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01,
- 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12,
- 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20,
- 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12,
- 0x36, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65,
- 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x15, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x70, 0x65,
- 0x6e, 0x64, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
- 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x72, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72,
+ 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x5d, 0x0a, 0x12, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18,
+ 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61,
- 0x74, 0x61, 0x12, 0x51, 0x0a, 0x10, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f,
- 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x67,
- 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65,
- 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74,
- 0x61, 0x74, 0x75, 0x73, 0x52, 0x0f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53,
- 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
- 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69,
- 0x6e, 0x74, 0x73, 0x1a, 0xd3, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x12, 0x40, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01,
- 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61,
- 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e,
- 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x14, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x68,
- 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x29, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65,
- 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e, 0x63,
- 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x74, 0x77, 0x69,
- 0x6e, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x74, 0x77, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62,
- 0x6c, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x47, 0x0a, 0x0f, 0x4f, 0x77, 0x6e,
- 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07,
- 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4f,
- 0x57, 0x4e, 0x45, 0x44, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x44, 0x10,
- 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44,
- 0x10, 0x03, 0x22, 0x40, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a,
- 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65,
- 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04,
- 0x64, 0x61, 0x74, 0x61, 0x22, 0xab, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52,
- 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41,
- 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
- 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67,
- 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
- 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76,
- 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c,
- 0x69, 0x76, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
- 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61,
- 0x63, 0x65, 0x22, 0x53, 0x0a, 0x16, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04,
- 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70,
- 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
- 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xaf, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61,
- 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
- 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73,
+ 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50,
+ 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x63, 0x0a, 0x14, 0x72, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64,
+ 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65,
- 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
- 0x63, 0x65, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65,
- 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07,
- 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f,
- 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74,
- 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x22, 0x53, 0x0a, 0x16, 0x43, 0x72, 0x65,
- 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
- 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x73, 0x55, 0x6e, 0x70, 0x75, 0x62,
+ 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x55, 0x6e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x52, 0x0a,
+ 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
+ 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x48, 0x00,
+ 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
+ 0x64, 0x12, 0x5b, 0x0a, 0x13, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70,
+ 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28,
+ 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e,
+ 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50,
+ 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x48, 0x00, 0x52, 0x12, 0x6f, 0x70, 0x65, 0x72,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x12, 0x61,
+ 0x0a, 0x15, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63,
+ 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e,
+ 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45,
+ 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+ 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x48, 0x00, 0x52, 0x14, 0x73, 0x75, 0x62,
+ 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65,
+ 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70,
+ 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0c, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67,
+ 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48,
+ 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67,
+ 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x6b, 0x0a, 0x19,
+ 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76,
+ 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x2d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
+ 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52,
+ 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00,
+ 0x52, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65,
+ 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x58, 0x0a, 0x12, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x18,
+ 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x64, 0x48, 0x00,
+ 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65,
+ 0x76, 0x65, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
+ 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x10,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61,
+ 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e,
+ 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c,
+ 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x11,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61,
+ 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x65,
+ 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
+ 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15,
+ 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65,
+ 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x52, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
+ 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x78, 0x0a, 0x1e, 0x64, 0x65, 0x76,
+ 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64,
+ 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72,
+ 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e,
+ 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x1b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64,
+ 0x69, 0x6e, 0x67, 0x12, 0x65, 0x0a, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x15,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61,
+ 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69,
+ 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
+ 0x64, 0x48, 0x00, 0x52, 0x15, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64,
+ 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x1a, 0xba, 0x02, 0x0a, 0x10, 0x44,
+ 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12,
+ 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20,
+ 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x46,
+ 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
+ 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d,
+ 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x76, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74,
+ 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72,
+ 0x18, 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74,
+ 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65,
+ 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2e, 0x4f,
+ 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72,
+ 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54, 0x65,
+ 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a, 0x47,
+ 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43,
+ 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
+ 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
+ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0xbe, 0x02, 0x0a, 0x12, 0x44, 0x65, 0x76, 0x69,
+ 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x12, 0x1d,
+ 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03,
+ 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, 0x46, 0x0a,
+ 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
+ 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x78, 0x0a, 0x16, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x65,
+ 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x18,
+ 0x64, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65,
+ 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x44, 0x65, 0x76,
+ 0x69, 0x63, 0x65, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2e,
+ 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72,
+ 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x6f, 0x70, 0x65, 0x6e, 0x54,
+ 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x1a,
+ 0x47, 0x0a, 0x19, 0x4f, 0x70, 0x65, 0x6e, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79,
+ 0x43, 0x61, 0x72, 0x72, 0x69, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
+ 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
+ 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
+ 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x90, 0x02, 0x0a, 0x12, 0x4f, 0x70, 0x65,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x12,
+ 0x57, 0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65,
+ 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, 0x70, 0x65,
+ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x2e,
+ 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0b, 0x65, 0x72, 0x72,
+ 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0xa0, 0x01, 0x0a, 0x0b, 0x45, 0x72, 0x72,
+ 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x4d, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x39, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74,
+ 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, 0x70,
+ 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64,
+ 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x43, 0x6f, 0x64,
+ 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
+ 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
+ 0x65, 0x22, 0x28, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10,
+ 0x00, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09,
+ 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x02, 0x1a, 0x2e, 0x0a, 0x14, 0x53,
+ 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65,
+ 0x6c, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x74,
+ 0x79, 0x70, 0x65, 0x22, 0x43, 0x0a, 0x0f, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64,
+ 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61,
+ 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61,
+ 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x93, 0x06, 0x0a, 0x06, 0x44, 0x65, 0x76,
+ 0x69, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
+ 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a,
+ 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62,
+ 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c, 0x0a, 0x11, 0x6d, 0x61,
+ 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+ 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65,
+ 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64,
+ 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74,
+ 0x75, 0x72, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x65,
+ 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
+ 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x69,
+ 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64,
+ 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e,
+ 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72,
0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x42, 0x2f,
- 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67,
- 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x72, 0x70,
- 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62, 0x3b, 0x70, 0x62, 0x62,
- 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x51,
+ 0x0a, 0x10, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74,
+ 0x75, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67,
+ 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
+ 0x2e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
+ 0x52, 0x0f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x0b,
+ 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x1a,
+ 0xd3, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x0a,
+ 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65,
+ 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
+ 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5c,
+ 0x0a, 0x14, 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69,
+ 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x72,
+ 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65,
+ 0x2e, 0x70, 0x62, 0x2e, 0x54, 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e,
+ 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x74, 0x77, 0x69, 0x6e, 0x53, 0x79, 0x6e,
+ 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c,
+ 0x74, 0x77, 0x69, 0x6e, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01,
+ 0x28, 0x08, 0x52, 0x0b, 0x74, 0x77, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4a,
+ 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x47, 0x0a, 0x0f, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68,
+ 0x69, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e,
+ 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4f, 0x57, 0x4e, 0x45, 0x44,
+ 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0f, 0x0a,
+ 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x03, 0x22, 0x40,
+ 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e,
+ 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04,
+ 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
+ 0x22, 0xd7, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x20, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
+ 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
+ 0x64, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x20, 0x0a,
+ 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x02, 0x20,
+ 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12,
+ 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x14,
+ 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66,
+ 0x6f, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x05, 0x20,
+ 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x22, 0x53, 0x0a, 0x16, 0x44, 0x65,
+ 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67,
+ 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22,
+ 0xdb, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+ 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x0b, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20,
+ 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61,
+ 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64,
+ 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x07,
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
+ 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x43,
+ 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12,
+ 0x20, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18,
+ 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76,
+ 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x22, 0x53, 0x0a,
+ 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x52, 0x04, 0x64, 0x61,
+ 0x74, 0x61, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32,
+ 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62,
+ 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/grpc-gateway/pb/devices.proto b/grpc-gateway/pb/devices.proto
index 54acada11..19fbe585e 100644
--- a/grpc-gateway/pb/devices.proto
+++ b/grpc-gateway/pb/devices.proto
@@ -67,6 +67,8 @@ message UpdateResourceRequest {
string resource_interface = 3;
int64 time_to_live = 4; // command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms).
Content content = 2;
+ bool force = 5; // if true, the command will be executed even if the resource does not exist
+ bool async = 6; // if true, the command will finish immediately after pending event is created
}
message UpdateResourceResponse {
@@ -220,6 +222,8 @@ message DeleteResourceRequest {
resourceaggregate.pb.ResourceId resource_id = 1;
int64 time_to_live = 2; // command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms).
string resource_interface = 3;
+ bool force = 4; // if true, the command will be executed even if the resource does not exist
+ bool async = 5; // if true, the command will finish immediately after pending event is created
}
message DeleteResourceResponse {
@@ -230,6 +234,8 @@ message CreateResourceRequest {
resourceaggregate.pb.ResourceId resource_id = 1;
Content content = 2;
int64 time_to_live = 3; // command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms).
+ bool force = 4; // if true, the command will be executed even if the resource does not exist
+ bool async = 5; // if true, the command will finish immediately after pending event is created
}
message CreateResourceResponse {
diff --git a/grpc-gateway/pb/doc.html b/grpc-gateway/pb/doc.html
index 5c2af8ccb..05126e27f 100644
--- a/grpc-gateway/pb/doc.html
+++ b/grpc-gateway/pb/doc.html
@@ -841,6 +841,20 @@
CreateResourceRequest
command validity in nanoseconds. 0 means forever and minimal value is 100000000 (100ms). |
+
+ force |
+ bool |
+ |
+ if true, the command will be executed even if the resource does not exist |
+
+
+
+ async |
+ bool |
+ |
+ if true, the command will finish immediately after pending event is created |
+
+
@@ -951,6 +965,20 @@ DeleteResourceRequest
|
+
+ force |
+ bool |
+ |
+ if true, the command will be executed even if the resource does not exist |
+
+
+
+ async |
+ bool |
+ |
+ if true, the command will finish immediately after pending event is created |
+
+
@@ -1951,6 +1979,20 @@ UpdateResourceRequest
|
+
+ force |
+ bool |
+ |
+ if true, the command will be executed even if the resource does not exist |
+
+
+
+ async |
+ bool |
+ |
+ if true, the command will finish immediately after pending event is created |
+
+
@@ -2483,6 +2525,13 @@ GetPendingCommandsRequest
New resource ID filter. For HTTP requests, use it multiple times as a query parameter like "resourceIdFilter={deviceID}{href}". |
+
+ include_hidden_resources |
+ bool |
+ |
+ Get all pending commands for all resources, even if the resource is not published. |
+
+
@@ -2889,6 +2938,13 @@ UIConfiguration
Address to device provisioning service HTTP API in format https://host:port |
+
+ snippet_service |
+ string |
+ |
+ Address to snippet service HTTP API in format https://host:port |
+
+
diff --git a/grpc-gateway/pb/getPendingCommands.pb.go b/grpc-gateway/pb/getPendingCommands.pb.go
index 65363c8a9..ba2113eac 100644
--- a/grpc-gateway/pb/getPendingCommands.pb.go
+++ b/grpc-gateway/pb/getPendingCommands.pb.go
@@ -83,10 +83,11 @@ type GetPendingCommandsRequest struct {
CommandFilter []GetPendingCommandsRequest_Command `protobuf:"varint,1,rep,packed,name=command_filter,json=commandFilter,proto3,enum=grpcgateway.pb.GetPendingCommandsRequest_Command" json:"command_filter,omitempty"`
// Deprecated: Marked as deprecated in grpc-gateway/pb/getPendingCommands.proto.
- HttpResourceIdFilter []string `protobuf:"bytes,2,rep,name=http_resource_id_filter,json=httpResourceIdFilter,proto3" json:"http_resource_id_filter,omitempty"`
- DeviceIdFilter []string `protobuf:"bytes,3,rep,name=device_id_filter,json=deviceIdFilter,proto3" json:"device_id_filter,omitempty"`
- TypeFilter []string `protobuf:"bytes,4,rep,name=type_filter,json=typeFilter,proto3" json:"type_filter,omitempty"`
- ResourceIdFilter []*ResourceIdFilter `protobuf:"bytes,5,rep,name=resource_id_filter,json=resourceIdFilter,proto3" json:"resource_id_filter,omitempty"` // New resource ID filter. For HTTP requests, use it multiple times as a query parameter like "resourceIdFilter={deviceID}{href}".
+ HttpResourceIdFilter []string `protobuf:"bytes,2,rep,name=http_resource_id_filter,json=httpResourceIdFilter,proto3" json:"http_resource_id_filter,omitempty"`
+ DeviceIdFilter []string `protobuf:"bytes,3,rep,name=device_id_filter,json=deviceIdFilter,proto3" json:"device_id_filter,omitempty"`
+ TypeFilter []string `protobuf:"bytes,4,rep,name=type_filter,json=typeFilter,proto3" json:"type_filter,omitempty"`
+ ResourceIdFilter []*ResourceIdFilter `protobuf:"bytes,5,rep,name=resource_id_filter,json=resourceIdFilter,proto3" json:"resource_id_filter,omitempty"` // New resource ID filter. For HTTP requests, use it multiple times as a query parameter like "resourceIdFilter={deviceID}{href}".
+ IncludeHiddenResources bool `protobuf:"varint,6,opt,name=include_hidden_resources,json=includeHiddenResources,proto3" json:"include_hidden_resources,omitempty"` // Get all pending commands for all resources, even if the resource is not published.
}
func (x *GetPendingCommandsRequest) Reset() {
@@ -157,6 +158,13 @@ func (x *GetPendingCommandsRequest) GetResourceIdFilter() []*ResourceIdFilter {
return nil
}
+func (x *GetPendingCommandsRequest) GetIncludeHiddenResources() bool {
+ if x != nil {
+ return x.IncludeHiddenResources
+ }
+ return false
+}
+
type PendingCommand struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -290,7 +298,7 @@ var file_grpc_gateway_pb_getPendingCommands_proto_rawDesc = []byte{
0x75, 0x72, 0x63, 0x65, 0x2d, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x70,
0x62, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d,
0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62, 0x2f,
- 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc8, 0x03,
+ 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x04,
0x0a, 0x19, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x58, 0x0a, 0x0e, 0x63,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20,
@@ -311,54 +319,58 @@ var file_grpc_gateway_pb_getPendingCommands_proto_rawDesc = []byte{
0x72, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61,
0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x10, 0x72, 0x65, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x7b, 0x0a, 0x07, 0x43,
- 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52,
- 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x52,
- 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x45,
- 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55,
- 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x53, 0x4f, 0x55,
- 0x52, 0x43, 0x45, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x12, 0x1a, 0x0a, 0x16,
- 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f,
- 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x04, 0x22, 0xb7, 0x04, 0x0a, 0x0e, 0x50, 0x65, 0x6e,
- 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72,
- 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70,
- 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72,
- 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65,
- 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61,
- 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69,
- 0x6e, 0x67, 0x12, 0x6b, 0x0a, 0x19, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72,
- 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18,
- 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e,
- 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12,
- 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61,
- 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
- 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65,
- 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52,
- 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50,
- 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
- 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e,
- 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
- 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52,
- 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e,
- 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x78, 0x0a,
- 0x1e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
- 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18,
- 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76,
- 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74,
- 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x1b, 0x64, 0x65, 0x76, 0x69,
- 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
- 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
- 0x6e, 0x64, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
- 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32,
- 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62,
- 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x72, 0x63, 0x65, 0x49, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x18, 0x69,
+ 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x68, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x5f, 0x72, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x69,
+ 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x48, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x6f,
+ 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x7b, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
+ 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x52, 0x45,
+ 0x41, 0x54, 0x45, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43,
+ 0x45, 0x5f, 0x52, 0x45, 0x54, 0x52, 0x49, 0x45, 0x56, 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f,
+ 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10,
+ 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x44, 0x45,
+ 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x12, 0x1a, 0x0a, 0x16, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45,
+ 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45,
+ 0x10, 0x04, 0x22, 0xb7, 0x04, 0x0a, 0x0e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f,
+ 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
+ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65,
+ 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64,
+ 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x6b, 0x0a, 0x19,
+ 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76,
+ 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x2d, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
+ 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52,
+ 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00,
+ 0x52, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65,
+ 0x76, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e,
+ 0x64, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73,
+ 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70,
+ 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
+ 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75,
+ 0x72, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67,
+ 0x12, 0x65, 0x0a, 0x17, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x65, 0x6c,
+ 0x65, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x2b, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72,
+ 0x65, 0x67, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+ 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x00,
+ 0x52, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
+ 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x78, 0x0a, 0x1e, 0x64, 0x65, 0x76, 0x69, 0x63,
+ 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74,
+ 0x65, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
+ 0x31, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67,
+ 0x61, 0x74, 0x65, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74,
+ 0x61, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69,
+ 0x6e, 0x67, 0x48, 0x00, 0x52, 0x1b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61,
+ 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e,
+ 0x67, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x2f, 0x5a, 0x2d,
+ 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d,
+ 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d,
+ 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/grpc-gateway/pb/getPendingCommands.proto b/grpc-gateway/pb/getPendingCommands.proto
index a2fb881ee..f0f57c9b9 100644
--- a/grpc-gateway/pb/getPendingCommands.proto
+++ b/grpc-gateway/pb/getPendingCommands.proto
@@ -20,6 +20,7 @@ message GetPendingCommandsRequest {
repeated string device_id_filter = 3;
repeated string type_filter = 4;
repeated ResourceIdFilter resource_id_filter = 5; // New resource ID filter. For HTTP requests, use it multiple times as a query parameter like "resourceIdFilter={deviceID}{href}".
+ bool include_hidden_resources = 6; // Get all pending commands for all resources, even if the resource is not published.
}
message PendingCommand {
diff --git a/grpc-gateway/pb/hubConfiguration.pb.go b/grpc-gateway/pb/hubConfiguration.pb.go
index 67304d6e9..229b6be6f 100644
--- a/grpc-gateway/pb/hubConfiguration.pb.go
+++ b/grpc-gateway/pb/hubConfiguration.pb.go
@@ -66,7 +66,7 @@ type OAuthClient struct {
ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"clientID"` // @gotags: yaml:"clientID"
Audience string `protobuf:"bytes,2,opt,name=audience,proto3" json:"audience,omitempty"`
Scopes []string `protobuf:"bytes,3,rep,name=scopes,proto3" json:"scopes,omitempty"`
- ProviderName string `protobuf:"bytes,4,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty" yaml:"providerName"` // @gotags: yaml:"providerName"
+ ProviderName string `protobuf:"bytes,4,opt,name=provider_name,json=providerName,proto3" json:"provider_name,omitempty" yaml:"providerName"` // @gotags: yaml:"providerName"
ClientAssertionType string `protobuf:"bytes,5,opt,name=client_assertion_type,json=clientAssertionType,proto3" json:"client_assertion_type,omitempty" yaml:"clientAssertionType"` // @gotags: yaml:"clientAssertionType"
Authority string `protobuf:"bytes,6,opt,name=authority,proto3" json:"authority,omitempty"`
GrantType string `protobuf:"bytes,7,opt,name=grant_type,json=grantType,proto3" json:"grant_type,omitempty" yaml:"grantType"` // @gotags: yaml:"grantType"
@@ -296,6 +296,8 @@ type UIConfiguration struct {
Visibility *UIVisibility `protobuf:"bytes,1,opt,name=visibility,proto3" json:"visibility,omitempty"`
// Address to device provisioning service HTTP API in format https://host:port
DeviceProvisioningService string `protobuf:"bytes,2,opt,name=device_provisioning_service,json=deviceProvisioningService,proto3" json:"device_provisioning_service,omitempty"`
+ // Address to snippet service HTTP API in format https://host:port
+ SnippetService string `protobuf:"bytes,3,opt,name=snippet_service,json=snippetService,proto3" json:"snippet_service,omitempty"`
}
func (x *UIConfiguration) Reset() {
@@ -344,6 +346,13 @@ func (x *UIConfiguration) GetDeviceProvisioningService() string {
return ""
}
+func (x *UIConfiguration) GetSnippetService() string {
+ if x != nil {
+ return x.SnippetService
+ }
+ return ""
+}
+
type HubConfigurationResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -731,7 +740,7 @@ var file_grpc_gateway_pb_hubConfiguration_proto_rawDesc = []byte{
0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x61, 0x70, 0x69, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x5f, 0x68, 0x75, 0x62,
0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x48, 0x75,
- 0x62, 0x22, 0x8f, 0x01, 0x0a, 0x0f, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
+ 0x62, 0x22, 0xb8, 0x01, 0x0a, 0x0f, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0a, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c,
0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x72, 0x70, 0x63,
0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x49, 0x56, 0x69, 0x73,
@@ -740,59 +749,62 @@ var file_grpc_gateway_pb_hubConfiguration_proto_rawDesc = []byte{
0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76,
- 0x69, 0x63, 0x65, 0x22, 0x8b, 0x06, 0x0a, 0x18, 0x48, 0x75, 0x62, 0x43, 0x6f, 0x6e, 0x66, 0x69,
- 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
- 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54,
- 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0f, 0x6a, 0x77, 0x74, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72,
- 0x5f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6a, 0x77,
- 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x2d, 0x0a, 0x13, 0x6a,
- 0x77, 0x74, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x63, 0x6c, 0x61,
- 0x69, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6a, 0x77, 0x74, 0x44, 0x65, 0x76,
- 0x69, 0x63, 0x65, 0x49, 0x64, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
- 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f,
- 0x61, 0x70, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
- 0x52, 0x0b, 0x63, 0x6f, 0x61, 0x70, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x37, 0x0a,
- 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74,
- 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16,
- 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f,
- 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
- 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f,
- 0x72, 0x69, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x1c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f,
- 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f,
- 0x6c, 0x69, 0x76, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x18, 0x64, 0x65, 0x66, 0x61,
- 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x6f,
- 0x4c, 0x69, 0x76, 0x65, 0x12, 0x33, 0x0a, 0x15, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
- 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20,
- 0x01, 0x28, 0x09, 0x52, 0x14, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
- 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x74, 0x74,
- 0x70, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
- 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x68, 0x74, 0x74, 0x70, 0x47, 0x61, 0x74,
- 0x65, 0x77, 0x61, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x45, 0x0a, 0x10, 0x77,
- 0x65, 0x62, 0x5f, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18,
- 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65,
- 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65,
- 0x6e, 0x74, 0x52, 0x0e, 0x77, 0x65, 0x62, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65,
- 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x13, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6f, 0x61, 0x75,
- 0x74, 0x68, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32,
- 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62,
- 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x11, 0x64, 0x65,
- 0x76, 0x69, 0x63, 0x65, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12,
- 0x45, 0x0a, 0x10, 0x6d, 0x32, 0x6d, 0x5f, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x63, 0x6c, 0x69,
- 0x65, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63,
- 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68,
- 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x0e, 0x6d, 0x32, 0x6d, 0x4f, 0x61, 0x75, 0x74, 0x68,
- 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x02, 0x75, 0x69, 0x18, 0x0e, 0x20, 0x01,
- 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
- 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x75, 0x69, 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64,
- 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x72,
- 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x69,
- 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66,
- 0x6f, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
- 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f,
- 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62, 0x3b,
- 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x69, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x6e, 0x69, 0x70, 0x70, 0x65, 0x74, 0x5f, 0x73,
+ 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x6e,
+ 0x69, 0x70, 0x70, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x8b, 0x06, 0x0a,
+ 0x18, 0x48, 0x75, 0x62, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72,
+ 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
+ 0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0f,
+ 0x6a, 0x77, 0x74, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18,
+ 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6a, 0x77, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x43,
+ 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x2d, 0x0a, 0x13, 0x6a, 0x77, 0x74, 0x5f, 0x64, 0x65, 0x76, 0x69,
+ 0x63, 0x65, 0x5f, 0x69, 0x64, 0x5f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x10, 0x6a, 0x77, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x43, 0x6c,
+ 0x61, 0x69, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x61, 0x70, 0x5f, 0x67, 0x61, 0x74, 0x65,
+ 0x77, 0x61, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x61, 0x70, 0x47,
+ 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x37, 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65,
+ 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12,
+ 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3e, 0x0a,
+ 0x1c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
+ 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x6f, 0x5f, 0x6c, 0x69, 0x76, 0x65, 0x18, 0x08, 0x20,
+ 0x01, 0x28, 0x03, 0x52, 0x18, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6d, 0x6d,
+ 0x61, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x54, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x33, 0x0a,
+ 0x15, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x75, 0x74,
+ 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x63, 0x65,
+ 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
+ 0x74, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77,
+ 0x61, 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x12, 0x68, 0x74, 0x74, 0x70, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x41, 0x64, 0x64,
+ 0x72, 0x65, 0x73, 0x73, 0x12, 0x45, 0x0a, 0x10, 0x77, 0x65, 0x62, 0x5f, 0x6f, 0x61, 0x75, 0x74,
+ 0x68, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
+ 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e,
+ 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x0e, 0x77, 0x65, 0x62,
+ 0x4f, 0x61, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x4b, 0x0a, 0x13, 0x64,
+ 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x63, 0x6c, 0x69, 0x65,
+ 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67,
+ 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43,
+ 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x61, 0x75,
+ 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x45, 0x0a, 0x10, 0x6d, 0x32, 0x6d, 0x5f,
+ 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01,
+ 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79,
+ 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52,
+ 0x0e, 0x6d, 0x32, 0x6d, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12,
+ 0x2f, 0x0a, 0x02, 0x75, 0x69, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x72,
+ 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x49, 0x43,
+ 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x02, 0x75, 0x69,
+ 0x12, 0x38, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x0d,
+ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x67, 0x61, 0x74, 0x65, 0x77,
+ 0x61, 0x79, 0x2e, 0x70, 0x62, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+ 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69,
+ 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6c, 0x67, 0x64, 0x2d, 0x64, 0x65,
+ 0x76, 0x2f, 0x68, 0x75, 0x62, 0x2f, 0x76, 0x32, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2d, 0x67, 0x61,
+ 0x74, 0x65, 0x77, 0x61, 0x79, 0x2f, 0x70, 0x62, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f,
+ 0x74, 0x6f, 0x33,
}
var (
diff --git a/grpc-gateway/pb/hubConfiguration.proto b/grpc-gateway/pb/hubConfiguration.proto
index 58503a18d..17d64e90f 100644
--- a/grpc-gateway/pb/hubConfiguration.proto
+++ b/grpc-gateway/pb/hubConfiguration.proto
@@ -58,6 +58,8 @@ message UIConfiguration {
UIVisibility visibility = 1;
// Address to device provisioning service HTTP API in format https://host:port
string device_provisioning_service = 2;
+ // Address to snippet service HTTP API in format https://host:port
+ string snippet_service = 3;
}
message HubConfigurationResponse {
diff --git a/grpc-gateway/pb/service.swagger.json b/grpc-gateway/pb/service.swagger.json
index be83686ce..78645c9a0 100644
--- a/grpc-gateway/pb/service.swagger.json
+++ b/grpc-gateway/pb/service.swagger.json
@@ -356,6 +356,20 @@
"in": "query",
"required": false,
"type": "string"
+ },
+ {
+ "name": "force",
+ "description": "if true, the command will be executed even if the resource does not exist",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
+ },
+ {
+ "name": "async",
+ "description": "if true, the command will finish immediately after pending event is created",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
}
],
"tags": [
@@ -408,6 +422,20 @@
"required": false,
"type": "string",
"format": "int64"
+ },
+ {
+ "name": "force",
+ "description": "if true, the command will be executed even if the resource does not exist",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
+ },
+ {
+ "name": "async",
+ "description": "if true, the command will finish immediately after pending event is created",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
}
],
"tags": [
@@ -530,6 +558,20 @@
"required": false,
"type": "string",
"format": "int64"
+ },
+ {
+ "name": "force",
+ "description": "if true, the command will be executed even if the resource does not exist",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
+ },
+ {
+ "name": "async",
+ "description": "if true, the command will finish immediately after pending event is created",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
}
],
"tags": [
@@ -674,6 +716,13 @@
"type": "string"
},
"collectionFormat": "multi"
+ },
+ {
+ "name": "includeHiddenResources",
+ "description": "Get all pending commands for all resources, even if the resource is not published.",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
}
],
"tags": [
@@ -2301,6 +2350,10 @@
"deviceProvisioningService": {
"type": "string",
"title": "Address to device provisioning service HTTP API in format https://host:port"
+ },
+ "snippetService": {
+ "type": "string",
+ "title": "Address to snippet service HTTP API in format https://host:port"
}
},
"title": "UI configuration"
diff --git a/grpc-gateway/pb/updateResource.go b/grpc-gateway/pb/updateResource.go
index 9790a5ad7..d4128b0f7 100644
--- a/grpc-gateway/pb/updateResource.go
+++ b/grpc-gateway/pb/updateResource.go
@@ -5,6 +5,7 @@ import (
"github.com/google/uuid"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
+ "github.com/plgd-dev/hub/v2/resource-aggregate/events"
"google.golang.org/grpc/peer"
)
@@ -36,5 +37,13 @@ func (req *UpdateResourceRequest) ToRACommand(ctx context.Context) (*commands.Up
CommandMetadata: &commands.CommandMetadata{
ConnectionId: connectionID,
},
+ Force: req.GetForce(),
}, nil
}
+
+func (x *UpdateResourceResponse) SetData(data *events.ResourceUpdated) {
+ if x == nil {
+ return
+ }
+ x.Data = data
+}
diff --git a/grpc-gateway/service/createResource.go b/grpc-gateway/service/createResource.go
index a633d301d..863b97ab6 100644
--- a/grpc-gateway/service/createResource.go
+++ b/grpc-gateway/service/createResource.go
@@ -6,25 +6,76 @@ import (
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
+ "google.golang.org/grpc"
"google.golang.org/grpc/codes"
)
-func createResourceError(err error) error {
- return kitNetGrpc.ForwardErrorf(codes.Internal, "cannot create resource: %v", err)
+func resourceError(action string, err error) error {
+ return kitNetGrpc.ForwardErrorf(codes.Internal, "cannot %s resource: %v", action, err)
}
-func (r *RequestHandler) CreateResource(ctx context.Context, req *pb.CreateResourceRequest) (*pb.CreateResourceResponse, error) {
- createCommand, err := req.ToRACommand(ctx)
+type reqRACommand interface {
+ *commands.CreateResourceRequest | *commands.DeleteResourceRequest | *commands.UpdateResourceRequest
+}
+
+type respCommand[Event any] interface {
+ SetData(v Event)
+}
+
+type reqCommand[v reqRACommand] interface {
+ ToRACommand(ctx context.Context) (v, error)
+ GetAsync() bool
+}
+
+type (
+ syncFunc[Req reqRACommand, Res commands.EventContent] func(ctx context.Context, owner string, req Req) (Res, error)
+ asyncFunc[Req reqRACommand, Res any] func(ctx context.Context, req Req, opts ...grpc.CallOption) (Res, error)
+)
+
+func handleResourceRequest[ReqRA reqRACommand, Event commands.EventContent, AsyncRes any](
+ ctx context.Context,
+ req reqCommand[ReqRA],
+ action string,
+ syncFunc syncFunc[ReqRA, Event],
+ asyncFunc asyncFunc[ReqRA, AsyncRes],
+ resp respCommand[Event],
+) error {
+ var err error
+ var event Event
+
+ raCommand, err := req.ToRACommand(ctx)
if err != nil {
- return nil, createResourceError(err)
+ return resourceError(action, err)
+ }
+
+ if req.GetAsync() {
+ _, err = asyncFunc(ctx, raCommand)
+ if err != nil {
+ return resourceError(action, err)
+ }
+ return nil
}
- createdEvent, err := r.resourceAggregateClient.SyncCreateResource(ctx, "*", createCommand)
+ event, err = syncFunc(ctx, "*", raCommand)
if err != nil {
- return nil, createResourceError(err)
+ return resourceError(action, err)
}
- if err = commands.CheckEventContent(createdEvent); err != nil {
- return nil, createResourceError(err)
+ if err = commands.CheckEventContent(event); err != nil {
+ return resourceError(action, err)
}
- return &pb.CreateResourceResponse{Data: createdEvent}, nil
+
+ resp.SetData(event)
+ return nil
+}
+
+func (r *RequestHandler) CreateResource(ctx context.Context, req *pb.CreateResourceRequest) (*pb.CreateResourceResponse, error) {
+ var resp pb.CreateResourceResponse
+ return &resp, handleResourceRequest(
+ ctx,
+ req,
+ "create",
+ r.resourceAggregateClient.SyncCreateResource,
+ r.resourceAggregateClient.CreateResource,
+ &resp,
+ )
}
diff --git a/grpc-gateway/service/deleteResource.go b/grpc-gateway/service/deleteResource.go
index 24a8beb00..3d9ef759b 100644
--- a/grpc-gateway/service/deleteResource.go
+++ b/grpc-gateway/service/deleteResource.go
@@ -4,26 +4,16 @@ import (
"context"
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
- kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
- "github.com/plgd-dev/hub/v2/resource-aggregate/commands"
- "google.golang.org/grpc/codes"
)
-func deleteResourceError(err error) error {
- return kitNetGrpc.ForwardErrorf(codes.Internal, "cannot delete resource: %v", err)
-}
-
func (r *RequestHandler) DeleteResource(ctx context.Context, req *pb.DeleteResourceRequest) (*pb.DeleteResourceResponse, error) {
- deleteCommand, err := req.ToRACommand(ctx)
- if err != nil {
- return nil, deleteResourceError(err)
- }
- deletedEvent, err := r.resourceAggregateClient.SyncDeleteResource(ctx, "*", deleteCommand)
- if err != nil {
- return nil, deleteResourceError(err)
- }
- if err = commands.CheckEventContent(deletedEvent); err != nil {
- return nil, deleteResourceError(err)
- }
- return &pb.DeleteResourceResponse{Data: deletedEvent}, err
+ var resp pb.DeleteResourceResponse
+ return &resp, handleResourceRequest(
+ ctx,
+ req,
+ "delete",
+ r.resourceAggregateClient.SyncDeleteResource,
+ r.resourceAggregateClient.DeleteResource,
+ &resp,
+ )
}
diff --git a/grpc-gateway/service/subscribeToEvents_test.go b/grpc-gateway/service/subscribeToEvents_test.go
index 913024c9b..b6593e815 100644
--- a/grpc-gateway/service/subscribeToEvents_test.go
+++ b/grpc-gateway/service/subscribeToEvents_test.go
@@ -667,9 +667,7 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) {
secureGWShutdown()
createFn := func(timeToLive time.Duration) {
- createCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{
+ _, errC := c.CreateResource(ctx, &pb.CreateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -678,8 +676,9 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) {
}),
},
TimeToLive: int64(timeToLive),
+ Async: true,
})
- require.Error(t, errC)
+ require.NoError(t, errC)
}
createFn(time.Millisecond * 500) // for test expired event
createFn(0)
@@ -697,9 +696,7 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) {
retrieveFn(0)
updateFn := func(timeToLive time.Duration) {
- updateCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{
+ _, errU := c.UpdateResource(ctx, &pb.UpdateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -708,20 +705,20 @@ func TestRequestHandlerSubscribeForPendingCommands(t *testing.T) {
}),
},
TimeToLive: int64(timeToLive),
+ Async: true,
})
- require.Error(t, errU)
+ require.NoError(t, errU)
}
updateFn(time.Millisecond * 500) // for test expired event
updateFn(0)
deleteFn := func(timeToLive time.Duration) {
- deleteCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{
+ _, errD := c.DeleteResource(ctx, &pb.DeleteResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
TimeToLive: int64(timeToLive),
+ Async: true,
})
- require.Error(t, errD)
+ require.NoError(t, errD)
}
deleteFn(time.Millisecond * 500) // for test expired event
deleteFn(0)
diff --git a/grpc-gateway/service/updateResource.go b/grpc-gateway/service/updateResource.go
index 715e97dd7..8c8164efb 100644
--- a/grpc-gateway/service/updateResource.go
+++ b/grpc-gateway/service/updateResource.go
@@ -4,27 +4,16 @@ import (
"context"
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
- kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
- "github.com/plgd-dev/hub/v2/resource-aggregate/commands"
- "google.golang.org/grpc/codes"
)
-func updateResourceError(err error) error {
- return kitNetGrpc.ForwardErrorf(codes.Internal, "cannot update resource: %v", err)
-}
-
func (r *RequestHandler) UpdateResource(ctx context.Context, req *pb.UpdateResourceRequest) (*pb.UpdateResourceResponse, error) {
- updateCommand, err := req.ToRACommand(ctx)
- if err != nil {
- return nil, updateResourceError(err)
- }
- updatedEvent, err := r.resourceAggregateClient.SyncUpdateResource(ctx, "*", updateCommand)
- if err != nil {
- return nil, updateResourceError(err)
- }
- err = commands.CheckEventContent(updatedEvent)
- if err != nil {
- return nil, updateResourceError(err)
- }
- return &pb.UpdateResourceResponse{Data: updatedEvent}, nil
+ var resp pb.UpdateResourceResponse
+ return &resp, handleResourceRequest(
+ ctx,
+ req,
+ "update",
+ r.resourceAggregateClient.SyncUpdateResource,
+ r.resourceAggregateClient.UpdateResource,
+ &resp,
+ )
}
diff --git a/grpc-gateway/service/updateResource_test.go b/grpc-gateway/service/updateResource_test.go
index 10e1f05f5..0653992b1 100644
--- a/grpc-gateway/service/updateResource_test.go
+++ b/grpc-gateway/service/updateResource_test.go
@@ -15,6 +15,8 @@ import (
"github.com/plgd-dev/go-coap/v3/message"
coapTest "github.com/plgd-dev/hub/v2/coap-gateway/test"
"github.com/plgd-dev/hub/v2/grpc-gateway/pb"
+ isPb "github.com/plgd-dev/hub/v2/identity-store/pb"
+ isTest "github.com/plgd-dev/hub/v2/identity-store/test"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
"github.com/plgd-dev/hub/v2/resource-aggregate/events"
@@ -412,3 +414,239 @@ func TestRequestHandlerRunMultipleParallelUpdateResource(t *testing.T) {
}
wg.Wait()
}
+
+func TestUpdateCreateOnNotExistingResource(t *testing.T) {
+ deviceID := test.MustFindDeviceByName(test.TestDeviceName)
+ switchID := "1"
+
+ ctx, cancel := context.WithTimeout(context.Background(), config.TEST_TIMEOUT)
+ defer cancel()
+
+ isCfg := isTest.MakeConfig(t)
+ isCfg.APIs.GRPC.TLS.ClientCertificateRequired = false
+ tearDown := service.SetUp(ctx, t, service.WithISConfig(isCfg))
+ defer tearDown()
+ ctx = kitNetGrpc.CtxWithToken(ctx, oauthTest.GetDefaultAccessToken(t))
+
+ // associate device with owner
+ isConn, err := grpc.NewClient(config.IDENTITY_STORE_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
+ RootCAs: test.GetRootCertificatePool(t),
+ })))
+ require.NoError(t, err)
+ defer func() {
+ _ = isConn.Close()
+ }()
+ isClient := isPb.NewIdentityStoreClient(isConn)
+ _, err = isClient.AddDevice(ctx, &isPb.AddDeviceRequest{
+ DeviceId: deviceID,
+ })
+ require.NoError(t, err)
+
+ // update/create resources of the registered device
+ conn, err := grpc.NewClient(config.GRPC_GW_HOST, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
+ RootCAs: test.GetRootCertificatePool(t),
+ })))
+ require.NoError(t, err)
+ defer func() {
+ _ = conn.Close()
+ }()
+ c := pb.NewGrpcGatewayClient(conn)
+
+ createResourceSub := &pb.SubscribeToEvents{
+ CorrelationId: "testToken",
+ Action: &pb.SubscribeToEvents_CreateSubscription_{
+ CreateSubscription: &pb.SubscribeToEvents_CreateSubscription{
+ EventFilter: []pb.SubscribeToEvents_CreateSubscription_Event{
+ pb.SubscribeToEvents_CreateSubscription_RESOURCE_CHANGED,
+ pb.SubscribeToEvents_CreateSubscription_RESOURCE_UPDATED,
+ pb.SubscribeToEvents_CreateSubscription_RESOURCE_CREATED,
+ pb.SubscribeToEvents_CreateSubscription_RESOURCE_DELETED,
+ pb.SubscribeToEvents_CreateSubscription_RESOURCE_UPDATE_PENDING,
+ pb.SubscribeToEvents_CreateSubscription_RESOURCE_CREATE_PENDING,
+ pb.SubscribeToEvents_CreateSubscription_RESOURCE_DELETE_PENDING,
+ },
+ },
+ },
+ }
+ subClient, err := c.SubscribeToEvents(ctx)
+ require.NoError(t, err)
+ defer func() {
+ err2 := subClient.CloseSend()
+ require.NoError(t, err2)
+ }()
+ err = subClient.Send(createResourceSub)
+ require.NoError(t, err)
+
+ ev, err := subClient.Recv()
+ require.NoError(t, err)
+ expectedEvent := &pb.Event{
+ SubscriptionId: ev.GetSubscriptionId(),
+ Type: &pb.Event_OperationProcessed_{
+ OperationProcessed: &pb.Event_OperationProcessed{
+ ErrorStatus: &pb.Event_OperationProcessed_ErrorStatus{
+ Code: pb.Event_OperationProcessed_ErrorStatus_OK,
+ },
+ },
+ },
+ CorrelationId: "testToken",
+ }
+ pbTest.CmpEvent(t, expectedEvent, ev, "")
+
+ powerTest := 654321
+ _, err = c.UpdateResource(ctx, &pb.UpdateResourceRequest{
+ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")),
+ Content: &pb.Content{
+ ContentType: message.AppOcfCbor.String(),
+ Data: test.EncodeToCbor(t, map[string]interface{}{
+ "power": powerTest,
+ }),
+ },
+ Force: true,
+ Async: true,
+ })
+ require.NoError(t, err)
+
+ _, err = c.CreateResource(ctx, &pb.CreateResourceRequest{
+ ResourceId: commands.NewResourceID(deviceID, test.TestResourceSwitchesHref),
+ Content: &pb.Content{
+ ContentType: message.AppOcfCbor.String(),
+ Data: test.EncodeToCbor(t, test.MakeSwitchResourceDefaultData()),
+ },
+ Force: true,
+ Async: true,
+ })
+ require.NoError(t, err)
+
+ _, err = c.DeleteResource(ctx, &pb.DeleteResourceRequest{
+ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")),
+ Force: true,
+ Async: true,
+ })
+ require.NoError(t, err)
+
+ pendingCommandsClient, err := c.GetPendingCommands(ctx, &pb.GetPendingCommandsRequest{
+ DeviceIdFilter: []string{deviceID},
+ IncludeHiddenResources: true,
+ })
+ require.NoError(t, err)
+ numPendingCommands := 0
+ for {
+ ev, err2 := pendingCommandsClient.Recv()
+ if errors.Is(err2, io.EOF) {
+ break
+ }
+ require.NoError(t, err2)
+ if ev.GetResourceCreatePending() != nil {
+ require.Equal(t, deviceID, ev.GetResourceCreatePending().GetResourceId().GetDeviceId())
+ require.Equal(t, test.TestResourceSwitchesHref, ev.GetResourceCreatePending().GetResourceId().GetHref())
+ numPendingCommands++
+ }
+ if ev.GetResourceUpdatePending() != nil {
+ require.Equal(t, deviceID, ev.GetResourceUpdatePending().GetResourceId().GetDeviceId())
+ switch ev.GetResourceUpdatePending().GetResourceId().GetHref() {
+ case test.TestResourceLightInstanceHref("1"):
+ numPendingCommands++
+ default:
+ require.FailNowf(t, "unexpected pending command", "%v", ev)
+ }
+ }
+ if ev.GetResourceDeletePending() != nil {
+ require.Equal(t, deviceID, ev.GetResourceDeletePending().GetResourceId().GetDeviceId())
+ require.Equal(t, test.TestResourceLightInstanceHref("1"), ev.GetResourceDeletePending().GetResourceId().GetHref())
+ numPendingCommands++
+ }
+ }
+ require.Equal(t, 3, numPendingCommands)
+
+ _, shutdownDevSim := test.OnboardDevSim(ctx, t, c, deviceID, config.ACTIVE_COAP_SCHEME+"://"+config.COAP_GW_HOST, nil)
+ defer shutdownDevSim()
+
+ var lightChanged *events.ResourceChanged
+ var switchChanged *events.ResourceChanged
+ var lightUpdated *events.ResourceUpdated
+ var switchCreated *events.ResourceCreated
+ var lightDeleted *events.ResourceDeleted
+ for {
+ ev, err2 := subClient.Recv()
+ require.NoError(t, err2)
+ if ch := ev.GetResourceChanged(); ch != nil {
+ if ch.GetResourceId().GetHref() == test.TestResourceLightInstanceHref("1") {
+ d := test.DecodeCbor(t, ch.GetContent().GetData())
+ if m, ok := d.(map[interface{}]interface{}); ok && m["power"] == uint64(powerTest) {
+ lightChanged = ch
+ }
+ }
+ if ch.GetResourceId().GetHref() == test.TestResourceSwitchesInstanceHref(switchID) {
+ switchChanged = ch
+ }
+ }
+ if updated := ev.GetResourceUpdated(); updated != nil {
+ if updated.GetResourceId().GetHref() == test.TestResourceLightInstanceHref("1") {
+ lightUpdated = updated
+ }
+ }
+ if created := ev.GetResourceCreated(); created != nil {
+ if created.GetResourceId().GetHref() == test.TestResourceSwitchesHref {
+ switchCreated = created
+ }
+ }
+ if deleted := ev.GetResourceDeleted(); deleted != nil {
+ if deleted.GetResourceId().GetHref() == test.TestResourceLightInstanceHref("1") {
+ lightDeleted = deleted
+ }
+ }
+ if lightChanged != nil && switchChanged != nil && lightUpdated != nil && switchCreated != nil && lightDeleted != nil {
+ break
+ }
+ }
+
+ _, err = c.UpdateResource(ctx, &pb.UpdateResourceRequest{
+ ResourceId: commands.NewResourceID(deviceID, "/not/existing/resource"),
+ Content: &pb.Content{
+ ContentType: message.AppOcfCbor.String(),
+ Data: test.EncodeToCbor(t, map[string]interface{}{
+ "power": powerTest,
+ }),
+ },
+ Force: true,
+ Async: true,
+ })
+ require.NoError(t, err)
+
+ pendingCommandsClient, err = c.GetPendingCommands(ctx, &pb.GetPendingCommandsRequest{
+ DeviceIdFilter: []string{deviceID},
+ IncludeHiddenResources: true,
+ })
+ require.NoError(t, err)
+ numPendingCommands = 0
+ for {
+ ev, err2 := pendingCommandsClient.Recv()
+ if errors.Is(err2, io.EOF) {
+ break
+ }
+ require.NoError(t, err2)
+ if ev.GetResourceUpdatePending() != nil {
+ require.Equal(t, deviceID, ev.GetResourceUpdatePending().GetResourceId().GetDeviceId())
+ switch ev.GetResourceUpdatePending().GetResourceId().GetHref() {
+ case "/not/existing/resource":
+ numPendingCommands++
+ default:
+ require.FailNowf(t, "unexpected pending command", "%v", ev)
+ }
+ } else {
+ require.FailNowf(t, "unexpected pending command", "%v", ev)
+ }
+ }
+ require.Equal(t, 1, numPendingCommands)
+
+ _, err = c.UpdateResource(ctx, &pb.UpdateResourceRequest{
+ ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")),
+ Content: &pb.Content{
+ ContentType: message.AppOcfCbor.String(),
+ Data: test.EncodeToCbor(t, map[string]interface{}{
+ "power": 0,
+ }),
+ },
+ })
+ require.NoError(t, err)
+}
diff --git a/grpc-gateway/test/test.go b/grpc-gateway/test/test.go
index 5cc26e62c..9ac9ebba1 100644
--- a/grpc-gateway/test/test.go
+++ b/grpc-gateway/test/test.go
@@ -2,16 +2,37 @@ package test
import (
"context"
+ "crypto/tls"
+ "crypto/x509"
"sync"
+ "testing"
"time"
+ "github.com/plgd-dev/hub/v2/grpc-gateway/client"
"github.com/plgd-dev/hub/v2/grpc-gateway/service"
"github.com/plgd-dev/hub/v2/pkg/fsnotify"
"github.com/plgd-dev/hub/v2/pkg/log"
+ "github.com/plgd-dev/hub/v2/test"
"github.com/plgd-dev/hub/v2/test/config"
"github.com/stretchr/testify/require"
)
+func NewTestClient(t *testing.T) *client.Client {
+ rootCAs := x509.NewCertPool()
+ for _, c := range test.GetRootCertificateAuthorities(t) {
+ rootCAs.AddCert(c)
+ }
+ tlsCfg := tls.Config{
+ RootCAs: rootCAs,
+ }
+ clientConfig := client.Config{
+ GatewayAddress: config.GRPC_GW_HOST,
+ }
+ c, err := client.NewFromConfig(&clientConfig, &tlsCfg)
+ require.NoError(t, err)
+ return c
+}
+
func MakeConfig(t require.TestingT) service.Config {
var cfg service.Config
diff --git a/http-gateway/config.yaml b/http-gateway/config.yaml
index e48c42a8a..53f85480d 100644
--- a/http-gateway/config.yaml
+++ b/http-gateway/config.yaml
@@ -71,6 +71,7 @@ ui:
webConfiguration:
httpGatewayAddress: ""
deviceProvisioningService: ""
+ snippetService: ""
webOAuthClient:
authority: ""
clientID: ""
diff --git a/http-gateway/service/config.go b/http-gateway/service/config.go
index 2a85bfc70..7e2f206f4 100644
--- a/http-gateway/service/config.go
+++ b/http-gateway/service/config.go
@@ -193,6 +193,7 @@ type WebConfiguration struct {
Authority string `yaml:"-" json:"authority"`
HTTPGatewayAddress string `yaml:"httpGatewayAddress" json:"httpGatewayAddress"`
DeviceProvisioningService string `yaml:"deviceProvisioningService" json:"deviceProvisioningService"`
+ SnippetService string `yaml:"snippetService" json:"snippetService"`
WebOAuthClient OAuthClient `yaml:"webOAuthClient" json:"webOauthClient"`
DeviceOAuthClient OAuthClient `yaml:"deviceOAuthClient" json:"deviceOauthClient"`
M2MOAuthClient *OAuthClient `yaml:"m2mOAuthClient" json:"m2mOauthClient"`
diff --git a/http-gateway/service/getDevicePendingCommands_test.go b/http-gateway/service/getDevicePendingCommands_test.go
index 42fe7bc5c..28c906605 100644
--- a/http-gateway/service/getDevicePendingCommands_test.go
+++ b/http-gateway/service/getDevicePendingCommands_test.go
@@ -253,9 +253,7 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) {
secureGWShutdown()
createFn := func() {
- createCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{
+ _, errC := c.CreateResource(ctx, &pb.CreateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -263,8 +261,9 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) {
"power": 1,
}),
},
+ Async: true,
})
- require.Error(t, errC)
+ require.NoError(t, errC)
}
createFn()
retrieveFn := func() {
@@ -277,9 +276,7 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) {
}
retrieveFn()
updateFn := func() {
- updateCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{
+ _, errU := c.UpdateResource(ctx, &pb.UpdateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -287,17 +284,17 @@ func TestRequestHandlerGetDevicePendingCommands(t *testing.T) {
"power": 1,
}),
},
+ Async: true,
})
- require.Error(t, errU)
+ require.NoError(t, errU)
}
updateFn()
deleteFn := func() {
- deleteCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{
+ _, errD := c.DeleteResource(ctx, &pb.DeleteResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
+ Async: true,
})
- require.Error(t, errD)
+ require.NoError(t, errD)
}
deleteFn()
updateDeviceMetadataFn := func() {
diff --git a/http-gateway/service/getDeviceResourceLinks_test.go b/http-gateway/service/getDeviceResourceLinks_test.go
index a7a71b7e1..13a8a650c 100644
--- a/http-gateway/service/getDeviceResourceLinks_test.go
+++ b/http-gateway/service/getDeviceResourceLinks_test.go
@@ -6,6 +6,7 @@ import (
"errors"
"io"
"net/http"
+ "slices"
"testing"
"time"
@@ -16,7 +17,6 @@ import (
httpgwTest "github.com/plgd-dev/hub/v2/http-gateway/test"
"github.com/plgd-dev/hub/v2/http-gateway/uri"
kitNetGrpc "github.com/plgd-dev/hub/v2/pkg/net/grpc"
- "github.com/plgd-dev/hub/v2/pkg/strings"
"github.com/plgd-dev/hub/v2/resource-aggregate/commands"
"github.com/plgd-dev/hub/v2/resource-aggregate/events"
test "github.com/plgd-dev/hub/v2/test"
@@ -100,8 +100,8 @@ func TestRequestHandlerGetDeviceResourceLinks(t *testing.T) {
{
DeviceId: deviceID,
Resources: test.ResourceLinksToResources(deviceID, test.FilterResourceLink(func(rl schema.ResourceLink) bool {
- return strings.Contains(rl.ResourceTypes, collection.ResourceType) ||
- strings.Contains(rl.ResourceTypes, types.BINARY_SWITCH)
+ return slices.Contains(rl.ResourceTypes, collection.ResourceType) ||
+ slices.Contains(rl.ResourceTypes, types.BINARY_SWITCH)
}, resourceLinks)),
AuditContext: commands.NewAuditContext(oauthService.DeviceUserID, "", oauthService.DeviceUserID),
},
diff --git a/http-gateway/service/getHubConfiguration.go b/http-gateway/service/getHubConfiguration.go
index 6467821b4..c693de243 100644
--- a/http-gateway/service/getHubConfiguration.go
+++ b/http-gateway/service/getHubConfiguration.go
@@ -75,6 +75,7 @@ func (requestHandler *RequestHandler) getHubConfiguration(w http.ResponseWriter,
resp.Ui = &pb.UIConfiguration{
Visibility: requestHandler.config.UI.WebConfiguration.Visibility.ToProto(),
DeviceProvisioningService: requestHandler.config.UI.WebConfiguration.DeviceProvisioningService,
+ SnippetService: requestHandler.config.UI.WebConfiguration.SnippetService,
}
if accept == pkgHttp.ApplicationProtoJsonContentType {
m := serverMux.NewJsonpbMarshaler()
diff --git a/http-gateway/service/getHubConfiguration_test.go b/http-gateway/service/getHubConfiguration_test.go
index 351500f83..fba747935 100644
--- a/http-gateway/service/getHubConfiguration_test.go
+++ b/http-gateway/service/getHubConfiguration_test.go
@@ -30,6 +30,7 @@ func TestRequestHandlerGetHubConfiguration(t *testing.T) {
expected.Ui = &pb.UIConfiguration{
Visibility: httpCfg.UI.WebConfiguration.Visibility.ToProto(),
DeviceProvisioningService: httpCfg.UI.WebConfiguration.DeviceProvisioningService,
+ SnippetService: httpCfg.UI.WebConfiguration.SnippetService,
}
tests := []struct {
name string
@@ -85,6 +86,7 @@ func TestRequestHandlerGetHubConfigurationWithoutM2MOAuthClient(t *testing.T) {
expected.Ui = &pb.UIConfiguration{
Visibility: httpCfg.UI.WebConfiguration.Visibility.ToProto(),
DeviceProvisioningService: httpCfg.UI.WebConfiguration.DeviceProvisioningService,
+ SnippetService: httpCfg.UI.WebConfiguration.SnippetService,
}
tests := []struct {
name string
diff --git a/http-gateway/service/getPendingCommands_test.go b/http-gateway/service/getPendingCommands_test.go
index d790d18a3..a39ca1c2f 100644
--- a/http-gateway/service/getPendingCommands_test.go
+++ b/http-gateway/service/getPendingCommands_test.go
@@ -300,9 +300,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) {
secureGWShutdown()
createFn := func() {
- createCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{
+ _, errC := c.CreateResource(ctx, &pb.CreateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -310,8 +308,9 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) {
"power": 1,
}),
},
+ Async: true,
})
- require.Error(t, errC)
+ require.NoError(t, errC)
}
createFn()
retrieveFn := func() {
@@ -324,9 +323,7 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) {
}
retrieveFn()
updateFn := func() {
- updateCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{
+ _, errU := c.UpdateResource(ctx, &pb.UpdateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -334,17 +331,17 @@ func TestRequestHandlerGetPendingCommands(t *testing.T) {
"power": 1,
}),
},
+ Async: true,
})
- require.Error(t, errU)
+ require.NoError(t, errU)
}
updateFn()
deleteFn := func() {
- deleteCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{
+ _, errD := c.DeleteResource(ctx, &pb.DeleteResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
+ Async: true,
})
- require.Error(t, errD)
+ require.NoError(t, errD)
}
deleteFn()
updateDeviceMetadataFn := func() {
diff --git a/http-gateway/service/getResourcePendingCommands_test.go b/http-gateway/service/getResourcePendingCommands_test.go
index 7d66de5d1..d75438626 100644
--- a/http-gateway/service/getResourcePendingCommands_test.go
+++ b/http-gateway/service/getResourcePendingCommands_test.go
@@ -165,9 +165,7 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) {
secureGWShutdown()
createFn := func() {
- createCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errC := c.CreateResource(createCtx, &pb.CreateResourceRequest{
+ _, errC := c.CreateResource(ctx, &pb.CreateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -175,8 +173,9 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) {
"power": 1,
}),
},
+ Async: true,
})
- require.Error(t, errC)
+ require.NoError(t, errC)
}
createFn()
retrieveFn := func() {
@@ -189,9 +188,7 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) {
}
retrieveFn()
updateFn := func() {
- updateCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errU := c.UpdateResource(updateCtx, &pb.UpdateResourceRequest{
+ _, errU := c.UpdateResource(ctx, &pb.UpdateResourceRequest{
ResourceId: commands.NewResourceID(deviceID, test.TestResourceLightInstanceHref("1")),
Content: &pb.Content{
ContentType: message.AppOcfCbor.String(),
@@ -199,17 +196,17 @@ func TestRequestHandlerGetResourcePendingCommands(t *testing.T) {
"power": 1,
}),
},
+ Async: true,
})
- require.Error(t, errU)
+ require.NoError(t, errU)
}
updateFn()
deleteFn := func() {
- deleteCtx, cancel := context.WithTimeout(ctx, time.Second)
- defer cancel()
- _, errD := c.DeleteResource(deleteCtx, &pb.DeleteResourceRequest{
+ _, errD := c.DeleteResource(ctx, &pb.DeleteResourceRequest{
ResourceId: commands.NewResourceID(deviceID, device.ResourceURI),
+ Async: true,
})
- require.Error(t, errD)
+ require.NoError(t, errD)
}
deleteFn()
updateDeviceMetadataFn := func() {
diff --git a/http-gateway/test/test.go b/http-gateway/test/test.go
index a15981d17..0019d542b 100644
--- a/http-gateway/test/test.go
+++ b/http-gateway/test/test.go
@@ -21,6 +21,7 @@ func MakeWebConfigurationConfig() service.WebConfiguration {
Authority: testHttp.HTTPS_SCHEME + config.OAUTH_SERVER_HOST,
HTTPGatewayAddress: testHttp.HTTPS_SCHEME + config.HTTP_GW_HOST,
DeviceProvisioningService: testHttp.HTTPS_SCHEME + config.HTTP_GW_HOST,
+ SnippetService: testHttp.HTTPS_SCHEME + config.SNIPPET_SERVICE_HTTP_HOST,
WebOAuthClient: service.OAuthClient{
Authority: testHttp.HTTPS_SCHEME + config.OAUTH_SERVER_HOST,
ClientID: config.OAUTH_MANAGER_CLIENT_ID,
@@ -51,7 +52,7 @@ func MakeConfig(t require.TestingT, enableUI bool) service.Config {
cfg.Log = log.MakeDefaultConfig()
- cfg.APIs.HTTP.Authorization = config.MakeAuthorizationConfig()
+ cfg.APIs.HTTP.Authorization = config.MakeValidatorConfig()
cfg.APIs.HTTP.Connection = config.MakeListenerConfig(config.HTTP_GW_HOST)
cfg.APIs.HTTP.Connection.TLS.ClientCertificateRequired = false
cfg.APIs.HTTP.WebSocket.StreamBodyLimit = 256 * 1024
diff --git a/http-gateway/uri/uri.go b/http-gateway/uri/uri.go
index 0a4fd3323..05aba37dd 100644
--- a/http-gateway/uri/uri.go
+++ b/http-gateway/uri/uri.go
@@ -7,21 +7,23 @@ const (
ResourceHrefKey = "resourceHref"
CorrelationIDKey = "correlationId"
- ResourceInterfaceQueryKey = "resourceInterface"
- TwinQueryKey = "twin"
- CommandFilterQueryKey = "commandFilter"
- TypeFilterQueryKey = "typeFilter"
- StatusFilterQueryKey = "statusFilter"
- DeviceIdFilterQueryKey = "deviceIdFilter"
- TimeToLiveQueryKey = "timeToLive"
- ResourceIdFilterQueryKey = "resourceIdFilter"
- HttpResourceIdFilterQueryKey = "httpResourceIdFilter"
- AcceptQueryKey = "accept" // for websocket
- CorrelationIDQueryKey = "correlationId"
- TimestampFilterQueryKey = "timestampFilter"
- CorrelationIdFilterQueryKey = "correlationIdFilter"
- ETagQueryKey = "etag"
- OnlyContentQueryKey = "onlyContent"
+ ResourceInterfaceQueryKey = "resourceInterface"
+ TwinQueryKey = "twin"
+ CommandFilterQueryKey = "commandFilter"
+ TypeFilterQueryKey = "typeFilter"
+ StatusFilterQueryKey = "statusFilter"
+ DeviceIdFilterQueryKey = "deviceIdFilter"
+ TimeToLiveQueryKey = "timeToLive"
+ ResourceIdFilterQueryKey = "resourceIdFilter"
+ HttpResourceIdFilterQueryKey = "httpResourceIdFilter"
+ AcceptQueryKey = "accept" // for websocket
+ CorrelationIDQueryKey = "correlationId"
+ TimestampFilterQueryKey = "timestampFilter"
+ CorrelationIdFilterQueryKey = "correlationIdFilter"
+ ETagQueryKey = "etag"
+ OnlyContentQueryKey = "onlyContent"
+ IncludeHiddenResourcesQueryKey = "includeHiddenResources"
+ ForceQueryKey = "force"
AliasInterfaceQueryKey = "interface"
AliasCommandFilterQueryKey = "command"
@@ -116,23 +118,25 @@ const (
)
var QueryCaseInsensitive = map[string]string{
- strings.ToLower(AliasInterfaceQueryKey): ResourceInterfaceQueryKey,
- strings.ToLower(CommandFilterQueryKey): CommandFilterQueryKey,
- strings.ToLower(DeviceIdFilterQueryKey): DeviceIdFilterQueryKey,
- strings.ToLower(ResourceIdFilterQueryKey): HttpResourceIdFilterQueryKey,
- strings.ToLower(ResourceInterfaceQueryKey): ResourceInterfaceQueryKey,
- strings.ToLower(TwinQueryKey): TwinQueryKey,
- strings.ToLower(TypeFilterQueryKey): TypeFilterQueryKey,
- strings.ToLower(AliasCommandFilterQueryKey): CommandFilterQueryKey,
- strings.ToLower(AliasDeviceIdFilterQueryKey): DeviceIdFilterQueryKey,
- strings.ToLower(AliasResourceIdFilterQueryKey): HttpResourceIdFilterQueryKey,
- strings.ToLower(AliasTypeFilterQueryKey): TypeFilterQueryKey,
- strings.ToLower(AcceptQueryKey): AcceptQueryKey,
- strings.ToLower(StatusFilterQueryKey): StatusFilterQueryKey,
- strings.ToLower(AliasStatusFilterQueryKey): StatusFilterQueryKey,
- strings.ToLower(CorrelationIDQueryKey): CorrelationIDQueryKey,
- strings.ToLower(TimestampFilterQueryKey): TimestampFilterQueryKey,
- strings.ToLower(TimeToLiveQueryKey): TimeToLiveQueryKey,
- strings.ToLower(CorrelationIdFilterQueryKey): CorrelationIdFilterQueryKey,
- strings.ToLower(OnlyContentQueryKey): OnlyContentQueryKey,
+ strings.ToLower(AliasInterfaceQueryKey): ResourceInterfaceQueryKey,
+ strings.ToLower(CommandFilterQueryKey): CommandFilterQueryKey,
+ strings.ToLower(DeviceIdFilterQueryKey): DeviceIdFilterQueryKey,
+ strings.ToLower(ResourceIdFilterQueryKey): HttpResourceIdFilterQueryKey,
+ strings.ToLower(ResourceInterfaceQueryKey): ResourceInterfaceQueryKey,
+ strings.ToLower(TwinQueryKey): TwinQueryKey,
+ strings.ToLower(TypeFilterQueryKey): TypeFilterQueryKey,
+ strings.ToLower(AliasCommandFilterQueryKey): CommandFilterQueryKey,
+ strings.ToLower(AliasDeviceIdFilterQueryKey): DeviceIdFilterQueryKey,
+ strings.ToLower(AliasResourceIdFilterQueryKey): HttpResourceIdFilterQueryKey,
+ strings.ToLower(AliasTypeFilterQueryKey): TypeFilterQueryKey,
+ strings.ToLower(AcceptQueryKey): AcceptQueryKey,
+ strings.ToLower(StatusFilterQueryKey): StatusFilterQueryKey,
+ strings.ToLower(AliasStatusFilterQueryKey): StatusFilterQueryKey,
+ strings.ToLower(CorrelationIDQueryKey): CorrelationIDQueryKey,
+ strings.ToLower(TimestampFilterQueryKey): TimestampFilterQueryKey,
+ strings.ToLower(TimeToLiveQueryKey): TimeToLiveQueryKey,
+ strings.ToLower(CorrelationIdFilterQueryKey): CorrelationIdFilterQueryKey,
+ strings.ToLower(OnlyContentQueryKey): OnlyContentQueryKey,
+ strings.ToLower(IncludeHiddenResourcesQueryKey): IncludeHiddenResourcesQueryKey,
+ strings.ToLower(ForceQueryKey): ForceQueryKey,
}
diff --git a/http-gateway/web/package-lock.json b/http-gateway/web/package-lock.json
index 5ecb906f0..0e5358ac4 100644
--- a/http-gateway/web/package-lock.json
+++ b/http-gateway/web/package-lock.json
@@ -36963,7 +36963,9 @@
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
- "express-validator": "^7.1.0"
+ "escape-html": "^1.0.3",
+ "express-validator": "^7.1.0",
+ "lodash": "^4.17.21"
},
"devDependencies": {
"express": "^4.18.2"
@@ -37051,6 +37053,7 @@
"react-table": "^7.8.0",
"react-toastify": "^9.1.3",
"react-transition-group": "^4.4.5",
+ "recoil": "^0.7.7",
"swiper": "^10.2.0",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"typescript": "^4.9.5",
@@ -37094,7 +37097,7 @@
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jest": "^27.6.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
- "eslint-plugin-prettier": "^5.0.1",
+ "eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-storybook": "^0.8.0",
@@ -37110,7 +37113,7 @@
"npm-run-all": "^4.1.5",
"path": "^0.12.7",
"postcss-modules": "^6.0.0",
- "prettier": "^3.1.0",
+ "prettier": "^3.3.2",
"prop-types": "^15.8.1",
"resize-observer-polyfill": "^1.5.1",
"rimraf": "^5.0.5",
@@ -37125,6 +37128,21 @@
"yargs": "^17.7.2"
}
},
+ "packages/shared-ui/node_modules/prettier": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
+ "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"packages/shared-ui/node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
diff --git a/http-gateway/web/packages/mock-server/package.json b/http-gateway/web/packages/mock-server/package.json
index 460b398b3..2fdafde62 100644
--- a/http-gateway/web/packages/mock-server/package.json
+++ b/http-gateway/web/packages/mock-server/package.json
@@ -14,6 +14,8 @@
},
"dependencies": {
"cors": "^2.8.5",
- "express-validator": "^7.1.0"
+ "escape-html": "^1.0.3",
+ "express-validator": "^7.1.0",
+ "lodash": "^4.17.21"
}
}
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/detail/4f0d3d81-0e09-4f1e-9706-0997488011af.json b/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/detail/4f0d3d81-0e09-4f1e-9706-0997488011af.json
new file mode 100644
index 000000000..a2f174a3d
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/detail/4f0d3d81-0e09-4f1e-9706-0997488011af.json
@@ -0,0 +1,17 @@
+{
+ "result": {
+ "id": "4f0d3d81-0e09-4f1e-9706-0997488011af",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "attestationMechanism": {
+ "x509": {
+ "certificateChain": "/secrets/enrollmentgroups/x509/4f0d3d81-0e09-4f1e-9706-0997488011af/certificatechain.crt",
+ "leadCertificateName": "MfgRootCA",
+ "expiredCertificateEnabled": false
+ }
+ },
+ "hubIds": [
+ "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ ],
+ "name": "4f0d3d81-0e09-4f1e-9706-0997488011af"
+ }
+}
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/detail/75eacc2f-ac28-4a42-a155-164393970ba4.json b/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/detail/75eacc2f-ac28-4a42-a155-164393970ba4.json
new file mode 100644
index 000000000..5092c07f9
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/detail/75eacc2f-ac28-4a42-a155-164393970ba4.json
@@ -0,0 +1,17 @@
+{
+ "result": {
+ "id": "75eacc2f-ac28-4a42-a155-164393970ba4",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "attestationMechanism": {
+ "x509": {
+ "certificateChain": "/secrets/enrollmentgroups/x509/75eacc2f-ac28-4a42-a155-164393970ba4/certificatechain.crt",
+ "leadCertificateName": "root.ca.plgd.cloud",
+ "expiredCertificateEnabled": false
+ }
+ },
+ "hubIds": [
+ "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ ],
+ "name": "75eacc2f-ac28-4a42-a155-164393970ba4"
+ }
+}
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/list/list.json b/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/list/list.json
new file mode 100644
index 000000000..fdd469730
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/enrollment-groups/list/list.json
@@ -0,0 +1,35 @@
+[
+ {
+ "result": {
+ "id": "75eacc2f-ac28-4a42-a155-164393970ba4",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "attestationMechanism": {
+ "x509": {
+ "certificateChain": "/secrets/enrollmentgroups/x509/75eacc2f-ac28-4a42-a155-164393970ba4/certificatechain.crt",
+ "leadCertificateName": "root.ca.plgd.cloud",
+ "expiredCertificateEnabled": false
+ }
+ },
+ "hubIds": [
+ "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ ],
+ "name": "75eacc2f-ac28-4a42-a155-164393970ba4"
+ }
+ },{
+ "result": {
+ "hubIds": [
+ "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ ],
+ "name": "4f0d3d81-0e09-4f1e-9706-0997488011af",
+ "id": "4f0d3d81-0e09-4f1e-9706-0997488011af",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "attestationMechanism": {
+ "x509": {
+ "certificateChain": "/secrets/enrollmentgroups/x509/4f0d3d81-0e09-4f1e-9706-0997488011af/certificatechain.crt",
+ "leadCertificateName": "MfgRootCA",
+ "expiredCertificateEnabled": false
+ }
+ }
+ }
+}
+]
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/linked-hubs/detail/1c10a3b6-287c-11ec-ac2d-13054959c274.json b/http-gateway/web/packages/mock-server/src/data/dps/linked-hubs/detail/1c10a3b6-287c-11ec-ac2d-13054959c274.json
new file mode 100644
index 000000000..b857b8c11
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/linked-hubs/detail/1c10a3b6-287c-11ec-ac2d-13054959c274.json
@@ -0,0 +1,56 @@
+{
+ "result": {
+ "name": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "hubId": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "id": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "gateways": [
+ "coaps+tcp://try.plgd.cloud:5684"
+ ],
+ "certificateAuthority": {
+ "grpc": {
+ "tls": {
+ "caPool": [
+ "/certs/client/ca.crt"
+ ],
+ "key": "/certs/client/tls.key",
+ "cert": "/certs/client/tls.crt",
+ "useSystemCaPool": true
+ },
+ "address": "csr.try.plgd.cloud:443",
+ "keepAlive": {
+ "timeout": "20000000000",
+ "permitWithoutStream": true,
+ "time": "10000000000"
+ }
+ }
+ },
+ "authorization": {
+ "ownerClaim": "owner-id",
+ "provider": {
+ "clientId": "p2elIQo8ZOQZ7pSgAfi0JyebeE6uwWNK",
+ "scopes": [
+ "openid"
+ ],
+ "clientSecret": "/secrets/enrollmentgroups/hubs/oauth/4f0d3d81-0e09-4f1e-9706-0997488011af/clientsecret",
+ "http": {
+ "maxConnsPerHost": 32,
+ "maxIdleConnsPerHost": 16,
+ "idleConnTimeout": "30000000000",
+ "timeout": "10000000000",
+ "tls": {
+ "key": "/certs/client/tls.key",
+ "cert": "/certs/client/tls.crt",
+ "useSystemCaPool": true,
+ "caPool": [
+ "/certs/client/ca.crt"
+ ]
+ },
+ "maxIdleConns": 16
+ },
+ "name": "plgd.dps",
+ "authority": "https://auth.plgd.cloud/realms/shared"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/linked-hubs/list/list.json b/http-gateway/web/packages/mock-server/src/data/dps/linked-hubs/list/list.json
new file mode 100644
index 000000000..63c7fc522
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/linked-hubs/list/list.json
@@ -0,0 +1,58 @@
+[
+ {
+ "result": {
+ "certificateAuthority": {
+ "grpc": {
+ "address": "csr.try.plgd.cloud:443",
+ "keepAlive": {
+ "time": "10000000000",
+ "timeout": "20000000000",
+ "permitWithoutStream": true
+ },
+ "tls": {
+ "cert": "/certs/client/tls.crt",
+ "useSystemCaPool": true,
+ "caPool": [
+ "/certs/client/ca.crt"
+ ],
+ "key": "/certs/client/tls.key"
+ }
+ }
+ },
+ "authorization": {
+ "provider": {
+ "clientSecret": "/secrets/enrollmentgroups/hubs/oauth/4f0d3d81-0e09-4f1e-9706-0997488011af/clientsecret",
+ "http": {
+ "maxIdleConns": 16,
+ "maxConnsPerHost": 32,
+ "maxIdleConnsPerHost": 16,
+ "idleConnTimeout": "30000000000",
+ "timeout": "10000000000",
+ "tls": {
+ "caPool": [
+ "/certs/client/ca.crt"
+ ],
+ "key": "/certs/client/tls.key",
+ "cert": "/certs/client/tls.crt",
+ "useSystemCaPool": true
+ }
+ },
+ "name": "plgd.dps",
+ "authority": "https://auth.plgd.cloud/realms/shared",
+ "clientId": "p2elIQo8ZOQZ7pSgAfi0JyebeE6uwWNK",
+ "scopes": [
+ "openid"
+ ]
+ },
+ "ownerClaim": "owner-id"
+ },
+ "name": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "hubId": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "id": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "gateways": [
+ "coaps+tcp://try.plgd.cloud:5684"
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/detail/4a0d78b2-9a21-557d-ab08-bb4eaccfcbb0.json b/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/detail/4a0d78b2-9a21-557d-ab08-bb4eaccfcbb0.json
new file mode 100644
index 000000000..95dd44eab
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/detail/4a0d78b2-9a21-557d-ab08-bb4eaccfcbb0.json
@@ -0,0 +1,250 @@
+{
+ "result": {
+ "deviceId": "bcd30976-10e4-4145-5282-eb50ee55dfae",
+ "enrollmentGroupId": "4f0d3d81-0e09-4f1e-9706-0997488011af",
+ "attestation": {
+ "date": "1717157743336135946",
+ "x509": {
+ "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIBhTCCASugAwIBAgIRAJ+UC+MPMl6jc9FVeHZEgB4wCgYIKoZIzj0EAwIwFDES\nMBAGA1UEAxMJTWZnUm9vdENBMCAXDTIzMTIxMTEyNTIwMVoYDzIxMjMxMTE3MTI1\nMjAxWjATMREwDwYDVQQDEwhNZmdDZXJ0MTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABFU2BHkqcNsiN68hGoFGzk+QtK78su3HpObu0U6Yhq5tnbGffQ4oTcel4Lhx\nlW5FHWUPI/l2LV9Ej/i3DSaurs6jXTBbMB8GA1UdIwQYMBaAFFyGFDlvMWlF0wb8\n0yDIfbRH7lTPMAwGA1UdEwQFMAMBAQAwCwYDVR0PBAQDAgOIMB0GA1UdJQQWMBQG\nCCsGAQUFBwMCBggrBgEFBQcDATAKBggqhkjOPQQDAgNIADBFAiBM31BMFp/ImqVt\nwH55aaqYSYp00pabSyIbKwFle6B+2wIhAMqXjZ3zoEECNU7zUo/hpYPTqanak2t6\ndPVwtlKcRlPx\n-----END CERTIFICATE-----\n",
+ "commonName": "MfgCert1"
+ }
+ },
+ "acl": {
+ "status": {
+ "date": "1717157743480774484",
+ "coapCode": 69
+ },
+ "accessControlList": [
+ {
+ "deviceSubject": {
+ "deviceId": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "href": "/CoapCloudConfResURI",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/sec/sp"
+ },
+ {
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "wildcard": "NONE",
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ]
+ },
+ {
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/mnt"
+ },
+ {
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ]
+ },
+ {
+ "connectionSubject": {
+ "type": "ANON_CLEAR"
+ },
+ "permissions": [
+ "READ"
+ ],
+ "resources": [
+ {
+ "href": "/oic/d",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/p",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/res",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/sec/sdi"
+ },
+ {
+ "href": "/oic/sec/doxm",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ }
+ ]
+ },
+ {
+ "deviceSubject": {
+ "deviceId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ },
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/mnt",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/x.plgd.dev/time"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ]
+ }
+ ]
+ },
+ "cloud": {
+ "status": {
+ "date": "1717157743426800468",
+ "coapCode": 68
+ },
+ "providerName": "plgd.dps",
+ "gateways": [
+ {
+ "id": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "uri": "coaps+tcp://try.plgd.cloud:5684"
+ }
+ ],
+ "selectedGateway": 0
+ },
+ "ownership": {
+ "status": {
+ "date": "1717157743352900277",
+ "coapCode": 69
+ },
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "localEndpoints": [
+ "coap://10.110.110.12:45396",
+ "coaps://10.110.110.12:52852",
+ "coap+tcp://10.110.110.12:51863",
+ "coaps+tcp://10.110.110.12:38145"
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "id": "4a0d78b2-9a21-557d-ab08-bb4eaccfcbb0",
+ "creationDate": "1716656687662199144",
+ "credential": {
+ "status": {
+ "date": "1717157743461436598",
+ "coapCode": 68
+ },
+ "identityCertificatePem": "-----BEGIN CERTIFICATE-----\nMIIBojCCAUigAwIBAgIQIm1TIO0PH7O+w+LXTfV1KTAKBggqhkjOPQQDAjASMRAw\nDgYDVQQDEwdwbGdkLWNhMB4XDTI0MDUzMTExMTU0M1oXDTI1MDUyNTE3MDI1MVow\nNDEyMDAGA1UEAxMpdXVpZDpiY2QzMDk3Ni0xMGU0LTQxNDUtNTI4Mi1lYjUwZWU1\nNWRmYWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQK9W+P4MDWdABFVSgZOWnW\nDGEkU8abmg2zVW1MlGPZF4YKpKWEUIoqeVxpm5D/yKtzG15uuvx3U2oU3UbRGL5t\no14wXDAOBgNVHQ8BAf8EBAMCA4gwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUF\nBwMBBgorBgEEAYLefAEGMB8GA1UdIwQYMBaAFCM9S7rizy2ArYhiARButOX7DTPa\nMAoGCCqGSM49BAMCA0gAMEUCIBMdkdXzDBJgThKP3Q1hTV/XzigwlSe7+YlXoINl\ngW8DAiEA7f9ghvAZzBbep1sMDmcTFFLquzAPNsRBSCkSquyYUNQ=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBkDCCATagAwIBAgIQFq/ergts3Jlaxk3N92FfzTAKBggqhkjOPQQDAjAdMRsw\nGQYDVQQDExJyb290LmNhLnBsZ2QuY2xvdWQwHhcNMjQwNTI1MTcwMjUxWhcNMjUw\nNTI1MTcwMjUxWjASMRAwDgYDVQQDEwdwbGdkLWNhMFkwEwYHKoZIzj0CAQYIKoZI\nzj0DAQcDQgAE5s5zak9SL6OCMM49iyJYpNvnHly3UVdTe4jaAxmMS2YM63e68Cix\nevhl849SzCnpoD9yJzFA2HmhEc82IVt66KNjMGEwDgYDVR0PAQH/BAQDAgGGMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM9S7rizy2ArYhiARButOX7DTPaMB8G\nA1UdIwQYMBaAFELK01Gtmvz99kTvIM5idzOLxerIMAoGCCqGSM49BAMCA0gAMEUC\nIG4Cnqkb+atbFIAeTFyIR4v3ABi0CjPub07xnt/bvN6FAiEAxgyW5sibfw7z3/xc\nQnA0w68sKmVRZhvfUNMYkqbk/2w=\n-----END CERTIFICATE-----\n",
+ "credentials": [
+ {
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ],
+ "usage": "CERT",
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvakNDQVVpZ0F3SUJBZ0lRSW0xVElPMFBIN08rdytMWFRmVjFLVEFLQmdncWhrak9QUVFEQWpBU01SQXcKRGdZRFZRUURFd2R3Ykdka0xXTmhNQjRYRFRJME1EVXpNVEV4TVRVME0xb1hEVEkxTURVeU5URTNNREkxTVZvdwpOREV5TURBR0ExVUVBeE1wZFhWcFpEcGlZMlF6TURrM05pMHhNR1UwTFRReE5EVXROVEk0TWkxbFlqVXdaV1UxCk5XUm1ZV1V3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFLOVcrUDRNRFdkQUJGVlNnWk9XblcKREdFa1U4YWJtZzJ6VlcxTWxHUFpGNFlLcEtXRVVJb3FlVnhwbTVEL3lLdHpHMTV1dXZ4M1Uyb1UzVWJSR0w1dApvMTR3WERBT0JnTlZIUThCQWY4RUJBTUNBNGd3S1FZRFZSMGxCQ0l3SUFZSUt3WUJCUVVIQXdJR0NDc0dBUVVGCkJ3TUJCZ29yQmdFRUFZTGVmQUVHTUI4R0ExVWRJd1FZTUJhQUZDTTlTN3JpenkyQXJZaGlBUkJ1dE9YN0RUUGEKTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSUJNZGtkWHpEQkpnVGhLUDNRMWhUVi9Yemlnd2xTZTcrWWxYb0lObApnVzhEQWlFQTdmOWdodkFaekJiZXAxc01EbWNURkZMcXV6QVBOc1JCU0NrU3F1eVlVTlE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrRENDQVRhZ0F3SUJBZ0lRRnEvZXJndHMzSmxheGszTjkyRmZ6VEFLQmdncWhrak9QUVFEQWpBZE1Sc3cKR1FZRFZRUURFeEp5YjI5MExtTmhMbkJzWjJRdVkyeHZkV1F3SGhjTk1qUXdOVEkxTVRjd01qVXhXaGNOTWpVdwpOVEkxTVRjd01qVXhXakFTTVJBd0RnWURWUVFERXdkd2JHZGtMV05oTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJCnpqMERBUWNEUWdBRTVzNXphazlTTDZPQ01NNDlpeUpZcE52bkhseTNVVmRUZTRqYUF4bU1TMllNNjNlNjhDaXgKZXZobDg0OVN6Q25wb0Q5eUp6RkEySG1oRWM4MklWdDY2S05qTUdFd0RnWURWUjBQQVFIL0JBUURBZ0dHTUE4RwpBMVVkRXdFQi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZDTTlTN3JpenkyQXJZaGlBUkJ1dE9YN0RUUGFNQjhHCkExVWRJd1FZTUJhQUZFTEswMUd0bXZ6OTlrVHZJTTVpZHpPTHhlcklNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUMKSUc0Q25xa2IrYXRiRklBZVRGeUlSNHYzQUJpMENqUHViMDd4bnQvYnZONkZBaUVBeGd5VzVzaWJmdzd6My94YwpRbkEwdzY4c0ttVlJaaHZmVU5NWWtxYmsvMnc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
+ "encoding": "PEM"
+ },
+ "id": "0",
+ "subject": "bcd30976-10e4-4145-5282-eb50ee55dfae"
+ },
+ {
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lSQUlwR0Jrb0U2ZXdwdFJMT1FaMXZrb1V3Q2dZSUtvWkl6ajBFQXdJd0hURWIKTUJrR0ExVUVBeE1TY205dmRDNWpZUzV3Ykdka0xtTnNiM1ZrTUNBWERUSXpNVEF4T1RBNE5EZ3hOVm9ZRHpJeApNak13T1RJMU1EZzBPREUxV2pBZE1Sc3dHUVlEVlFRREV4SnliMjkwTG1OaExuQnNaMlF1WTJ4dmRXUXdXVEFUCkJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFtMHgrMTZCdWt2ditIV0FlcnkvMG8vVlFBTzhib3hzNHcKT2lhWFRybDBhbi9iUkR6REFwc1J2cDY5SHdJY2haS0FjZTVPQ3JkZFNpVVJOdDZRZWYwQ28wSXdRREFPQmdOVgpIUThCQWY4RUJBTUNBUVl3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVUXNyVFVhMmEvUDMyClJPOGd6bUozTTR2RjZzZ3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdOMHBnS1N4d2RvUklkV1RxaTdUcDd0eVAKb05LNERxeElsWWJuRUlJb3BlZ0NJUURsd2FUMmg2RUtaM1R3SHFBcTU1UXl3TDM3RzJwdjVKOE03dDFFcVBnQQpZQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
+ "encoding": "PEM"
+ },
+ "id": "0",
+ "subject": "beb32777-9680-4f42-8761-350eebe76a85",
+ "usage": "TRUST_CA",
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ]
+ }
+ ]
+ },
+ "plgdTime": {
+ "date": "1717157743283612068",
+ "coapCode": 69
+ }
+ }
+}
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/detail/69f23484-171a-56a9-b300-89cd3007a70c.json b/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/detail/69f23484-171a-56a9-b300-89cd3007a70c.json
new file mode 100644
index 000000000..7c7b62a56
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/detail/69f23484-171a-56a9-b300-89cd3007a70c.json
@@ -0,0 +1,250 @@
+{
+ "result": {
+ "localEndpoints": [
+ "coap://10.110.110.12:41885",
+ "coaps://10.110.110.12:49997",
+ "coap+tcp://10.110.110.12:35389",
+ "coaps+tcp://10.110.110.12:33711"
+ ],
+ "deviceId": "d9dde79c-3916-433b-4789-ca10aad6fc4a",
+ "creationDate": "1716652467413672050",
+ "attestation": {
+ "date": "1719474938251929779",
+ "x509": {
+ "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIBgjCCASmgAwIBAgIQdYzG5cWdt18FWrG0WxBqNzAKBggqhkjOPQQDAjAUMRIw\nEAYDVQQDEwlNZmdSb290Q0EwIBcNMjMxMTA2MDcyNzU5WhgPMjEyMzEwMTMwNzI3\nNTlaMBIxEDAOBgNVBAMTB01mZ0NlcnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\nAAQMkz/uQi1sbMmuxgagH/A5II6CcxZz9sWpSjuxLEqPNEbL021yUaQX6/U2GBYs\npFVWzGPWIog30mgGq/jvDyQKo10wWzAfBgNVHSMEGDAWgBRchhQ5bzFpRdMG/NMg\nyH20R+5UzzAMBgNVHRMEBTADAQEAMAsGA1UdDwQEAwIDiDAdBgNVHSUEFjAUBggr\nBgEFBQcDAgYIKwYBBQUHAwEwCgYIKoZIzj0EAwIDRwAwRAIgbqEU4iOhHpD4YnjC\nO5J8lTIw+RbZ+r9uZD1K2fz4ZfkCIGFzidJQAmBSPVvEdK4X4CSf76BjEoRwXxm2\nKaeI8Vkl\n-----END CERTIFICATE-----\n",
+ "commonName": "MfgCert"
+ }
+ },
+ "cloud": {
+ "status": {
+ "coapCode": 68,
+ "date": "1719474938285092512"
+ },
+ "providerName": "plgd.dps",
+ "gateways": [
+ {
+ "uri": "coaps+tcp://try.plgd.cloud:5684",
+ "id": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ }
+ ],
+ "selectedGateway": 0
+ },
+ "ownership": {
+ "status": {
+ "date": "1719474938266133666",
+ "coapCode": 69
+ },
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "plgdTime": {
+ "date": "1719474938192355476",
+ "coapCode": 69
+ },
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "id": "69f23484-171a-56a9-b300-89cd3007a70c",
+ "enrollmentGroupId": "4f0d3d81-0e09-4f1e-9706-0997488011af",
+ "credential": {
+ "status": {
+ "date": "1719474938324358862",
+ "coapCode": 68
+ },
+ "identityCertificatePem": "-----BEGIN CERTIFICATE-----\nMIIBpDCCAUmgAwIBAgIRAPJNdAgYEQhNPjTxlF3/1v0wCgYIKoZIzj0EAwIwEjEQ\nMA4GA1UEAxMHcGxnZC1jYTAeFw0yNDA2MjcwNjU1MzhaFw0yNTA1MjUxNzAyNTFa\nMDQxMjAwBgNVBAMTKXV1aWQ6ZDlkZGU3OWMtMzkxNi00MzNiLTQ3ODktY2ExMGFh\nZDZmYzRhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaWg0Wurmnrl8LTvARHc+\nCu8eiLBIsKXp/RALqr2htsFK0jlkStpuxMWfSofbTiY/8gD1YmM3Q833CL0Sg+C5\nZaNeMFwwDgYDVR0PAQH/BAQDAgOIMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEF\nBQcDAQYKKwYBBAGC3nwBBjAfBgNVHSMEGDAWgBQjPUu64s8tgK2IYgEQbrTl+w0z\n2jAKBggqhkjOPQQDAgNJADBGAiEA/bvt26yZJozHeXJGusuH4HLZd4eAkQy7Bc9x\nSmt3UukCIQDx9g2DUPECP/20MV18FKkitUAN3Ed4tB/gmX17tCBuQw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBkDCCATagAwIBAgIQFq/ergts3Jlaxk3N92FfzTAKBggqhkjOPQQDAjAdMRsw\nGQYDVQQDExJyb290LmNhLnBsZ2QuY2xvdWQwHhcNMjQwNTI1MTcwMjUxWhcNMjUw\nNTI1MTcwMjUxWjASMRAwDgYDVQQDEwdwbGdkLWNhMFkwEwYHKoZIzj0CAQYIKoZI\nzj0DAQcDQgAE5s5zak9SL6OCMM49iyJYpNvnHly3UVdTe4jaAxmMS2YM63e68Cix\nevhl849SzCnpoD9yJzFA2HmhEc82IVt66KNjMGEwDgYDVR0PAQH/BAQDAgGGMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM9S7rizy2ArYhiARButOX7DTPaMB8G\nA1UdIwQYMBaAFELK01Gtmvz99kTvIM5idzOLxerIMAoGCCqGSM49BAMCA0gAMEUC\nIG4Cnqkb+atbFIAeTFyIR4v3ABi0CjPub07xnt/bvN6FAiEAxgyW5sibfw7z3/xc\nQnA0w68sKmVRZhvfUNMYkqbk/2w=\n-----END CERTIFICATE-----\n",
+ "credentials": [
+ {
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ],
+ "usage": "CERT",
+ "id": "0",
+ "subject": "d9dde79c-3916-433b-4789-ca10aad6fc4a",
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJwRENDQVVtZ0F3SUJBZ0lSQVBKTmRBZ1lFUWhOUGpUeGxGMy8xdjB3Q2dZSUtvWkl6ajBFQXdJd0VqRVEKTUE0R0ExVUVBeE1IY0d4blpDMWpZVEFlRncweU5EQTJNamN3TmpVMU16aGFGdzB5TlRBMU1qVXhOekF5TlRGYQpNRFF4TWpBd0JnTlZCQU1US1hWMWFXUTZaRGxrWkdVM09XTXRNemt4TmkwME16TmlMVFEzT0RrdFkyRXhNR0ZoClpEWm1ZelJoTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFYVdnMFd1cm1ucmw4TFR2QVJIYysKQ3U4ZWlMQklzS1hwL1JBTHFyMmh0c0ZLMGpsa1N0cHV4TVdmU29mYlRpWS84Z0QxWW1NM1E4MzNDTDBTZytDNQpaYU5lTUZ3d0RnWURWUjBQQVFIL0JBUURBZ09JTUNrR0ExVWRKUVFpTUNBR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGCkJRY0RBUVlLS3dZQkJBR0MzbndCQmpBZkJnTlZIU01FR0RBV2dCUWpQVXU2NHM4dGdLMklZZ0VRYnJUbCt3MHoKMmpBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQS9idnQyNnlaSm96SGVYSkd1c3VINEhMWmQ0ZUFrUXk3QmM5eApTbXQzVXVrQ0lRRHg5ZzJEVVBFQ1AvMjBNVjE4RktraXRVQU4zRWQ0dEIvZ21YMTd0Q0J1UXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCa0RDQ0FUYWdBd0lCQWdJUUZxL2VyZ3RzM0psYXhrM045MkZmelRBS0JnZ3Foa2pPUFFRREFqQWRNUnN3CkdRWURWUVFERXhKeWIyOTBMbU5oTG5Cc1oyUXVZMnh2ZFdRd0hoY05NalF3TlRJMU1UY3dNalV4V2hjTk1qVXcKTlRJMU1UY3dNalV4V2pBU01SQXdEZ1lEVlFRREV3ZHdiR2RrTFdOaE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSQp6ajBEQVFjRFFnQUU1czV6YWs5U0w2T0NNTTQ5aXlKWXBOdm5IbHkzVVZkVGU0amFBeG1NUzJZTTYzZTY4Q2l4CmV2aGw4NDlTekNucG9EOXlKekZBMkhtaEVjODJJVnQ2NktOak1HRXdEZ1lEVlIwUEFRSC9CQVFEQWdHR01BOEcKQTFVZEV3RUIvd1FGTUFNQkFmOHdIUVlEVlIwT0JCWUVGQ005UzdyaXp5MkFyWWhpQVJCdXRPWDdEVFBhTUI4RwpBMVVkSXdRWU1CYUFGRUxLMDFHdG12ejk5a1R2SU01aWR6T0x4ZXJJTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDCklHNENucWtiK2F0YkZJQWVURnlJUjR2M0FCaTBDalB1YjA3eG50L2J2TjZGQWlFQXhneVc1c2liZnc3ejMveGMKUW5BMHc2OHNLbVZSWmh2ZlVOTVlrcWJrLzJ3PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
+ "encoding": "PEM"
+ }
+ },
+ {
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lSQUlwR0Jrb0U2ZXdwdFJMT1FaMXZrb1V3Q2dZSUtvWkl6ajBFQXdJd0hURWIKTUJrR0ExVUVBeE1TY205dmRDNWpZUzV3Ykdka0xtTnNiM1ZrTUNBWERUSXpNVEF4T1RBNE5EZ3hOVm9ZRHpJeApNak13T1RJMU1EZzBPREUxV2pBZE1Sc3dHUVlEVlFRREV4SnliMjkwTG1OaExuQnNaMlF1WTJ4dmRXUXdXVEFUCkJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFtMHgrMTZCdWt2ditIV0FlcnkvMG8vVlFBTzhib3hzNHcKT2lhWFRybDBhbi9iUkR6REFwc1J2cDY5SHdJY2haS0FjZTVPQ3JkZFNpVVJOdDZRZWYwQ28wSXdRREFPQmdOVgpIUThCQWY4RUJBTUNBUVl3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVUXNyVFVhMmEvUDMyClJPOGd6bUozTTR2RjZzZ3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdOMHBnS1N4d2RvUklkV1RxaTdUcDd0eVAKb05LNERxeElsWWJuRUlJb3BlZ0NJUURsd2FUMmg2RUtaM1R3SHFBcTU1UXl3TDM3RzJwdjVKOE03dDFFcVBnQQpZQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
+ "encoding": "PEM"
+ },
+ "subject": "beb32777-9680-4f42-8761-350eebe76a85",
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ],
+ "usage": "TRUST_CA",
+ "id": "0"
+ }
+ ]
+ },
+ "acl": {
+ "accessControlList": [
+ {
+ "deviceSubject": {
+ "deviceId": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "href": "/CoapCloudConfResURI",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/sec/sp"
+ },
+ {
+ "wildcard": "NONE",
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ]
+ },
+ {
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/mnt",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/x.plgd.dev/time"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ]
+ },
+ {
+ "resources": [
+ {
+ "href": "/oic/d",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/p"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/res"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/sec/sdi"
+ },
+ {
+ "href": "/oic/sec/doxm",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ }
+ ],
+ "connectionSubject": {
+ "type": "ANON_CLEAR"
+ },
+ "permissions": [
+ "READ"
+ ]
+ },
+ {
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "wildcard": "NONE",
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ]
+ },
+ {
+ "wildcard": "NONE",
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ]
+ },
+ {
+ "href": "/oic/mnt",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ],
+ "deviceSubject": {
+ "deviceId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ }
+ }
+ ],
+ "status": {
+ "date": "1719474938340859252",
+ "coapCode": 69
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/list/list.json b/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/list/list.json
new file mode 100644
index 000000000..b337d0998
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/dps/provisioning-records/list/list.json
@@ -0,0 +1,501 @@
+[
+ {
+ "result": {
+ "enrollmentGroupId": "4f0d3d81-0e09-4f1e-9706-0997488011af",
+ "creationDate": "1716652467413672050",
+ "attestation": {
+ "date": "1719474938251929779",
+ "x509": {
+ "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIBgjCCASmgAwIBAgIQdYzG5cWdt18FWrG0WxBqNzAKBggqhkjOPQQDAjAUMRIw\nEAYDVQQDEwlNZmdSb290Q0EwIBcNMjMxMTA2MDcyNzU5WhgPMjEyMzEwMTMwNzI3\nNTlaMBIxEDAOBgNVBAMTB01mZ0NlcnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\nAAQMkz/uQi1sbMmuxgagH/A5II6CcxZz9sWpSjuxLEqPNEbL021yUaQX6/U2GBYs\npFVWzGPWIog30mgGq/jvDyQKo10wWzAfBgNVHSMEGDAWgBRchhQ5bzFpRdMG/NMg\nyH20R+5UzzAMBgNVHRMEBTADAQEAMAsGA1UdDwQEAwIDiDAdBgNVHSUEFjAUBggr\nBgEFBQcDAgYIKwYBBQUHAwEwCgYIKoZIzj0EAwIDRwAwRAIgbqEU4iOhHpD4YnjC\nO5J8lTIw+RbZ+r9uZD1K2fz4ZfkCIGFzidJQAmBSPVvEdK4X4CSf76BjEoRwXxm2\nKaeI8Vkl\n-----END CERTIFICATE-----\n",
+ "commonName": "MfgCert"
+ }
+ },
+ "cloud": {
+ "status": {
+ "coapCode": 68,
+ "date": "1719474938285092512"
+ },
+ "providerName": "plgd.dps",
+ "gateways": [
+ {
+ "id": "1c10a3b6-287c-11ec-ac2d-13054959c274",
+ "uri": "coaps+tcp://try.plgd.cloud:5684"
+ }
+ ],
+ "selectedGateway": 0
+ },
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "id": "69f23484-171a-56a9-b300-89cd3007a70c",
+ "deviceId": "d9dde79c-3916-433b-4789-ca10aad6fc4a",
+ "credential": {
+ "status": {
+ "date": "1719474938324358862",
+ "coapCode": 68
+ },
+ "identityCertificatePem": "-----BEGIN CERTIFICATE-----\nMIIBpDCCAUmgAwIBAgIRAPJNdAgYEQhNPjTxlF3/1v0wCgYIKoZIzj0EAwIwEjEQ\nMA4GA1UEAxMHcGxnZC1jYTAeFw0yNDA2MjcwNjU1MzhaFw0yNTA1MjUxNzAyNTFa\nMDQxMjAwBgNVBAMTKXV1aWQ6ZDlkZGU3OWMtMzkxNi00MzNiLTQ3ODktY2ExMGFh\nZDZmYzRhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaWg0Wurmnrl8LTvARHc+\nCu8eiLBIsKXp/RALqr2htsFK0jlkStpuxMWfSofbTiY/8gD1YmM3Q833CL0Sg+C5\nZaNeMFwwDgYDVR0PAQH/BAQDAgOIMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEF\nBQcDAQYKKwYBBAGC3nwBBjAfBgNVHSMEGDAWgBQjPUu64s8tgK2IYgEQbrTl+w0z\n2jAKBggqhkjOPQQDAgNJADBGAiEA/bvt26yZJozHeXJGusuH4HLZd4eAkQy7Bc9x\nSmt3UukCIQDx9g2DUPECP/20MV18FKkitUAN3Ed4tB/gmX17tCBuQw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBkDCCATagAwIBAgIQFq/ergts3Jlaxk3N92FfzTAKBggqhkjOPQQDAjAdMRsw\nGQYDVQQDExJyb290LmNhLnBsZ2QuY2xvdWQwHhcNMjQwNTI1MTcwMjUxWhcNMjUw\nNTI1MTcwMjUxWjASMRAwDgYDVQQDEwdwbGdkLWNhMFkwEwYHKoZIzj0CAQYIKoZI\nzj0DAQcDQgAE5s5zak9SL6OCMM49iyJYpNvnHly3UVdTe4jaAxmMS2YM63e68Cix\nevhl849SzCnpoD9yJzFA2HmhEc82IVt66KNjMGEwDgYDVR0PAQH/BAQDAgGGMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM9S7rizy2ArYhiARButOX7DTPaMB8G\nA1UdIwQYMBaAFELK01Gtmvz99kTvIM5idzOLxerIMAoGCCqGSM49BAMCA0gAMEUC\nIG4Cnqkb+atbFIAeTFyIR4v3ABi0CjPub07xnt/bvN6FAiEAxgyW5sibfw7z3/xc\nQnA0w68sKmVRZhvfUNMYkqbk/2w=\n-----END CERTIFICATE-----\n",
+ "credentials": [
+ {
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ],
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJwRENDQVVtZ0F3SUJBZ0lSQVBKTmRBZ1lFUWhOUGpUeGxGMy8xdjB3Q2dZSUtvWkl6ajBFQXdJd0VqRVEKTUE0R0ExVUVBeE1IY0d4blpDMWpZVEFlRncweU5EQTJNamN3TmpVMU16aGFGdzB5TlRBMU1qVXhOekF5TlRGYQpNRFF4TWpBd0JnTlZCQU1US1hWMWFXUTZaRGxrWkdVM09XTXRNemt4TmkwME16TmlMVFEzT0RrdFkyRXhNR0ZoClpEWm1ZelJoTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFYVdnMFd1cm1ucmw4TFR2QVJIYysKQ3U4ZWlMQklzS1hwL1JBTHFyMmh0c0ZLMGpsa1N0cHV4TVdmU29mYlRpWS84Z0QxWW1NM1E4MzNDTDBTZytDNQpaYU5lTUZ3d0RnWURWUjBQQVFIL0JBUURBZ09JTUNrR0ExVWRKUVFpTUNBR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGCkJRY0RBUVlLS3dZQkJBR0MzbndCQmpBZkJnTlZIU01FR0RBV2dCUWpQVXU2NHM4dGdLMklZZ0VRYnJUbCt3MHoKMmpBS0JnZ3Foa2pPUFFRREFnTkpBREJHQWlFQS9idnQyNnlaSm96SGVYSkd1c3VINEhMWmQ0ZUFrUXk3QmM5eApTbXQzVXVrQ0lRRHg5ZzJEVVBFQ1AvMjBNVjE4RktraXRVQU4zRWQ0dEIvZ21YMTd0Q0J1UXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlCa0RDQ0FUYWdBd0lCQWdJUUZxL2VyZ3RzM0psYXhrM045MkZmelRBS0JnZ3Foa2pPUFFRREFqQWRNUnN3CkdRWURWUVFERXhKeWIyOTBMbU5oTG5Cc1oyUXVZMnh2ZFdRd0hoY05NalF3TlRJMU1UY3dNalV4V2hjTk1qVXcKTlRJMU1UY3dNalV4V2pBU01SQXdEZ1lEVlFRREV3ZHdiR2RrTFdOaE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSQp6ajBEQVFjRFFnQUU1czV6YWs5U0w2T0NNTTQ5aXlKWXBOdm5IbHkzVVZkVGU0amFBeG1NUzJZTTYzZTY4Q2l4CmV2aGw4NDlTekNucG9EOXlKekZBMkhtaEVjODJJVnQ2NktOak1HRXdEZ1lEVlIwUEFRSC9CQVFEQWdHR01BOEcKQTFVZEV3RUIvd1FGTUFNQkFmOHdIUVlEVlIwT0JCWUVGQ005UzdyaXp5MkFyWWhpQVJCdXRPWDdEVFBhTUI4RwpBMVVkSXdRWU1CYUFGRUxLMDFHdG12ejk5a1R2SU01aWR6T0x4ZXJJTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDCklHNENucWtiK2F0YkZJQWVURnlJUjR2M0FCaTBDalB1YjA3eG50L2J2TjZGQWlFQXhneVc1c2liZnc3ejMveGMKUW5BMHc2OHNLbVZSWmh2ZlVOTVlrcWJrLzJ3PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
+ "encoding": "PEM"
+ },
+ "id": "0",
+ "subject": "d9dde79c-3916-433b-4789-ca10aad6fc4a",
+ "usage": "CERT"
+ },
+ {
+ "subject": "beb32777-9680-4f42-8761-350eebe76a85",
+ "usage": "TRUST_CA",
+ "id": "0",
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ],
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lSQUlwR0Jrb0U2ZXdwdFJMT1FaMXZrb1V3Q2dZSUtvWkl6ajBFQXdJd0hURWIKTUJrR0ExVUVBeE1TY205dmRDNWpZUzV3Ykdka0xtTnNiM1ZrTUNBWERUSXpNVEF4T1RBNE5EZ3hOVm9ZRHpJeApNak13T1RJMU1EZzBPREUxV2pBZE1Sc3dHUVlEVlFRREV4SnliMjkwTG1OaExuQnNaMlF1WTJ4dmRXUXdXVEFUCkJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFtMHgrMTZCdWt2ditIV0FlcnkvMG8vVlFBTzhib3hzNHcKT2lhWFRybDBhbi9iUkR6REFwc1J2cDY5SHdJY2haS0FjZTVPQ3JkZFNpVVJOdDZRZWYwQ28wSXdRREFPQmdOVgpIUThCQWY4RUJBTUNBUVl3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVUXNyVFVhMmEvUDMyClJPOGd6bUozTTR2RjZzZ3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdOMHBnS1N4d2RvUklkV1RxaTdUcDd0eVAKb05LNERxeElsWWJuRUlJb3BlZ0NJUURsd2FUMmg2RUtaM1R3SHFBcTU1UXl3TDM3RzJwdjVKOE03dDFFcVBnQQpZQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
+ "encoding": "PEM"
+ }
+ }
+ ]
+ },
+ "acl": {
+ "status": {
+ "coapCode": 69,
+ "date": "1719474938340859252"
+ },
+ "accessControlList": [
+ {
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "href": "/CoapCloudConfResURI",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/sec/sp",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/mnt"
+ },
+ {
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ],
+ "deviceSubject": {
+ "deviceId": "beb32777-9680-4f42-8761-350eebe76a85"
+ }
+ },
+ {
+ "connectionSubject": {
+ "type": "ANON_CLEAR"
+ },
+ "permissions": [
+ "READ"
+ ],
+ "resources": [
+ {
+ "href": "/oic/d",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/p"
+ },
+ {
+ "href": "/oic/res",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/sec/sdi",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "wildcard": "NONE",
+ "href": "/oic/sec/doxm",
+ "interfaces": [
+ "*"
+ ]
+ }
+ ]
+ },
+ {
+ "deviceSubject": {
+ "deviceId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ },
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/mnt"
+ },
+ {
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ]
+ }
+ ]
+ },
+ "ownership": {
+ "status": {
+ "coapCode": 69,
+ "date": "1719474938266133666"
+ },
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "plgdTime": {
+ "date": "1719474938192355476",
+ "coapCode": 69
+ },
+ "localEndpoints": [
+ "coap://10.110.110.12:41885",
+ "coaps://10.110.110.12:49997",
+ "coap+tcp://10.110.110.12:35389",
+ "coaps+tcp://10.110.110.12:33711"
+ ]
+ }
+ },{
+ "result": {
+ "attestation": {
+ "date": "1717157743336135946",
+ "x509": {
+ "commonName": "MfgCert1",
+ "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIBhTCCASugAwIBAgIRAJ+UC+MPMl6jc9FVeHZEgB4wCgYIKoZIzj0EAwIwFDES\nMBAGA1UEAxMJTWZnUm9vdENBMCAXDTIzMTIxMTEyNTIwMVoYDzIxMjMxMTE3MTI1\nMjAxWjATMREwDwYDVQQDEwhNZmdDZXJ0MTBZMBMGByqGSM49AgEGCCqGSM49AwEH\nA0IABFU2BHkqcNsiN68hGoFGzk+QtK78su3HpObu0U6Yhq5tnbGffQ4oTcel4Lhx\nlW5FHWUPI/l2LV9Ej/i3DSaurs6jXTBbMB8GA1UdIwQYMBaAFFyGFDlvMWlF0wb8\n0yDIfbRH7lTPMAwGA1UdEwQFMAMBAQAwCwYDVR0PBAQDAgOIMB0GA1UdJQQWMBQG\nCCsGAQUFBwMCBggrBgEFBQcDATAKBggqhkjOPQQDAgNIADBFAiBM31BMFp/ImqVt\nwH55aaqYSYp00pabSyIbKwFle6B+2wIhAMqXjZ3zoEECNU7zUo/hpYPTqanak2t6\ndPVwtlKcRlPx\n-----END CERTIFICATE-----\n"
+ }
+ },
+ "cloud": {
+ "gateways": [
+ {
+ "uri": "coaps+tcp://try.plgd.cloud:5684",
+ "id": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ }
+ ],
+ "selectedGateway": 0,
+ "status": {
+ "coapCode": 68,
+ "date": "1717157743426800468"
+ },
+ "providerName": "plgd.dps"
+ },
+ "ownership": {
+ "status": {
+ "date": "1717157743352900277",
+ "coapCode": 69
+ },
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "plgdTime": {
+ "date": "1717157743283612068",
+ "coapCode": 69
+ },
+ "id": "4a0d78b2-9a21-557d-ab08-bb4eaccfcbb0",
+ "deviceId": "bcd30976-10e4-4145-5282-eb50ee55dfae",
+ "creationDate": "1716656687662199144",
+ "localEndpoints": [
+ "coap://10.110.110.12:45396",
+ "coaps://10.110.110.12:52852",
+ "coap+tcp://10.110.110.12:51863",
+ "coaps+tcp://10.110.110.12:38145"
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "enrollmentGroupId": "4f0d3d81-0e09-4f1e-9706-0997488011af",
+ "credential": {
+ "identityCertificatePem": "-----BEGIN CERTIFICATE-----\nMIIBojCCAUigAwIBAgIQIm1TIO0PH7O+w+LXTfV1KTAKBggqhkjOPQQDAjASMRAw\nDgYDVQQDEwdwbGdkLWNhMB4XDTI0MDUzMTExMTU0M1oXDTI1MDUyNTE3MDI1MVow\nNDEyMDAGA1UEAxMpdXVpZDpiY2QzMDk3Ni0xMGU0LTQxNDUtNTI4Mi1lYjUwZWU1\nNWRmYWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQK9W+P4MDWdABFVSgZOWnW\nDGEkU8abmg2zVW1MlGPZF4YKpKWEUIoqeVxpm5D/yKtzG15uuvx3U2oU3UbRGL5t\no14wXDAOBgNVHQ8BAf8EBAMCA4gwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUF\nBwMBBgorBgEEAYLefAEGMB8GA1UdIwQYMBaAFCM9S7rizy2ArYhiARButOX7DTPa\nMAoGCCqGSM49BAMCA0gAMEUCIBMdkdXzDBJgThKP3Q1hTV/XzigwlSe7+YlXoINl\ngW8DAiEA7f9ghvAZzBbep1sMDmcTFFLquzAPNsRBSCkSquyYUNQ=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBkDCCATagAwIBAgIQFq/ergts3Jlaxk3N92FfzTAKBggqhkjOPQQDAjAdMRsw\nGQYDVQQDExJyb290LmNhLnBsZ2QuY2xvdWQwHhcNMjQwNTI1MTcwMjUxWhcNMjUw\nNTI1MTcwMjUxWjASMRAwDgYDVQQDEwdwbGdkLWNhMFkwEwYHKoZIzj0CAQYIKoZI\nzj0DAQcDQgAE5s5zak9SL6OCMM49iyJYpNvnHly3UVdTe4jaAxmMS2YM63e68Cix\nevhl849SzCnpoD9yJzFA2HmhEc82IVt66KNjMGEwDgYDVR0PAQH/BAQDAgGGMA8G\nA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFCM9S7rizy2ArYhiARButOX7DTPaMB8G\nA1UdIwQYMBaAFELK01Gtmvz99kTvIM5idzOLxerIMAoGCCqGSM49BAMCA0gAMEUC\nIG4Cnqkb+atbFIAeTFyIR4v3ABi0CjPub07xnt/bvN6FAiEAxgyW5sibfw7z3/xc\nQnA0w68sKmVRZhvfUNMYkqbk/2w=\n-----END CERTIFICATE-----\n",
+ "credentials": [
+ {
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJvakNDQVVpZ0F3SUJBZ0lRSW0xVElPMFBIN08rdytMWFRmVjFLVEFLQmdncWhrak9QUVFEQWpBU01SQXcKRGdZRFZRUURFd2R3Ykdka0xXTmhNQjRYRFRJME1EVXpNVEV4TVRVME0xb1hEVEkxTURVeU5URTNNREkxTVZvdwpOREV5TURBR0ExVUVBeE1wZFhWcFpEcGlZMlF6TURrM05pMHhNR1UwTFRReE5EVXROVEk0TWkxbFlqVXdaV1UxCk5XUm1ZV1V3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFLOVcrUDRNRFdkQUJGVlNnWk9XblcKREdFa1U4YWJtZzJ6VlcxTWxHUFpGNFlLcEtXRVVJb3FlVnhwbTVEL3lLdHpHMTV1dXZ4M1Uyb1UzVWJSR0w1dApvMTR3WERBT0JnTlZIUThCQWY4RUJBTUNBNGd3S1FZRFZSMGxCQ0l3SUFZSUt3WUJCUVVIQXdJR0NDc0dBUVVGCkJ3TUJCZ29yQmdFRUFZTGVmQUVHTUI4R0ExVWRJd1FZTUJhQUZDTTlTN3JpenkyQXJZaGlBUkJ1dE9YN0RUUGEKTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDSUJNZGtkWHpEQkpnVGhLUDNRMWhUVi9Yemlnd2xTZTcrWWxYb0lObApnVzhEQWlFQTdmOWdodkFaekJiZXAxc01EbWNURkZMcXV6QVBOc1JCU0NrU3F1eVlVTlE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJrRENDQVRhZ0F3SUJBZ0lRRnEvZXJndHMzSmxheGszTjkyRmZ6VEFLQmdncWhrak9QUVFEQWpBZE1Sc3cKR1FZRFZRUURFeEp5YjI5MExtTmhMbkJzWjJRdVkyeHZkV1F3SGhjTk1qUXdOVEkxTVRjd01qVXhXaGNOTWpVdwpOVEkxTVRjd01qVXhXakFTTVJBd0RnWURWUVFERXdkd2JHZGtMV05oTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJCnpqMERBUWNEUWdBRTVzNXphazlTTDZPQ01NNDlpeUpZcE52bkhseTNVVmRUZTRqYUF4bU1TMllNNjNlNjhDaXgKZXZobDg0OVN6Q25wb0Q5eUp6RkEySG1oRWM4MklWdDY2S05qTUdFd0RnWURWUjBQQVFIL0JBUURBZ0dHTUE4RwpBMVVkRXdFQi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZDTTlTN3JpenkyQXJZaGlBUkJ1dE9YN0RUUGFNQjhHCkExVWRJd1FZTUJhQUZFTEswMUd0bXZ6OTlrVHZJTTVpZHpPTHhlcklNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUMKSUc0Q25xa2IrYXRiRklBZVRGeUlSNHYzQUJpMENqUHViMDd4bnQvYnZONkZBaUVBeGd5VzVzaWJmdzd6My94YwpRbkEwdzY4c0ttVlJaaHZmVU5NWWtxYmsvMnc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
+ "encoding": "PEM"
+ },
+ "subject": "bcd30976-10e4-4145-5282-eb50ee55dfae",
+ "usage": "CERT",
+ "id": "0",
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ]
+ },
+ {
+ "id": "0",
+ "type": [
+ "ASYMMETRIC_SIGNING_WITH_CERTIFICATE"
+ ],
+ "subject": "beb32777-9680-4f42-8761-350eebe76a85",
+ "usage": "TRUST_CA",
+ "publicData": {
+ "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmVENDQVNPZ0F3SUJBZ0lSQUlwR0Jrb0U2ZXdwdFJMT1FaMXZrb1V3Q2dZSUtvWkl6ajBFQXdJd0hURWIKTUJrR0ExVUVBeE1TY205dmRDNWpZUzV3Ykdka0xtTnNiM1ZrTUNBWERUSXpNVEF4T1RBNE5EZ3hOVm9ZRHpJeApNak13T1RJMU1EZzBPREUxV2pBZE1Sc3dHUVlEVlFRREV4SnliMjkwTG1OaExuQnNaMlF1WTJ4dmRXUXdXVEFUCkJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFtMHgrMTZCdWt2ditIV0FlcnkvMG8vVlFBTzhib3hzNHcKT2lhWFRybDBhbi9iUkR6REFwc1J2cDY5SHdJY2haS0FjZTVPQ3JkZFNpVVJOdDZRZWYwQ28wSXdRREFPQmdOVgpIUThCQWY4RUJBTUNBUVl3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVUXNyVFVhMmEvUDMyClJPOGd6bUozTTR2RjZzZ3dDZ1lJS29aSXpqMEVBd0lEU0FBd1JRSWdOMHBnS1N4d2RvUklkV1RxaTdUcDd0eVAKb05LNERxeElsWWJuRUlJb3BlZ0NJUURsd2FUMmg2RUtaM1R3SHFBcTU1UXl3TDM3RzJwdjVKOE03dDFFcVBnQQpZQT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
+ "encoding": "PEM"
+ }
+ }
+ ],
+ "status": {
+ "date": "1717157743461436598",
+ "coapCode": 68
+ }
+ },
+ "acl": {
+ "status": {
+ "date": "1717157743480774484",
+ "coapCode": 69
+ },
+ "accessControlList": [
+ {
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "href": "/CoapCloudConfResURI",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/sec/sp",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/mnt"
+ },
+ {
+ "wildcard": "NONE",
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ]
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ],
+ "deviceSubject": {
+ "deviceId": "beb32777-9680-4f42-8761-350eebe76a85"
+ }
+ },
+ {
+ "connectionSubject": {
+ "type": "ANON_CLEAR"
+ },
+ "permissions": [
+ "READ"
+ ],
+ "resources": [
+ {
+ "href": "/oic/d",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "href": "/oic/p",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/res"
+ },
+ {
+ "href": "/oic/sec/sdi",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE",
+ "href": "/oic/sec/doxm"
+ }
+ ]
+ },
+ {
+ "deviceSubject": {
+ "deviceId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ },
+ "permissions": [
+ "CREATE",
+ "READ",
+ "WRITE",
+ "DELETE",
+ "NOTIFY"
+ ],
+ "resources": [
+ {
+ "href": "/oc/con",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "wildcard": "NONE",
+ "href": "/oc/swu",
+ "interfaces": [
+ "*"
+ ]
+ },
+ {
+ "href": "/oic/mnt",
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONE"
+ },
+ {
+ "wildcard": "NONE",
+ "href": "/x.plgd.dev/time",
+ "interfaces": [
+ "*"
+ ]
+ },
+ {
+ "interfaces": [
+ "*"
+ ],
+ "wildcard": "NONCFG_ALL"
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
+]
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/pending-commands.json b/http-gateway/web/packages/mock-server/src/data/pending-commands.json
index 0ab710b6d..f827e419f 100644
--- a/http-gateway/web/packages/mock-server/src/data/pending-commands.json
+++ b/http-gateway/web/packages/mock-server/src/data/pending-commands.json
@@ -1,50 +1,82 @@
[
{
- "resourceUpdatePending": {
- "resourceId": {
- "deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
- "href": "/light/1"
- },
- "content": {
- "state": false,
- "power": 1,
- "powera": 1,
- "powerb": 1,
- "powerc": 1,
- "powerd": 1,
- "powere": 1,
- "powerf": 1,
- "powerg": 1,
- "powerh": 1,
- "poweri": 1,
- "powerj": 1,
- "powerk": 1,
- "powerl": 1,
- "powerm": 1,
- "powern": 1,
- "powero": 1,
- "powerp": 1,
- "powerq": 1,
- "powerr": 1,
- "name": "Light"
- },
- "auditContext": {
- "correlationId": "a3e05bc0-205a-48b1-92ed-78ea0b23e78f",
- "userId": "98120ad9-eefa-4b93-aa53-696420b639fd"
- },
- "eventMetadata": {
- "connectionId": "10.1.65.233:38320",
- "sequence": "0",
- "version": "4",
- "timestamp": "1679950925732370668"
- },
- "validUntil": "1679950935732388581",
- "openTelemetryCarrier": {
- "traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
+ "result": {
+ "resourceUpdatePending": {
+ "resourceId": {
+ "deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
+ "href": "/light/1"
+ },
+ "content": {
+ "state": false,
+ "power": 1,
+ "powera": 1,
+ "powerb": 1,
+ "powerc": 1,
+ "powerd": 1,
+ "powere": 1,
+ "powerf": 1,
+ "powerg": 1,
+ "powerh": 1,
+ "poweri": 1,
+ "powerj": 1,
+ "powerk": 1,
+ "powerl": 1,
+ "powerm": 1,
+ "powern": 1,
+ "powero": 1,
+ "powerp": 1,
+ "powerq": 1,
+ "powerr": 1,
+ "name": "Light"
+ },
+ "auditContext": {
+ "correlationId": "a3e05bc0-205a-48b1-92ed-78ea0b23e78f",
+ "userId": "98120ad9-eefa-4b93-aa53-696420b639fd"
+ },
+ "eventMetadata": {
+ "connectionId": "10.1.65.233:38320",
+ "sequence": "0",
+ "version": "4",
+ "timestamp": "1679950925732370668"
+ },
+ "validUntil": "1679950935732388581",
+ "openTelemetryCarrier": {
+ "traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
+ }
+ }
+ }
+},
+{
+ "result": {
+ "resourceUpdatePending": {
+ "resourceId": {
+ "deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
+ "href": "/light/1"
+ },
+ "content": {
+ "state": false,
+ "power": 1,
+ "name": "Light"
+ },
+ "auditContext": {
+ "correlationId": "a3e05bc0-205a-48b1-92ed-78ea0b23e78f",
+ "userId": "98120ad9-eefa-4b93-aa53-696420b639fd"
+ },
+ "eventMetadata": {
+ "connectionId": "10.1.65.233:38320",
+ "sequence": "0",
+ "version": "4",
+ "timestamp": "1679950925732370668"
+ },
+ "validUntil": "1679950935732388581",
+ "openTelemetryCarrier": {
+ "traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
+ }
}
}
- },
- {
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -69,9 +101,11 @@
"openTelemetryCarrier": {
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
- }
- },
- {
+ }
+}
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -97,8 +131,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+}
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -124,8 +160,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+ }
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -151,8 +189,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+ }
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -178,8 +218,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+ }
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -205,8 +247,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+}
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -232,8 +276,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+}
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -259,8 +305,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+}
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -286,8 +334,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+}
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -313,8 +363,10 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
- {
+}
+},
+{
+ "result": {
"resourceUpdatePending": {
"resourceId": {
"deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
@@ -340,59 +392,59 @@
"traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
}
}
- },
+ }
+},
{
- "resourceUpdatePending": {
- "resourceId": {
- "deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
- "href": "/light/1"
- },
- "content": {
- "state": false,
- "power": 1,
- "name": "Light"
- },
- "auditContext": {
- "correlationId": "a3e05bc0-205a-48b1-92ed-78ea0b23e78f",
- "userId": "98120ad9-eefa-4b93-aa53-696420b639fd"
- },
- "eventMetadata": {
- "connectionId": "10.1.65.233:38320",
- "sequence": "0",
- "version": "4",
- "timestamp": "1679950925732370668"
- },
- "validUntil": "1679950935732388581",
- "openTelemetryCarrier": {
- "traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
+ "result": {
+ "resourceUpdatePending": {
+ "resourceId": {
+ "deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
+ "href": "/light/1"
+ },
+ "content": {
+ "state": false,
+ "power": 1,
+ "name": "Light"
+ },
+ "auditContext": {
+ "correlationId": "a3e05bc0-205a-48b1-92ed-78ea0b23e78f",
+ "userId": "98120ad9-eefa-4b93-aa53-696420b639fd"
+ },
+ "eventMetadata": {
+ "connectionId": "10.1.65.233:38320",
+ "sequence": "0",
+ "version": "4",
+ "timestamp": "1679950925732370668"
+ },
+ "validUntil": "1679950935732388581",
+ "openTelemetryCarrier": {
+ "traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
+ }
}
}
},
{
- "resourceUpdatePending": {
- "resourceId": {
- "deviceId": "9c387d90-6ca4-4473-4b6c-f4fb2f8ad0e9",
- "href": "/light/1"
- },
- "content": {
- "state": false,
- "power": 1,
- "name": "Light"
- },
- "auditContext": {
- "correlationId": "a3e05bc0-205a-48b1-92ed-78ea0b23e78f",
- "userId": "98120ad9-eefa-4b93-aa53-696420b639fd"
- },
- "eventMetadata": {
- "connectionId": "10.1.65.233:38320",
- "sequence": "0",
- "version": "4",
- "timestamp": "1679950925732370668"
- },
- "validUntil": "1679950935732388581",
- "openTelemetryCarrier": {
- "traceparent": "00-8177df6ddb079f50d1eef17eb893b048-992be580d42978b1-01"
+ "result": {
+ "resourceUpdatePending": {
+ "eventMetadata": {
+ "version": "2",
+ "timestamp": "1718962348706048929",
+ "connectionId": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "sequence": "0",
+ "hubId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ },
+ "validUntil": "1719480748706050211",
+ "resourceId": {
+ "deviceId": "bcd30976-10e4-4145-5282-eb50ee55dfae",
+ "href": "/not/existing"
+ },
+ "content": 123456,
+ "auditContext": {
+ "correlationId": "b3e46873-228b-403e-ad91-b5f97be3b3d7",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "userId": "beb32777-9680-4f42-8761-350eebe76a85"
+ }
}
}
}
-]
\ No newline at end of file
+]
diff --git a/http-gateway/web/packages/mock-server/src/data/snippet-service/applied-configurations/list/httpConfigurationIdFilter-48998f7d-2a70-46a4-8a68-745b69d55489.json b/http-gateway/web/packages/mock-server/src/data/snippet-service/applied-configurations/list/httpConfigurationIdFilter-48998f7d-2a70-46a4-8a68-745b69d55489.json
new file mode 100644
index 000000000..f56e8a539
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/snippet-service/applied-configurations/list/httpConfigurationIdFilter-48998f7d-2a70-46a4-8a68-745b69d55489.json
@@ -0,0 +1,272 @@
+[
+ {
+ "result": {
+ "resources": [
+ {
+ "resourceUpdated": {
+ "auditContext": {
+ "correlationId": "8d140cad-62ac-4fff-aa8f-48f413ca85ca.412a4dd7-3c9b-4dcb-9696-1f0eb6918a6d",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "eventMetadata": {
+ "version": "0",
+ "timestamp": "0",
+ "connectionId": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "sequence": "0"
+ },
+ "resourceId": {
+ "deviceId": "7b645eab-01c3-483a-6289-98fc24e32bc1",
+ "href": "/not/existing"
+ },
+ "status": "ERROR",
+ "content": "pending resource update canceled"
+ },
+ "validUntil": "0",
+ "href": "/not/existing",
+ "correlationId": "8d140cad-62ac-4fff-aa8f-48f413ca85ca.412a4dd7-3c9b-4dcb-9696-1f0eb6918a6d",
+ "status": "DONE"
+ },
+ {
+ "status": "DONE",
+ "resourceUpdated": {
+ "resourceId": {
+ "deviceId": "7b645eab-01c3-483a-6289-98fc24e32bc1",
+ "href": "/oc/con"
+ },
+ "status": "CANCELED",
+ "auditContext": {
+ "userId": "beb32777-9680-4f42-8761-350eebe76a85",
+ "correlationId": "8d140cad-62ac-4fff-aa8f-48f413ca85ca.55d8f61c-f85b-4a0c-aaba-c77f237600dd",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "eventMetadata": {
+ "version": "2",
+ "timestamp": "1719582951907143230",
+ "connectionId": "10.1.65.223:46696",
+ "sequence": "0",
+ "hubId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ },
+ "resourceTypes": [
+ "oic.wk.con"
+ ]
+ },
+ "validUntil": "0",
+ "href": "/oc/con",
+ "correlationId": "8d140cad-62ac-4fff-aa8f-48f413ca85ca.55d8f61c-f85b-4a0c-aaba-c77f237600dd"
+ }
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "timestamp": "1719817002027697453",
+ "id": "8d140cad-62ac-4fff-aa8f-48f413ca85ca",
+ "deviceId": "7b645eab-01c3-483a-6289-98fc24e32bc1",
+ "configurationId": {
+ "id": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "version": "0"
+ },
+ "onDemand": true
+ }
+ },
+ {
+ "result": {
+ "onDemand": true,
+ "resources": [
+ {
+ "href": "/not/existing",
+ "correlationId": "0f9dc817-333f-4556-9888-c01ed2676478.dd79c0ab-004f-43e3-bc03-58c8c44c6fcd",
+ "status": "DONE",
+ "resourceUpdated": {
+ "status": "ERROR",
+ "content": "pending resource update canceled",
+ "auditContext": {
+ "correlationId": "0f9dc817-333f-4556-9888-c01ed2676478.dd79c0ab-004f-43e3-bc03-58c8c44c6fcd",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "eventMetadata": {
+ "connectionId": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "sequence": "0",
+ "version": "0",
+ "timestamp": "0"
+ },
+ "resourceId": {
+ "deviceId": "bcd30976-10e4-4145-5282-eb50ee55dfae",
+ "href": "/not/existing"
+ }
+ },
+ "validUntil": "0"
+ },
+ {
+ "href": "/oc/con",
+ "correlationId": "0f9dc817-333f-4556-9888-c01ed2676478.75be0ddc-e1e0-4738-9a88-b704ae0fc248",
+ "status": "DONE",
+ "resourceUpdated": {
+ "resourceTypes": [
+ "oic.wk.con"
+ ],
+ "resourceId": {
+ "deviceId": "bcd30976-10e4-4145-5282-eb50ee55dfae",
+ "href": "/oc/con"
+ },
+ "status": "OK",
+ "content": {
+ "n": "prezentacia dankovi"
+ },
+ "auditContext": {
+ "userId": "1e3a67e3-ec52-42e2-8bb0-aae61d4af7c8",
+ "correlationId": "0f9dc817-333f-4556-9888-c01ed2676478.75be0ddc-e1e0-4738-9a88-b704ae0fc248",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "eventMetadata": {
+ "version": "281",
+ "timestamp": "1719595063306772686",
+ "connectionId": "10.110.110.10:30226",
+ "sequence": "10159",
+ "hubId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ }
+ },
+ "validUntil": "0"
+ }
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "timestamp": "1719817002006350403",
+ "id": "0f9dc817-333f-4556-9888-c01ed2676478",
+ "deviceId": "bcd30976-10e4-4145-5282-eb50ee55dfae",
+ "configurationId": {
+ "id": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "version": "0"
+ }
+ }
+},
+ {
+ "result": {
+ "deviceId": "d9dde79c-3916-433b-4789-ca10aad6fc4a",
+ "configurationId": {
+ "id": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "version": "0"
+ },
+ "onDemand": true,
+ "resources": [
+ {
+ "status": "DONE",
+ "resourceUpdated": {
+ "resourceId": {
+ "deviceId": "d9dde79c-3916-433b-4789-ca10aad6fc4a",
+ "href": "/not/existing"
+ },
+ "status": "ERROR",
+ "content": "pending resource update canceled",
+ "auditContext": {
+ "correlationId": "9dae740f-a598-4411-8cd0-cbf7c804426a.a0c76318-6f04-4c04-9c98-c0f87a0e8a1f",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "eventMetadata": {
+ "connectionId": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "sequence": "0",
+ "version": "0",
+ "timestamp": "0"
+ }
+ },
+ "validUntil": "0",
+ "href": "/not/existing",
+ "correlationId": "9dae740f-a598-4411-8cd0-cbf7c804426a.a0c76318-6f04-4c04-9c98-c0f87a0e8a1f"
+ },
+ {
+ "status": "DONE",
+ "resourceUpdated": {
+ "resourceId": {
+ "deviceId": "d9dde79c-3916-433b-4789-ca10aad6fc4a",
+ "href": "/oc/con"
+ },
+ "status": "OK",
+ "content": {
+ "n": "prezentacia dankovi"
+ },
+ "auditContext": {
+ "correlationId": "9dae740f-a598-4411-8cd0-cbf7c804426a.38e0d0de-4b86-468f-8a61-e7e5df3edf98",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "userId": "1e3a67e3-ec52-42e2-8bb0-aae61d4af7c8"
+ },
+ "eventMetadata": {
+ "version": "5",
+ "timestamp": "1719595063306023868",
+ "connectionId": "10.110.110.10:56076",
+ "sequence": "10153",
+ "hubId": "1c10a3b6-287c-11ec-ac2d-13054959c274"
+ },
+ "resourceTypes": [
+ "oic.wk.con"
+ ]
+ },
+ "validUntil": "0",
+ "href": "/oc/con",
+ "correlationId": "9dae740f-a598-4411-8cd0-cbf7c804426a.38e0d0de-4b86-468f-8a61-e7e5df3edf98"
+ }
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "timestamp": "1719817002023535166",
+ "id": "9dae740f-a598-4411-8cd0-cbf7c804426a"
+ }
+},
+ {
+ "result": {
+ "timestamp": "1719595103190656748",
+ "id": "40cab4b8-e9d6-47d7-bd70-4daa85c094ad",
+ "deviceId": "wdsw",
+ "configurationId": {
+ "id": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "version": "0"
+ },
+ "onDemand": true,
+ "resources": [
+ {
+ "validUntil": "0",
+ "href": "/not/existing",
+ "correlationId": "40cab4b8-e9d6-47d7-bd70-4daa85c094ad.18830e29-5204-4fc9-a76f-91ab65409431",
+ "status": "DONE",
+ "resourceUpdated": {
+ "status": "ERROR",
+ "content": "rpc error: code = PermissionDenied desc = cannot validate user access: rpc error: code = PermissionDenied desc = access denied",
+ "auditContext": {
+ "correlationId": "40cab4b8-e9d6-47d7-bd70-4daa85c094ad.18830e29-5204-4fc9-a76f-91ab65409431",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "eventMetadata": {
+ "version": "0",
+ "timestamp": "0",
+ "connectionId": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "sequence": "0"
+ },
+ "resourceId": {
+ "deviceId": "wdsw",
+ "href": "/not/existing"
+ }
+ }
+ },
+ {
+ "href": "/oc/con",
+ "correlationId": "40cab4b8-e9d6-47d7-bd70-4daa85c094ad.d4de7422-8543-4a67-bb25-4f41e1fc7e6d",
+ "status": "DONE",
+ "resourceUpdated": {
+ "resourceId": {
+ "deviceId": "wdsw",
+ "href": "/oc/con"
+ },
+ "status": "ERROR",
+ "content": "rpc error: code = PermissionDenied desc = cannot validate user access: rpc error: code = PermissionDenied desc = access denied",
+ "auditContext": {
+ "correlationId": "40cab4b8-e9d6-47d7-bd70-4daa85c094ad.d4de7422-8543-4a67-bb25-4f41e1fc7e6d",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ },
+ "eventMetadata": {
+ "sequence": "0",
+ "version": "0",
+ "timestamp": "0",
+ "connectionId": "48998f7d-2a70-46a4-8a68-745b69d55489"
+ }
+ },
+ "validUntil": "0"
+ }
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85"
+ }
+}
+]
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/snippet-service/conditions/list/list.json b/http-gateway/web/packages/mock-server/src/data/snippet-service/conditions/list/list.json
new file mode 100644
index 000000000..2667ea980
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/snippet-service/conditions/list/list.json
@@ -0,0 +1,18 @@
+[
+ {
+ "result": {
+ "id": "00fa41ad-b3bf-4f00-bfe1-c71c439e4cda",
+ "enabled": true,
+ "jqExpressionFilter": ".n == \"new name value\"",
+ "version": "6",
+ "name": "jkralik-cond-0",
+ "configurationId": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "resourceHrefFilter": [
+ "/oic/d"
+ ],
+ "apiAccessToken": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJRQkp3R192eHhVSUNXVjFlZjRlOHlFamgtVHZmYW1FWFBMZGt4WGtENU1jIn0.eyJleHAiOjE3MTk1MDE1MTcsImlhdCI6MTcxOTQ5NDMxNywiYXV0aF90aW1lIjoxNzE5NDc0NzA3LCJqdGkiOiJhM2UyYjU2OC0zYWY4LTQ2ZDMtOGJlOC1jMDMyYWU5NDM0YTgiLCJpc3MiOiJodHRwczovL2F1dGgucGxnZC5jbG91ZC9yZWFsbXMvc2hhcmVkIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImJlYjMyNzc3LTk2ODAtNGY0Mi04NzYxLTM1MGVlYmU3NmE4NSIsInR5cCI6IkJlYXJlciIsImF6cCI6IkxYWjlPaEtXV1JZcWYxMlcwQjVPWGR1cXQwMnEwempTIiwic2Vzc2lvbl9zdGF0ZSI6ImRlYzBhNjk5LWE2NWYtNDcxYy05MGMyLWNlZTAwM2VmMDIxMCIsImFjciI6IjAiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovLzEyNy4wLjAuMTozMDAwIiwiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwiaHR0cHM6Ly90cnkucGxnZC5jbG91ZCJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1zaGFyZWQiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgZW1haWwgcHJvZmlsZSIsInNpZCI6ImRlYzBhNjk5LWE2NWYtNDcxYy05MGMyLWNlZTAwM2VmMDIxMCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJvd25lci1pZCI6ImJlYjMyNzc3LTk2ODAtNGY0Mi04NzYxLTM1MGVlYmU3NmE4NSIsIm5hbWUiOiJUZXN0IFRlc3QiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0LnVzZXIub2NmY2xvdWRAZ21haWwuY29tIiwiZ2l2ZW5fbmFtZSI6IlRlc3QiLCJmYW1pbHlfbmFtZSI6IlRlc3QiLCJlbWFpbCI6InRlc3QudXNlci5vY2ZjbG91ZEBnbWFpbC5jb20ifQ.aL52J-JuGuW_2R2x33pAVUX3fxJzPcz7OUeqvrPaijOqikOiQSwDyVdt0QIJtD2WBq0StTI-YqSHpt01Kpy1CgUricVWXoCI1j9eRBgveQ7zwiWKqNa1-ctXOHmDugVwSuhYoNBUP94qK1yrTFxSU5Lamj8l7H6pN4KVOMhs48Xbn-EJ7DPbJJ7Z26fJaYwj2P-e_ucV5JrIDPzSGRCBsXpqGlm6w2E2Z-SbwRclU4Xvf7V44bIJLFOV8wS0PrIz030n41F52c0dF1CC-ebnRQsFih6unR0l6J1P2sVoM4EKnR-mVIzfxmCxpXgduIaQU-jVo420vMrgCmluc23vnw",
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "timestamp": "1719494607886702017"
+ }
+ }
+]
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/snippet-service/configurations/detail/48998f7d-2a70-46a4-8a68-745b69d55489.json b/http-gateway/web/packages/mock-server/src/data/snippet-service/configurations/detail/48998f7d-2a70-46a4-8a68-745b69d55489.json
new file mode 100644
index 000000000..26e548bd8
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/snippet-service/configurations/detail/48998f7d-2a70-46a4-8a68-745b69d55489.json
@@ -0,0 +1,50 @@
+[
+ {
+ "result": {
+ "id": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "version": "0",
+ "name": "my-cfg-1",
+ "resources": [
+ {
+ "href": "/not/existing",
+ "content": 123456,
+ "timeToLive": "0"
+ },
+ {
+ "timeToLive": "0",
+ "href": "/oc/con",
+ "content": {
+ "n": "prezentacia dankovi"
+ }
+ }
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "timestamp": "1718961203704580832"
+ }
+ },
+ {
+ "result": {
+ "id": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "version": "1",
+ "name": "my-cfg-11",
+ "resources": [
+ {
+ "href": "/not/existing",
+ "content": 123456,
+ "timeToLive": "0"
+ },
+ {
+ "href": "/oc/con",
+ "content": {
+ "data": "W29iamVjdCBPYmplY3Rd",
+ "contentType": "application/json",
+ "coapContentFormat": -1
+ },
+ "timeToLive": "0"
+ }
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "timestamp": "1719739387326389953"
+ }
+}
+]
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/data/snippet-service/configurations/list/list.json b/http-gateway/web/packages/mock-server/src/data/snippet-service/configurations/list/list.json
new file mode 100644
index 000000000..a941dd07c
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/data/snippet-service/configurations/list/list.json
@@ -0,0 +1,25 @@
+[
+ {
+ "result": {
+ "id": "48998f7d-2a70-46a4-8a68-745b69d55489",
+ "version": "1",
+ "name": "my-cfg-1",
+ "resources": [
+ {
+ "href": "/not/existing",
+ "content": 123456,
+ "timeToLive": "0"
+ },
+ {
+ "href": "/oc/con",
+ "content": {
+ "n": "prezentacia dankovi"
+ },
+ "timeToLive": "0"
+ }
+ ],
+ "owner": "beb32777-9680-4f42-8761-350eebe76a85",
+ "timestamp": "1718961203704580832"
+ }
+ }
+]
\ No newline at end of file
diff --git a/http-gateway/web/packages/mock-server/src/index.js b/http-gateway/web/packages/mock-server/src/index.js
index b03978aa2..45f303a15 100644
--- a/http-gateway/web/packages/mock-server/src/index.js
+++ b/http-gateway/web/packages/mock-server/src/index.js
@@ -1,25 +1,15 @@
const express = require('express')
-const { check, validationResult } = require('express-validator')
const cors = require('cors')
-const path = require('path')
+const axios = require('axios')
+const { checkError, loadResponseStreamFromFile } = require('./utils')
+
+const devices = require('./routes/devices')
+const dps = require('./routes/dps')
+const snippetService = require('./routes/snippet-service')
const app = express()
const port = 8181
-let deletedDevice = false
-let resourceColorUpdatedValue = false
-
-const deviceIdCheck = [check('deviceId').notEmpty().withMessage('Device ID must be alphanumeric')]
-
-const checkError = (req, res) => {
- const errors = validationResult(req)
- if (!errors.isEmpty()) {
- return res.status(400).json({ errors: errors.array() })
- }
-
- console.log(`${req.method}`, req.url)
-}
-
app.use(
cors({
origin: '*',
@@ -27,116 +17,46 @@ app.use(
})
)
-const loadResponseFromFile = (file, res) => {
- const targetDirectory = `${__dirname}/data`
-
- res.sendFile(file, { root: targetDirectory })
-}
-
-// ----- DEVICES -----
-app.get('/api/v1/devices', function (req, res) {
- console.log(`${req.method}`, req.url)
-
- if (deletedDevice) {
- loadResponseFromFile(path.join('devices', 'list', 'list-deleted-state.json'), res)
- } else {
- loadResponseFromFile(path.join('devices', 'list', 'list.json'), res)
- }
-})
-
-app.delete('/api/v1/devices', function (req, res) {
+// ----- PENDING COMMANDS -----
+app.get('/api/v1/pending-commands', function (req, res) {
console.log(`${req.method}`, req.url)
- deletedDevice = true
- res.send()
-})
-
-app.get('/api/v1/devices/:deviceId', deviceIdCheck, function (req, res) {
- checkError(req, res)
- loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}.json`), res)
-})
-
-app.get('/api/v1/devices/:deviceId/pending-commands', deviceIdCheck, function (req, res) {
- checkError(req, res)
- res.send()
-})
-
-app.get('/api/v1/devices/:deviceId/resources', deviceIdCheck, function (req, res) {
- checkError(req, res)
- res.send()
-})
-
-app.put('/api/v1/devices/:deviceId/metadata', deviceIdCheck, function (req, res) {
- checkError(req, res)
- res.send()
-})
-
-// change device name
-app.put('/api/v1/devices/:deviceId/resources/oc/con', deviceIdCheck, function (req, res) {
- checkError(req, res)
- res.send({ n: 'New Device Name' })
-})
-
-// resource detail
-app.get('/api/v1/devices/:deviceId/resources/light/1', deviceIdCheck, function (req, res) {
- checkError(req, res)
- loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-light-1.json`), res)
+ loadResponseStreamFromFile('pending-commands.json', res)
})
-// resource detail
-app.get('/api/v1/devices/:deviceId/resources/.well-known/wot', deviceIdCheck, function (req, res) {
- checkError(req, res)
- loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-well-known-wot.json`), res)
+app.get('/', () => {
+ console.log(`HUB API mock server listening on port ${port}`)
})
-app.get('/api/v1/devices/:deviceId/resources/color', deviceIdCheck, function (req, res) {
- checkError(req, res)
-
- if (resourceColorUpdatedValue) {
- loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-color-update.json`), res)
- } else {
- loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-color.json`), res)
+app.get('/.well-known/configuration', (req, res) => {
+ try {
+ checkError(req, res)
+ axios.get('https://try.plgd.cloud/.well-known/configuration').then((r) => res.send(r.data))
+ } catch (e) {
+ res.status(500).send(e.toString())
}
})
-app.put('/api/v1/devices/:deviceId/resources/color', deviceIdCheck, function (req, res) {
- checkError(req, res)
- resourceColorUpdatedValue = true
- loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-color-update.json`), res)
-})
-
-// resource detail update
-app.put('/api/v1/devices/:deviceId/resources/light/1', deviceIdCheck, function (req, res) {
- checkError(req, res)
- loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-light-1.json`), res)
-})
-
-// ----- GENERAL for devices -----
-app.get('/api/v1/resource-links', function (req, res) {
- console.log(`${req.method}`, req.url)
- loadResponseFromFile(path.join('devices', 'detail', `${req.query['device_id_filter']}-resource-links.json`), res)
-})
-
-app.get('/api/v1/provisioning-records', function (req, res) {
- console.log(`${req.method}`, req.url)
- loadResponseFromFile(path.join('devices', 'detail', `${req.query['deviceIdFilter']}-provisioning-records.json`), res)
-})
-
-app.get('/api/v1/signing/records', function (req, res) {
- console.log(`${req.method}`, req.url)
- loadResponseFromFile(path.join('devices', 'detail', `${req.query['deviceIdFilter']}-signin-records.json`), res)
+app.get('/theme/theme.json', (req, res) => {
+ try {
+ checkError(req, res)
+ axios.get('https://try.plgd.cloud/theme/theme.json').then((r) => res.send(r.data))
+ } catch (e) {
+ res.status(500).send(e.toString())
+ }
})
-// ----- PENDING COMMANDS -----
-app.get('/api/v1/pending-commands', function (req, res) {
- console.log(`${req.method}`, req.url)
- loadResponseFromFile('pending-commands.json', res)
+app.get('/repos/plgd-dev/hub/releases/latest', (req, res) => {
+ try {
+ checkError(req, res)
+ axios.get('https://api.github.com/repos/plgd-dev/hub/releases/latest').then((r) => res.send(r.data))
+ } catch (e) {
+ res.status(500).send(e.toString())
+ }
})
-app.get('/', () => {
- console.log(`HUB API mock server listening on port ${port}`)
- deletedDevice = false
- resourceColorUpdatedValue = false
-})
+app.use(devices)
+app.use(dps)
+app.use('/snippet-service', snippetService)
app.listen(port, () => {
console.log(`HUB API mock server listening on port ${port}`)
diff --git a/http-gateway/web/packages/mock-server/src/routes/devices.js b/http-gateway/web/packages/mock-server/src/routes/devices.js
new file mode 100644
index 000000000..f16a7e2e4
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/routes/devices.js
@@ -0,0 +1,181 @@
+const express = require('express')
+const { checkError, loadResponseFromFile } = require('../utils')
+const path = require('path')
+const { check } = require('express-validator')
+const escapeHtml = require('escape-html')
+
+const router = express.Router()
+
+let deletedDevice = false
+let resourceColorUpdatedValue = false
+
+const deviceIdCheck = [check('deviceId').notEmpty().withMessage('Device ID must be alphanumeric')]
+
+router.get('/api/v1/devices/api-reset', (req, res) => {
+ try {
+ checkError(req, res)
+
+ deletedDevice = false
+ resourceColorUpdatedValue = false
+
+ res.send('OK')
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/devices', (req, res) => {
+ try {
+ checkError(req, res)
+
+ if (deletedDevice) {
+ loadResponseFromFile(path.join('devices', 'list', 'list-deleted-state.json'), res)
+ } else {
+ loadResponseFromFile(path.join('devices', 'list', 'list.json'), res)
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.delete('/api/v1/devices', (req, res) => {
+ try {
+ checkError(req, res)
+ deletedDevice = true
+
+ res.send('OK')
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/devices/:deviceId', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}.json`), res)
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/devices/:deviceId/pending-commands', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ res.send()
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/devices/:deviceId/resources', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ res.send()
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.put('/api/v1/devices/:deviceId/metadata', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ res.send()
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+// change device name
+router.put('/api/v1/devices/:deviceId/resources/oc/con', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ res.send({ n: 'New Device Name' })
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+// resource detail
+router.get('/api/v1/devices/:deviceId/resources/light/1', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-light-1.json`), res)
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+// resource detail update
+router.put('/api/v1/devices/:deviceId/resources/light/1', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-light-1.json`), res)
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+// resource detail wot
+router.get('/api/v1/devices/:deviceId/resources/.well-known/wot', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-well-known-wot.json`), res)
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+// resource detail color
+router.get('/api/v1/devices/:deviceId/resources/color', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+
+ if (resourceColorUpdatedValue) {
+ loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-color-update.json`), res)
+ } else {
+ loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-color.json`), res)
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+// resource detail color update
+router.put('/api/v1/devices/:deviceId/resources/color', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ resourceColorUpdatedValue = true
+ loadResponseFromFile(path.join('devices', 'detail', `${req.params['deviceId']}-resources-color-update.json`), res)
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/resource-links', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ loadResponseFromFile(path.join('devices', 'detail', `${req.query['device_id_filter']}-resource-links.json`), res)
+ } catch (e) {
+ res.status(500).send(e.toString())
+ }
+})
+
+// router.get('/api/v1/provisioning-records', deviceIdCheck, (req, res) => {
+// try {
+// checkError(req, res)
+// loadResponseFromFile(path.join('devices', 'detail', `${req.query['deviceIdFilter']}-provisioning-records.json`), res)
+// } catch (e) {
+// res.status(500).send(escapeHtml(e.toString()))
+// }
+// })
+
+router.get('/api/v1/signing/records', deviceIdCheck, (req, res) => {
+ try {
+ checkError(req, res)
+ loadResponseFromFile(path.join('devices', 'detail', `${req.query['deviceIdFilter']}-signin-records.json`), res)
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+module.exports = router
diff --git a/http-gateway/web/packages/mock-server/src/routes/dps.js b/http-gateway/web/packages/mock-server/src/routes/dps.js
new file mode 100644
index 000000000..059e1087e
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/routes/dps.js
@@ -0,0 +1,57 @@
+const { checkError, loadResponseStreamFromFile, loadResponseFromFile } = require('../utils')
+const get = require('lodash/get')
+const path = require('path')
+const escapeHtml = require('escape-html')
+const express = require('express')
+
+const router = express.Router()
+
+router.get('/api/v1/hubs', (req, res) => {
+ try {
+ checkError(req, res)
+ const httpIdFilter = get(req.query, 'idFilter', null)
+
+ // detail configuration page
+ if (httpIdFilter) {
+ loadResponseFromFile(path.join('dps', 'linked-hubs', 'detail', `${httpIdFilter}.json`), res)
+ } else {
+ loadResponseStreamFromFile(path.join('dps', 'linked-hubs', 'list', `list.json`), res)
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/enrollment-groups', (req, res) => {
+ try {
+ checkError(req, res)
+ const httpIdFilter = get(req.query, 'idFilter', null)
+
+ // detail configuration page
+ if (httpIdFilter) {
+ loadResponseFromFile(path.join('dps', 'enrollment-groups', 'detail', `${httpIdFilter}.json`), res)
+ } else {
+ loadResponseStreamFromFile(path.join('dps', 'enrollment-groups', 'list', `list.json`), res)
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/provisioning-records', (req, res) => {
+ try {
+ checkError(req, res)
+ const httpIdFilter = get(req.query, 'idFilter', null)
+
+ // detail configuration page
+ if (httpIdFilter) {
+ loadResponseFromFile(path.join('dps', 'provisioning-records', 'detail', `${httpIdFilter}.json`), res)
+ } else {
+ loadResponseStreamFromFile(path.join('dps', 'provisioning-records', 'list', `list.json`), res)
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+module.exports = router
diff --git a/http-gateway/web/packages/mock-server/src/routes/snippet-service.js b/http-gateway/web/packages/mock-server/src/routes/snippet-service.js
new file mode 100644
index 000000000..75386803a
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/routes/snippet-service.js
@@ -0,0 +1,62 @@
+const express = require('express')
+const { loadResponseStreamFromFile, checkError } = require('../utils')
+const path = require('path')
+const escapeHtml = require('escape-html')
+const get = require('lodash/get')
+
+const router = express.Router()
+
+router.get('/api/v1/configurations/applied', (req, res) => {
+ try {
+ checkError(req, res)
+ const httpConfigurationIdFilter = get(req.query, 'httpConfigurationIdFilter', null)?.replace('/all', '')
+
+ // detail configuration page
+ if (httpConfigurationIdFilter) {
+ loadResponseStreamFromFile(
+ path.join('snippet-service', 'applied-configurations', 'list', `httpConfigurationIdFilter-${httpConfigurationIdFilter}.json`),
+ res
+ )
+ } else {
+ // res.send([])
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/configurations', (req, res) => {
+ try {
+ checkError(req, res)
+ const filter = get(req.query, 'httpIdFilter', null)?.replace('/all', '')
+
+ // detail page
+ if (filter) {
+ loadResponseStreamFromFile(path.join('snippet-service', 'configurations', 'detail', `${filter}.json`), res)
+ } else {
+ // list page
+ loadResponseStreamFromFile(path.join('snippet-service', 'configurations', 'list', `list.json`), res)
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+router.get('/api/v1/conditions', (req, res) => {
+ try {
+ checkError(req, res)
+ const filter = get(req.query, 'httpIdFilter', null)?.replace('/all', '')
+
+ // detail page
+ if (filter) {
+ loadResponseStreamFromFile(path.join('snippet-service', 'conditions', 'detail', `${filter}.json`), res)
+ } else {
+ // list page
+ loadResponseStreamFromFile(path.join('snippet-service', 'conditions', 'list', `list.json`), res)
+ }
+ } catch (e) {
+ res.status(500).send(escapeHtml(e.toString()))
+ }
+})
+
+module.exports = router
diff --git a/http-gateway/web/packages/mock-server/src/utils.js b/http-gateway/web/packages/mock-server/src/utils.js
new file mode 100644
index 000000000..e422fcab1
--- /dev/null
+++ b/http-gateway/web/packages/mock-server/src/utils.js
@@ -0,0 +1,35 @@
+const { validationResult } = require('express-validator')
+const fs = require('fs-extra')
+
+const checkError = (req, res) => {
+ const errors = validationResult(req)
+ if (!errors.isEmpty()) {
+ return res.status(400).json({ errors: errors.array() })
+ }
+
+ console.log(`${req.method}`, req.url)
+}
+
+const loadResponseFromFile = (file, res) => {
+ const targetDirectory = `${__dirname}/data`
+
+ res.sendFile(file, { root: targetDirectory })
+}
+
+const loadResponseStreamFromFile = (file, res) => {
+ const targetDirectory = `${__dirname}/data`
+
+ const dataArray = fs.readJsonSync(`${targetDirectory}/${file}`)
+
+ dataArray.forEach((data, key) => {
+ res.write(JSON.stringify(data) + `${key === dataArray.length - 1 ? '' : '\n\n'}`)
+ })
+
+ res.send()
+}
+
+module.exports = {
+ checkError,
+ loadResponseFromFile,
+ loadResponseStreamFromFile,
+}
diff --git a/http-gateway/web/packages/shared-ui b/http-gateway/web/packages/shared-ui
index 05fb14ee6..efddbe595 160000
--- a/http-gateway/web/packages/shared-ui
+++ b/http-gateway/web/packages/shared-ui
@@ -1 +1 @@
-Subproject commit 05fb14ee633229500abb840737b581d9b6c6f3f7
+Subproject commit efddbe595bb44a53b5b10eb9e406c74eec6bf141
diff --git a/http-gateway/web/playwright/package-lock.json b/http-gateway/web/playwright/package-lock.json
index 99e974b6b..759d51848 100644
--- a/http-gateway/web/playwright/package-lock.json
+++ b/http-gateway/web/playwright/package-lock.json
@@ -8,9 +8,11 @@
"name": "hub-playwright-test",
"version": "1.0.0",
"license": "ISC",
+ "dependencies": {
+ "axios": "^1.7.2"
+ },
"devDependencies": {
- "@playwright/test": "^1.44.0",
- "axios": "^0.24.0"
+ "@playwright/test": "^1.44.0"
}
},
"node_modules/@playwright/test": {
@@ -28,20 +30,44 @@
"node": ">=16"
}
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
"node_modules/axios": {
- "version": "0.24.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
- "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
- "dev": true,
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
+ "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
- "follow-redirects": "^1.14.4"
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
}
},
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
- "dev": true,
"funding": [
{
"type": "individual",
@@ -57,6 +83,19 @@
}
}
},
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
@@ -71,6 +110,25 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/playwright": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.0.tgz",
@@ -100,6 +158,11 @@
"engines": {
"node": ">=16"
}
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
}
},
"dependencies": {
@@ -112,20 +175,48 @@
"playwright": "1.44.0"
}
},
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
"axios": {
- "version": "0.24.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
- "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
- "dev": true,
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
+ "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
"requires": {
- "follow-redirects": "^1.14.4"
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
}
},
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
+ },
"follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
- "dev": true
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA=="
+ },
+ "form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
},
"fsevents": {
"version": "2.3.2",
@@ -134,6 +225,19 @@
"dev": true,
"optional": true
},
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
"playwright": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.0.tgz",
@@ -149,6 +253,11 @@
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.0.tgz",
"integrity": "sha512-ZTbkNpFfYcGWohvTTl+xewITm7EOuqIqex0c7dNZ+aXsbrLj0qI8XlGKfPpipjm0Wny/4Lt4CJsWJk1stVS5qQ==",
"dev": true
+ },
+ "proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
}
}
}
diff --git a/http-gateway/web/playwright/package.json b/http-gateway/web/playwright/package.json
index 95b91f1f9..dc563308e 100644
--- a/http-gateway/web/playwright/package.json
+++ b/http-gateway/web/playwright/package.json
@@ -8,13 +8,15 @@
"test": "npx playwright test",
"test:ui": "npx playwright test --ui",
"test:debug": "npx playwright test --debug",
- "test:r": "npx playwright test devices/detail.spec.ts --debug --update-snapshots"
+ "test:r": "npx playwright test snippet-service/list.spec.ts --debug --update-snapshots"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
- "axios": "^0.24.0",
"@playwright/test": "^1.44.0"
+ },
+ "dependencies": {
+ "axios": "^1.7.2"
}
}
diff --git a/http-gateway/web/playwright/tests/snippet-service/configuratiions/deail.spec.ts b/http-gateway/web/playwright/tests/snippet-service/configuratiions/deail.spec.ts
new file mode 100644
index 000000000..a9960dacc
--- /dev/null
+++ b/http-gateway/web/playwright/tests/snippet-service/configuratiions/deail.spec.ts
@@ -0,0 +1,17 @@
+import { test, expect, Page } from '@playwright/test'
+import testId from '../../../../src/testId'
+
+const urlBase = 'http://localhost:3000'
+
+const openConfigurationItem = async (page: Page) => {
+ await page.goto(urlBase)
+ await page.getByTestId(testId.menu.snippetService.link).click()
+ await page.getByTestId(testId.menu.snippetService.configurations).click()
+ await page.getByTestId(`${testId.snippetService.configurations.list.table}-row-0`).click()
+}
+
+test('snippet-service-configurations-detail-version', async ({ page }) => {
+ await openConfigurationItem(page)
+
+ await expect(page.getByTestId(`${testId.snippetService.configurations.detail.versionSelector}`)).toBeVisible()
+})
diff --git a/http-gateway/web/playwright/tests/snippet-service/configuratiions/list.spec.ts b/http-gateway/web/playwright/tests/snippet-service/configuratiions/list.spec.ts
new file mode 100644
index 000000000..3f65b3d24
--- /dev/null
+++ b/http-gateway/web/playwright/tests/snippet-service/configuratiions/list.spec.ts
@@ -0,0 +1,13 @@
+import { test, expect } from '@playwright/test'
+import testId from '../../../../src/testId'
+
+const urlBase = 'http://localhost:3000'
+
+test('snippet-service-configurations-list-open', async ({ page }) => {
+ await page.goto(urlBase)
+ await page.getByTestId(testId.menu.snippetService.link).click()
+ await page.getByTestId(testId.menu.snippetService.configurations).click()
+
+ await expect(page).toHaveTitle(/Configuraions | plgd Dashboard/)
+ await expect(page).toHaveScreenshot({ fullPage: true, omitBackground: true })
+})
diff --git a/http-gateway/web/src/containers/App/App.i18n.ts b/http-gateway/web/src/containers/App/App.i18n.ts
index c48b35d3d..7f8bb7f2a 100644
--- a/http-gateway/web/src/containers/App/App.i18n.ts
+++ b/http-gateway/web/src/containers/App/App.i18n.ts
@@ -121,4 +121,20 @@ export const messages = defineMessages({
id: 'app.menuConfiguration',
defaultMessage: 'Configuration',
},
+ menuSnippetService: {
+ id: 'app.menuSnippetService',
+ defaultMessage: 'Snippet Service',
+ },
+ menuConditions: {
+ id: 'app.menuConditions',
+ defaultMessage: 'Conditions',
+ },
+ menuConfigurations: {
+ id: 'app.menuConfigurations',
+ defaultMessage: 'Configurations',
+ },
+ menuAppliedConfigurations: {
+ id: 'app.menuAppliedConfigurations',
+ defaultMessage: 'Applied Configurations',
+ },
})
diff --git a/http-gateway/web/src/containers/Common/DetailHeaderLayout/DetailHeaderLayout.tsx b/http-gateway/web/src/containers/Common/DetailHeaderLayout/DetailHeaderLayout.tsx
new file mode 100644
index 000000000..f5efa8004
--- /dev/null
+++ b/http-gateway/web/src/containers/Common/DetailHeaderLayout/DetailHeaderLayout.tsx
@@ -0,0 +1,76 @@
+import React, { FC, useCallback, useState } from 'react'
+import isFunction from 'lodash/isFunction'
+
+import Button from '@shared-ui/components/Atomic/Button'
+import { IconTrash } from '@shared-ui/components/Atomic/Icon'
+import DeleteModal from '@shared-ui/components/Atomic/Modal/components/DeleteModal'
+
+import { Props } from './DetailHeaderLayout.types'
+
+const DetailHeaderLayout: FC = (props) => {
+ const { customButton, deleteApiMethod, deleteInformation, id, i18n, loading, onDeleteSuccess, onDeleteError, testIds } = props
+
+ const [deleteModal, setDeleteModal] = useState(false)
+ const [deleting, setDeleting] = useState(false)
+
+ const handleDelete = useCallback(async () => {
+ try {
+ setDeleting(true)
+
+ await deleteApiMethod([id])
+
+ setDeleting(false)
+ setDeleteModal(false)
+
+ isFunction(onDeleteSuccess) && onDeleteSuccess()
+ } catch (e: any) {
+ setDeleting(false)
+ setDeleteModal(false)
+
+ isFunction(onDeleteError) && onDeleteError(e)
+ }
+ }, [deleteApiMethod, id, onDeleteError, onDeleteSuccess])
+
+ return (
+
+ {customButton}
+ }
+ onClick={() => setDeleteModal(true)}
+ variant='tertiary'
+ >
+ {i18n.delete}
+
+ setDeleteModal(false),
+ variant: 'tertiary',
+ },
+ {
+ dataTestId: testIds?.deleteButtonConfirm,
+ label: i18n.delete,
+ loading: deleting,
+ loadingText: i18n.deleting,
+ onClick: handleDelete,
+ variant: 'primary',
+ },
+ ]}
+ onClose={() => setDeleteModal(false)}
+ show={deleteModal}
+ subTitle={i18n.subTitle}
+ title={i18n.title}
+ />
+
+ )
+}
+
+DetailHeaderLayout.displayName = 'DetailHeaderLayout'
+
+export default DetailHeaderLayout
diff --git a/http-gateway/web/src/containers/Common/DetailHeaderLayout/DetailHeaderLayout.types.ts b/http-gateway/web/src/containers/Common/DetailHeaderLayout/DetailHeaderLayout.types.ts
new file mode 100644
index 000000000..25875be52
--- /dev/null
+++ b/http-gateway/web/src/containers/Common/DetailHeaderLayout/DetailHeaderLayout.types.ts
@@ -0,0 +1,27 @@
+import { ReactNode } from 'react'
+
+import { DeleteInformationType } from '@shared-ui/components/Atomic/Modal/components/DeleteModal/DeleteModal.types'
+
+export type Props = {
+ customButton?: ReactNode
+ deleteApiMethod: (ids: string[]) => Promise
+ deleteInformation: DeleteInformationType[]
+ id: string
+ loading: boolean
+ i18n: {
+ cancel: string
+ delete: string
+ deleting: string
+ id: string
+ name: string
+ subTitle: string
+ title: string
+ }
+ onDeleteSuccess?: () => void
+ onDeleteError?: (error: any) => void
+ testIds?: {
+ deleteButton?: string
+ deleteButtonCancel?: string
+ deleteButtonConfirm?: string
+ }
+}
diff --git a/http-gateway/web/src/containers/Common/DetailHeaderLayout/index.ts b/http-gateway/web/src/containers/Common/DetailHeaderLayout/index.ts
new file mode 100644
index 000000000..7b4b3ccaa
--- /dev/null
+++ b/http-gateway/web/src/containers/Common/DetailHeaderLayout/index.ts
@@ -0,0 +1,2 @@
+export { default } from './DetailHeaderLayout'
+export * from './DetailHeaderLayout'
diff --git a/http-gateway/web/src/containers/Common/PageLayout/PageLayout.tsx b/http-gateway/web/src/containers/Common/PageLayout/PageLayout.tsx
index 2865aa6a8..c19fc2ac7 100644
--- a/http-gateway/web/src/containers/Common/PageLayout/PageLayout.tsx
+++ b/http-gateway/web/src/containers/Common/PageLayout/PageLayout.tsx
@@ -3,6 +3,7 @@ import { useIntl } from 'react-intl'
import isFunction from 'lodash/isFunction'
import ReactDOM from 'react-dom'
import { useRecoilState } from 'recoil'
+import get from 'lodash/get'
import { default as PageLayoutShared } from '@shared-ui/components/Atomic/PageLayout/PageLayout'
import Footer from '@shared-ui/components/Layout/Footer'
@@ -18,7 +19,7 @@ import { messages as t } from '@/containers/App/App.i18n'
const PageLayout = forwardRef((props, ref) => {
const { formatMessage: _ } = useIntl()
- const { children, breadcrumbs, deviceId, notFound, pendingCommands, innerPortalTarget, size, ...rest } = props
+ const { children, breadcrumbs, deviceId, notFound, pendingCommands, innerPortalTarget, size, headlineCustomContent, ...rest } = props
const { footerExpanded, setFooterExpanded, collapsed } = useContext(AppContext)
const [isDomReady, setIsDomReady] = useState(false)
@@ -37,7 +38,7 @@ const PageLayout = forwardRef((props, ref) => {
collapsed={collapsed}
footer={