diff --git a/.gitignore b/.gitignore index b9f6532..7ede5c8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ build out server/ui +server/src/main/resources/ui diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..2f9ffd7 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,3 @@ +library('jenkins-pipeline') + +demoServerUiPipeline("ripple") \ No newline at end of file diff --git a/k8s.yml b/k8s.yml new file mode 100644 index 0000000..82d87a3 --- /dev/null +++ b/k8s.yml @@ -0,0 +1,31 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: demo-ripple + namespace: demo-ripple +spec: + replicas: 1 + selector: + matchLabels: + demo: ripple + serviceName: demo + template: + metadata: + labels: + demo: ripple + spec: + containers: + - image: DOCKER_IMAGE + imagePullPolicy: Always + name: demo + ports: + - containerPort: 9001 + protocol: TCP + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: "1" + memory: 1Gi \ No newline at end of file diff --git a/run.sh b/run.sh index ad47efc..4839ca0 100755 --- a/run.sh +++ b/run.sh @@ -1,8 +1,9 @@ cd ui npm install npm run compile && npm run bundle -mkdir -p ../server/ui +mkdir -p ../server/ui ../server/src/main/resources/ui/ cp -rf index.html dist ../server/ui/ +cp -rf index.html dist ../server/src/main/resources/ui/ cd ../server ./gradlew clean run diff --git a/server/build.gradle b/server/build.gradle index a62a342..517cbdf 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -9,6 +9,11 @@ buildscript { } } +plugins { + id 'com.google.cloud.tools.jib' version '3.3.1' +} + + apply plugin: 'java-library' apply plugin: 'application' apply plugin: 'nebula.ospackage-application' @@ -19,6 +24,7 @@ version = project.property('application.version') mainClassName = 'swim.ripple.RipplePlane' ext.moduleName = 'swim.ripple' ext.compilerArgs = ['-Xlint:all'] +ext.swimVersion = project.property('swim.version') // Build with `gradle -Pno-modules` to force compatibility with legacy JVMs. def javaVersion = System.getProperty('java.version').split('\\.') @@ -31,9 +37,9 @@ repositories { } dependencies { - implementation group: 'org.swimos', name: 'swim-recon', version: version - api group: 'org.swimos', name: 'swim-api', version: version - implementation group: 'org.swimos', name: 'swim-server', version: version + implementation group: 'org.swimos', name: 'swim-recon', version: swimVersion + api group: 'org.swimos', name: 'swim-api', version: swimVersion + implementation group: 'org.swimos', name: 'swim-server', version: swimVersion } afterEvaluate { @@ -93,6 +99,34 @@ afterEvaluate { } } + jib { + from { + image = "openjdk:11" + } + to { + image = "nstream/demo-ripple:${version}" + auth { + username = "$System.env.REGISTRY_USERNAME" + password = "$System.env.REGISTRY_PASSWORD" + } + } + container { + mainClass = mainClassName + ports = ['9001/tcp'] + jvmFlags = ['-Dswim.config=/config/server.recon'] + } + extraDirectories { + paths { + path { + // copies a single-file.xml + from = 'src/main/resources' + into = '/config' + includes = ['*.recon'] + } + } + } + } + run { dependsOn jar if (useModules) { diff --git a/server/gradle.properties b/server/gradle.properties index 7bea8ad..645e15c 100644 --- a/server/gradle.properties +++ b/server/gradle.properties @@ -1 +1,2 @@ -application.version=4.0.1 +application.version=1.0.0 +swim.version=4.0.1 diff --git a/server/src/main/java/module-info.java b/server/src/main/java/module-info.java index e706cc4..b5abb85 100644 --- a/server/src/main/java/module-info.java +++ b/server/src/main/java/module-info.java @@ -20,4 +20,5 @@ exports swim.ripple; provides swim.api.plane.Plane with swim.ripple.RipplePlane; + provides swim.kernel.Kernel with swim.ripple.RippleUiRouter; } diff --git a/server/src/main/java/swim/ripple/RippleUiRouter.java b/server/src/main/java/swim/ripple/RippleUiRouter.java new file mode 100644 index 0000000..9a6287a --- /dev/null +++ b/server/src/main/java/swim/ripple/RippleUiRouter.java @@ -0,0 +1,101 @@ +// Copyright 2015-2022 Swim.inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swim.ripple; + +import swim.kernel.KernelProxy; +import swim.structure.Value; +import swim.uri.UriPath; +import swim.web.WebRequest; +import swim.web.WebResponse; +import swim.web.WebRoute; +import swim.web.route.ResourceDirectoryRoute; + +/** + * SwimOS kernel module for routing HTTP requests for the bundled UI. + */ +public class RippleUiRouter extends KernelProxy { + final double kernelPriority; + final WebRoute uiRoute; + + public RippleUiRouter(double kernelPriority) { + this.kernelPriority = kernelPriority; + this.uiRoute = new ResourceDirectoryRoute(getClass().getClassLoader(), UriPath.parse("ui/"), "index.html"); + } + + public RippleUiRouter() { + this(KERNEL_PRIORITY); + } + + @Override + public final double kernelPriority() { + return this.kernelPriority; + } + + @Override + public WebResponse routeRequest(WebRequest request) { + final WebResponse response = this.uiRoute.routeRequest(request); + if (response.isAccepted()) { + return response; + } else { + return super.routeRequest(request); + } + } + + @Override + public void trace(Object message) { + // Use this hook to intercept and forward trace log messages + } + + @Override + public void debug(Object message) { + // Use this hook to intercept and forward debug log messages + } + + @Override + public void info(Object message) { + super.info(message); + // Use this hook to intercept and forward info log messages + } + + @Override + public void warn(Object message) { + super.warn(message); + // Use this hook to intercept and forward warning log messages + } + + @Override + public void error(Object message) { + super.error(message); + // Use this hook to intercept and forward error log messages + } + + @Override + public void fail(Object message) { + super.fail(message); + // Use this hook to intercept and forward failure log messages + } + + private static final double KERNEL_PRIORITY = 100.0; + + public static RippleUiRouter fromValue(Value moduleConfig) { + final Value header = moduleConfig.getAttr("kernel"); + final String kernelClassName = header.get("class").stringValue(null); + if (kernelClassName == null || RippleUiRouter.class.getName().equals(kernelClassName)) { + final double kernelPriority = header.get("priority").doubleValue(KERNEL_PRIORITY); + return new RippleUiRouter(kernelPriority); + } + return null; + } +} diff --git a/server/src/main/resources/server.recon b/server/src/main/resources/server.recon index bf009b4..da53d03 100644 --- a/server/src/main/resources/server.recon +++ b/server/src/main/resources/server.recon @@ -1,5 +1,6 @@ @kernel(class: 'swim.store.db.DbStoreKernel', optional: true) @kernel(class: 'swim.reflect.ReflectKernel', optional: true) +@kernel(class: "swim.ripple.RippleUiRouter") ripple: @fabric { @plane(class: "swim.ripple.RipplePlane") @@ -14,7 +15,6 @@ ripple: @fabric { @web(port: 9001) { space: "ripple" - documentRoot: "../ui/" @websocket { serverCompressionLevel: 0# -1 = default; 0 = off; 1-9 = deflate level clientCompressionLevel: 0# -1 = default; 0 = off; 1-9 = deflate level diff --git a/ui/index.html b/ui/index.html index 0c284fc..a44cd00 100644 --- a/ui/index.html +++ b/ui/index.html @@ -22,7 +22,30 @@ var host = documentUri.query().get("host"); var room = documentUri.fragmentIdentifier() || "wall"; -var hostUri = host || "warp://localhost:9001"; +const baseUri = swim.Uri.parse(document.location.href); +const hostParam = baseUri.host().toString(); +const schemeParam = baseUri.scheme().toString(); +const portParam = baseUri.port(); +const warpScheme = schemeParam === "https" ? "warps":"warp" + +let warpHost; + +if(hostParam.endsWith("swim.services")) { + warpHost = "ripple.swim.services" +} else if(hostParam.endsWith("nstream-demo.io")) { + warpHost = "ripple.services.nstream-demo.io" +} else { + warpHost = hostParam; +} + +let hostUri; + +if (portParam === undefined) { + hostUri = `${warpScheme}://${warpHost}` +} else { + hostUri = `${warpScheme}://${warpHost}:${portParam.toString()}` +} + var nodeUri = swim.UriPath.from("mirror", room).toString(); var nodeRef = swim.client.nodeRef(hostUri, nodeUri); var mirrorController = new swim.SwimMirrorViewController(nodeRef); @@ -32,5 +55,13 @@ canvas.append(mirror); + +