├── project
├── build.properties
├── plugins.sbt
└── project-info.conf
├── version.sbt
├── discoveryx-server
└── src
│ ├── universal
│ ├── conf
│ │ ├── application.ini
│ │ ├── logback.xml
│ │ └── application.conf
│ └── share
│ │ ├── jdbc
│ │ └── schema
│ │ │ ├── mysql
│ │ │ └── mysql-schema.sql
│ │ │ ├── postgres
│ │ │ └── postgres-schema.sql
│ │ │ ├── sqlserver
│ │ │ └── sqlserver-schema.sql
│ │ │ ├── h2
│ │ │ └── h2-schema.sql
│ │ │ └── oracle
│ │ │ └── oracle-schema.sql
│ │ └── cassandra
│ │ └── schema
│ │ └── snapshot-schema.cql
│ ├── main
│ ├── resources
│ │ ├── application.conf
│ │ ├── sql
│ │ │ └── schemas
│ │ │ │ └── h2.sql
│ │ ├── logback.xml
│ │ └── reference.conf
│ └── scala
│ │ └── fusion
│ │ └── discoveryx
│ │ └── server
│ │ ├── FusionDiscoveryXMain.scala
│ │ ├── package.scala
│ │ ├── route
│ │ └── package.scala
│ │ ├── config
│ │ ├── ConfigSettings.scala
│ │ ├── ConfigManager.scala
│ │ └── service
│ │ │ └── ConfigManagerServiceImpl.scala
│ │ ├── ManagementSettings.scala
│ │ ├── naming
│ │ ├── NamingSettings.scala
│ │ ├── NamingManager.scala
│ │ └── service
│ │ │ └── NamingServiceHelper.scala
│ │ ├── util
│ │ ├── ProtobufJson4s.scala
│ │ └── SessionUtils.scala
│ │ ├── DiscoveryPersistenceQuery.scala
│ │ ├── BaseSettings.scala
│ │ └── namespace
│ │ ├── NamespaceRef.scala
│ │ └── service
│ │ └── NamespaceManagerServiceImpl.scala
│ └── test
│ ├── resources
│ ├── application-helloscala.conf
│ ├── logback-test.xml
│ ├── application-test.conf
│ └── persistence-postgres.conf
│ └── scala
│ ├── fusion
│ └── discoveryx
│ │ └── server
│ │ ├── util
│ │ ├── SessionUtilsTest.scala
│ │ └── ActorTest.scala
│ │ ├── naming
│ │ └── internal
│ │ │ └── SniffUtilsTest.scala
│ │ ├── user
│ │ ├── UserServiceClientTest.scala
│ │ └── service
│ │ │ └── UserServiceTest.scala
│ │ ├── config
│ │ └── ConfigManagerServiceTest.scala
│ │ └── route
│ │ └── FusionRouteTest.scala
│ └── akka
│ └── fusion
│ └── testkit
│ └── FusionActorTestKit.scala
├── discoveryx-docs
├── src
│ └── main
│ │ └── paradox
│ │ ├── _template
│ │ ├── lbHeader.st
│ │ ├── source.st
│ │ └── copyright.st
│ │ ├── releases.md
│ │ ├── design
│ │ ├── config.md
│ │ ├── naming.md
│ │ ├── architecture.md
│ │ ├── index.md
│ │ └── concept.md
│ │ ├── use
│ │ ├── spring.md
│ │ ├── index.md
│ │ ├── akka.md
│ │ ├── quick-start.md
│ │ └── sdk-scala.md
│ │ ├── api
│ │ ├── open
│ │ │ ├── grpc.md
│ │ │ ├── index.md
│ │ │ └── config.md
│ │ ├── management
│ │ │ ├── grpc.md
│ │ │ ├── index.md
│ │ │ └── config.md
│ │ ├── index.md
│ │ └── json.md
│ │ ├── deploy
│ │ ├── docker.md
│ │ ├── single.md
│ │ ├── persistence-cassandra.md
│ │ ├── index.md
│ │ ├── package.md
│ │ └── other-persistence.md
│ │ ├── intro.md
│ │ └── index.md
└── docs
│ ├── tmp.md
│ └── Fusion DiscoveryX.drawio
├── web-console
├── static
│ ├── html
│ │ ├── 404
│ │ │ └── 404.png
│ │ ├── loading
│ │ │ ├── loading.js
│ │ │ ├── loading.html
│ │ │ ├── loading.css
│ │ │ └── webpack.loading.config.js
│ │ └── loveOrHate
│ │ │ └── index.html
│ └── assets
│ │ └── images
│ │ ├── aiwrap.png
│ │ ├── qrcode.png
│ │ └── logo.svg
├── .eslintignore
├── src
│ ├── components
│ │ ├── Pagination
│ │ │ ├── index.less
│ │ │ └── index.js
│ │ ├── Breadcrumb
│ │ │ ├── index.less
│ │ │ └── index.js
│ │ ├── Loadable
│ │ │ ├── index.less
│ │ │ └── index.js
│ │ ├── Clamp
│ │ │ └── index.less
│ │ ├── Mismatch
│ │ │ ├── index.js
│ │ │ └── index.less
│ │ ├── SearchTable
│ │ │ └── index.less
│ │ ├── Highlight
│ │ │ └── index.js
│ │ ├── PhotoSwipe
│ │ │ └── index.less
│ │ ├── NamespaceChoose
│ │ │ └── index.js
│ │ └── Chart
│ │ │ └── index.js
│ ├── global.less
│ ├── pages
│ │ ├── config
│ │ │ ├── constants.js
│ │ │ └── management
│ │ │ │ └── Detail
│ │ │ │ └── index.js
│ │ └── App
│ │ │ └── index.less
│ ├── router
│ │ ├── constants.js
│ │ ├── feature.js
│ │ └── index.js
│ ├── stores
│ │ ├── index.js
│ │ ├── GlobalStore.js
│ │ └── ConfigStore.js
│ ├── utils
│ │ └── constants.js
│ └── index.js
├── .prettierignore
├── .gitignore
├── .prettierrc
├── index.html
├── deploy.sh
├── .eslintrc
├── babel.config.js
├── README.md
└── config
│ └── index.js
├── docs
├── paradox.json
├── css
│ ├── fonts
│ │ ├── icons.eot
│ │ ├── icons.ttf
│ │ ├── icons.woff
│ │ ├── icons.woff2
│ │ ├── proxima-nova-bold.eot
│ │ ├── proxima-nova-bold.ttf
│ │ ├── proxima-nova-bold.woff
│ │ ├── proxima-nova-regular.eot
│ │ ├── proxima-nova-regular.ttf
│ │ ├── proxima-nova-regular.woff
│ │ ├── source-code-pro-regular.eot
│ │ ├── source-code-pro-regular.ttf
│ │ ├── source-code-pro-regular.woff
│ │ └── icons.svg
│ └── icons.css
├── images
│ ├── favicon.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── mstile-150x150.png
│ ├── apple-touch-icon.png
│ ├── footer-background.jpg
│ ├── header-background.jpg
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── akka-icon.svg
│ ├── akka-icon-reverse.svg
│ ├── manifest.json
│ └── akka-logo-reverse.svg
├── lib
│ └── prettify
│ │ ├── prettify.css
│ │ └── lang-scala.js
└── js
│ ├── metadata-toggle.js
│ ├── magellan.js
│ ├── page.js
│ └── scrollsneak.js
├── scripts
├── travis-test-scala13.sh
├── travis-paradox.sh
├── travis-test-scala12.sh
├── dockers
│ ├── fusion-discoveryx
│ │ └── Dockerfile
│ ├── postgres
│ │ ├── Dockerfile
│ │ └── postgres-schema.sql
│ └── cassandra
│ │ ├── Dockerfile
│ │ └── docker-entrypoint.sh
├── publish-docs.sh
└── publish-dist.sh
├── .travis-jvmopts
├── discoveryx-functest
├── README.md
└── src
│ └── multi-jvm
│ ├── resources
│ ├── application.conf
│ └── logback-test.xml
│ └── scala
│ ├── akka
│ └── remote
│ │ └── testkit
│ │ └── STMultiNodeSpec.scala
│ └── fusion
│ └── discoveryx
│ └── functest
│ └── TestUtils.scala
├── discoveryx-client-play-ws
└── src
│ ├── main
│ ├── resources
│ │ └── reference.conf
│ └── scala
│ │ └── fusion
│ │ └── discoveryx
│ │ └── client
│ │ └── play
│ │ ├── javadsl
│ │ ├── DiscoveryXPlay.java
│ │ ├── DiscoveryXPlayWSClient.scala
│ │ ├── DiscoveryXStandaloneWSClient.scala
│ │ ├── module
│ │ │ └── DiscoveryXWSModule.java
│ │ └── DiscoveryXWSClient.java
│ │ └── scaladsl
│ │ ├── DiscoveryXPlay.java
│ │ └── module
│ │ └── DiscoveryXWSModule.scala
│ └── test
│ ├── resources
│ └── application-test.conf
│ └── scala
│ └── fusion
│ └── discoveryx
│ └── client
│ └── play
│ └── scaladsl
│ └── DiscoveryXWSClientTest.scala
├── release.sh
├── discoveryx-common
└── src
│ └── main
│ ├── resources
│ └── reference.conf
│ ├── protobuf
│ └── fusion
│ │ └── define.proto
│ └── scala
│ └── fusion
│ └── discoveryx
│ ├── DiscoveryXSettings.scala
│ └── common
│ └── Constants.scala
├── discoveryx-client
└── src
│ ├── test
│ ├── resources
│ │ ├── application-test.conf
│ │ ├── application-local.conf
│ │ ├── application-helloscala.conf
│ │ ├── application-local-2.conf
│ │ ├── application-helloscala-2.conf
│ │ └── logback-test.xml
│ └── scala
│ │ └── fusion
│ │ └── discoveryx
│ │ └── client
│ │ ├── NamingClientDemo.scala
│ │ └── DefaultNamingClientTest.scala
│ └── main
│ ├── resources
│ ├── logback.xml
│ └── reference.conf
│ └── scala
│ └── fusion
│ └── discoveryx
│ └── client
│ ├── DefaultNamingClient.scala
│ ├── ConfigClientSettings.scala
│ ├── impl
│ └── ConfigClientImpl.scala
│ └── HttpUtils.scala
├── docker-compose.yml
├── .scalafmt.conf
├── .travis.yml
├── README.md
└── .gitignore
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=1.3.7
2 |
--------------------------------------------------------------------------------
/version.sbt:
--------------------------------------------------------------------------------
1 | ThisBuild / version := "0.1.0"
2 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/conf/application.ini:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/_template/lbHeader.st:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web-console/static/html/loading/loading.js:
--------------------------------------------------------------------------------
1 | // TODO
2 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/releases.md:
--------------------------------------------------------------------------------
1 | # 发布
2 |
3 | TODO
4 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/design/config.md:
--------------------------------------------------------------------------------
1 | # 配置管理设计
2 |
3 | TODO
4 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/use/spring.md:
--------------------------------------------------------------------------------
1 | # 在 Spring 中使用
2 |
3 | TODO
4 |
--------------------------------------------------------------------------------
/docs/paradox.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "discoveryx-docs",
3 | "version" : "0.1.0"
4 | }
--------------------------------------------------------------------------------
/web-console/.eslintignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 |
3 | dist/
4 | static/
--------------------------------------------------------------------------------
/docs/css/fonts/icons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/icons.eot
--------------------------------------------------------------------------------
/docs/css/fonts/icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/icons.ttf
--------------------------------------------------------------------------------
/docs/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/favicon.ico
--------------------------------------------------------------------------------
/docs/css/fonts/icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/icons.woff
--------------------------------------------------------------------------------
/docs/css/fonts/icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/icons.woff2
--------------------------------------------------------------------------------
/docs/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/images/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/mstile-150x150.png
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/design/naming.md:
--------------------------------------------------------------------------------
1 | # 服务注册、发现设计
2 |
3 | `NamingManager` -> `NamingService` -> `NamingInstance`
4 |
--------------------------------------------------------------------------------
/docs/images/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/images/footer-background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/footer-background.jpg
--------------------------------------------------------------------------------
/docs/images/header-background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/header-background.jpg
--------------------------------------------------------------------------------
/docs/css/fonts/proxima-nova-bold.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/proxima-nova-bold.eot
--------------------------------------------------------------------------------
/docs/css/fonts/proxima-nova-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/proxima-nova-bold.ttf
--------------------------------------------------------------------------------
/web-console/static/html/404/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/web-console/static/html/404/404.png
--------------------------------------------------------------------------------
/docs/css/fonts/proxima-nova-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/proxima-nova-bold.woff
--------------------------------------------------------------------------------
/docs/css/fonts/proxima-nova-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/proxima-nova-regular.eot
--------------------------------------------------------------------------------
/docs/css/fonts/proxima-nova-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/proxima-nova-regular.ttf
--------------------------------------------------------------------------------
/docs/images/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/images/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/images/android-chrome-512x512.png
--------------------------------------------------------------------------------
/docs/css/fonts/proxima-nova-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/proxima-nova-regular.woff
--------------------------------------------------------------------------------
/docs/css/fonts/source-code-pro-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/source-code-pro-regular.eot
--------------------------------------------------------------------------------
/docs/css/fonts/source-code-pro-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/source-code-pro-regular.ttf
--------------------------------------------------------------------------------
/docs/css/fonts/source-code-pro-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/docs/css/fonts/source-code-pro-regular.woff
--------------------------------------------------------------------------------
/web-console/static/assets/images/aiwrap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/web-console/static/assets/images/aiwrap.png
--------------------------------------------------------------------------------
/web-console/static/assets/images/qrcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akka-fusion/fusion-discoveryx/HEAD/web-console/static/assets/images/qrcode.png
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/design/architecture.md:
--------------------------------------------------------------------------------
1 | # 架构
2 |
3 | ## 基本架构及概念
4 |
5 | TODO 总图
6 |
7 | 详细概念请阅读 @ref[Fusion DiscoveryX 概念](concept.md) 。
8 |
9 |
--------------------------------------------------------------------------------
/web-console/src/components/Pagination/index.less:
--------------------------------------------------------------------------------
1 | .rs-pagination {
2 | margin: 16px 0;
3 | float: right;
4 |
5 | &:before,
6 | &:after {
7 | clear: both;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/scripts/travis-test-scala13.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | cd "$BASEDIR"
4 |
5 | start "RUNNING TESTS FOR SCALA 2.13"
6 |
7 | runSbt test:compile
8 |
9 | end "ALL TESTS PASSED"
10 |
--------------------------------------------------------------------------------
/.travis-jvmopts:
--------------------------------------------------------------------------------
1 | # This is used to configure the sbt instance that Travis launches
2 |
3 | -Xms2G
4 | -Xmx2G
5 | -Xss2M
6 | -XX:MaxInlineLevel=18
7 | -XX:MaxMetaspaceSize=1G
8 | -Dfile.encoding=UTF-8
9 |
--------------------------------------------------------------------------------
/scripts/travis-paradox.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | cd "$BASEDIR"
4 |
5 | start test "RUNNING Generate paradox"
6 |
7 | runSbt "discoveryx-docs/paradox"
8 |
9 | end test "ALL TESTS PASSED"
10 |
--------------------------------------------------------------------------------
/scripts/travis-test-scala12.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | cd "$BASEDIR"
4 |
5 | start "RUNNING TESTS FOR SCALA 2.12"
6 |
7 | runSbt "++2.12.10 test:compile"
8 |
9 | end "ALL TESTS PASSED"
10 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/open/grpc.md:
--------------------------------------------------------------------------------
1 | # gRPC Service Descriptor
2 |
3 | @@snip [discoveryx.proto](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/grpc/discoveryx.proto)
4 |
--------------------------------------------------------------------------------
/scripts/dockers/fusion-discoveryx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:11
2 |
3 | COPY ../../../discoveryx-server/target/universal/stage /fusion-discoveryx
4 | CMD ["/fusion-discoveryx/bin/discoveryx-server > /dev/null"]
5 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/management/grpc.md:
--------------------------------------------------------------------------------
1 | # gRPC Service Descriptor
2 |
3 | @@snip [config.proto](../../../../../../discoveryx-server/src/main/protobuf/fusion/discoveryx/server/grpc/server.proto)
4 |
--------------------------------------------------------------------------------
/discoveryx-functest/README.md:
--------------------------------------------------------------------------------
1 | # discoveryx-functest
2 |
3 | 功能测试
4 |
5 | **多节点功能集成测试**
6 |
7 | ```sbtshell
8 | > discoveryx-functest/multi-jvm:testOnly fusion.discoveryx.functest.DiscoveryXMultiTest
9 | ```
10 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/_template/source.st:
--------------------------------------------------------------------------------
1 | $if(page.source_url)$
2 |
3 | 在此文档中发现错误?该页面的源代码可以在
这里 找到。欢迎随时编辑并提交Pull Request。
4 |
5 | $endif$
6 |
--------------------------------------------------------------------------------
/scripts/dockers/postgres/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM postgres:latest
2 |
3 | RUN localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8
4 |
5 | ENV LANG zh_CN.utf8
6 |
7 | COPY postgres-schema.sql /docker-entrypoint-initdb.d/
8 |
--------------------------------------------------------------------------------
/scripts/dockers/cassandra/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM cassandra:latest
2 |
3 | #RUN localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8
4 |
5 | ENV LANG zh_CN.utf8
6 |
7 | COPY ./cassandra-schema.cql /docker-entrypoint-initdb.d/
8 |
--------------------------------------------------------------------------------
/scripts/publish-docs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | directory=../docs/
4 |
5 | if [ ! -d $directory ]; then
6 | mkdir -p $directory
7 | fi
8 |
9 | rm -rf ${directory}/*
10 | cp -r ../discoveryx-docs/target/paradox/site/main/* ${directory}/
11 |
--------------------------------------------------------------------------------
/web-console/.prettierignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 |
3 | /dist
4 | /static
5 | /scripts
6 | /.idea
7 |
8 | .eslintignore
9 | .gitignore
10 | .prettierignore
11 | .DS_Store
12 |
13 | yarn.lock
14 | deploy.sh
15 |
--------------------------------------------------------------------------------
/scripts/publish-dist.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | directory=../discoveryx-server/src/main/resources/dist
4 |
5 | if [ ! -d $directory ]; then
6 | mkdir -p $directory
7 | fi
8 |
9 | rm -rf ${directory}/*
10 | cp -r ../web-console/dist/* ${directory}/
11 |
--------------------------------------------------------------------------------
/web-console/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
16 | *.tar.gz
--------------------------------------------------------------------------------
/web-console/src/components/Breadcrumb/index.less:
--------------------------------------------------------------------------------
1 | .fd-breadcrumb {
2 | background-color: #fff;
3 | padding: 16px 24px;
4 | margin-bottom: 16px;
5 |
6 | .ant-page-header-heading {
7 | display: flex;
8 | align-items: center;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/resources/reference.conf:
--------------------------------------------------------------------------------
1 | play {
2 | modules {
3 | enabled += "fusion.discoveryx.client.play.scaladsl.module.DiscoveryXWSModule"
4 | enabled += "fusion.discoveryx.client.play.javadsl.module.DiscoveryXWSModule"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/use/index.md:
--------------------------------------------------------------------------------
1 | # 使用
2 |
3 | @@toc { depth=2 }
4 |
5 | @@@ index
6 |
7 | - [quick-start](quick-start.md)
8 | - [sdk-scala](sdk-scala.md)
9 | - [akka](akka.md)
10 | - [play](play.md)
11 | - [spring](spring.md)
12 |
13 | @@@
14 |
15 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | sbt "project discoveryx-docs" paradox
4 |
5 | pushd web-console/
6 | yarn
7 | yarn build
8 | popd
9 |
10 | pushd scripts/
11 | sh publish-docs.sh
12 | sh publish-dist.sh
13 | popd
14 |
15 | sbt "project discoveryx-server" dist
16 |
--------------------------------------------------------------------------------
/web-console/src/components/Loadable/index.less:
--------------------------------------------------------------------------------
1 | .loadable-box {
2 | height: 100vh;
3 | width: 100%;
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 |
8 | p {
9 | font-size: 14px;
10 | font-weight: 400;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/open/index.md:
--------------------------------------------------------------------------------
1 | # 开放API
2 |
3 | Fusion DiscoveryX 开放 API 提供了配置发布、获取、管理和服务注册、负载均衡等API,提供了 gRPC 和 REST 两种实现。
4 |
5 | @@toc { depth=3 }
6 |
7 | @@@ index
8 |
9 | - [config](config.md)
10 | - [naming](naming.md)
11 | - [grpc](grpc.md)
12 |
13 | @@@
14 |
--------------------------------------------------------------------------------
/web-console/src/components/Clamp/index.less:
--------------------------------------------------------------------------------
1 | .clamp-container {
2 | overflow: hidden;
3 |
4 | .clamp-container-text {
5 | word-break: break-all;
6 | }
7 |
8 | .clamp-container-btn {
9 | margin: 0;
10 | padding: 0;
11 | border: 0;
12 | outline: none;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/index.md:
--------------------------------------------------------------------------------
1 | # API
2 |
3 | Fusion DiscoveryX 提供两大类API。开放 API 提供客户端访问接口,管理 API 提供了附带Web管理控制台所需要使用的接口。所有 API 均同时提供 gRPC 和 RESTful 。
4 |
5 | @@toc { depth=3 }
6 |
7 | @@@ index
8 |
9 | - [open](open/index.md)
10 | - [management](management/index.md)
11 | - [json](json.md)
12 |
13 | @@@
14 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/deploy/docker.md:
--------------------------------------------------------------------------------
1 | # Docker
2 |
3 | ## 单节点
4 |
5 | Fusion DiscoveryX 提供了 Docker 构建脚本:
6 |
7 | ```
8 | cd fusion-discoveryx/
9 | sbt "project discoveryx-server" dist
10 | scripts/dockers/fusion-discoveryx
11 | docker build -t fusion-discoveryx .
12 | ```
13 |
14 | ## 集群
15 |
16 | TODO
17 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/management/index.md:
--------------------------------------------------------------------------------
1 | # 管理API
2 |
3 | 管理 API 为 Fusion DiscoveryX 提供了 Web 控制台使用的访问接口,提供了命名空间管理、配置管理、名称服务管理、用户管理等接口。
4 |
5 | @@toc { depth=3 }
6 |
7 | @@@ index
8 |
9 | - [namespace](namespace.md)
10 | - [config](config.md)
11 | - [naming](naming.md)
12 | - [user](user.md)
13 | - [grpc](grpc.md)
14 |
15 | @@@
16 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/design/index.md:
--------------------------------------------------------------------------------
1 | # 设计
2 |
3 | Fusion DiscoveryX 完全基于 Akka 开放,使用 Actor 模型来处理各类异步任务。通过 Akka Persistence 来实现事件存储和状态保持,通过 gRPC 提供客户端接口协议。
4 |
5 | @@toc { depth=3 }
6 |
7 | @@@ index
8 |
9 | - [concept](concept.md)
10 | - [architecture](architecture.md)
11 | - [config](config.md)
12 | - [naming](naming.md)
13 | - [technology](technology.md)
14 |
15 | @@@
16 |
--------------------------------------------------------------------------------
/web-console/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all",
4 | "printWidth": 100,
5 | "proseWrap": "never",
6 | "overrides": [
7 | {
8 | "files": ".prettierrc",
9 | "options": {
10 | "parser": "json"
11 | }
12 | },
13 | {
14 | "files": ".eslintrc",
15 | "options": {
16 | "parser": "json"
17 | }
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/web-console/src/global.less:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 | // 全局样式
3 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4 |
5 | body {
6 | font-family: PingFangSC-Regular, 'Avenir', Helvetica, Arial, sans-serif;
7 | }
8 |
9 | .fe-highlight {
10 | color: #f50;
11 | }
12 |
--------------------------------------------------------------------------------
/web-console/static/assets/images/logo.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/web-console/src/components/Mismatch/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 2018/6/20 gongtiexin 404
5 | * */
6 |
7 | import React from 'react';
8 | import './index.less';
9 |
10 | const Mismatch = () => (
11 |
12 |
404
13 |
抱歉,你访问的页面不存在
14 |
15 | );
16 |
17 | export default React.memo(Mismatch);
18 |
--------------------------------------------------------------------------------
/docs/images/akka-icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/images/akka-icon-reverse.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | fusion.http.default {
2 | server {
3 | host = 127.0.0.1
4 | port = 48000
5 | }
6 | }
7 | discoveryx {
8 | akka {
9 | actor.provider = cluster
10 | cluster.seed-nodes = ["127.0.0.1:49000"]
11 | }
12 | }
13 |
14 | jdbc-journal {
15 | use-shared-db = "postgres"
16 | }
17 | jdbc-snapshot-store {
18 | use-shared-db = "postgres"
19 | }
20 | jdbc-read-journal {
21 | use-shared-db = "postgres"
22 | }
23 |
--------------------------------------------------------------------------------
/web-console/src/pages/config/constants.js:
--------------------------------------------------------------------------------
1 | const CONFIG_TYPE_ENUM = {
2 | TEXT: 0,
3 | HOCON: 1,
4 | JSON: 2,
5 | YAML: 3,
6 | PROPERTIES: 4,
7 | INI: 5,
8 | properties: {
9 | 0: { label: 'TEXT', value: 0 },
10 | 1: { label: 'HOCON', value: 1 },
11 | 2: { label: 'JSON', value: 2 },
12 | 3: { label: 'YAML', value: 3 },
13 | 4: { label: 'PROPERTIES', value: 4 },
14 | 5: { label: 'INI', value: 5 },
15 | },
16 | };
17 |
18 | export { CONFIG_TYPE_ENUM };
19 |
--------------------------------------------------------------------------------
/discoveryx-common/src/main/resources/reference.conf:
--------------------------------------------------------------------------------
1 | fusion.http.default.server {
2 | host = "127.0.0.1"
3 | port = 48000
4 | }
5 | discoveryx {
6 | name = discoveryx
7 |
8 | akka {
9 | actor.provider = cluster
10 | remote {
11 | artery {
12 | canonical {
13 | hostname = "127.0.0.1"
14 | port = 49000
15 | }
16 | }
17 | }
18 | cluster {
19 | roles = []
20 | }
21 | }
22 |
23 | config-modules = [akka]
24 | }
25 |
--------------------------------------------------------------------------------
/web-console/src/components/SearchTable/index.less:
--------------------------------------------------------------------------------
1 | .search-table {
2 | //padding: 24px;
3 |
4 | .ant-advanced-search-form {
5 | padding: 24px;
6 | background: #fbfbfb;
7 | border: 1px solid #d9d9d9;
8 | border-radius: 6px;
9 | margin-bottom: 20px;
10 |
11 | .ant-form-item {
12 | display: flex;
13 | }
14 |
15 | .ant-form-item-control-wrapper {
16 | flex: 1;
17 | }
18 | }
19 |
20 | .search-expand {
21 | margin-bottom: 20px;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/discoveryx-common/src/main/protobuf/fusion/define.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package fusion;
3 |
4 | import "google/protobuf/any.proto";
5 | import "google/protobuf/wrappers.proto";
6 | import "scalapb/scalapb.proto";
7 |
8 | enum CommonStatus {
9 | DISABLE = 0;
10 | ENABLE = 1;
11 | }
12 |
13 | message ResultBO {
14 | int32 status = 1;
15 | string msg = 2;
16 | //google.protobuf.Any data = 3;
17 | map data = 3;
18 | CommonStatus common_status = 4;
19 | }
20 |
--------------------------------------------------------------------------------
/docs/images/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Akka",
3 | "icons": [
4 | {
5 | "src": "android-chrome-192x192.png",
6 | "sizes": "192x192",
7 | "type": "image/png"
8 | },
9 | {
10 | "src": "android-chrome-512x512.png",
11 | "sizes": "512x512",
12 | "type": "image/png"
13 | }
14 | ],
15 | "theme_color": "#15a9ce",
16 | "background_color": "#ffffff",
17 | "display": "standalone"
18 | }
19 |
--------------------------------------------------------------------------------
/web-console/src/pages/App/index.less:
--------------------------------------------------------------------------------
1 | #app {
2 | .logo {
3 | height: 32px;
4 | line-height: 32px;
5 | text-align: center;
6 | font-weight: 700;
7 | background: rgba(255, 255, 255, 0.2);
8 | margin: 16px;
9 | color: #fff;
10 | }
11 |
12 | .ant-layout-header {
13 | display: flex;
14 | justify-content: flex-end;
15 | align-items: center;
16 |
17 | background: #fff;
18 | padding: 0;
19 | box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
20 | z-index: 2;
21 |
22 | span,
23 | a {
24 | margin-right: 40px;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/use/akka.md:
--------------------------------------------------------------------------------
1 | # 在 Akka 中使用
2 |
3 | ## Module Info
4 |
5 | 需要在项目中添加如下依赖:
6 |
7 | @@dependency[sbt,Gradle,Maven] { group="com.akka-fusion.fusion" artifact="discoveryx-client_$scala.binary_version$" version="$version$" }
8 |
9 | ## 服务发现
10 |
11 | Akka通过 [akka-discovery](https://doc.akka.io/docs/akka/current/discovery/index.html) 提供了默认的服务发现功能,DiscoveryX Client提供了对其的支持。我们只需要配置`akka.discovery`设置使用`fusion-discoveryx`使用 DiscoveryX Client 来为 akka-discovery 提供服务发现功能。
12 |
13 | @@snip [discovery](../../../../../discoveryx-client/src/main/resources/reference.conf) { #discovery }
14 |
15 |
--------------------------------------------------------------------------------
/discoveryx-client/src/test/resources/application-test.conf:
--------------------------------------------------------------------------------
1 | akka.grpc.client {
2 | "fusion.discoveryx.grpc.NamingService" {
3 | use-tls = false
4 | host = "helloscala.com"
5 | // host = "127.0.0.1"
6 | port = 48000
7 | }
8 | }
9 | discoveryx.client {
10 | naming {
11 | heartbeat-interval = 20.seconds
12 | namespace = "890cd0cd-22d8-11ea-8bfe-5254002e9e52" // helloscala.com gtx
13 | // namespace = "6e2864d3-22fe-11ea-89f4-d2680721077d" // local
14 | service-name = "discoveryx"
15 | ip = "127.0.0.1"
16 | port = 8000
17 | enable = true
18 | weight = 1.5
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/deploy/single.md:
--------------------------------------------------------------------------------
1 | # 单机部署
2 |
3 | *请先阅读 @ref[软件包](package.md) 。*
4 |
5 | ## 使用
6 |
7 | 单机部署默认使用嵌入式数据库 **H2**。Fusion DiscoveryX 将在第一次启动服务时在用户主目录下创建 H2 数据库目录并初始化数据表和用户,默认用户:
8 |
9 | - SN: `discoveryx`
10 | - PW: `discoveryx`
11 |
12 | @@@vars
13 | ```
14 | unzip discoveryx-server-$version$.zip
15 | cd discoveryx-server-$version$
16 | ./bin/discoveryx-server
17 | ```
18 | @@@
19 |
20 | ## H2 数据库配置
21 |
22 | 默认 H2 数据库表将创建在 `$HOME` 目录,如:
23 |
24 | ```
25 | yangjing@yangbajing:~$ tree fusion-discoveryx/
26 | fusion-discoveryx/
27 | └── db.mv.db
28 |
29 | 0 directories, 1 file
30 | ```
31 |
--------------------------------------------------------------------------------
/discoveryx-client/src/test/resources/application-local.conf:
--------------------------------------------------------------------------------
1 | akka.grpc.client {
2 | "fusion.discoveryx.grpc.NamingService" {
3 | use-tls = false
4 | host = "localhost"
5 | port = 48000
6 | }
7 | }
8 | discoveryx.client {
9 | naming {
10 | auto-registration = false
11 | heartbeat-interval = 10.seconds
12 | namespace = "3d355123-3081-11ea-887d-4a7eb37c5068" // local public
13 | service-name = "fusion-schedulerx"
14 | port = 8000
15 | enable = true
16 | health = true
17 | weight = 1.0
18 | metadata {
19 | env = dev
20 | application = dev.schedulerx
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/web-console/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 | <%= htmlWebpackPlugin.options.title %>
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/discoveryx-client/src/test/resources/application-helloscala.conf:
--------------------------------------------------------------------------------
1 | akka.grpc.client {
2 | "fusion.discoveryx.grpc.NamingService" {
3 | use-tls = false
4 | host = "helloscala.com"
5 | port = 48000
6 | }
7 | }
8 | discoveryx.client {
9 | naming {
10 | auto-registration = false
11 | heartbeat-interval = 10.seconds
12 | namespace = "ce6340c5-3066-11ea-b4fa-5254002e9e52" // helloscala.com public
13 | service-name = "fusion-schedulerx"
14 | port = 8000
15 | enable = true
16 | health = true
17 | weight = 1.0
18 | metadata {
19 | env = dev
20 | application = dev.schedulerx
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/web-console/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # 若无法执行 运行命令 chmod +x deploy.sh
4 |
5 | # 当前时间
6 | date=`date +%F`
7 | # 编译后资源所在的文件名
8 | dist_name="dist"
9 | # 压缩后的文件名
10 | file_name="dist-${date}.tar.gz"
11 | # 服务器用户名
12 | user="hl"
13 | # 服务器地址
14 | host="dn5"
15 | # 服务器上资源所在的路劲
16 | pwd="/home/app/frontend/recommender-app/"
17 |
18 | # 删除之前的文件
19 | rm -rf ${dist_name}
20 | rm -rf *.tar.gz
21 |
22 | # 构建项目
23 | npm run build
24 |
25 | # 压缩打包
26 | tar -zcvf ${file_name} ${dist_name}
27 |
28 | # 上传到服务器
29 | scp ${file_name} ${user}@${host}:${pwd}
30 |
31 | # 登录到目标服务器并发布
32 | ssh ${user}@${host} "cd ${pwd};tar -zxvf ${file_name} ${dist_name}"
33 |
34 | echo "发布成功"
--------------------------------------------------------------------------------
/discoveryx-client/src/test/resources/application-local-2.conf:
--------------------------------------------------------------------------------
1 | akka.grpc.client {
2 | "fusion.discoveryx.grpc.NamingService" {
3 | use-tls = false
4 | host = "localhost"
5 | port = 48000
6 | }
7 | }
8 | discoveryx.client {
9 | naming {
10 | auto-registration = true
11 | heartbeat-interval = 10.seconds
12 | namespace = "3d355123-3081-11ea-887d-4a7eb37c5068" // local public
13 | service-name = "fusion-schedulerx"
14 | ip = "127.0.0.1"
15 | port = 8001
16 | enable = true
17 | health = true
18 | weight = 2.0
19 | metadata {
20 | env = dev
21 | application = dev.schedulerx
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/test/resources/application-test.conf:
--------------------------------------------------------------------------------
1 | akka.grpc.client {
2 | "fusion.discoveryx.grpc.NamingService" {
3 | use-tls = false
4 | host = "localhost"
5 | port = 48000
6 | }
7 | }
8 | discoveryx.client {
9 | naming {
10 | auto-registration = true
11 | heartbeat-interval = 15.seconds
12 | namespace = "e43263f8-2df0-11ea-b7a8-1a022201bc26" // local public
13 | service-name = "fusion-discoveryx"
14 | port = 8888
15 | health = true
16 | enable = true
17 | ephemeral = true
18 | weight = 1.5
19 | metadata {
20 | env = dev
21 | application = dev.schedulerx
22 | }
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/_template/copyright.st:
--------------------------------------------------------------------------------
1 |
2 | $if(page.property_is.("project.license").("Apache-2.0"))$
3 | $page.properties.("project.name")$ is Open Source and available under the Apache 2 License.
4 | $endif$
5 |
6 | © 2019-$page.properties.("date.year")$ Akka Fusion |
7 | Fusion DiscoveryX |
8 | Fusion SchedulerX
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/discoveryx-functest/src/multi-jvm/resources/application.conf:
--------------------------------------------------------------------------------
1 | //akka-persistence-jdbc.shared-databases.h2 {
2 | // db {
3 | // url = "jdbc:h2:mem:discoveryx;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;"
4 | // }
5 | //}
6 |
7 | jdbc-journal {
8 | use-shared-db = "h2"
9 | }
10 | jdbc-snapshot-store {
11 | use-shared-db = "h2"
12 | }
13 | jdbc-read-journal {
14 | use-shared-db = "h2"
15 | }
16 |
17 | akka.persistence {
18 | journal {
19 | plugin = "jdbc-journal"
20 | //auto-start-journals = ["jdbc-journal"]
21 | }
22 | snapshot-store {
23 | plugin = "jdbc-snapshot-store"
24 | //auto-start-snapshot-stores = ["jdbc-snapshot-store"]
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/discoveryx-client/src/test/resources/application-helloscala-2.conf:
--------------------------------------------------------------------------------
1 | akka.grpc.client {
2 | "fusion.discoveryx.grpc.NamingService" {
3 | use-tls = false
4 | host = "helloscala.com"
5 | port = 48000
6 | }
7 | }
8 | discoveryx.client {
9 | naming {
10 | auto-registration = true
11 | heartbeat-interval = 10.seconds
12 | namespace = "ce6340c5-3066-11ea-b4fa-5254002e9e52" // helloscala.com public
13 | service-name = "fusion-schedulerx"
14 | ip = "127.0.0.1"
15 | port = 8001
16 | enable = true
17 | health = true
18 | weight = 2.0
19 | metadata {
20 | env = dev
21 | application = dev.schedulerx
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/lib/prettify/prettify.css:
--------------------------------------------------------------------------------
1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
--------------------------------------------------------------------------------
/discoveryx-server/src/test/resources/application-helloscala.conf:
--------------------------------------------------------------------------------
1 | akka.grpc.client {
2 | "*" {
3 | use-tls = false
4 | host = "helloscala.com"
5 | port = 48000
6 | }
7 | "fusion.discoveryx.grpc.NamingService" {}
8 | "fusion.discoveryx.server.grpc.UserService" {}
9 | }
10 | discoveryx.client {
11 | naming {
12 | heartbeat-interval = 30.seconds
13 | namespace = "ce6340c5-3066-11ea-b4fa-5254002e9e52" // helloscala.com gtx
14 | service-name = "discoveryx"
15 | ip = "172.31.130.182"
16 | port = 8000
17 | enable = true
18 | weight = 1.5
19 | metadata {
20 | env = test
21 | application = web-backend
22 | }
23 | }
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/docs/js/metadata-toggle.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 | var hiddenText = "[+] Show project info",
3 | shownText = "[-] Hide project info",
4 | toggle = $('' + hiddenText + ''),
5 | hidden = true,
6 | infotable = $('table.project-info')
7 |
8 | toggle.insertBefore(infotable)
9 | toggle.on("click", function(event) {
10 | if (hidden) {
11 | infotable.css("display", "block")
12 | toggle.text(shownText)
13 | hidden = false
14 | } else {
15 | infotable.css("display", "none")
16 | toggle.text(hiddenText)
17 | hidden = true
18 | }
19 | })
20 | })
--------------------------------------------------------------------------------
/web-console/src/components/Mismatch/index.less:
--------------------------------------------------------------------------------
1 | #noMatch {
2 | margin: 0;
3 | cursor: default;
4 | user-select: none;
5 | -webkit-font-smoothing: antialiased;
6 | text-rendering: optimizeLegibility;
7 | position: absolute;
8 | left: 50%;
9 | top: 50%;
10 | transform: translate(-50%, -50%);
11 | display: flex;
12 | justify-content: center;
13 | align-items: center;
14 |
15 | span {
16 | font-size: 24px;
17 | font-weight: 500;
18 | border-bottom: 0;
19 | border-right: 1px solid #eaeaea;
20 | padding: 0 20px 0 0;
21 | width: auto;
22 | }
23 |
24 | p {
25 | margin: 0;
26 | padding-left: 20px;
27 | font-size: 14px;
28 | font-weight: 400;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/web-console/static/html/loading/loading.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 4A系统——华龙海数
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/resources/sql/schemas/h2.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS public."journal" (
2 | "ordering" BIGINT AUTO_INCREMENT,
3 | "persistence_id" VARCHAR(255) NOT NULL,
4 | "sequence_number" BIGINT NOT NULL,
5 | "deleted" BOOLEAN DEFAULT FALSE NOT NULL,
6 | "tags" VARCHAR(255) DEFAULT NULL,
7 | "message" BYTEA NOT NULL,
8 | PRIMARY KEY("persistence_id", "sequence_number")
9 | );
10 |
11 | CREATE UNIQUE INDEX IF NOT EXISTS "journal_ordering_idx" ON public."journal"("ordering");
12 |
13 | CREATE TABLE IF NOT EXISTS public."snapshot" (
14 | "persistence_id" VARCHAR(255) NOT NULL,
15 | "sequence_number" BIGINT NOT NULL,
16 | "created" BIGINT NOT NULL,
17 | "snapshot" BYTEA NOT NULL,
18 | PRIMARY KEY("persistence_id", "sequence_number")
19 | );
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/share/jdbc/schema/mysql/mysql-schema.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS journal;
2 |
3 | CREATE TABLE IF NOT EXISTS journal (
4 | ordering SERIAL,
5 | persistence_id VARCHAR(255) NOT NULL,
6 | sequence_number BIGINT NOT NULL,
7 | deleted BOOLEAN DEFAULT FALSE NOT NULL,
8 | tags VARCHAR(255) DEFAULT NULL,
9 | message BLOB NOT NULL,
10 | PRIMARY KEY(persistence_id, sequence_number)
11 | );
12 |
13 | CREATE UNIQUE INDEX journal_ordering_idx ON journal(ordering);
14 |
15 | DROP TABLE IF EXISTS snapshot;
16 |
17 | CREATE TABLE IF NOT EXISTS snapshot (
18 | persistence_id VARCHAR(255) NOT NULL,
19 | sequence_number BIGINT NOT NULL,
20 | created BIGINT NOT NULL,
21 | snapshot BLOB NOT NULL,
22 | PRIMARY KEY (persistence_id, sequence_number)
23 | );
24 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | # For detailed information about docker-compose visit https://docs.docker.com/compose/
2 | # To start all docker containers required to execute the tests locally run:
3 | # docker-compose up
4 |
5 | version: '3'
6 | services:
7 | cassandra:
8 | container_name: fusion-discoveryx_cassandra
9 | build:
10 | context: ./scripts/dockers/cassandra
11 | dockerfile: Dockerfile
12 | ports:
13 | - "9042:9042"
14 | postgres:
15 | container_name: fusion-discoveryx_postgres
16 | build:
17 | context: ./scripts/dockers/postgres
18 | dockerfile: Dockerfile
19 | ports:
20 | - "5432:5432"
21 | environment:
22 | POSTGRES_DB: fusion_discoveryx
23 | POSTGRES_USER: devuser
24 | POSTGRES_PASSWORD: devPass.2019
25 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DEBUG
6 |
7 |
8 | [%date{ISO8601}] [%level] [%logger] [%thread] [%X{akkaSource}] - %msg%n
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/web-console/src/router/constants.js:
--------------------------------------------------------------------------------
1 | // 配置管理
2 | const CONFIG_MANAGEMENT_LIST = '/config/management/list';
3 | // 新建配置
4 | const CONFIG_MANAGEMENT_CREATE = '/config/management/create';
5 | // 新建配置
6 | const CONFIG_MANAGEMENT_DETAIL = '/config/management/detail';
7 | // 服务管理
8 | const SERVICE_MANAGEMENT_LIST = '/service/management/list';
9 | // 服务详情
10 | const SERVICE_MANAGEMENT_DETAIL = '/service/management/detail';
11 | // 命名空间管理
12 | const NAMESPACE_MANAGEMENT_LIST = '/namespace/management/list';
13 | // 用户管理
14 | const USER_MANAGEMENT_LIST = '/user/management/list';
15 |
16 | export {
17 | CONFIG_MANAGEMENT_LIST,
18 | CONFIG_MANAGEMENT_CREATE,
19 | CONFIG_MANAGEMENT_DETAIL,
20 | NAMESPACE_MANAGEMENT_LIST,
21 | SERVICE_MANAGEMENT_LIST,
22 | SERVICE_MANAGEMENT_DETAIL,
23 | USER_MANAGEMENT_LIST,
24 | };
25 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/intro.md:
--------------------------------------------------------------------------------
1 | # 介绍
2 |
3 | *Fusion DiscoveryX 成长于作者对 Akka 生态的学习,API上参考了Nacos的某些设计。*
4 |
5 | Fusion DiscoveryX(之后简称 DiscoveryX)是一款服务注册与发现管理系统,致力于帮助您发现、配置及管理微服务。基于Akka生态开发。
6 |
7 | @@project-info{ projectId="fusion-discoveryx" }
8 |
9 | ## 特性
10 |
11 | - 配置管理
12 | - 服务发现
13 | - 动态配置服务
14 |
15 | ## 开发技术
16 |
17 | DiscoveryX 在开发中主要使用到以下技术:
18 |
19 | | 功能 | 使用技术 |
20 | | ---------- | --------------------- |
21 | | 开放API | Akka gRPC |
22 | | 集群序例化 | Protobuf |
23 | | 配置持久化 | Akka Persistence |
24 | | 容错与扩展 | Akka Cluster Sharding |
25 | | REST | Akka HTTP |
26 |
27 | ## 接下来
28 |
29 | 访问 @ref[quick-start](use/quick-start.md) 开始快速使用 DiscoveryX 。
30 |
31 | 也可以访问 @ref[architecture](design/architecture.md) 了解 DiscoveryX 的架构设计与技术选择。
32 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/share/jdbc/schema/postgres/postgres-schema.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS public.journal;
2 |
3 | CREATE TABLE IF NOT EXISTS public.journal (
4 | ordering BIGSERIAL,
5 | persistence_id VARCHAR(255) NOT NULL,
6 | sequence_number BIGINT NOT NULL,
7 | deleted BOOLEAN DEFAULT FALSE NOT NULL,
8 | tags VARCHAR(255) DEFAULT NULL,
9 | message BYTEA NOT NULL,
10 | PRIMARY KEY(persistence_id, sequence_number)
11 | );
12 |
13 | CREATE UNIQUE INDEX journal_ordering_idx ON public.journal(ordering);
14 |
15 | DROP TABLE IF EXISTS public.snapshot;
16 |
17 | CREATE TABLE IF NOT EXISTS public.snapshot (
18 | persistence_id VARCHAR(255) NOT NULL,
19 | sequence_number BIGINT NOT NULL,
20 | created BIGINT NOT NULL,
21 | snapshot BYTEA NOT NULL,
22 | PRIMARY KEY(persistence_id, sequence_number)
23 | );
24 |
25 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/share/jdbc/schema/sqlserver/sqlserver-schema.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS journal;
2 |
3 | CREATE TABLE journal (
4 | "ordering" BIGINT IDENTITY(1,1) NOT NULL,
5 | "deleted" BIT DEFAULT 0 NOT NULL,
6 | "persistence_id" VARCHAR(255) NOT NULL,
7 | "sequence_number" NUMERIC(10,0) NOT NULL,
8 | "tags" VARCHAR(255) NULL DEFAULT NULL,
9 | "message" VARBINARY(max) NOT NULL,
10 | PRIMARY KEY ("persistence_id", "sequence_number")
11 | );
12 |
13 | CREATE UNIQUE INDEX journal_ordering_idx ON journal (ordering);
14 |
15 | DROP TABLE IF EXISTS snapshot;
16 |
17 | CREATE TABLE snapshot (
18 | "persistence_id" VARCHAR(255) NOT NULL,
19 | "sequence_number" NUMERIC(10,0) NOT NULL,
20 | "created" NUMERIC NOT NULL,
21 | "snapshot" VARBINARY(max) NOT NULL,
22 | PRIMARY KEY ("persistence_id", "sequence_number")
23 | );
24 |
--------------------------------------------------------------------------------
/discoveryx-client/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DEBUG
6 |
7 |
8 | [%date{ISO8601}] [%level] [%logger] [%thread] [%X{akkaSource}] - %msg%n
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/discoveryx-client/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DEBUG
6 |
7 |
8 | [%date{ISO8601}] [%level] [%logger] [%thread] [%X{akkaSource}] - %msg%n
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/deploy/persistence-cassandra.md:
--------------------------------------------------------------------------------
1 | # 集群部署(使用Cassandra作为存储)
2 |
3 | ## 基本配置
4 |
5 | Fusion DiscoveryX 使用 Akka Persistence 作为存储层,[akka-persistence-cassandra](https://doc.akka.io/docs/akka-persistence-cassandra/current/) 为 Akka Persistence 提供了 JDBC 访问插件。
6 |
7 | ```hocon
8 | akka {
9 | persistence {
10 | journal {
11 | plugin = "cassandra-journal"
12 | // auto-start-journals = ["cassandra-journal"]
13 | }
14 | snapshot-store {
15 | plugin = "cassandra-snapshot-store"
16 | // auto-start-snapshot-stores = ["cassandra-snapshot-store"]
17 | }
18 | }
19 | }
20 | ```
21 |
22 | ### 初始化数据库
23 |
24 | 在启动 Fusion DiscoveryX 之前,需要提前建好 Cassandra 数据库表。在软件包的 `share/cassandra/schema` 目录下能找到 Cassandra 数据库表的创建脚本。
25 |
26 | ```
27 | ├── journal-schema.cql
28 | └── snapshot-schema.cql
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/js/magellan.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // add magellan targets to anchor headers, for h1 and h2
4 | $("a.anchor").each(function() {
5 | var anchor = $(this);
6 | var name = anchor.attr("name");
7 | var header = anchor.parent();
8 | header.attr("id", name);
9 | if (header.is("h1") || header.is("h2")) {
10 | header.attr("data-magellan-target", name);
11 | }
12 | });
13 |
14 | // enable magellan plugin on the active page header links in the navigation
15 | var nav = $(".site-nav a.active.page").parent("li");
16 | if (nav.length > 0) {
17 | // strip navigation links down to just the hash fragment
18 | nav.find("a.active.page, a.header").attr('href', function(_, current){
19 | return this.hash ? this.hash : current;
20 | });
21 | new Foundation.Magellan(nav);
22 | }
23 |
24 | });
25 |
--------------------------------------------------------------------------------
/discoveryx-functest/src/multi-jvm/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DEBUG
6 |
7 |
8 | [%date{ISO8601}] [%level] [%logger] [%thread] [%X{akkaSource}] - %msg%n
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/scala/fusion/discoveryx/client/play/javadsl/DiscoveryXPlay.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.javadsl;
18 |
19 | public @interface DiscoveryXPlay {
20 | }
21 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/scala/fusion/discoveryx/client/play/scaladsl/DiscoveryXPlay.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.scaladsl;
18 |
19 | public @interface DiscoveryXPlay {
20 | }
21 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/share/jdbc/schema/h2/h2-schema.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS PUBLIC."journal";
2 |
3 | CREATE TABLE IF NOT EXISTS PUBLIC."journal" (
4 | "ordering" BIGINT AUTO_INCREMENT,
5 | "persistence_id" VARCHAR(255) NOT NULL,
6 | "sequence_number" BIGINT NOT NULL,
7 | "deleted" BOOLEAN DEFAULT FALSE NOT NULL,
8 | "tags" VARCHAR(255) DEFAULT NULL,
9 | "message" BYTEA NOT NULL,
10 | PRIMARY KEY("persistence_id", "sequence_number")
11 | );
12 |
13 | CREATE UNIQUE INDEX "journal_ordering_idx" ON PUBLIC."journal"("ordering");
14 |
15 | DROP TABLE IF EXISTS PUBLIC."snapshot";
16 |
17 | CREATE TABLE IF NOT EXISTS PUBLIC."snapshot" (
18 | "persistence_id" VARCHAR(255) NOT NULL,
19 | "sequence_number" BIGINT NOT NULL,
20 | "created" BIGINT NOT NULL,
21 | "snapshot" BYTEA NOT NULL,
22 | PRIMARY KEY("persistence_id", "sequence_number")
23 | );
24 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DEBUG
6 |
7 |
8 | [%date{ISO8601}] [%level] [%logger] [%thread] [%X{akkaSource}] - %msg%n
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/web-console/src/stores/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin mobx统一注册store
5 | * */
6 | import { store, hotRehydrate, rehydrate } from 'rfx-core';
7 | import GlobalStore from './GlobalStore';
8 | import ConfigStore from './ConfigStore';
9 | import NamespaceStore from './NamespaceStore';
10 | import ServiceStore from './ServiceStore';
11 | import UserStore from './UserStore';
12 | import { isProduction } from '../utils/constants';
13 |
14 | store.setup({
15 | globalStore: GlobalStore,
16 | userStore: UserStore,
17 | configStore: ConfigStore,
18 | namespaceStore: NamespaceStore,
19 | serviceStore: ServiceStore,
20 | });
21 |
22 | // mobx hmr
23 | const stores = rehydrate();
24 | const hmrStores = isProduction ? stores : hotRehydrate();
25 |
26 | export default hmrStores;
27 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/deploy/index.md:
--------------------------------------------------------------------------------
1 | # 部署
2 |
3 | Fusion DiscoveryX 提供 **zip** 包和 **Docker** 镜像两种打包部署方式,高级用户亦可以下载源码自行编译打包以获得更多的定制性。Fusion DiscoveryX 支持单机、集群部署,官方集群部署提供了对 JDBC 、Cassandra 的后端存储支持,用户通过 Akka Persistence Plugins 可以很方便的集成其它存储方式。如:
4 |
5 | - MongoDB: [https://github.com/scullxbones/akka-persistence-mongo](https://github.com/scullxbones/akka-persistence-mongo)
6 | - DynamoDB: [https://github.com/akka/akka-persistence-dynamodb](https://github.com/akka/akka-persistence-dynamodb)
7 | - CouchBase: [https://github.com/akka/akka-persistence-couchbase](https://github.com/akka/akka-persistence-couchbase)
8 |
9 | @@toc { depth=3 }
10 |
11 | @@@ index
12 |
13 | - [package](package.md)
14 | - [single](single.md)
15 | - [cluster-jdbc](cluster-jdbc.md)
16 | - [persistence-cassandra](persistence-cassandra.md)
17 | - [docker](docker.md)
18 | - [other-persistence](other-persistence.md)
19 |
20 | @@@
21 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/use/quick-start.md:
--------------------------------------------------------------------------------
1 | # 快速开始
2 |
3 | ## 下载
4 |
5 | @@@vars
6 | 下载压缩包 [discoveryx-server-$version$.zip](https://github.com/akka-fusion/fusion-discoveryx/releases),解压到目录。如:
7 | @@@
8 |
9 | @@@vars
10 | ```
11 | /home/yangjing/discoveryx-server-$version$
12 | ```
13 | @@@
14 |
15 | ## 启动服务
16 |
17 | 进入软件根目录执行启动脚本运行:
18 |
19 | @@@vars
20 | ```
21 | cd discoveryx-server-$version$/
22 | ./bin/discoveryx-server
23 | ```
24 | @@@
25 |
26 | **Windows**系统请执行 `bin/discoveryx-server.bat` 。
27 |
28 | 打开浏览器,输入:`http://localhost:48000`即可访问 Fusion DiscoveryX 管理控制台。
29 |
30 | @@@note
31 | 默认将使用 H2 嵌入式文件数据库,这种方式只适合测试使用。若需要在产品中使用,请使用独立数据库,参阅: @ref[集群部署(使用JDBC持久化)](../deploy/cluster-jdbc.md) 或 @ref[集群部署(使用Cassandra作为存储)](../deploy/persistence-cassandra.md) 。
32 | @@@
33 |
34 | ## 接下来
35 |
36 | - @ref[在 Akka 中使用](akka.md)
37 | - @ref[在 Play 中使用](play.md)
38 | - @ref[在 Spring 中使用](spring.md)
39 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/FusionDiscoveryXMain.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server
18 |
19 | object FusionDiscoveryXMain {
20 | def main(args: Array[String]): Unit = {
21 | DiscoveryXServer().start()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/docs/lib/prettify/lang-scala.js:
--------------------------------------------------------------------------------
1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
2 | ["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:0(?:[0-7]+|x[\da-f]+)l?|(?:0|[1-9]\d*)(?:(?:\.\d+)?(?:e[+-]?\d+)?f?|l?)|\\.\d+(?:e[+-]?\d+)?f?)/i],["typ",/^[$_]*[A-Z][\d$A-Z_]*[a-z][\w$]*/],["pln",/^[$A-Z_a-z][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"]);
3 |
--------------------------------------------------------------------------------
/scripts/dockers/postgres/postgres-schema.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS public.journal;
2 |
3 | CREATE TABLE IF NOT EXISTS public.journal
4 | (
5 | ordering BIGSERIAL,
6 | persistence_id VARCHAR(255) NOT NULL,
7 | sequence_number BIGINT NOT NULL,
8 | deleted BOOLEAN DEFAULT FALSE,
9 | tags VARCHAR(255) DEFAULT NULL,
10 | message BYTEA NOT NULL,
11 | PRIMARY KEY (persistence_id, sequence_number)
12 | );
13 |
14 | CREATE UNIQUE INDEX IF NOT EXISTS journal_ordering_idx ON public.journal (ordering);
15 |
16 | DROP TABLE IF EXISTS public.snapshot;
17 |
18 | CREATE TABLE IF NOT EXISTS public.snapshot
19 | (
20 | persistence_id VARCHAR(255) NOT NULL,
21 | sequence_number BIGINT NOT NULL,
22 | created BIGINT NOT NULL,
23 | snapshot BYTEA NOT NULL,
24 | PRIMARY KEY (persistence_id, sequence_number)
25 | );
26 |
--------------------------------------------------------------------------------
/discoveryx-common/src/main/scala/fusion/discoveryx/DiscoveryXSettings.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx
18 |
19 | import com.typesafe.config.Config
20 |
21 | case class DiscoveryXSettings()
22 |
23 | object DiscoveryXSettings {
24 | def apply(config: Config): DiscoveryXSettings = {
25 | DiscoveryXSettings()
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/index.md:
--------------------------------------------------------------------------------
1 | # Fusion DiscoveryX
2 |
3 | [](https://travis-ci.org/akka-fusion/fusion-discoveryx)
4 |
5 | Fusion DiscoveryX(之后简称 DiscoveryX)是一款服务注册与发现管理系统,致力于帮助您发现、配置及管理微服务。基于Akka生态开发。
6 |
7 | 产品文档:[https://akka-fusion.github.io/fusion-discoveryx/](https://akka-fusion.github.io/fusion-discoveryx/)
8 |
9 | *码云镜像:[https://akka-fusion.gitee.io/fusion-discoveryx/](https://akka-fusion.gitee.io/fusion-discoveryx/)*
10 |
11 | 在线演示Demo:http://helloscala.com:48000/ 。
12 |
13 | @@@note
14 | *gRPC需要HTTP 2,akka-http支持不使用tls访问HTTP 2。这里直接使用端口访问。*
15 |
16 | 在线演示Demo账号:
17 |
18 | - SN: discoveryx
19 | - PW: discoveryx
20 | @@@
21 |
22 | @@toc { depth=2 }
23 |
24 | @@@ index
25 |
26 | - [intro](intro.md)
27 | - [use](use/index.md)
28 | - [design](design/index.md)
29 | - [api](api/index.md)
30 | - [deploy](deploy/index.md)
31 | - [release](releases.md)
32 |
33 | @@@
34 |
--------------------------------------------------------------------------------
/.scalafmt.conf:
--------------------------------------------------------------------------------
1 | version = 2.2.2
2 | style = defaultWithAlign
3 | lineEndings = unix
4 | encoding = "UTF-8"
5 | project.git = true
6 | docstrings = JavaDoc
7 | maxColumn = 120
8 | indentOperator = spray
9 | unindentTopLevelOperators = true
10 | align.tokens = [{code = "=>", owner = "Case"}]
11 | align.openParenDefnSite = false
12 | align.openParenCallSite = false
13 | optIn.breakChainOnFirstMethodDot = false
14 | optIn.configStyleArguments = false
15 | danglingParentheses = false
16 | spaces.inImportCurlyBraces = true
17 | rewrite.neverInfix.excludeFilters = [
18 | and
19 | min
20 | max
21 | until
22 | to
23 | by
24 | eq
25 | ne
26 | "should.*"
27 | "contain.*"
28 | "must.*"
29 | in
30 | ignore
31 | be
32 | taggedAs
33 | thrownBy
34 | synchronized
35 | have
36 | when
37 | size
38 | only
39 | noneOf
40 | oneElementOf
41 | noElementsOf
42 | atLeastOneElementOf
43 | atMostOneElementOf
44 | allElementsOf
45 | inOrderElementsOf
46 | theSameElementsAs
47 | ]
48 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx
18 |
19 | import akka.persistence.query.scaladsl._
20 |
21 | package object server {
22 | type DiscoveryXReadJournal = ReadJournal
23 | with PersistenceIdsQuery
24 | with CurrentPersistenceIdsQuery
25 | with EventsByTagQuery
26 | with EventsByPersistenceIdQuery
27 | }
28 |
--------------------------------------------------------------------------------
/web-console/src/components/Highlight/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 高亮
5 | * */
6 |
7 | import React, { Fragment } from 'react';
8 | import shortid from 'shortid';
9 | import * as PropTypes from 'prop-types';
10 |
11 | const Highlight = ({ text, keyword }) => {
12 | const reg = new RegExp(keyword, 'gi');
13 | const match = text.match(reg);
14 | if (!match) {
15 | return text;
16 | }
17 | return (
18 |
19 | {text.split(reg).map((fragment, i) =>
20 | i > 0 ? (
21 |
22 | {match[0]}
23 | {fragment}
24 |
25 | ) : (
26 | fragment
27 | ),
28 | )}
29 |
30 | );
31 | };
32 |
33 | Highlight.propTypes = {
34 | text: PropTypes.string.isRequired,
35 | keyword: PropTypes.string.isRequired,
36 | };
37 |
38 | export default Highlight;
39 |
--------------------------------------------------------------------------------
/web-console/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "node": true
5 | },
6 | "extends": ["airbnb", "plugin:prettier/recommended"],
7 | "parser": "babel-eslint",
8 | "parserOptions": {
9 | "ecmaFeatures": {
10 | "legacyDecorators": true
11 | }
12 | },
13 | "rules": {
14 | "prettier/prettier": [
15 | "error",
16 | {
17 | "singleQuote": true,
18 | "trailingComma": "all",
19 | "printWidth": 100,
20 | "proseWrap": "never"
21 | }
22 | ],
23 | "react/jsx-filename-extension": [
24 | 0,
25 | {
26 | "extensions": [".js", ".jsx"]
27 | }
28 | ],
29 | "react/forbid-prop-types": 0,
30 | "jsx-a11y/anchor-is-valid": [
31 | "error",
32 | {
33 | "components": ["Link"],
34 | "specialLink": ["to"]
35 | }
36 | ],
37 | "react/static-property-placement": 0,
38 | "react/state-in-constructor": 0,
39 | "react/destructuring-assignment": 0,
40 | "react/jsx-props-no-spreading": 0
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/use/sdk-scala.md:
--------------------------------------------------------------------------------
1 | # Scala SDK
2 |
3 | ## Module Info
4 |
5 | 需要在项目中添加如下依赖:
6 |
7 | @@dependency[sbt,Gradle,Maven] { group="com.akka-fusion.fusion" artifact="discoveryx-client_$scala.binary_version$" version="$version$" }
8 |
9 | @@dependencies{ projectId="discoveryx-client" }
10 |
11 | ## 使用
12 |
13 | ### gRPC Client配置
14 |
15 | Fusion DiscoveryX Client for Scala SDK 使用 akka-grpc 开发,使用时需要配置 `akka.grpc.client` 指定 DiscoveryX Server 地址。
16 |
17 | @@snip [discovery](../../../../../discoveryx-client/src/main/resources/reference.conf) { #grpc-client }
18 |
19 | @@@note
20 | gRPC服务全限定名在HOCON配置里需要使用英文双引号括起来,因为HOCON默认使用英文点号来区分配置层级。
21 |
22 | 测试时可以把`use-tls`参数设置为`false`,但在生产环境中建议使用默认值`true`。
23 | @@@
24 |
25 | ### 自动注册服务
26 |
27 | 若需要把服务自动注册到 DiscoveryX Server,需要配置 `discoveryx.client.naming.auto-registration = true` 。同时,还需要设置`namespace`、`service-name`、`ip`、`port`,其中`ip`可通过自动检测获取(当不指定或设置为空字符串时,若发现自动检测到的IP地址不正确请手动指定)。
28 |
29 | @@snip [discovery](../../../../../discoveryx-client/src/main/resources/reference.conf) { #discoveryx-client }
30 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/resources/application-test.conf:
--------------------------------------------------------------------------------
1 | discoveryx {
2 | name = discoveryx
3 | server {
4 | naming {
5 | heartbeat-interval = 2.seconds
6 | }
7 | }
8 | client {
9 | naming {
10 | heartbeat-interval = 2.seconds
11 | }
12 | }
13 |
14 | akka {
15 | loglevel = INFO
16 | remote.artery.canonical.port = 49001
17 | cluster.seed-nodes = ["127.0.0.1:49001"]
18 | }
19 | }
20 |
21 | akka.persistence {
22 | journal {
23 | plugin = "jdbc-journal"
24 | plugin = ${?JOURNAL_PLUIGN}
25 | // auto-start-journals = ["jdbc-journal"]
26 | }
27 | snapshot-store {
28 | plugin = "jdbc-snapshot-store"
29 | plugin = ${?SNAPSHOT_PLUGIN}
30 | // auto-start-snapshot-stores = ["jdbc-snapshot-store"]
31 | }
32 | }
33 |
34 | include "persistence-postgres.conf"
35 |
36 | akka.grpc.client {
37 | "*" {
38 | use-tls = false
39 | host = "helloscala.com"
40 | port = 48000
41 | }
42 | "fusion.discoveryx.grpc.NamingService" {}
43 | "fusion.discoveryx.server.grpc.UserService" {}
44 | }
45 |
--------------------------------------------------------------------------------
/web-console/src/components/PhotoSwipe/index.less:
--------------------------------------------------------------------------------
1 | #photoSwipe {
2 | a {
3 | display: unset;
4 | }
5 |
6 | .my-gallery {
7 | width: 100%;
8 | display: flex;
9 | align-items: center;
10 | justify-content: flex-start;
11 | flex-direction: column;
12 | }
13 |
14 | .my-gallery figure {
15 | display: block;
16 | margin: 10px 0 0 0;
17 | width: 100%;
18 | }
19 |
20 | .my-gallery img {
21 | width: 100%;
22 | height: auto;
23 | }
24 |
25 | .my-gallery figcaption {
26 | display: none;
27 | }
28 |
29 | //.pswp__counter {
30 | // height: 44px; /* no */
31 | // font-size: 14px; /* no */
32 | // line-height: 44px; /* no */
33 | // padding: 0 10px; /* no */
34 | //}
35 | //
36 | //.pswp__button {
37 | // width: 44px; /* no */
38 | // height: 44px; /* no */
39 | // background-size: 264px 88px; /* no */
40 | //}
41 | //
42 | //.pswp__button--share {
43 | // background-position: -44px -44px; /* no */
44 | //}
45 | //
46 | //.pswp__button--close {
47 | // background-position: 0 -44px; /* no */
48 | //}
49 | }
50 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/json.md:
--------------------------------------------------------------------------------
1 | # JSON 说明
2 |
3 | ## Protobuf、JSON转换说明
4 |
5 | REST API使用JSON作为序例化,由Protobuf数据自动序例化为JSON(或反之)。
6 |
7 | 1. Protobuf里使用下划线定义的字段在序例化为JSON时将自动转换成驼峰格式;
8 | 2. 当某个字段未设置时,将使用Protobuf里定义的默认值。也就是说客户在提交请求时不需要每个字段都设置,同时,服务端返回结果时未设置的字段将使用默认值返回;
9 | 3. `oneof`类型字段在序例化为JSON时将不包含外层的包裹,将直接返回设置的字段。
10 |
11 | ## 示例
12 |
13 | **protobuf**
14 |
15 | @@snip [protocol](../../../../../discoveryx-server/src/main/protobuf/fusion/discoveryx/server/protocol/naming.proto) { #NamingResponse }
16 |
17 | **json**
18 |
19 | ```json
20 | {
21 | "status":200,
22 | "message":"",
23 | "serviceInfo":{
24 | "namespace":"namespace",
25 | "serviceName":"fusion-discoveryx",
26 | "groupName":"default",
27 | "instances":[
28 | {
29 | "instanceId":"127.0.0.1:8000",
30 | "ip":"127.0.0.1",
31 | "port":8000,
32 | "weight":0,
33 | "healthy":true,
34 | "enabled":false,
35 | "metadata":{
36 |
37 | }
38 | }
39 | ]
40 | }
41 | }
42 | ```
--------------------------------------------------------------------------------
/discoveryx-server/src/test/resources/persistence-postgres.conf:
--------------------------------------------------------------------------------
1 |
2 | akka-persistence-jdbc {
3 | logicalDeletion.enable = false
4 | shared-databases {
5 | slick {
6 | profile = "slick.jdbc.PostgresProfile$"
7 | db {
8 | //dataSourceClassName = "org.postgresql.ds.PGSimpleDataSource"
9 | host = "localhost"
10 | host = ${?POSTGRES_HOST}
11 | url = "jdbc:postgresql://"${akka-persistence-jdbc.shared-databases.slick.db.host}":5432/fusion_discoveryx?reWriteBatchedInserts=true"
12 | user = "devuser"
13 | user = ${?POSTGRES_USER}
14 | password = "devPass.2019"
15 | password = ${?POSTGRES_PASSWORD}
16 | driver = "org.postgresql.Driver"
17 | numThreads = 5
18 | maxConnections = 5
19 | minConnections = 1
20 | }
21 | }
22 | }
23 | }
24 |
25 | jdbc-journal {
26 | use-shared-db = "slick"
27 | }
28 |
29 | # the akka-persistence-snapshot-store in use
30 | jdbc-snapshot-store {
31 | use-shared-db = "slick"
32 | }
33 |
34 | # the akka-persistence-query provider in use
35 | jdbc-read-journal {
36 | use-shared-db = "slick"
37 | }
38 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/share/cassandra/schema/snapshot-schema.cql:
--------------------------------------------------------------------------------
1 | CREATE KEYSPACE IF NOT EXISTS akka_snapshot WITH REPLICATION = { 'class': 'SimpleStrategy', 'replication_factor': 1 };
2 |
3 | CREATE TABLE IF NOT EXISTS akka_snapshot.snapshots
4 | (
5 | persistence_id text,
6 | sequence_nr bigint,
7 | timestamp bigint,
8 | ser_id int,
9 | ser_manifest text,
10 | snapshot_data blob,
11 | snapshot blob,
12 | meta_ser_id int,
13 | meta_ser_manifest text,
14 | meta blob,
15 | PRIMARY KEY (persistence_id, sequence_nr)
16 | )
17 | WITH CLUSTERING ORDER BY (sequence_nr DESC) AND gc_grace_seconds =864000
18 | AND compaction = {
19 | 'class' : 'SizeTieredCompactionStrategy',
20 | 'enabled' : true,
21 | 'tombstone_compaction_interval' : 86400,
22 | 'tombstone_threshold' : 0.2,
23 | 'unchecked_tombstone_compaction' : false,
24 | 'bucket_high' : 1.5,
25 | 'bucket_low' : 0.5,
26 | 'max_threshold' : 32,
27 | 'min_threshold' : 4,
28 | 'min_sstable_size' : 50
29 | };
30 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/deploy/package.md:
--------------------------------------------------------------------------------
1 | # 软件包
2 |
3 | ## 下载
4 |
5 | 在 https://github.com/akka-fusion/fusion-discoveryx/releases 下载最新版本,解压缩到目录执行。
6 |
7 | **Unix/Linux**
8 |
9 | ```shell script
10 | unzip discoveryx-server-[VERSION].zip
11 | cd discoveryx-server
12 | ./bin/discoveryx-server
13 | ```
14 |
15 | **Windows**
16 |
17 | ```
18 | unzip discoveryx-server-[VERSION].zip
19 | cd discoveryx-server
20 | bin/discoveryx-server.bat
21 | ```
22 |
23 | ## 源码构建
24 |
25 | ```
26 | git clone https://github.com/akka-fusion/fusion-discoveryx.git
27 | cd fusion-discoveryx
28 | pushd web-console
29 | yarn && yarn build
30 | popd
31 | pushd ../scripts
32 | ./publish-dist.sh
33 | popd
34 | sbt "discoveryx-server" dist
35 | ```
36 |
37 | @@@vars
38 | 最终将在 `discoveryx-server/target/universal` 目录生成 discoveryx-server-$version$.zip 软件包。解压生成的 **zip** 软件包(discoveryx-server-$version$.zip),执行 `bin` 目录里的 `sh` 或 `bat` 脚本即可运行程序。
39 | @@@
40 |
41 | @@@vars
42 | ```
43 | cd discoveryx-server/target/universal
44 | unzip discoveryx-server-$version$.zip
45 | cd discoveryx-server-$version$
46 | ./bin/discoveryx-server
47 | ```
48 | @@@
49 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/route/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server
18 |
19 | import akka.http.scaladsl.server.Directives._
20 | import akka.http.scaladsl.server.{ Directive, PathMatcher }
21 |
22 | package object route {
23 | def pathPost[L](pm: PathMatcher[L]): Directive[L] = path(pm) & post
24 | def pathGet[L](pm: PathMatcher[L]): Directive[L] = path(pm) & get
25 | def pathPut[L](pm: PathMatcher[L]): Directive[L] = path(pm) & put
26 | def pathDelete[L](pm: PathMatcher[L]): Directive[L] = path(pm) & delete
27 | }
28 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/fusion/discoveryx/server/util/SessionUtilsTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.util
18 |
19 | import java.net.URLEncoder
20 | import java.nio.charset.StandardCharsets
21 |
22 | import org.scalatest.wordspec.AnyWordSpec
23 |
24 | class SessionUtilsTest extends AnyWordSpec {
25 | "SessionUtilsTest" should {
26 | "tokenFromCookie" in {
27 | val str = URLEncoder.encode("abCD0/|_=-", StandardCharsets.UTF_8)
28 | println(str)
29 | }
30 |
31 | "decodeToken" in {}
32 |
33 | "generateSessionToken" in {}
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/docs/css/icons.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'icons';
3 | font-weight: normal;
4 | font-style: normal;
5 | src: url('fonts/icons.eot?2');
6 | src: url('fonts/icons.eot?2#iefix') format('embedded-opentype'),
7 | url('fonts/icons.woff2?2') format('woff2'),
8 | url('fonts/icons.woff?2') format('woff'),
9 | url('fonts/icons.ttf?2') format('truetype'),
10 | url('fonts/icons.svg?2#icons') format('svg');
11 | }
12 |
13 | .icon-prev:before,
14 | .icon-next:before,
15 | .icon-up:before,
16 | .icon-down:before,
17 | .icon-link:before {
18 | font-family: "icons";
19 | font-style: normal;
20 | font-weight: normal;
21 | speak: none;
22 | display: inline-block;
23 | text-decoration: inherit;
24 | width: 1em;
25 | margin-right: .2em;
26 | text-align: center;
27 | font-variant: normal;
28 | text-transform: none;
29 | line-height: 1em;
30 | -webkit-font-smoothing: antialiased;
31 | -moz-osx-font-smoothing: grayscale;
32 | }
33 |
34 | .icon-prev:before { content: '\3c'; } /* '<' */
35 | .icon-next:before { content: '\3e'; } /* '>' */
36 | .icon-up:before { content: '\5e'; } /* '^' */
37 | .icon-down:before { content: '\76'; } /* 'v' */
38 | .icon-link:before { content: '\a7'; } /* '§' */
39 |
--------------------------------------------------------------------------------
/web-console/static/html/loveOrHate/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Love or Hate ?
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/deploy/other-persistence.md:
--------------------------------------------------------------------------------
1 | # 其它存储机制
2 |
3 | Fusion DiscoveryX 使用 Akka Persistence 作为存储层,且使用 Akka Persistence 来存储所有数据,所以理论上只要实现了 Akka Persistence Plugins 的存储系统都可应用于 Fusion DiscoveryX。
4 |
5 | 需要修改 `akka.persistence` 配置使用想要使用的存储插件,同时,还需要将相应插件依赖的 **jar** 包入到 Fusion DiscoveryX 软件 `lib` 目录里面。
6 |
7 | ## MongoDB
8 |
9 | - [https ://github.com/scullxbones/akka-persistence-mongo](https://github.com/scullxbones/akka-persistence-mongo)
10 |
11 | @@dependency[sbt,Gradle,Maven] { group="com.github.scullxbones" artifact="akka-persistence-mongo-rxmongo_2.12" version="$akka.persistence.mongo.version$" }
12 |
13 | ## DynamoDB
14 |
15 | - [https://github.com/akka/akka-persistence-dynamodb](https://github.com/akka/akka-persistence-dynamodb)
16 |
17 | @@dependency[sbt,Gradle,Maven] { group="com.typesafe.akka" artifact="akka-persistence-dynamodb_$scala.binary_version$" version="$akka.persistence.dynamodb.version$" }
18 |
19 | ## CouchBase
20 |
21 | - [https://github.com/akka/akka-persistence-couchbase](https://github.com/akka/akka-persistence-couchbase)
22 |
23 | @@dependency[sbt,Gradle,Maven] { group="com.lightbend.akka" artifact="akka-persistence-couchbase_$scala.binary_version$" version="$akka.persistence.couchbase.version$" }
24 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/akka/fusion/testkit/FusionActorTestKit.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package akka.fusion.testkit
18 |
19 | import akka.actor.testkit.typed.scaladsl.ActorTestKit
20 | import com.typesafe.config.ConfigFactory
21 | import fusion.common.config.FusionConfigFactory
22 | import fusion.discoveryx.common.Constants
23 |
24 | object FusionActorTestKit {
25 | def apply(): ActorTestKit =
26 | new ActorTestKit(
27 | name = Constants.DISCOVERYX,
28 | config = FusionConfigFactory.arrangeConfig(ConfigFactory.load("application-test"), Constants.DISCOVERYX),
29 | settings = None)
30 | }
31 |
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | logLevel := Level.Info
2 |
3 | resolvers += Resolver.bintrayIvyRepo("2m", "sbt-plugins")
4 |
5 | addSbtPlugin("com.github.mwz" % "sbt-sonar" % "1.6.0")
6 | addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0")
7 | addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.4.0")
8 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.9")
9 | addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.0")
10 | addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.5.2")
11 | addSbtPlugin("com.lightbend.akka" % "sbt-paradox-akka" % "0.29")
12 | addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.0.0")
13 | addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")
14 | addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
15 | addSbtPlugin("com.lightbend.sbt" % "sbt-javaagent" % "0.1.5")
16 | addSbtPlugin("com.lightbend.akka.grpc" % "sbt-akka-grpc" % "0.7.3")
17 | addSbtPlugin("com.lightbend.sbt" % "sbt-java-formatter" % "0.4.4")
18 | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.2.1")
19 | addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.7-1")
20 | addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.5")
21 |
22 | resolvers += Resolver.bintrayIvyRepo("helloscala", "ivy")
23 | addSbtPlugin("com.helloscala.fusion" % "fusion-sbt-plugin" % "2.0.6")
24 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/fusion/discoveryx/server/util/ActorTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.util
18 |
19 | import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit
20 | import akka.actor.typed.Behavior
21 | import akka.actor.typed.scaladsl.Behaviors
22 | import org.scalatest.WordSpecLike
23 |
24 | object ActorTest {
25 | def apply(): Behavior[String] = Behaviors.ignore
26 | }
27 | class ActorTest extends ScalaTestWithActorTestKit with WordSpecLike {
28 | "ActorTest" must {
29 | "ip-port" in {
30 | val ref = spawn(ActorTest(), "127.0.0.1:2882")
31 | println(ref)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/project/project-info.conf:
--------------------------------------------------------------------------------
1 | project-info {
2 | version: "current"
3 | scaladoc: "https://doc.akka.io/api/akka-http/current/akka/http/scaladsl"
4 | javadoc: "https://doc.akka.io/japi/akka-http/current"
5 | shared-info {
6 | jdk-versions: ["Adopt OpenJDK 8"]
7 | // snapshots: { }
8 | issues: {
9 | url: "https://github.com/akka-fusion/fusion-discoveryx/issues"
10 | text: "Fusion DiscoveryX - Github issues"
11 | }
12 | release-notes: {
13 | url: "https://github.com/akka-fusion/fusion-discoveryx/releases"
14 | text: "Fusion DiscoveryX - Github releases"
15 | }
16 | forums: [
17 | {
18 | text: "akka-fusion/fusion-discoveryx Gitter channel"
19 | url: "https://gitter.im/akka-fusion/fusion-discoveryx"
20 | }
21 | ]
22 | levels: [
23 | {
24 | readiness: CommunityDriven
25 | since: "2019-11-26"
26 | since-version: "0.1.0"
27 | }
28 | ]
29 | }
30 | fusion-discoveryx: ${project-info.shared-info} {
31 | title: "Fusion DiscoveryX"
32 | }
33 | discoveryx-client: ${project-info.shared-info} {
34 | title: "Fusion DiscoveryX Client"
35 | }
36 | discoveryx-client-play-ws: ${project-info.shared-info} {
37 | title: "Fusion DiscoveryX Client for Play"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/web-console/src/stores/GlobalStore.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin global
5 | * */
6 |
7 | import { action, observable } from 'mobx';
8 | import request from '../utils/request';
9 |
10 | export default class GlobalStore {
11 | /**
12 | * *************************** observable ***************************
13 | * */
14 |
15 | @observable
16 | list = [];
17 |
18 | /**
19 | * ****************************** ajax ******************************
20 | * */
21 |
22 | /**
23 | * 获取数据
24 | * */
25 | getList = async params => {
26 | const { data } = await request({
27 | config: { method: 'GET', url: '/api/list', params },
28 | });
29 | this.setList(data);
30 | return data;
31 | };
32 |
33 | /**
34 | * ***************************** action *****************************
35 | * */
36 |
37 | @action
38 | setList(data = []) {
39 | this.list = data;
40 | }
41 |
42 | /**
43 | * **************************** computed ****************************
44 | * */
45 | // @computed
46 | // get computedData() {
47 | // if (this.msg.length > 0) {
48 | // return 'computed';
49 | // }
50 | // return [];
51 | // }
52 | }
53 |
--------------------------------------------------------------------------------
/web-console/static/html/loading/loading.css:
--------------------------------------------------------------------------------
1 | .spinner {
2 | margin: 100px auto;
3 | width: 60px;
4 | height: 60px;
5 | text-align: center;
6 | font-size: 10px;
7 | }
8 |
9 | .spinner > div {
10 | background-color: #1890FF;
11 | height: 100%;
12 | width: 6px;
13 | display: inline-block;
14 |
15 | -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
16 | animation: stretchdelay 1.2s infinite ease-in-out;
17 | }
18 |
19 | .spinner .rect2 {
20 | -webkit-animation-delay: -1.1s;
21 | animation-delay: -1.1s;
22 | }
23 |
24 | .spinner .rect3 {
25 | -webkit-animation-delay: -1.0s;
26 | animation-delay: -1.0s;
27 | }
28 |
29 | .spinner .rect4 {
30 | -webkit-animation-delay: -0.9s;
31 | animation-delay: -0.9s;
32 | }
33 |
34 | .spinner .rect5 {
35 | -webkit-animation-delay: -0.8s;
36 | animation-delay: -0.8s;
37 | }
38 |
39 | @-webkit-keyframes stretchdelay {
40 | 0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
41 | 20% { -webkit-transform: scaleY(1.0) }
42 | }
43 |
44 | @keyframes stretchdelay {
45 | 0%, 40%, 100% {
46 | transform: scaleY(0.4);
47 | -webkit-transform: scaleY(0.4);
48 | } 20% {
49 | transform: scaleY(1.0);
50 | -webkit-transform: scaleY(1.0);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/management/config.md:
--------------------------------------------------------------------------------
1 | # ConfigManagerService
2 |
3 | - gRPC服务地址:`/fusion.discoveryx.server.grpc.ConfigManagerService`
4 | - REST URL前缀:`/fusion/discoveryx/console/config`
5 |
6 | REST URL路径由 **REST URL前缀** + 服务名组织,均使用 **POST** 方法的请求,JSON序例化格式。如查询配置列表接口访问地址为:`POST /fusion/discoveryx/management/config/ListConfig`。Protobuf与JSON格式转换请参阅: @ref[JSON 说明](../json.md)。
7 |
8 | ## ListConfig
9 |
10 | **gRPC**
11 |
12 | @@snip [gRPC](../../../../../../discoveryx-server/src/main/protobuf/fusion/discoveryx/server/grpc/server.proto) { #ListConfig }
13 |
14 | **请求**
15 |
16 | @@snip [protocol](../../../../../../discoveryx-server/src/main/protobuf/fusion/discoveryx/server/protocol/config.proto) { #ListConfig }
17 |
18 | **响应**
19 |
20 | @@snip [protocol](../../../../../../discoveryx-server/src/main/protobuf/fusion/discoveryx/server/protocol/config.proto) { #ConfigResponse }
21 |
22 | `oneof`字段`listed`有效:
23 |
24 | @@snip [protocol](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigQueried }
25 |
26 | ## GetConfig
27 |
28 | 见 @ref[GetConfig](../open/config.md#getconfig) 。
29 |
30 | ## PublishConfig
31 |
32 | 见 @ref[PublishConfig](../open/config.md#publishconfig) 。
33 |
34 | ## RemoveConfig
35 |
36 | 见 @ref[RemoveConfig](../open/config.md#removeconfig) 。
37 |
--------------------------------------------------------------------------------
/docs/js/page.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // close the overlay navigation when header links are clicked
4 | $(".overlay-nav .nav-toc a.header, .overlay-nav .nav-toc a.active.page").attr("data-toggle", "underlay overlay");
5 |
6 | // TOCs support three styles:
7 | // - box: wrap in a shadowed box and apply TOC styling
8 | // - blocks: section TOCs in boxes in a block grid with equal heights
9 | // - list: regular list of links
10 | var tocs = $(".page-content .toc");
11 | tocs.each(function() {
12 | var toc = $(this);
13 | // if there's no style already set then add .box for TOCs of depth 1 otherwise .blocks
14 | if (!(toc.hasClass("blocks") || toc.hasClass("box") || toc.hasClass("list"))) {
15 | toc.addClass((toc.children("ul").children("li").has("ul").length == 0) ? "box" : "blocks");
16 | }
17 | if (toc.hasClass("blocks")) {
18 | var list = toc.children("ul");
19 | list.addClass("row medium-up-2 large-up-3 toc-grid");
20 | list.children("li").addClass("column column-block toc-block").attr("data-equalizer-watch", "").wrapInner("");
21 | new Foundation.Equalizer(list, { equalizeByRow: true, equalizeOn: "medium" });
22 | } else if (toc.hasClass("box")) {
23 | toc.wrapInner("");
24 | }
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/web-console/src/components/Loadable/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin react-loadable
5 | * */
6 |
7 | import React from 'react';
8 | import ReactLoadable from 'react-loadable';
9 | import PropTypes from 'prop-types';
10 | import './index.less';
11 |
12 | const Loading = ({ error, timedOut, pastDelay }) => {
13 | if (error) {
14 | return (
15 |
18 | );
19 | }
20 | if (timedOut) {
21 | return (
22 |
23 |
Taking a long time...
24 |
25 | );
26 | }
27 | if (pastDelay) {
28 | return (
29 |
32 | );
33 | }
34 | return null;
35 | };
36 |
37 | Loading.propTypes = {
38 | error: PropTypes.bool,
39 | timedOut: PropTypes.bool,
40 | pastDelay: PropTypes.bool,
41 | };
42 |
43 | Loading.defaultProps = {
44 | error: false,
45 | timedOut: false,
46 | pastDelay: false,
47 | };
48 |
49 | const Loadable = opts =>
50 | ReactLoadable({
51 | loading: Loading,
52 | delay: 300,
53 | timeout: 10000,
54 | ...opts,
55 | });
56 |
57 | export default Loadable;
58 |
--------------------------------------------------------------------------------
/discoveryx-client/src/test/scala/fusion/discoveryx/client/NamingClientDemo.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client
18 |
19 | import akka.actor.typed.ActorSystem
20 | import com.typesafe.config.ConfigFactory
21 | import fusion.common.FusionProtocol
22 |
23 | import scala.concurrent.Await
24 | import scala.concurrent.duration.Duration
25 |
26 | object NamingClientDemo {
27 | def main(args: Array[String]): Unit = {
28 | val system = ActorSystem(FusionProtocol.behavior, "NamingClient", ConfigFactory.load())
29 | val settings = NamingClientSettings(system)
30 | val namingClient = NamingClient(settings, system)
31 |
32 | val f = namingClient.registerOnSettings()
33 | val reply = Await.result(f, Duration.Inf)
34 | println(reply)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/web-console/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function config(api) {
2 | const presets = [
3 | [
4 | '@babel/env',
5 | {
6 | modules: false,
7 | useBuiltIns: 'usage',
8 | corejs: 3,
9 | },
10 | ],
11 | '@babel/react',
12 | ];
13 | const plugins = [
14 | // Stage 1
15 | '@babel/plugin-proposal-export-default-from',
16 | '@babel/plugin-proposal-logical-assignment-operators',
17 | ['@babel/plugin-proposal-pipeline-operator', { proposal: 'minimal' }],
18 |
19 | // Stage 2
20 | ['@babel/plugin-proposal-decorators', { legacy: true }],
21 | '@babel/plugin-proposal-function-sent',
22 | '@babel/plugin-proposal-export-namespace-from',
23 | '@babel/plugin-proposal-numeric-separator',
24 | '@babel/plugin-proposal-throw-expressions',
25 |
26 | // Stage 3
27 | ['@babel/plugin-proposal-nullish-coalescing-operator', { loose: false }],
28 | ['@babel/plugin-proposal-optional-chaining', { loose: false }],
29 | '@babel/plugin-syntax-dynamic-import',
30 | '@babel/plugin-syntax-import-meta',
31 | ['@babel/plugin-proposal-class-properties', { loose: true }],
32 | '@babel/plugin-proposal-json-strings',
33 | [
34 | 'import',
35 | {
36 | libraryName: 'antd',
37 | style: true,
38 | },
39 | ],
40 | ];
41 |
42 | api.cache(true);
43 | return {
44 | presets,
45 | plugins,
46 | };
47 | };
48 |
--------------------------------------------------------------------------------
/web-console/src/components/Breadcrumb/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 面包屑导航,根据route.js生成
5 | * */
6 |
7 | import React from 'react';
8 | import { Link, withRouter } from 'react-router-dom';
9 | import { Breadcrumb as AntdBreadcrumb, PageHeader } from 'antd';
10 | import { breadcrumbNameMap, routes } from '../../router';
11 | import './index.less';
12 |
13 | const Breadcrumb = props => {
14 | const {
15 | location: { pathname },
16 | } = props.history;
17 |
18 | const pathSnippets = pathname.split('/').filter(i => i);
19 | const extraBreadcrumbItems = pathSnippets.map((_, index) => {
20 | const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
21 |
22 | if (!routes.find(({ path }) => path === url) || index + 1 === pathSnippets.length) {
23 | return {breadcrumbNameMap[url]};
24 | }
25 | return (
26 |
27 | {breadcrumbNameMap[url]}
28 |
29 | );
30 | });
31 |
32 | const breadcrumb = {extraBreadcrumbItems};
33 |
34 | return ;
35 | };
36 |
37 | export default withRouter(props => );
38 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/config/ConfigSettings.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.config
18 |
19 | import akka.actor.typed.ActorSystem
20 | import com.typesafe.config.Config
21 | import fusion.discoveryx.common.Constants
22 | import fusion.discoveryx.server.{ BaseSettings, RetentionCriteriaSettings }
23 | import helloscala.common.Configuration
24 |
25 | final class ConfigSettings(configuration: Configuration) extends BaseSettings with RetentionCriteriaSettings {
26 | val c = configuration.getConfiguration(s"${Constants.DISCOVERYX}.server.config")
27 | }
28 |
29 | object ConfigSettings {
30 | def apply(system: ActorSystem[_]): ConfigSettings = apply(system.settings.config)
31 | def apply(config: Config): ConfigSettings = new ConfigSettings(Configuration(config))
32 | }
33 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/share/jdbc/schema/oracle/oracle-schema.sql:
--------------------------------------------------------------------------------
1 | CREATE SEQUENCE "ordering_seq" START WITH 1 INCREMENT BY 1 NOMAXVALUE
2 | /
3 |
4 | CREATE TABLE "journal" (
5 | "ordering" NUMERIC,
6 | "deleted" char check ("deleted" in (0,1)) NOT NULL,
7 | "persistence_id" VARCHAR(255) NOT NULL,
8 | "sequence_number" NUMERIC NOT NULL,
9 | "tags" VARCHAR(255) DEFAULT NULL,
10 | "message" BLOB NOT NULL,
11 | PRIMARY KEY("persistence_id", "sequence_number")
12 | )
13 | /
14 |
15 | CREATE UNIQUE INDEX "journal_ordering_idx" ON "journal"("ordering")
16 | /
17 |
18 | CREATE OR REPLACE TRIGGER "ordering_seq_trigger"
19 | BEFORE INSERT ON "journal"
20 | FOR EACH ROW
21 | BEGIN
22 | SELECT "ordering_seq".NEXTVAL INTO :NEW."ordering" FROM DUAL;
23 | END;
24 | /
25 |
26 | CREATE OR REPLACE PROCEDURE "reset_sequence"
27 | IS
28 | l_value NUMBER;
29 | BEGIN
30 | EXECUTE IMMEDIATE 'SELECT "ordering_seq".nextval FROM dual' INTO l_value;
31 | EXECUTE IMMEDIATE 'ALTER SEQUENCE "ordering_seq" INCREMENT BY -' || l_value || ' MINVALUE 0';
32 | EXECUTE IMMEDIATE 'SELECT "ordering_seq".nextval FROM dual' INTO l_value;
33 | EXECUTE IMMEDIATE 'ALTER SEQUENCE "ordering_seq" INCREMENT BY 1 MINVALUE 0';
34 | END;
35 | /
36 |
37 | CREATE TABLE "snapshot" (
38 | "persistence_id" VARCHAR(255) NOT NULL,
39 | "sequence_number" NUMERIC NOT NULL,
40 | "created" NUMERIC NOT NULL,
41 | "snapshot" BLOB NOT NULL,
42 | PRIMARY KEY ("persistence_id", "sequence_number")
43 | )
44 | /
--------------------------------------------------------------------------------
/discoveryx-client/src/main/scala/fusion/discoveryx/client/DefaultNamingClient.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client
18 |
19 | import akka.actor.typed.{ ActorSystem, ExtensionId }
20 |
21 | import scala.util.{ Failure, Success }
22 |
23 | object DefaultNamingClient extends ExtensionId[NamingClient] {
24 | override def createExtension(system: ActorSystem[_]): NamingClient = {
25 | val client = NamingClient(system)
26 | if (NamingClientSettings(system).autoRegistration) {
27 | client
28 | .registerOnSettings()
29 | .onComplete {
30 | case Success(value) => system.log.info(s"Auto registration success, return is $value.")
31 | case Failure(exception) => system.log.error("Auto registration failure.", exception)
32 | }(system.executionContext)
33 | }
34 | client
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/web-console/static/html/loading/webpack.loading.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const webpack = require("webpack");
3 | const CopyWebpackPlugin = require("copy-webpack-plugin");
4 |
5 | module.exports = {
6 | entry: {
7 | loading: ["babel-polyfill", path.join(__dirname, "loading")],
8 | },
9 | output: {
10 | path: path.join(__dirname, "../../../dist/static/html/loading"),
11 | filename: "[name].js",
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.js$/,
17 | include: path.join(__dirname),
18 | loader: "babel-loader",
19 | },
20 | {
21 | test: /\.css$/,
22 | include: path.join(__dirname),
23 | use: "css-loader",
24 | },
25 | ],
26 | },
27 | plugins: [
28 | new webpack.optimize.UglifyJsPlugin({
29 | uglifyOptions: {
30 | minimize: true,
31 | ie8: false,
32 | output: {
33 | comments: false,
34 | beautify: false,
35 | },
36 | mangle: {
37 | keep_fnames: true,
38 | },
39 | compress: {
40 | warnings: false,
41 | // drop_console: true,
42 | drop_debugger: true,
43 | unused: true,
44 | },
45 | },
46 | }),
47 | new CopyWebpackPlugin([
48 | {
49 | from: path.resolve(__dirname),
50 | to: path.join(__dirname, "../../../dist/static/html/loading"),
51 | ignore: ["*.js"],
52 | },
53 | ]),
54 | ],
55 | };
56 |
--------------------------------------------------------------------------------
/discoveryx-docs/docs/tmp.md:
--------------------------------------------------------------------------------
1 | ConfigManagerServiceImpl:
2 |
3 | ```scala
4 | readJournal
5 | .eventsByTag(ConfigEntity.TypeKey.name, Offset.noOffset)
6 | .filter(event => event.event.isInstanceOf[ChangedConfigEvent])
7 | .mapConcat { event =>
8 | event.persistenceId.split("\\" + PersistenceId.DefaultSeparator) match {
9 | case Array(_, ConfigEntity.ConfigKey(configKey)) if event.event.isInstanceOf[ChangedConfigEvent] =>
10 | (configKey, event.event.asInstanceOf[ChangedConfigEvent]) :: Nil
11 | case _ => Nil
12 | }
13 | }
14 | .groupedWithin(1024, 5.seconds)
15 | .runForeach { list =>
16 | for ((namespace, items) <- list.groupBy(_._1.namespace)) {
17 | configManager ! ShardingEnvelope(namespace, InitialConfigKeyEvents(items.map {
18 | case (key, event) => ConfigKeyEvent(key, event)
19 | }))
20 | }
21 | }
22 | ```
23 |
24 | ConfigManager:
25 |
26 | ```scala
27 | case InitialConfigKeyEvents(keyEvents) =>
28 | var tmpKeys = Vector.empty[ConfigKey]
29 | for (keyEvent <- keyEvents) {
30 | if (!dataIds.contains(keyEvent.key)) {
31 | tmpKeys :+= keyEvent.key
32 | }
33 | configEntity ! ShardingEnvelope(ConfigEntity.ConfigKey.makeEntityId(keyEvent.key), keyEvent.event.con)
34 | }
35 | dataIds ++= tmpKeys
36 | Behaviors.same
37 |
38 | .receiveSignal {
39 | case (_, Terminated(ref)) =>
40 | configRefs = configRefs.filterNot(_ == ref)
41 | Behaviors.same
42 | }
43 | ```
44 |
--------------------------------------------------------------------------------
/docs/images/akka-logo-reverse.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/discoveryx-common/src/main/scala/fusion/discoveryx/common/Constants.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.common
18 |
19 | import fusion.discoveryx.model.HealthyCheckProtocol
20 |
21 | object Constants {
22 | val DISCOVERYX = "discoveryx"
23 | val DEFAULT_GROUP_NAME = "default"
24 | val ENTITY_ID_SEPARATOR = ':'
25 |
26 | val MANAGEMENT = "management"
27 | val CONFIG = "config"
28 | val NAMING = "naming"
29 |
30 | val SESSION_TOKEN_NAME = "discoveryx-session-token"
31 | }
32 |
33 | object Headers {
34 | val NAMESPACE = "x-discoveryx-namespace"
35 | val SERVICE_NAME = "x-discoveryx-service-name"
36 | val IP = "x-discoveryx-ip"
37 | val PORT = "x-discoveryx-port"
38 | val INSTANCE_ID = "x-discoveryx-instance-id"
39 | }
40 |
41 | object Protocols {
42 | @inline def formatProtocol(protocol: HealthyCheckProtocol): HealthyCheckProtocol =
43 | if (protocol.isUnknown || protocol.isUnrecognized) HealthyCheckProtocol.HTTP else protocol
44 | }
45 |
--------------------------------------------------------------------------------
/web-console/src/pages/config/management/Detail/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 2019/12/20 gongtiexin 服务详情
5 | * */
6 |
7 | import React, { Component } from 'react';
8 | import { inject, observer } from 'mobx-react';
9 | import qs from 'query-string';
10 | import { Descriptions, Table } from 'antd';
11 | import PropTypes from 'prop-types';
12 | import { CONFIG_TYPE_ENUM } from '../../constants';
13 |
14 | @inject(({ store: { configStore } }) => ({ configStore }))
15 | @observer
16 | export default class Detail extends Component {
17 | static propTypes = {
18 | configStore: PropTypes.object.isRequired,
19 | };
20 |
21 | componentDidMount() {
22 | this.props.configStore.getConfig(qs.parse(window.location.search));
23 | }
24 |
25 | componentWillUnmount() {
26 | this.props.configStore.setConfig();
27 | }
28 |
29 | render() {
30 | const {
31 | configStore: { config },
32 | } = this.props;
33 |
34 | return (
35 |
36 | {config.namespace}
37 | {config.dataId}
38 | {config.groupName}
39 |
40 | {CONFIG_TYPE_ENUM.properties[config.type]?.label}
41 |
42 | {config.content}
43 |
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/ManagementSettings.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server
18 |
19 | import akka.actor.typed.ActorSystem
20 | import com.typesafe.config.Config
21 | import fusion.discoveryx.common.Constants
22 | import helloscala.common.Configuration
23 |
24 | import scala.concurrent.duration.FiniteDuration
25 |
26 | class ManagementSettings(configuration: Configuration) extends BaseSettings with RetentionCriteriaSettings {
27 | val c: Configuration = configuration.getConfiguration(s"${Constants.DISCOVERYX}.server.management")
28 | lazy val sessionTimeout: Long = c.get[FiniteDuration]("session-timeout").toMillis
29 |
30 | @inline def isValidSession(activeTime: Long) = (System.currentTimeMillis() - activeTime) < sessionTimeout
31 | }
32 |
33 | object ManagementSettings {
34 | def apply(system: ActorSystem[_]): ManagementSettings = apply(system.settings.config)
35 | def apply(config: Config): ManagementSettings = new ManagementSettings(Configuration(config))
36 | }
37 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/conf/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | logs/server.log
5 | false
6 |
7 | logs/server_%d{yyyy-MM-dd}.log
8 |
9 |
10 | [%date{ISO8601}] [%level] [%logger] [%marker] [%thread] - %msg {%mdc}%n
11 |
12 |
13 |
14 |
15 | 8192
16 | true
17 |
18 |
19 |
20 |
21 |
22 | DEBUG
23 |
24 |
25 | [%date{ISO8601}] [%level] [%logger] [%thread] [%X{akkaSource}] - %msg%n
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/naming/NamingSettings.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.naming
18 |
19 | import akka.actor.typed.ActorSystem
20 | import com.typesafe.config.Config
21 | import fusion.discoveryx.common.Constants
22 | import fusion.discoveryx.server.{ BaseSettings, RetentionCriteriaSettings }
23 | import helloscala.common.Configuration
24 |
25 | import scala.concurrent.duration.FiniteDuration
26 |
27 | final class NamingSettings(configuration: Configuration) extends BaseSettings with RetentionCriteriaSettings {
28 | override val c = configuration.getConfiguration(s"${Constants.DISCOVERYX}.server.naming")
29 | val heartbeatTimeout: FiniteDuration = c.get[FiniteDuration]("heartbeat-timeout")
30 | val allowReplaceRegistration: Boolean = c.getBoolean("allow-replace-registration")
31 | }
32 |
33 | object NamingSettings {
34 | def apply(system: ActorSystem[_]): NamingSettings = apply(system.settings.config)
35 | def apply(config: Config): NamingSettings = new NamingSettings(Configuration(config))
36 | }
37 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/fusion/discoveryx/server/naming/internal/SniffUtilsTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.naming.internal
18 |
19 | import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit
20 | import org.scalatest.FunSuiteLike
21 |
22 | import scala.concurrent.Await
23 | import scala.concurrent.duration._
24 |
25 | class SniffUtilsTest extends ScalaTestWithActorTestKit with FunSuiteLike {
26 | test("testSniffTcp") {
27 | val result = Await.result(SniffUtils.sniffTcp(false, "114.67.71.244", 80), 1.minute)
28 | println(result)
29 | result shouldBe true
30 | }
31 |
32 | test("testSniffUdp") {
33 | val result = SniffUtils.sniffUdp("localhost", 137).futureValue
34 | result shouldBe true
35 | }
36 |
37 | test("testSniffHttp") {
38 | val result = SniffUtils.sniffHttp("http://gitee.com").futureValue
39 | result shouldBe true
40 | }
41 |
42 | test("testSniffHttps") {
43 | val result = SniffUtils.sniffHttp("https://gitee.com").futureValue
44 | result shouldBe true
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/web-console/README.md:
--------------------------------------------------------------------------------
1 | Welcome to react-template 👋
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | > A frontend project template for React.js
16 |
17 | ### 🏠 [Homepage](https://github.com/gongtiexin/react-template#readme)
18 |
19 | ## Install
20 |
21 | ```sh
22 | yarn
23 | ```
24 |
25 | ## Author
26 |
27 | 👤 **tiexin.gong **
28 |
29 | - Github: [@gongtiexin](https://github.com/gongtiexin)
30 |
31 | ## 🤝 Contributing
32 |
33 | Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/gongtiexin/react-template/issues).
34 |
35 | ## Show your support
36 |
37 | Give a ⭐️ if this project helped you!
38 |
39 | ## 📝 License
40 |
41 | Copyright © 2019 [tiexin.gong ](https://github.com/gongtiexin).
42 |
43 |
44 |
45 | ---
46 |
47 | _This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_
48 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: scala
2 |
3 | sudo: false
4 |
5 | #scala:
6 | # - "2.12.10"
7 | # - "2.13.1"
8 |
9 | before_install: curl -Ls https://git.io/jabba | bash && . ~/.jabba/jabba.sh
10 | install: jabba install "adopt@~1.$TRAVIS_JDK.0-0" && jabba use "$_" && java -Xmx32m -version
11 |
12 | addons:
13 | apt:
14 | packages:
15 | - graphviz
16 |
17 | before_cache:
18 | - find $HOME/.ivy2 -name "ivydata-*.properties" -print -delete
19 | - find $HOME/.sbt -name "*.lock" -print -delete
20 |
21 | cache:
22 | directories:
23 | - $HOME/.cache/coursier
24 | - $HOME/.ivy2/cache
25 | - $HOME/.sbt
26 | - $HOME/.jabba/jdk
27 |
28 | #git:
29 | # depth: 1 # Avoid sbt-dynver not seeing the tag
30 |
31 | branches:
32 | only:
33 | - master
34 | - develop
35 |
36 | env:
37 | global:
38 | - TRAVIS_JDK=11
39 |
40 | stages:
41 | - test
42 | if: (branch = master) AND (NOT (type IN (push, pull_request)))
43 | - name: test-scala212
44 | if: (branch = develop)
45 | # - paradox
46 |
47 | jobs:
48 | include:
49 | - stage: test
50 | script: sbt test:compile "discoveryx-functest/multi-jvm:testOnly fusion.discoveryx.functest.DiscoveryXMultiTest"
51 | name: "Master discoveryx-functest/multi-jvm:testOnly fusion.discoveryx.functest.DiscoveryXMultiTest"
52 | - stage: test-scala212
53 | script: sbt ";++ 2.12.10 ;test:compile ;discoveryx-functest/multi-jvm:testOnly fusion.discoveryx.functest.DiscoveryXMultiTest"
54 | env: TRAVIS_JDK=8
55 | name: "Develop discoveryx-functest/multi-jvm:testOnly fusion.discoveryx.functest.DiscoveryXMultiTest for Java 8"
56 | # - stage: paradox
57 | # script: scripts/travis-paradox.sh
58 | # name: "Generate paradox"
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fusion DiscoveryX
2 |
3 | [](https://travis-ci.org/akka-fusion/fusion-discoveryx)
4 |
5 | 服务注册与发现管理系统,基于Akka生态开发。
6 |
7 | 产品文档:[https://akka-fusion.github.io/fusion-discoveryx/](https://akka-fusion.github.io/fusion-discoveryx/)
8 |
9 | ## 开发
10 |
11 | ### Docker运行环境
12 |
13 | ```shell script
14 | docker-compose -f docker-compose.yml up -d // --build
15 | ```
16 |
17 | > *若使用Cassandra做为后端存储,还需要初始化keyspace和相关表(PostgreSQL,Dockerfile已经初始化数据库表)。*
18 | >
19 | > ```shell script
20 | > docker exec fusion-discoveryx_cassandra cqlsh -f /docker-entrypoint-initdb.d/cassandra-schema.cql
21 | > ```
22 |
23 | `-d`后可添加参数:`postgres`或`cassandra`只启动特定数据库。
24 |
25 | ### 服务发现测试
26 |
27 | *默认使用akka-persistence-jdbc(postgres) 数据库,若需要使用akka-persistence-cassandra请将测试类的配置文件修改为`application-test_cassandra.conf`。*
28 |
29 | ```sbtshell
30 | > discoveryx-server/testOnly fusion.discoveryx.server.naming.route.NamingManagementRouteTest
31 | ```
32 |
33 | **配置管理测试**
34 |
35 | ```sbtshell
36 | > discoveryx-server/testOnly fusion.discoveryx.server.config.route.ConfigManagementRouteTest
37 | ```
38 |
39 | ### Multi Node 测试
40 |
41 | ```sbtshell
42 | > discoveryx-functest/multi-jvm:testOnly fusion.discoveryx.functest.DiscoveryXMultiTest
43 | ```
44 |
45 | ## Package, Deployment
46 |
47 | ```
48 | ./release.sh
49 | ```
50 |
51 | 生成的zip软件包在目录:`discoveryx-server/target/universal`。
52 |
53 | ## 技术
54 |
55 | | 功能 | 使用技术 |
56 | | ---------- | --------------------- |
57 | | 开放API | Akka gRPC |
58 | | 集群序例化 | Protobuf |
59 | | 配置持久化 | Akka Persistence |
60 | | 容错与扩展 | Akka Cluster Sharding |
61 | | REST | Akka HTTP |
62 |
63 |
--------------------------------------------------------------------------------
/web-console/src/components/Pagination/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 分页组件
5 | * */
6 |
7 | import React, { Component } from 'react';
8 | import { observer } from 'mobx-react';
9 | import { Pagination as AntdPagination } from 'antd';
10 | import PropTypes from 'prop-types';
11 | import './index.less';
12 |
13 | @observer
14 | export default class Pagination extends Component {
15 | static propTypes = {
16 | page: PropTypes.number.isRequired,
17 | size: PropTypes.number,
18 | totalElements: PropTypes.number.isRequired,
19 | handleChange: PropTypes.func.isRequired,
20 | showSizeChanger: PropTypes.bool,
21 | };
22 |
23 | static defaultProps = {
24 | size: 10,
25 | showSizeChanger: true,
26 | };
27 |
28 | onShowSizeChange = (current, pageSize) => {
29 | const { handleChange } = this.props;
30 | handleChange({ page: current, size: pageSize });
31 | };
32 |
33 | onChange = (pageNumber, pageSize) => {
34 | const { handleChange } = this.props;
35 | handleChange({ page: pageNumber, size: pageSize });
36 | };
37 |
38 | showTotal = total => `共 ${total || 0} 条`;
39 |
40 | render() {
41 | const { page, size, totalElements, showSizeChanger } = this.props;
42 |
43 | return (
44 |
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/discoveryx-functest/src/multi-jvm/scala/akka/remote/testkit/STMultiNodeSpec.scala:
--------------------------------------------------------------------------------
1 | package akka.remote.testkit
2 |
3 | import akka.actor.typed.ActorSystem
4 | import com.typesafe.config.{ Config, ConfigFactory }
5 | import fusion.discoveryx.server.DiscoveryX
6 | import org.scalatest.concurrent.ScalaFutures
7 | import org.scalatest.time.{ Millis, Span }
8 | import org.scalatest._
9 |
10 | import scala.language.implicitConversions
11 |
12 | trait STMultiNodeSpec
13 | extends MultiNodeSpecCallbacks
14 | with WordSpecLike
15 | with Matchers
16 | with OptionValues
17 | with EitherValues
18 | with BeforeAndAfterAll
19 | with ScalaFutures {
20 | self: SchudulerXMultiNodeSpec =>
21 |
22 | override def initialParticipants: Int = roles.size
23 |
24 | implicit override def patienceConfig: PatienceConfig =
25 | PatienceConfig(scaled(Span(5000, Millis)), scaled(Span(50, Millis)))
26 |
27 | def typedSystem: ActorSystem[_] = discoveryX.system
28 |
29 | override def beforeAll(): Unit = multiNodeSpecBeforeAll()
30 |
31 | override def afterAll(): Unit = multiNodeSpecAfterAll()
32 |
33 | // Might not be needed anymore if we find a nice way to tag all logging from a node
34 | implicit override def convertToWordSpecStringWrapper(s: String): WordSpecStringWrapper =
35 | new WordSpecStringWrapper(s"$s (on node '${self.myself.name}', $getClass)")
36 | }
37 |
38 | abstract class SchudulerXMultiNodeSpec(nodeConfig: MultiNodeConfig, protected val discoveryX: DiscoveryX)
39 | extends MultiNodeSpec(nodeConfig.myself, discoveryX.classicSystem, nodeConfig.roles, nodeConfig.deployments) {
40 | def this(nodeConfig: MultiNodeConfig, create: Config => DiscoveryX) {
41 | this(nodeConfig, create(ConfigFactory.load(nodeConfig.config)))
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/discoveryx-client/src/main/scala/fusion/discoveryx/client/ConfigClientSettings.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client
18 |
19 | import akka.actor.typed.ActorSystem
20 | import com.typesafe.config.Config
21 | import fusion.discoveryx.common.Constants
22 | import helloscala.common.Configuration
23 |
24 | object ConfigClientSettings {
25 | def apply(system: ActorSystem[_]): ConfigClientSettings = fromConfig(system.settings.config)
26 | def fromConfig(config: Config, prefix: String = s"${Constants.DISCOVERYX}.client.config"): ConfigClientSettings =
27 | fromConfiguration(Configuration(config), prefix)
28 | def fromConfiguration(
29 | config: Configuration,
30 | prefix: String = s"${Constants.DISCOVERYX}.client.config"): ConfigClientSettings =
31 | new ConfigClientSettings(config.getConfiguration(prefix))
32 | }
33 | final class ConfigClientSettings private (c: Configuration) {
34 | val namespace: Option[String] = c.get[Option[String]]("namespace")
35 | val dataId: Option[String] = c.get[Option[String]]("data-id") orElse c.get[Option[String]]("dataId")
36 | override def toString: String = c.underlying.root().toString
37 | }
38 |
--------------------------------------------------------------------------------
/web-console/src/components/NamespaceChoose/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { inject, observer } from 'mobx-react';
3 | import { Tabs } from 'antd';
4 | import PropTypes from 'prop-types';
5 | import { upStorage } from 'up-utils';
6 |
7 | const { TabPane } = Tabs;
8 |
9 | @inject(({ store: { namespaceStore } }) => ({ namespaceStore }))
10 | @observer
11 | export default class NamespaceChoose extends Component {
12 | static propTypes = {
13 | namespaceStore: PropTypes.object.isRequired,
14 | fetchData: PropTypes.func.isRequired,
15 | };
16 |
17 | constructor(props) {
18 | super(props);
19 | this.state = { namespace: upStorage.getSession('namespace') };
20 | }
21 |
22 | componentDidMount() {
23 | this.props.namespaceStore.getNamespaceList().then(namespaceList => {
24 | let { namespace } = this.state;
25 | if (!namespaceList.some(item => item.namespace === upStorage.getSession('namespace'))) {
26 | namespace = namespaceList[0]?.namespace;
27 | }
28 | this.handleNamespaceChange(namespace);
29 | });
30 | }
31 |
32 | componentWillUnmount() {
33 | this.props.namespaceStore.setNamespaceList();
34 | }
35 |
36 | handleNamespaceChange = namespace => {
37 | this.setState({ namespace });
38 | upStorage.setSession('namespace', namespace);
39 | this.props.fetchData(namespace);
40 | };
41 |
42 | render() {
43 | const {
44 | namespaceStore: { namespaceList },
45 | } = this.props;
46 | const { namespace } = this.state;
47 |
48 | return (
49 |
50 | {namespaceList.map(item => (
51 |
52 | ))}
53 |
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/discoveryx-client/src/test/scala/fusion/discoveryx/client/DefaultNamingClientTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client
18 |
19 | import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit
20 | import com.typesafe.config.ConfigFactory
21 | import fusion.discoveryx.model.InstanceQuery
22 | import org.scalatest.wordspec.AnyWordSpecLike
23 |
24 | class DefaultNamingClientTest
25 | extends ScalaTestWithActorTestKit(ConfigFactory.load("application-local.conf"))
26 | with AnyWordSpecLike {
27 | private val client = DefaultNamingClient(system)
28 | "DefaultNamingClient" must {
29 | "url" in {
30 | val url = "http://fusion-schedulerx/cluster/health"
31 | // val uris = Future.sequence(Vector.fill(4)(client.generateUri(url))).futureValue
32 | val uris = (0 until 4).map(_ => client.generateUri(url).futureValue).toVector
33 | println(uris)
34 | }
35 |
36 | "queryService" in {
37 | val reply = client.queryInstance(InstanceQuery(client.settings.namespace.get, "fusion-schedulerx")).futureValue
38 | println(reply.status)
39 | reply.getServiceInfo.instances.foreach(println)
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/config/ConfigManager.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.config
18 |
19 | import akka.actor.typed.scaladsl.Behaviors
20 | import akka.actor.typed.{ ActorRef, ActorSystem, Behavior }
21 | import akka.cluster.sharding.typed.scaladsl.{ ClusterSharding, Entity, EntityTypeKey }
22 | import akka.cluster.sharding.typed.{ ClusterShardingSettings, ShardingEnvelope }
23 | import fusion.discoveryx.server.config.internal.ConfigManagerBehavior
24 |
25 | import scala.concurrent.duration._
26 |
27 | object ConfigManager {
28 | trait Command
29 | trait Event
30 |
31 | val NAME = "ConfigManager"
32 | val TypeKey: EntityTypeKey[Command] = EntityTypeKey(NAME)
33 |
34 | def init(system: ActorSystem[_]): ActorRef[ShardingEnvelope[Command]] =
35 | ClusterSharding(system).init(
36 | Entity(TypeKey)(entityContext => apply(entityContext.entityId))
37 | .withSettings(ClusterShardingSettings(system).withPassivateIdleEntityAfter(Duration.Zero)))
38 |
39 | private def apply(entityId: String): Behavior[Command] =
40 | Behaviors.setup(context => new ConfigManagerBehavior(entityId, context).eventSourcedBehavior())
41 | }
42 |
--------------------------------------------------------------------------------
/web-console/src/router/feature.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Redirect, Route } from 'react-router-dom';
3 | import PropTypes from 'prop-types';
4 |
5 | // class RecordRoute extends PureComponent {
6 | // // static propTypes = {};
7 | //
8 | // // constructor(props) {
9 | // // super(props);
10 | // // }
11 | //
12 | // componentDidMount() {}
13 | //
14 | // componentWillUnmount() {}
15 | //
16 | // render() {
17 | // return ;
18 | // }
19 | // }
20 | //
21 | // const PrivateRoute = ({
22 | // component: RouteComponent,
23 | // loggedIn,
24 | // protect,
25 | // ...rest
26 | // }) => (
27 | //
30 | // loggedIn || !protect ? (
31 | //
32 | // ) : (
33 | //
38 | // )
39 | // }
40 | // />
41 | // );
42 |
43 | const PrivateRoute = ({ component: Component, isAuthenticated, ...rest }) => {
44 | return (
45 |
48 | isAuthenticated ? (
49 |
50 | ) : (
51 |
57 | )
58 | }
59 | />
60 | );
61 | };
62 |
63 | PrivateRoute.propTypes = {
64 | component: PropTypes.func.isRequired,
65 | isAuthenticated: PropTypes.bool,
66 | };
67 |
68 | PrivateRoute.defaultProps = {
69 | isAuthenticated: true,
70 | };
71 |
72 | export { PrivateRoute };
73 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/scala/fusion/discoveryx/client/play/scaladsl/module/DiscoveryXWSModule.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.scaladsl.module
18 |
19 | import akka.actor.typed.ActorSystem
20 | import fusion.discoveryx.client.play.scaladsl.{ DiscoveryXPlay, DiscoveryXPlayWSClient, DiscoveryXWSClient }
21 | import fusion.discoveryx.common.Constants
22 | import javax.inject.{ Inject, Provider, Singleton }
23 | import play.api.inject.{ SimpleModule, bind }
24 | import play.api.libs.ws.WSClient
25 | import play.shaded.ahc.org.asynchttpclient.AsyncHttpClient
26 |
27 | class DiscoveryXWSModule
28 | extends SimpleModule(
29 | bind[DiscoveryXPlayWSClient].toProvider[DiscoveryXPlayWSClientProvider],
30 | bind[WSClient].qualifiedWith(Constants.DISCOVERYX).to[DiscoveryXPlayWSClient],
31 | bind[WSClient].qualifiedWith[DiscoveryXPlay].to[DiscoveryXPlayWSClient])
32 |
33 | @Singleton
34 | class DiscoveryXPlayWSClientProvider @Inject() (asyncHttpClient: AsyncHttpClient)(implicit system: ActorSystem[_])
35 | extends Provider[DiscoveryXPlayWSClient] {
36 | override lazy val get: DiscoveryXPlayWSClient = DiscoveryXWSClient.wsClient(asyncHttpClient)
37 | }
38 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/scala/fusion/discoveryx/client/play/javadsl/DiscoveryXPlayWSClient.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.javadsl
18 |
19 | import akka.actor.typed.ActorSystem
20 | import fusion.discoveryx.client.{ DefaultNamingClient, NamingClient }
21 | import play.libs.ws.{ WSClient, WSRequest }
22 |
23 | import scala.concurrent.duration._
24 | import scala.concurrent.{ Await, Future }
25 |
26 | final class DiscoveryXPlayWSClient(client: WSClient)(implicit system: ActorSystem[_]) extends WSClient {
27 | val namingClient: NamingClient = DefaultNamingClient(system)
28 |
29 | override def getUnderlying: AnyRef = client.getUnderlying
30 |
31 | override def asScala(): play.api.libs.ws.WSClient = client.asScala()
32 |
33 | override def url(uri: String): WSRequest = url(uri, namingClient.settings.queryTimeout)
34 |
35 | def url(uri: String, timeout: FiniteDuration): WSRequest = Await.result(asyncUrl(uri), timeout)
36 |
37 | def asyncUrl(url: String): Future[WSRequest] =
38 | namingClient.generateUri(url).map(uri => client.url(uri.map(_.toString()).getOrElse(url)))(system.executionContext)
39 |
40 | override def close(): Unit = client.close()
41 | }
42 |
--------------------------------------------------------------------------------
/web-console/src/utils/constants.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 常量
5 | * */
6 | const browserRedirect = () => {
7 | const sUserAgent = navigator.userAgent.toLowerCase();
8 | const bIsIpad = sUserAgent.includes('ipad');
9 | const bIsIphoneOs = sUserAgent.includes('iphone os');
10 | const bIsMidp = sUserAgent.includes('midp');
11 | const bIsUc7 = sUserAgent.includes('rv:1.2.3.4');
12 | const bIsUc = sUserAgent.includes('ucweb');
13 | const bIsAndroid = sUserAgent.includes('android');
14 | const bIsCE = sUserAgent.includes('windows ce');
15 | const bIsWM = sUserAgent.includes('windows mobile');
16 | if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
17 | // phone
18 | return 'phone';
19 | }
20 | // pc
21 | return 'pc';
22 | };
23 |
24 | const isProduction = process.env.NODE_ENV === 'production';
25 |
26 | const ECHARTS_DEFULT_OPTION = {
27 | tooltip: {
28 | trigger: 'axis',
29 | },
30 | legend: {},
31 | xAxis: {
32 | type: 'category',
33 | },
34 | yAxis: [
35 | {
36 | type: 'value',
37 | name: '数量',
38 | nameTextStyle: {
39 | color: '#000000a6',
40 | },
41 | splitLine: { show: false },
42 | },
43 | {
44 | type: 'value',
45 | splitLine: { show: false },
46 | name: '百分比',
47 | min: 0,
48 | max: 100,
49 | interval: 20,
50 | axisLabel: {
51 | formatter: '{value} %',
52 | },
53 | nameTextStyle: {
54 | color: '#000000a6',
55 | },
56 | },
57 | ],
58 | series: [],
59 | };
60 |
61 | const PAGE_OBJECT = { page: 1, size: 20, totalElements: 0, data: [] };
62 |
63 | export { isProduction, ECHARTS_DEFULT_OPTION, browserRedirect, PAGE_OBJECT };
64 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/scala/fusion/discoveryx/client/play/javadsl/DiscoveryXStandaloneWSClient.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.javadsl
18 |
19 | import akka.actor.typed.ActorSystem
20 | import fusion.discoveryx.client.{ DefaultNamingClient, NamingClient }
21 | import play.libs.ws.{ StandaloneWSClient, StandaloneWSRequest }
22 |
23 | import scala.concurrent.duration.FiniteDuration
24 | import scala.concurrent.{ Await, Future }
25 |
26 | final class DiscoveryXStandaloneWSClient(client: StandaloneWSClient)(implicit system: ActorSystem[_])
27 | extends StandaloneWSClient {
28 | val namingClient: NamingClient = DefaultNamingClient(system)
29 |
30 | override def getUnderlying: AnyRef = client.getUnderlying
31 |
32 | override def url(uri: String): StandaloneWSRequest = url(uri, namingClient.settings.queryTimeout)
33 |
34 | def url(uri: String, timeout: FiniteDuration): StandaloneWSRequest = Await.result(asyncUrl(uri), timeout)
35 |
36 | def asyncUrl(url: String): Future[StandaloneWSRequest] =
37 | namingClient.generateUri(url).map(uri => client.url(uri.map(_.toString()).getOrElse(url)))(system.executionContext)
38 |
39 | override def close(): Unit = client.close()
40 | }
41 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/naming/NamingManager.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.naming
18 |
19 | import akka.actor.typed.scaladsl.Behaviors
20 | import akka.actor.typed.{ ActorRef, ActorSystem, Behavior }
21 | import akka.cluster.sharding.typed.scaladsl.{ ClusterSharding, Entity, EntityTypeKey }
22 | import akka.cluster.sharding.typed.{ ClusterShardingSettings, ShardingEnvelope }
23 | import fusion.discoveryx.server.naming.internal.NamingManagerBehavior
24 |
25 | import scala.concurrent.duration._
26 |
27 | object NamingManager {
28 | trait Command extends NamingService.Command
29 | trait Event
30 |
31 | val NAME = "NamingManager"
32 | val TypeKey: EntityTypeKey[Command] = EntityTypeKey(NAME)
33 |
34 | def init(system: ActorSystem[_]): ActorRef[ShardingEnvelope[Command]] = {
35 | ClusterSharding(system).init(
36 | Entity(TypeKey)(entityContext => NamingManager(entityContext.entityId))
37 | .withSettings(ClusterShardingSettings(system).withPassivateIdleEntityAfter(Duration.Zero)))
38 | }
39 |
40 | private def apply(namespace: String): Behavior[Command] =
41 | Behaviors.setup(context => new NamingManagerBehavior(namespace, context).eventSourcedBehavior())
42 | }
43 |
--------------------------------------------------------------------------------
/web-console/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 单页应用的入口文件
5 | * */
6 | import 'core-js/stable';
7 | import 'regenerator-runtime/runtime';
8 |
9 | import React from 'react';
10 | import { render } from 'react-dom';
11 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
12 | import { Provider } from 'mobx-react';
13 | import { hotRehydrate, rehydrate } from 'rfx-core';
14 | import moment from 'moment';
15 | import { ConfigProvider } from 'antd';
16 | import zhCN from 'antd/lib/locale-provider/zh_CN';
17 | import 'normalize.css';
18 | import { isProduction } from './utils/constants';
19 | import './stores';
20 | import './global.less';
21 | import Loadable from './components/Loadable';
22 |
23 | /**
24 | * 代码拆分和按需加载
25 | */
26 | const LoadableApp = Loadable({
27 | loader: () => import(/* webpackChunkName: "route-root" */ './pages/App'),
28 | });
29 |
30 | const LoadableLogin = Loadable({
31 | loader: () => import(/* webpackChunkName: "route-login" */ './components/Login'),
32 | });
33 |
34 | /**
35 | * moment时区设置为中国
36 | */
37 | moment.locale('zh-cn');
38 |
39 | const store = rehydrate();
40 |
41 | const renderApp = () => {
42 | render(
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | ,
53 | document.getElementById('root'),
54 | );
55 | };
56 |
57 | function run() {
58 | renderApp();
59 | if (module.hot) {
60 | module.hot.accept(renderApp);
61 | }
62 | }
63 |
64 | store.userStore.getCurrentSessionUser().then(run, run);
65 |
--------------------------------------------------------------------------------
/docs/css/fonts/icons.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/discoveryx-functest/src/multi-jvm/scala/fusion/discoveryx/functest/TestUtils.scala:
--------------------------------------------------------------------------------
1 | package fusion.discoveryx.functest
2 |
3 | import akka.actor.typed.ActorSystem
4 | import akka.http.scaladsl.model.HttpMethods
5 | import akka.http.scaladsl.model.headers.Cookie
6 | import fusion.discoveryx.client.HttpUtils
7 | import fusion.discoveryx.common.Constants
8 | import fusion.discoveryx.server.protocol._
9 |
10 | import scala.concurrent.Future
11 |
12 | object TestUtils {
13 | def apply(system: ActorSystem[_]): TestUtils = new TestUtils()(system)
14 | }
15 |
16 | import fusion.discoveryx.server.util.ProtobufJsonSupport._
17 | class TestUtils private ()(implicit system: ActorSystem[_]) {
18 | private val httpClient = HttpUtils(system)
19 |
20 | def login(): Future[UserResponse] = {
21 | httpClient
22 | .singleRequest(
23 | HttpMethods.POST,
24 | "http://localhost:48000/fusion/discoveryx/console/sign/Login",
25 | entity = Login(Constants.DISCOVERYX, Constants.DISCOVERYX))
26 | .onSuccessResponseAs[UserResponse]
27 | }
28 |
29 | def listNamespace(logined: Logined, page: Int = 1, size: Int = 20)(): Future[ManagementResponse] = {
30 | httpClient
31 | .singleRequest(
32 | HttpMethods.POST,
33 | "http://localhost:48000/fusion/discoveryx/console/namespace/ListNamespace",
34 | List(Cookie(Constants.SESSION_TOKEN_NAME, logined.token)),
35 | ListNamespace(page, size))
36 | .onSuccessResponseAs[ManagementResponse]
37 | }
38 |
39 | def createNamespace(logined: Logined, namespace: String): Future[ManagementResponse] = {
40 | httpClient
41 | .singleRequest(
42 | HttpMethods.POST,
43 | "http://localhost:48000/fusion/discoveryx/console/namespace/CreateNamespace",
44 | List(Cookie(Constants.SESSION_TOKEN_NAME, logined.token)),
45 | CreateNamespace(namespace, s"Default namespace: $namespace."))
46 | .onSuccessResponseAs[ManagementResponse]
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/fusion/discoveryx/server/user/UserServiceClientTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.user
18 |
19 | import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit
20 | import akka.grpc.GrpcClientSettings
21 | import akka.stream.SystemMaterializer
22 | import com.typesafe.config.ConfigFactory
23 | import fusion.core.extension.FusionCore
24 | import fusion.discoveryx.server.grpc.{ UserService, UserServiceClient }
25 | import fusion.discoveryx.server.protocol.CreateUser
26 | import fusion.discoveryx.server.util.ProtobufJson4s
27 | import org.scalatest.WordSpecLike
28 |
29 | class UserServiceClientTest
30 | extends ScalaTestWithActorTestKit(ConfigFactory.load("application-helloscala.conf"))
31 | with WordSpecLike {
32 | "UserServiceClient" must {
33 | implicit val classicSystem = FusionCore(system).classicSystem
34 | implicit val mat = SystemMaterializer(system).materializer
35 | implicit val ec = system.executionContext
36 | val client = UserServiceClient(GrpcClientSettings.fromConfig(UserService.name))
37 |
38 | "CreateUser" in {
39 | val resp =
40 | client.createUser(CreateUser("discoveryx", "discoveryx", "Fusion DiscoveryX Administrator")).futureValue
41 | println(ProtobufJson4s.toJsonPrettyString(resp))
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/fusion/discoveryx/server/config/ConfigManagerServiceTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.config
18 |
19 | import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit
20 | import akka.fusion.testkit.FusionActorTestKit
21 | import fusion.discoveryx.server.config.service.ConfigManagerServiceImpl
22 | import fusion.discoveryx.server.namespace.NamespaceRef.ExistNamespace
23 | import fusion.discoveryx.server.namespace.{ NamespaceManager, NamespaceRef }
24 | import fusion.discoveryx.server.protocol.ListConfig
25 | import fusion.discoveryx.server.util.ProtobufJson4s
26 | import helloscala.common.IntStatus
27 | import org.scalatest.WordSpecLike
28 |
29 | class ConfigManagerServiceTest extends ScalaTestWithActorTestKit(FusionActorTestKit()) with WordSpecLike {
30 | NamespaceManager.init(system)
31 | private val namespaceRef = spawn(NamespaceRef()).narrow[ExistNamespace]
32 | private val configManagerService = new ConfigManagerServiceImpl(namespaceRef)
33 |
34 | "ConfigManagerService" must {
35 | val namespace = "me.yangbajing"
36 |
37 | "listConfig" in {
38 | val resp = configManagerService.listConfig(ListConfig(namespace)).futureValue
39 | resp.status shouldBe IntStatus.OK
40 | println(ProtobufJson4s.toJsonPrettyString(resp))
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/web-console/config/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 配置参数
5 | * */
6 |
7 | const path = require('path');
8 |
9 | const entry = path.resolve(__dirname, '../src/index');
10 | const indexHtml = path.resolve(__dirname, '../index.html');
11 | const root = path.resolve(__dirname, '../');
12 | const srcPath = path.resolve(__dirname, '../src');
13 | const distPath = path.resolve(__dirname, '../dist');
14 | const staticPath = path.resolve(__dirname, '../static');
15 | const distStaticPath = path.resolve(__dirname, '../dist/static');
16 | const nodeModulesPath = path.resolve(__dirname, '../node_modules');
17 |
18 | // alias
19 | const componentsPath = path.resolve(__dirname, '../src/components');
20 | const stylesPath = path.resolve(__dirname, '../src/styles');
21 | const utilsPath = path.resolve(__dirname, '../src/utils');
22 |
23 | module.exports = {
24 | root,
25 | webpack: {
26 | build: {
27 | env: {
28 | NODE_ENV: 'production',
29 | },
30 | vendor: ['react', 'react-dom', 'react-router-dom', 'mobx', 'mobx-react'],
31 | plugins: {
32 | CopyWebpackPlugin: [
33 | {
34 | from: staticPath,
35 | to: distStaticPath,
36 | ignore: ['assets/*/*.*'],
37 | },
38 | ],
39 | },
40 | },
41 | dev: {
42 | env: {
43 | NODE_ENV: 'development',
44 | },
45 | devServer: {
46 | port: 3000,
47 | },
48 | },
49 | publicPath: '/',
50 | alias: {
51 | '@components': componentsPath,
52 | '@styles': stylesPath,
53 | '@utils': utilsPath,
54 | },
55 | modifyVars: {
56 | // "primary-color": "#1890ff",
57 | },
58 | },
59 | path: {
60 | entry,
61 | indexHtml,
62 | srcPath,
63 | distPath,
64 | staticPath,
65 | distStaticPath,
66 | nodeModulesPath,
67 | },
68 | };
69 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/util/ProtobufJson4s.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.util
18 |
19 | import org.json4s.JValue
20 | import org.json4s.jackson.JsonMethods
21 | import scalapb.json4s.{ Parser, Printer }
22 | import scalapb.{ GeneratedMessage, GeneratedMessageCompanion, Message }
23 |
24 | object ProtobufJson4s {
25 | val printer: Printer = new Printer().includingDefaultValueFields.formattingEnumsAsNumber.formattingLongAsNumber
26 | val parser: Parser = new Parser().ignoringUnknownFields
27 |
28 | def toJsonString[A <: GeneratedMessage](m: A): String = JsonMethods.compact(toJson(m))
29 |
30 | def toJsonPrettyString[A <: GeneratedMessage](m: A): String = JsonMethods.pretty(toJson(m))
31 |
32 | def toJson[A <: GeneratedMessage](m: A): JValue = printer.toJson(m)
33 |
34 | @inline def parse[A <: GeneratedMessage](m: A): JValue = toJson(m)
35 |
36 | def fromJson[A <: GeneratedMessage with Message[A]: GeneratedMessageCompanion](value: JValue): A =
37 | parser.fromJson(value)
38 |
39 | def fromJsonString[A <: GeneratedMessage with Message[A]: GeneratedMessageCompanion](str: String): A =
40 | parser.fromJsonString(str)
41 |
42 | @inline def extract[A <: GeneratedMessage with Message[A]: GeneratedMessageCompanion](value: JValue): A =
43 | fromJson(value)
44 | }
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # General
2 | .DS_Store
3 | .AppleDouble
4 | .LSOverride
5 |
6 | # Thumbnails
7 | ._*
8 |
9 | # Files that might appear in the root of a volume
10 | .DocumentRevisions-V100
11 | .fseventsd
12 | .Spotlight-V100
13 | .TemporaryItems
14 | .Trashes
15 | .VolumeIcon.icns
16 | .com.apple.timemachine.donotpresent
17 |
18 | # Directories potentially created on remote AFP share
19 | .AppleDB
20 | .AppleDesktop
21 | Network Trash Folder
22 | Temporary Items
23 | .apdisk
24 | ### Vim template
25 | # Swap
26 | [._]*.s[a-v][a-z]
27 | [._]*.sw[a-p]
28 | [._]s[a-rt-v][a-z]
29 | [._]ss[a-gi-z]
30 | [._]sw[a-p]
31 | *.swp
32 |
33 | ### Eclipse template
34 | .classpath
35 | .settings/
36 | .metadata
37 |
38 | # External tool builders
39 | .externalToolBuilders/
40 |
41 | # Locally stored "Eclipse launch configurations"
42 | *.launch
43 |
44 | # Code Recommenders
45 | .recommenders/
46 |
47 | # Annotation Processing
48 | .apt_generated/
49 |
50 | # Scala IDE specific (Scala & Java development for Eclipse)
51 | .cache-main
52 | .scala_dependencies
53 | .worksheet
54 | ### Windows template
55 | # Windows thumbnail cache files
56 | Thumbs.db
57 | ehthumbs.db
58 | ehthumbs_vista.db
59 |
60 | # Dump file
61 | *.stackdump
62 |
63 | # Folder config file
64 | [Dd]esktop.ini
65 |
66 | # Recycle Bin used on file shares
67 | $RECYCLE.BIN/
68 |
69 | # Windows Installer files
70 | *.cab
71 | *.msi
72 | *.msix
73 | *.msm
74 | *.msp
75 |
76 | # Windows shortcuts
77 | *.lnk
78 |
79 | # Linux
80 | .directory
81 | .Trash-*
82 | .nfs*
83 |
84 | ### VisualStudioCode template
85 | .vscode/*
86 | !.vscode/settings.json
87 | !.vscode/tasks.json
88 | !.vscode/launch.json
89 | !.vscode/extensions.json
90 |
91 |
92 | .idea/
93 | out/
94 | .metals/
95 | .scannerwork/
96 | /.jvmopts
97 | *.log
98 | target/
99 | logs/
100 | ~*
101 | *.tmp
102 | *.bak
103 | !/sbt-dist/bin/
104 |
105 | node_modules/
106 | /discoveryx-server/src/main/resources/dist/
107 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/DiscoveryPersistenceQuery.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server
18 |
19 | import akka.actor.typed.ActorSystem
20 | import akka.persistence.cassandra.query.scaladsl.CassandraReadJournal
21 | import akka.persistence.jdbc.query.scaladsl.JdbcReadJournal
22 | import akka.persistence.query.PersistenceQuery
23 | import com.typesafe.scalalogging.StrictLogging
24 |
25 | class DiscoveryPersistenceQuery private (system: ActorSystem[_]) extends StrictLogging {
26 | def readJournal: DiscoveryXReadJournal = {
27 | val reader = system.settings.config.getString("akka.persistence.journal.plugin") match {
28 | case s if s.startsWith("cassandra") =>
29 | PersistenceQuery(system).readJournalFor[CassandraReadJournal](CassandraReadJournal.Identifier)
30 | case s if s.startsWith("jdbc") =>
31 | PersistenceQuery(system).readJournalFor[JdbcReadJournal](JdbcReadJournal.Identifier)
32 | case s =>
33 | throw new ExceptionInInitializerError(
34 | s"The configuration key `akka-persistence` has an invalid value [$s], only support `cassandra-journal`, `jdbc-journal`.")
35 | }
36 | logger.debug(s"ReadJournal is [$reader].")
37 | reader
38 | }
39 | }
40 |
41 | object DiscoveryPersistenceQuery {
42 | def apply(system: ActorSystem[_]): DiscoveryPersistenceQuery = new DiscoveryPersistenceQuery(system)
43 | }
44 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/test/scala/fusion/discoveryx/client/play/scaladsl/DiscoveryXWSClientTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.scaladsl
18 |
19 | import akka.actor.testkit.typed.scaladsl.ScalaTestWithActorTestKit
20 | import org.scalatest.WordSpecLike
21 | import play.api.libs.ws.ahc.AhcWSClient
22 |
23 | class DiscoveryXWSClientTest extends ScalaTestWithActorTestKit with WordSpecLike {
24 | "StandaloneWSClient" must {
25 | "create" in {
26 | // #standaloneWSClient-create
27 | val client = DiscoveryXWSClient.standaloneWSClient()
28 | val url = "http://fusion-schedulerx/cluster/health"
29 | val req = client.url(url)
30 | req.url should not be url
31 | req.url should not contain "fusion-schedulerx"
32 | // #standaloneWSClient-create
33 | }
34 | }
35 |
36 | "WSClient" must {
37 | "create" in {
38 | val client = DiscoveryXWSClient.wsClient()
39 | val url = "http://fusion-schedulerx/cluster/health"
40 | val req = client.url(url)
41 | req.url should not be url
42 | req.url should not contain "fusion-schedulerx"
43 | }
44 |
45 | "wrapper" in {
46 | val client = DiscoveryXWSClient.wsClient(AhcWSClient())
47 | val url = "http://fusion-schedulerx/cluster/health"
48 | val req = client.url(url)
49 | req.url should not be url
50 | req.url should not contain "fusion-schedulerx"
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/discoveryx-docs/docs/Fusion DiscoveryX.drawio:
--------------------------------------------------------------------------------
1 | 7Vtbc5s4FP41ntl9aMZI4Mtj7LhNdrcdN3an7b7JIIM2AnlAju399SuMMBfJl3ZtwHHzEnQAgb4Pfecc6bgFh/76Q4gW3kfmYNoCbWfdgg8tAAyjDcS/2LJJLL22mRjckDjyoswwIf9iaWxL65I4OCpcyBmjnCyKRpsFAbZ5wYbCkK2Kl80ZLT51gVysGCY2oqr1K3G4l46r089OPGLievLRPdBNTvgovViOJPKQw1Y5Exy14DBkjCdH/nqIaQxeikty3/s9Z3cvFuKAn3LDdPZ1PkXO397naIW7T/3vz4+rd0Cy8YroUo5Yvi3fpBCEbBk4OO6l3YKDlUc4niyQHZ9dCdKFzeM+FS1DHCJK3EAcUzwXbzVQX1K+9ysOOV7nTPKlP2DmYx5uxCXyrJUCuPuCkuYqo8NKbV6OCdOURiQ/AXfXdYaSOJBA/QBoRv/MoJ0BpU6/iBI0VJjMtgYmo3cxmHrNh8loAEwKSh9RIFTFj0cJOjSeRrNQHLnx0W8TErgUcxa0gHhee4zDiEQcBzb+vXZ0LbOILuiq6BqmBt3OpcDtHcGEhdxjLgsQ/YuxhUTiH8z5RroitOSsiBNeE/4td/w97urOkq2Htex529ikjUAM5lu+kbsrbma3bVvpfXs5idgytPEhYZe+EoUu5geuk/qPnYIbVBkOMUWcvBa94tnp6v+i6zBd3UbRBRTpGrJgTtxEwEKdenkodOoXqm675AZ0QqVzAxcTqtQP3d6nD0/89DuN+vQN4xdfh/myGsUXVKTqE/JFKHV1UgVrlyo1ZUxUfxRwwjf7kGxguNqHvaIXgBpowYWg/TJAvT/ffXl8mvTZ4rP3x8Ns9Cl17zlM4ukzkc1MUkaZdXAh2QGX1J2SKPycEFmqEGlBBRXpjvbhagJSG6Pdw4zWwIxZp0ew9niECQ5fiRje9ehYDxZdhKlZ1KhWx6zmfPXN17HOibOlqvhJ+/BOcxg9omNXxCisU/86b1b/YJVx3KFlmrcXIoMqXYs+8VYXnZ5Hk6mwDCnZLpmXIIs8tIgPlz69tzkLBTDx+IkthAjNMB2ziHDC4k2rGeOc+eICGp8YIPvF3QI+ZDS+T/QG59u/XB/3csOLsxL6bMkpCfBwtzF5MO3+gS0Mq8CIYamMwEoJUVNr93k8vFlCTFAzIeBwzhGw4PrCrUj4Un4f7+cLg01RFBE7Nb8n9KjiHXXZhqn6bP2FzVqHBOqWSXVkH4nEGkRas/ZNDHUJ7f7lBQnL43Q6rt3pg9KSo6biotqCC6hujlT3kf+coIH6FU2ThRysAWrK5FATkyR43iUmNU8PWKpyMDp1x8RQ3Yxq+vzo1j8/ulc6P9TkspS4N2x+QI3/qHZ+pA/LQXa3/VOwEkPkRUAiHrIXnCYccirNxQdYMqWFj7YADudzmjQf8YnjbJfFdAwUOToDCf1S1aSp2TbUVWKBi3Gg1rndGge6crhqOVDXThLXKmxJKh4n7csoBu/8rMiS4Ho5OaUA1NCl65cjZV9pwu2SoiterpgUdXdQZmhvnIoTqu0rZkJNBxTs0xXFOcVrGTKKaNJRo8dTAp2jYV7+hwcaJFLbydGgfMKYkXixNCXCKG1qGN3+nVXsJAlx5X0ZzGpXZc1Tu0qCYKWrLWO7of8PEtWY9SZJNM2zkajp6nwk7t9/1vipp0AkZcF5Eg9FqDTs7o+3eiU3otsH1JXKwTOI1/7So2uCTFs6Uilk+6KhxkIGdcs/lUKmriY3HLLdSvEFIBPN7DeVifRlv0yFo/8A
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/fusion/discoveryx/server/route/FusionRouteTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.route
18 |
19 | import akka.actor.ActorSystem
20 | import akka.http.scaladsl.testkit.{ RouteTestTimeout, ScalatestRouteTest }
21 | import akka.testkit.TestDuration
22 | import com.typesafe.config.{ Config, ConfigFactory }
23 | import fusion.core.extension.FusionCore
24 | import fusion.discoveryx.server.DiscoveryX
25 | import org.scalatest.concurrent.ScalaFutures
26 | import org.scalatest.time.{ Millis, Span }
27 | import org.scalatest.{ EitherValues, Matchers, OptionValues, Suite }
28 |
29 | import scala.concurrent.duration._
30 |
31 | // TODO 不依赖 DiscoveryX,依赖 SpawnFactory 即可
32 |
33 | trait FusionRouteTest extends ScalatestRouteTest with Matchers with OptionValues with EitherValues with ScalaFutures {
34 | this: Suite =>
35 | protected implicit val timeout: RouteTestTimeout = RouteTestTimeout(5.seconds.dilated)
36 | protected var discoveryX: DiscoveryX = _
37 |
38 | implicit override def patienceConfig: PatienceConfig =
39 | PatienceConfig(scaled(Span(10.second.toMillis, Millis)), scaled(Span(15, Millis)))
40 |
41 | override protected def createActorSystem(): ActorSystem = {
42 | discoveryX = DiscoveryX.fromOriginalConfig(ConfigFactory.load("application-test.conf"))
43 | FusionCore(discoveryX.system)
44 | discoveryX.classicSystem
45 | }
46 |
47 | override def testConfig: Config = discoveryX.config
48 | }
49 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/design/concept.md:
--------------------------------------------------------------------------------
1 | # Fusion DiscoveryX 概念
2 |
3 | ## 命名空间(namespace)
4 |
5 | 用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
6 |
7 | ## 配置
8 |
9 | 在系统开发过程中,开发者通常会将一些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物理运行环境进行适配。配置管理一般包含在系统部署的过程中,由系统管理员或者运维人员完成。配置变更是调整系统运行时的行为的有效手段。
10 |
11 | ## 配置管理
12 |
13 | 系统配置的编辑、存储、分发、变更管理、历史版本管理、变更审计等所有与配置相关的活动。
14 |
15 | ## 配置项
16 |
17 | 一个具体的可配置的参数与其值域,通常以 param-key=param-value 的形式存在。例如我们常配置系统的日志输出级别(logLevel=INFO|WARN|ERROR) 就是一个配置项。
18 |
19 | ## 配置集
20 |
21 | 一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。
22 |
23 | ## 配置集 ID(dataId)
24 |
25 | DiscoveryX 中的某个配置集的 ID(dataId)。配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。Data ID 通常采用类 Java 包(如 com.akka-fusion.schedulerx.log.level)的命名规则保证全局唯一性。此命名规则非强制。
26 |
27 | ## 配置分组
28 |
29 | DiscoveryX 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或 Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 DiscoveryX 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 `default` 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置和 MQ_topic 配置。
30 |
31 | ## 配置快照
32 |
33 | DiscoveryX 的客户端 SDK 会在本地生成配置的快照。当客户端无法连接到 DiscoveryX Server 时,可以使用配置快照显示系统的整体容灾能力。配置快照类似于 Git 中的本地 commit,也类似于缓存,会在适当的时机更新,但是并没有缓存过期(expiration)的概念。 *DiscoveryX 使用 akka-persistence 提供配置快照(通过把每次配置修改事件都进行存储),理论上可以提供无线版本的配置快照。*
34 |
35 | ## 服务
36 |
37 | 通过预定义接口网络访问的提供给客户端的软件功能。
38 |
39 | ## 服务名
40 |
41 | 服务提供的标识,通过该标识可以唯一确定其指代的服务。
42 |
43 | ## 服务注册中心
44 |
45 | 存储服务实例和服务负载均衡策略的数据库。
46 |
47 | ## 服务发现
48 |
49 | 在计算机网络上,(通常使用服务名)对服务下的实例的地址和元数据进行探测,并以预先定义的接口提供给客户端进行查询。
50 |
51 | ## 元信息
52 |
53 | DiscoveryX 数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义标签 (label),从作用范围来看,分为服务级别的元信息、集群的元信息及实例的元信息。
54 |
55 | ## 应用
56 |
57 | 用于标识服务提供方的服务的属性。
58 |
59 | ## 服务分组
60 |
61 | 不同的服务可以归类到同一分组。
62 |
63 | ## 实例
64 |
65 | 提供一个或多个服务的具有可访问网络地址(ip:port)的进程。
66 |
67 | ## 权重
68 |
69 | 实例级别的配置。权重为浮点数。权重越大,分配给该实例的流量越大。
70 |
71 | ## 健康检查
72 |
73 | 以指定方式检查服务下挂载的实例 (Instance) 的健康度,从而确认该实例 (Instance) 是否能提供服务。根据检查结果,实例 (Instance) 会被判断为健康或不健康。对服务发起解析请求时,不健康的实例 (Instance) 不会返回给客户端。
74 |
--------------------------------------------------------------------------------
/discoveryx-client/src/main/scala/fusion/discoveryx/client/impl/ConfigClientImpl.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.impl
18 |
19 | import akka.NotUsed
20 | import akka.actor.typed.ActorSystem
21 | import akka.stream.scaladsl.Source
22 | import com.typesafe.scalalogging.StrictLogging
23 | import fusion.core.extension.FusionCore
24 | import fusion.discoveryx.client.{ ConfigClient, ConfigClientSettings }
25 | import fusion.discoveryx.grpc.ConfigServiceClient
26 | import fusion.discoveryx.model._
27 |
28 | import scala.concurrent.Future
29 |
30 | private[client] class ConfigClientImpl(val settings: ConfigClientSettings, val configClient: ConfigServiceClient)(
31 | implicit system: ActorSystem[_])
32 | extends ConfigClient
33 | with StrictLogging {
34 | FusionCore(system).shutdowns.beforeServiceUnbind("ConfigClient") { () =>
35 | configClient.close()
36 | }
37 | logger.info(s"ConfigClient was instanced, setting is [$settings], class is [$getClass].")
38 |
39 | override def serverStatus(in: ServerStatusQuery): Future[ServerStatusBO] = configClient.serverStatus(in)
40 |
41 | override def getConfig(in: ConfigGet): Future[ConfigReply] = configClient.getConfig(in)
42 |
43 | override def publishConfig(in: ConfigItem): Future[ConfigReply] = configClient.publishConfig(in)
44 |
45 | override def removeConfig(in: ConfigRemove): Future[ConfigReply] = configClient.removeConfig(in)
46 |
47 | override def listenerConfig(in: ConfigChangeListen): Source[ConfigChanged, NotUsed] = configClient.listenerConfig(in)
48 | }
49 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/BaseSettings.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server
18 |
19 | import akka.persistence.typed.scaladsl.{ RetentionCriteria, SnapshotCountRetentionCriteria }
20 | import helloscala.common.Configuration
21 |
22 | trait BaseSettings {
23 | val c: Configuration
24 |
25 | def defaultPage: Int = c.getInt("default-page")
26 | def defaultSize: Int = c.getInt("default-size")
27 |
28 | def findSize(size: Int): Int = if (size < defaultSize) defaultSize else size
29 |
30 | def findPage(page: Int): Int = if (page < defaultPage) defaultPage else page
31 |
32 | def findOffset(page: Int, size: Int): Int = if (page > 0) (page - 1) * size else 0
33 |
34 | /**
35 | * @return (page, size, offset)
36 | */
37 | def generatePageSizeOffset(_page: Int, _size: Int): (Int, Int, Int) = {
38 | val page = findPage(_page)
39 | val size = findSize(_size)
40 | val offset = if (page > 0) (page - 1) * size else 0
41 | (page, size, offset)
42 | }
43 | }
44 |
45 | trait RetentionCriteriaSettings {
46 | val c: Configuration
47 | def journalOnDelete: Boolean = c.getBoolean("journal-on-delete")
48 | def numberOfEvents: Int = c.getInt("snapshot.number-of-events")
49 | def keepNSnapshots: Int = c.getInt("snapshot.keep-n-snapshots")
50 |
51 | def retentionCriteria: SnapshotCountRetentionCriteria = {
52 | val retention = RetentionCriteria.snapshotEvery(numberOfEvents, keepNSnapshots)
53 | if (journalOnDelete) retention.withDeleteEventsOnSnapshot else retention
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/docs/js/scrollsneak.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Based on Scroll Sneak:
3 | * http://mrcoles.com/scroll-sneak/
4 | *
5 | * Note: this version of scroll adjustment assumes auto expanding/collapsing navigation
6 | */
7 | $(function() {
8 |
9 | var prefix = "docs.nav.scroll";
10 | var nav = $(".site-nav");
11 |
12 | // if window.name matches, then scroll to the position and clean up window.name
13 | if (window.name.search('^'+prefix+'_(\\d+)_') == 0) {
14 | var name = window.name.split('_');
15 | nav.scrollTop(name[1]);
16 | window.name = name.slice(2).join('_');
17 | }
18 |
19 | var originalName;
20 | var active = nav.find("a.active.page").parent("li");
21 | var activeParents = active.parentsUntil(nav);
22 |
23 | // add scroll sneak to all the page links in the navigation
24 | // most of this is adjusting for the auto expanding/collapsing
25 | nav.find("a.page").each(function() {
26 | var link = $(this);
27 | // if the active page is positioned above this link but not an ancestor,
28 | // then scroll needs to be adjusted because of the active sections collapsing
29 | var collapseHeight = 0;
30 | if ((active.length > 0) && (active.position().top < link.position().top) && (link.parentsUntil(nav).filter(active).length == 0)) {
31 | // find the active section that will collapse, by searching for the first common parent
32 | var collapsing = active;
33 | activeParents.each(function() {
34 | var ancestor = $(this);
35 | if (ancestor.has(link).length > 0) return false;
36 | collapsing = ancestor;
37 | });
38 | collapseHeight = Math.round(collapsing.children("ul").first().outerHeight(true));
39 | }
40 | link.click(function() {
41 | var link = $(this);
42 | var adjustment = collapseHeight;
43 | // prevent multiple clicks storing the scroll position on window.name
44 | if (typeof(originalName) == 'undefined') originalName = window.name;
45 | // store the current scroll position into the window.name
46 | var position = Math.max(0, nav.scrollTop() - adjustment);
47 | if (position) window.name = prefix + '_' + position + '_' + originalName;
48 | });
49 | });
50 |
51 | });
52 |
--------------------------------------------------------------------------------
/web-console/src/components/Chart/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin React Echarts Component
5 | *
6 | * option: {
7 | * option: 基础配置项,
8 | * data: 数据源,
9 | * row: 横坐标上的属性(对于data里面的key),
10 | * column: 纵坐标上的属性(对于data里面的key),
11 | * value: 图上的属性(对于data里面的key),
12 | * seriesTemplates: 每个series的配置
13 | * }
14 | * */
15 |
16 | import React, { useEffect, useRef } from 'react';
17 | import echarts from 'echarts';
18 | import { computedEchartsOption } from 'up-utils';
19 | import lodashIsEqual from 'lodash/isEqual';
20 | import * as PropTypes from 'prop-types';
21 |
22 | const EChart = props => {
23 | const { option, style } = props;
24 | const echartsRef = useRef(null);
25 | let echartsInstance;
26 |
27 | const renderChart = () => {
28 | if (echartsRef.current) {
29 | const renderedInstance = echarts.getInstanceByDom(echartsRef.current);
30 | if (renderedInstance) {
31 | echartsInstance = renderedInstance;
32 | } else {
33 | echartsInstance = echarts.init(echartsRef.current);
34 | }
35 | echartsInstance.setOption(computedEchartsOption(option));
36 | }
37 | };
38 |
39 | useEffect(() => {
40 | const handleWindowResize = () => {
41 | console.log('echarts resize');
42 | echartsInstance.resize();
43 | };
44 | window.addEventListener('resize', handleWindowResize);
45 | return () => {
46 | window.removeEventListener('resize', handleWindowResize);
47 | echartsInstance.dispose();
48 | console.log('echarts dispose');
49 | };
50 | }, []);
51 |
52 | useEffect(() => {
53 | renderChart();
54 | console.log('echarts render');
55 | });
56 |
57 | return ;
58 | };
59 |
60 | const areEqual = (prevProps, nextProps) => {
61 | return lodashIsEqual(prevProps.option.data, nextProps.option.data);
62 | };
63 |
64 | EChart.propTypes = {
65 | option: PropTypes.object.isRequired,
66 | style: PropTypes.object,
67 | };
68 |
69 | EChart.defaultProps = {
70 | style: { width: '100%', height: 400 },
71 | };
72 |
73 | export default React.memo(EChart, areEqual);
74 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/namespace/NamespaceRef.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.namespace
18 |
19 | import akka.actor.typed.scaladsl.Behaviors
20 | import akka.actor.typed.{ ActorRef, Behavior }
21 | import akka.cluster.ddata.typed.scaladsl.{ DistributedData, Replicator }
22 | import akka.cluster.ddata.{ ORSet, ORSetKey }
23 |
24 | /**
25 | * 需要 Singleton actor Management() 已启动
26 | */
27 | object NamespaceRef {
28 | sealed trait Command
29 | final case class ExistNamespace(namespace: String, replyTo: ActorRef[NamespaceExists]) extends Command
30 | private final case class InternalNamespaceExists(exists: Boolean, replyTo: ActorRef[NamespaceExists]) extends Command
31 |
32 | final case class NamespaceExists(exists: Boolean)
33 |
34 | val NAME = "Namespace"
35 | val Key: ORSetKey[String] = ORSetKey(NAME)
36 |
37 | def apply(): Behavior[Command] = DistributedData.withReplicatorMessageAdapter[Command, ORSet[String]] {
38 | replicatorAdapter =>
39 | Behaviors.receive[Command] {
40 | case (ctx, ExistNamespace(namespace, replyTo)) =>
41 | replicatorAdapter.askGet(Replicator.Get(Key, Replicator.ReadLocal), {
42 | case chg @ Replicator.GetSuccess(Key) =>
43 | InternalNamespaceExists(chg.get(Key).contains(namespace), replyTo)
44 | case _ =>
45 | ctx.log.warn(s"ORSet key is [$Key], it's not found.")
46 | InternalNamespaceExists(false, replyTo)
47 | })
48 | Behaviors.same
49 |
50 | case (_, InternalNamespaceExists(exists, replyTo)) =>
51 | replyTo ! NamespaceExists(exists)
52 | Behaviors.same
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/namespace/service/NamespaceManagerServiceImpl.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.namespace.service
18 |
19 | import akka.actor.typed.scaladsl.AskPattern._
20 | import akka.actor.typed.{ ActorRef, ActorSystem }
21 | import akka.util.Timeout
22 | import fusion.discoveryx.server.grpc.NamespaceManagerService
23 | import fusion.discoveryx.server.namespace.NamespaceManager
24 | import fusion.discoveryx.server.protocol.ManagementCommand.Cmd
25 | import fusion.discoveryx.server.protocol._
26 |
27 | import scala.concurrent.Future
28 | import scala.concurrent.duration._
29 |
30 | class NamespaceManagerServiceImpl(managementRef: ActorRef[NamespaceManager.Command])(implicit system: ActorSystem[_])
31 | extends NamespaceManagerService {
32 | implicit private val timeout: Timeout = 5.seconds
33 |
34 | /**
35 | * #ListNamespace
36 | */
37 | override def listNamespace(in: ListNamespace): Future[ManagementResponse] =
38 | askCommand(Cmd.List(in))
39 |
40 | /**
41 | * #CreateNamespace
42 | */
43 | override def createNamespace(in: CreateNamespace): Future[ManagementResponse] =
44 | askCommand(Cmd.Create(in))
45 |
46 | /**
47 | * #ModifyNamespace
48 | */
49 | override def modifyNamespace(in: ModifyNamespace): Future[ManagementResponse] =
50 | askCommand(Cmd.Modify(in))
51 |
52 | /**
53 | * #RemoveNamespace
54 | */
55 | override def removeNamespace(in: RemoveNamespace): Future[ManagementResponse] =
56 | askCommand(Cmd.Remove(in))
57 |
58 | @inline private def askCommand(cmd: Cmd): Future[ManagementResponse] =
59 | managementRef.ask[ManagementResponse](replyTo => ManagementCommand(replyTo, cmd))
60 | }
61 |
--------------------------------------------------------------------------------
/discoveryx-server/src/test/scala/fusion/discoveryx/server/user/service/UserServiceTest.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.user.service
18 |
19 | import akka.actor.testkit.typed.scaladsl.{ ActorTestKit, ScalaTestWithActorTestKit }
20 | import com.typesafe.config.ConfigFactory
21 | import fusion.common.config.FusionConfigFactory
22 | import fusion.discoveryx.common.Constants
23 | import fusion.discoveryx.server.user.{ UserEntity, UserManager }
24 | import fusion.discoveryx.server.protocol.{ CreateUser, Login, UserRole }
25 | import fusion.discoveryx.server.util.ProtobufJson4s
26 | import helloscala.common.IntStatus
27 | import org.scalatest.WordSpecLike
28 |
29 | class UserServiceTest
30 | extends ScalaTestWithActorTestKit(
31 | ActorTestKit(
32 | Constants.DISCOVERYX,
33 | FusionConfigFactory
34 | .arrangeConfig(ConfigFactory.load("application-test.conf"), Constants.DISCOVERYX, Seq("akka"))))
35 | with WordSpecLike {
36 | private val userService = new UserServiceImpl(UserEntity.init(system), UserManager.init(system))
37 |
38 | "UserServiceTest" should {
39 | "removeUser" in {}
40 |
41 | "logout" in {}
42 |
43 | "createUser" in {
44 | val in = CreateUser("discoveryx", "discoveryx", "DiscoveryX Administrator", UserRole.ADMIN)
45 | val response = userService.createUser(in).futureValue
46 | println(ProtobufJson4s.toJsonPrettyString(response))
47 | response.status should be(IntStatus.OK)
48 | }
49 |
50 | "modifyUser" in {}
51 |
52 | "listUser" in {}
53 |
54 | "login" in {
55 | val response = userService.login(Login("discoveryx", "discoveryx")).futureValue
56 | println(ProtobufJson4s.toJsonPrettyString(response))
57 | response.status should be(IntStatus.OK)
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/discoveryx-client/src/main/resources/reference.conf:
--------------------------------------------------------------------------------
1 | // #discoveryx-client
2 | discoveryx.client {
3 | naming {
4 | // 自动注册服务。default: false
5 | #auto-registration = false
6 |
7 | // 心跳间隔
8 | heartbeat-interval = 10.seconds
9 |
10 | // 查询服务实例时只返回一个健康实例(轮询)
11 | one-healthy = true
12 |
13 | // 查询服务实例时返回所有健康实例(若 one-healthy 设置为 true,则 all-healthy 不进行判断)
14 | all-healthy = false
15 |
16 | // 名称空间
17 | #namespace = ""
18 |
19 | // 注册的服务实例名
20 | #service-name = "discoveryx"
21 |
22 | // 注册的服务实例IP地址
23 | #ip = "127.0.0.1"
24 |
25 | // 注册的服务实例网络端口
26 | #port = 8000
27 |
28 | // 是否启用。default: true
29 | #enable = true
30 |
31 | // 设置为true服务注册后立即可用,否则等一次心跳消息后可用。default: true
32 | #health = true
33 |
34 | // 注册的服务实例权重。default: 1.0
35 | #weight = 1.0
36 |
37 | // 注册的服务实例元数据
38 | #metadata {
39 | # env = test
40 | # application = web-backend
41 | #}
42 |
43 | // 健康检查方法,支持:CLIENT_REPORT, SERVER_SNIFF。default:CLIENT_REPORT
44 | #healthy-check-method = CLIENT_REPORT
45 |
46 | // 健康检查间隔(秒),当 healthy-check-method = SERVER_SNIFF 时有效。default:15
47 | #healthy-check-interval = 15
48 |
49 | // 几次健康检查失败设置服务实例为不健康状态。default:1
50 | #unhealthy-check-count = 1
51 |
52 | // 健康检查协议,支持:UDP、TCP、HTTP(当 healthy-check-method = SERVER_SNIFF 时有效 )。default:HTTP
53 | #protocol = HTTP
54 |
55 | // 健康检查是否使用 TLS。default: false
56 | # use-tls = false
57 |
58 | // protocol 设置为 HTTP 或 HTTPS 时指定的GET请求URI PATH路径
59 | // 对于HTTP(HTTPS)检测,当HTTP响应状态值为 [200, 299] 范围内时认为服务实例状态为 healthy。
60 | #http-path =
61 |
62 | // 调用NamingClient.generateUri默认超时时间。default: 5 seconds
63 | #query-timeout = 5.seconds
64 | }
65 | }
66 | // #discoveryx-client
67 |
68 | // #grpc-client
69 | akka.grpc.client {
70 | // DiscoveryX 配置管理服务
71 | "fusion.discoveryx.grpc.ConfigService" {
72 | // 是否使用 tls
73 | use-tls = false
74 | host = "127.0.0.1"
75 | port = 48000
76 | }
77 | // DiscoveryX 服务注册、发现管理服务
78 | "fusion.discoveryx.grpc.NamingService" {
79 | // 是否使用 tls
80 | use-tls = false
81 | host = "127.0.0.1"
82 | port = 48000
83 | }
84 | }
85 | // #grpc-client
86 |
87 | // #discovery
88 | akka.discovery {
89 | method = fusion-discoveryx
90 |
91 | fusion-discoveryx {
92 | class = fusion.discoveryx.client.DiscoveryXAkkaDiscovery
93 |
94 | setting = discoveryx.client.naming
95 | }
96 | }
97 | // #discovery
98 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/scala/fusion/discoveryx/client/play/javadsl/module/DiscoveryXWSModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.javadsl.module;
18 |
19 | import akka.actor.typed.ActorSystem;
20 | import com.typesafe.config.Config;
21 | import fusion.discoveryx.client.play.javadsl.DiscoveryXPlay;
22 | import fusion.discoveryx.client.play.javadsl.DiscoveryXPlayWSClient;
23 | import fusion.discoveryx.client.play.javadsl.DiscoveryXWSClient;
24 | import fusion.discoveryx.common.Constants;
25 | import play.Environment;
26 | import play.inject.Binding;
27 | import play.inject.Module;
28 | import play.libs.ws.WSClient;
29 | import play.shaded.ahc.org.asynchttpclient.AsyncHttpClient;
30 |
31 | import javax.inject.Provider;
32 | import java.util.Arrays;
33 | import java.util.List;
34 |
35 | public class DiscoveryXWSModule extends Module {
36 | @Override
37 | public List> bindings(Environment environment, Config config) {
38 | return Arrays.asList(bindClass(DiscoveryXPlayWSClient.class).toProvider(DiscoveryXWSPlayClientProvider.class),
39 | bindClass(WSClient.class).qualifiedWith(Constants.DISCOVERYX()).to(DiscoveryXPlayWSClient.class),
40 | bindClass(WSClient.class).qualifiedWith(DiscoveryXPlay.class).to(DiscoveryXPlayWSClient.class));
41 | }
42 |
43 | public static class DiscoveryXWSPlayClientProvider implements Provider {
44 | private final DiscoveryXPlayWSClient client;
45 |
46 | public DiscoveryXWSPlayClientProvider(AsyncHttpClient asyncHttpClient, ActorSystem> system) {
47 | this.client = DiscoveryXWSClient.wsClient(asyncHttpClient, system);
48 | }
49 |
50 | @Override
51 | public DiscoveryXPlayWSClient get() {
52 | return client;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/util/SessionUtils.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.util
18 |
19 | import java.net.{ URLDecoder, URLEncoder }
20 | import java.nio.charset.StandardCharsets
21 | import java.util.concurrent.ThreadLocalRandom
22 |
23 | import akka.http.scaladsl.model.HttpRequest
24 | import akka.http.scaladsl.model.headers.Cookie
25 | import fusion.discoveryx.common.Constants
26 | import fusion.discoveryx.server.protocol.TokenAccount
27 | import helloscala.common.util.DigestUtils
28 |
29 | import scala.util.control.NonFatal
30 |
31 | object SessionUtils {
32 | def getTokenFromRequest(request: HttpRequest): Option[String] = {
33 | request
34 | .header[Cookie]
35 | .flatMap(tokenFromCookie)
36 | .orElse(request.headers.find(_.name == Constants.SESSION_TOKEN_NAME).map(_.value))
37 | }
38 |
39 | def tokenFromCookie(cookie: Cookie): Option[String] =
40 | cookie.cookies.find(_.name == Constants.SESSION_TOKEN_NAME).map(_.value)
41 |
42 | def decodeToken(token: String): String = new String(URLDecoder.decode(token, StandardCharsets.UTF_8.toString))
43 |
44 | def parseAccount(originalToken: String): Either[String, TokenAccount] =
45 | try {
46 | val token = decodeToken(originalToken)
47 | SessionUtils.decodeToken(token).split("\\|") match {
48 | case Array(account, _) => Right(TokenAccount(originalToken, account))
49 | case other => Left(s"Parsing account error from token. the parse value is [$other].")
50 | }
51 | } catch {
52 | case NonFatal(e) => Left(e.getLocalizedMessage)
53 | }
54 |
55 | def generateSessionToken(account: String): String = {
56 | val bytes = Array.ofDim[Byte](40)
57 | ThreadLocalRandom.current().nextBytes(bytes)
58 | val token = DigestUtils.md5Hex(bytes)
59 | URLEncoder.encode(s"$account|$token", StandardCharsets.UTF_8.toString)
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/naming/service/NamingServiceHelper.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.naming.service
18 |
19 | import java.util.concurrent.TimeoutException
20 |
21 | import akka.actor.typed.scaladsl.AskPattern._
22 | import akka.actor.typed.{ ActorRef, Scheduler }
23 | import akka.cluster.sharding.typed.ShardingEnvelope
24 | import akka.util.Timeout
25 | import fusion.discoveryx.model.NamingReply
26 | import fusion.discoveryx.server.namespace.NamespaceRef.{ ExistNamespace, NamespaceExists }
27 | import fusion.discoveryx.server.naming.NamingService
28 | import fusion.discoveryx.server.protocol.NamingReplyCommand
29 | import helloscala.common.IntStatus
30 |
31 | import scala.concurrent.{ ExecutionContext, Future }
32 |
33 | trait NamingServiceHelper {
34 | val serviceInstanceRegion: ActorRef[ShardingEnvelope[NamingService.Command]]
35 | val namespaceRef: ActorRef[ExistNamespace]
36 |
37 | protected def askNaming(namespace: String, serviceName: String, cmd: NamingReplyCommand.Cmd)(
38 | implicit timeout: Timeout,
39 | scheduler: Scheduler,
40 | ec: ExecutionContext): Future[NamingReply] = {
41 | namespaceRef.ask[NamespaceExists](replyTo => ExistNamespace(namespace, replyTo)).flatMap {
42 | case NamespaceExists(true) =>
43 | NamingService.makeEntityId(namespace, serviceName) match {
44 | case Right(entityId) =>
45 | serviceInstanceRegion
46 | .ask[NamingReply](replyTo => ShardingEnvelope(entityId, NamingReplyCommand(replyTo, cmd)))
47 | .recover {
48 | case _: TimeoutException => NamingReply(IntStatus.GATEWAY_TIMEOUT)
49 | }
50 | case Left(errMsg) => Future.successful(NamingReply(IntStatus.INTERNAL_ERROR, errMsg))
51 | }
52 | case _ =>
53 | Future.successful(NamingReply(IntStatus.NOT_FOUND, s"Namespace [$namespace] not found."))
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/discoveryx-docs/src/main/paradox/api/open/config.md:
--------------------------------------------------------------------------------
1 | # ConfigService
2 |
3 | - gRPC服务地址:`/fusion.discoveryx.grpc.ConfigService`
4 | - REST URL前缀:`/fusion/discoveryx/v1/config`
5 |
6 | REST URL路径由 **REST URL前缀** + 服务名组织,均使用 **POST** 方法的请求,JSON序例化格式。如查询配置接口访问地址为:`POST /fusion/discoveryx/v1/config/QueryConfig`。Protobuf与JSON格式转换请参阅: @ref[JSON 说明](../json.md)。
7 |
8 | ### GetConfig
9 |
10 | **gRPC**
11 |
12 | @@snip [gRPC](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/grpc/discoveryx.proto) { #GetConfig }
13 |
14 | **请求**
15 |
16 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigGet }
17 |
18 | **响应**
19 |
20 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigReply }
21 |
22 | `oneof`的`queried`字段将返回已注册实例信息,如下:
23 |
24 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigQueried }
25 |
26 | ### PublishConfig
27 |
28 | **gRPC**
29 |
30 | @@snip [gRPC](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/grpc/discoveryx.proto) { #PublishConfig }
31 |
32 | **请求**
33 |
34 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigItem }
35 |
36 | **响应**
37 |
38 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigReply }
39 |
40 | ### RemoveConfig
41 |
42 | **gRPC**
43 |
44 | @@snip [gRPC](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/grpc/discoveryx.proto) { #RemoveConfig }
45 |
46 | **请求**
47 |
48 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigRemove }
49 |
50 | **响应**
51 |
52 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigReply }
53 |
54 | ### ListenerConfig
55 |
56 | **gRPC**
57 |
58 | @@snip [gRPC](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/grpc/discoveryx.proto) { #ListenerConfig }
59 |
60 | **请求**
61 |
62 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigChangeListen }
63 |
64 | **响应**
65 |
66 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ConfigChanged }
67 | @@snip [model](../../../../../../discoveryx-common/src/main/protobuf/fusion/discoveryx/model/discoveryx.proto) { #ChangeType }
68 |
--------------------------------------------------------------------------------
/discoveryx-client/src/main/scala/fusion/discoveryx/client/HttpUtils.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client
18 |
19 | import akka.actor.typed.ActorSystem
20 | import akka.http.scaladsl.Http
21 | import akka.http.scaladsl.marshalling.{ Marshal, Marshaller }
22 | import akka.http.scaladsl.model._
23 | import akka.http.scaladsl.unmarshalling.{ Unmarshal, Unmarshaller }
24 | import akka.stream.Materializer
25 |
26 | import scala.collection.immutable
27 | import scala.concurrent.Future
28 |
29 | final class ResponseAs(val response: Future[HttpResponse])(implicit mat: Materializer) {
30 | import mat.executionContext
31 | def responseAs[R](implicit um: Unmarshaller[ResponseEntity, R]): Future[R] =
32 | response.flatMap(resp => Unmarshal(resp.entity).to[R])
33 |
34 | def onSuccessResponseAs[R](implicit um: Unmarshaller[ResponseEntity, R]): Future[R] =
35 | response.flatMap {
36 | case resp if resp.status.isSuccess() => Unmarshal(resp.entity).to[R]
37 | case resp => Future.failed(new IllegalStateException(s"Http request failed, the response is $resp."))
38 | }
39 | }
40 |
41 | final class HttpUtils private ()(implicit system: ActorSystem[_]) {
42 | def singleRequest[A](
43 | method: HttpMethod = HttpMethods.GET,
44 | uri: Uri = "/",
45 | headers: immutable.Seq[HttpHeader] = Nil,
46 | entity: A = null,
47 | protocol: HttpProtocol = HttpProtocols.`HTTP/1.1`)(
48 | implicit
49 | m: Marshaller[A, RequestEntity]): ResponseAs = {
50 | import system.executionContext
51 | val entityF = if (null == entity) Future.successful(HttpEntity.Empty) else Marshal(entity).to[RequestEntity]
52 | val responseF = entityF.flatMap { entity =>
53 | val request = HttpRequest(method, uri, headers, entity, protocol)
54 | Http(system).singleRequest(request)
55 | }
56 | new ResponseAs(responseF)
57 | }
58 | }
59 |
60 | object HttpUtils {
61 | def apply(system: ActorSystem[_]): HttpUtils = new HttpUtils()(system)
62 | }
63 |
--------------------------------------------------------------------------------
/scripts/dockers/cassandra/docker-entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # first arg is `-f` or `--some-option`
5 | # or there are no args
6 | if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
7 | set -- cassandra -f "$@"
8 | fi
9 |
10 | # allow the container to be started with `--user`
11 | if [ "$1" = 'cassandra' -a "$(id -u)" = '0' ]; then
12 | find /var/lib/cassandra /var/log/cassandra "$CASSANDRA_CONFIG" \
13 | \! -user cassandra -exec chown cassandra '{}' +
14 | exec gosu cassandra "$BASH_SOURCE" "$@"
15 | fi
16 |
17 | _ip_address() {
18 | # scrape the first non-localhost IP address of the container
19 | # in Swarm Mode, we often get two IPs -- the container IP, and the (shared) VIP, and the container IP should always be first
20 | ip address | awk '
21 | $1 == "inet" && $NF != "lo" {
22 | gsub(/\/.+$/, "", $2)
23 | print $2
24 | exit
25 | }
26 | '
27 | }
28 |
29 | # "sed -i", but without "mv" (which doesn't work on a bind-mounted file, for example)
30 | _sed-in-place() {
31 | local filename="$1"; shift
32 | local tempFile
33 | tempFile="$(mktemp)"
34 | sed "$@" "$filename" > "$tempFile"
35 | cat "$tempFile" > "$filename"
36 | rm "$tempFile"
37 | }
38 |
39 | if [ "$1" = 'cassandra' ]; then
40 | : ${CASSANDRA_RPC_ADDRESS='0.0.0.0'}
41 |
42 | : ${CASSANDRA_LISTEN_ADDRESS='auto'}
43 | if [ "$CASSANDRA_LISTEN_ADDRESS" = 'auto' ]; then
44 | CASSANDRA_LISTEN_ADDRESS="$(_ip_address)"
45 | fi
46 |
47 | : ${CASSANDRA_BROADCAST_ADDRESS="$CASSANDRA_LISTEN_ADDRESS"}
48 |
49 | if [ "$CASSANDRA_BROADCAST_ADDRESS" = 'auto' ]; then
50 | CASSANDRA_BROADCAST_ADDRESS="$(_ip_address)"
51 | fi
52 | : ${CASSANDRA_BROADCAST_RPC_ADDRESS:=$CASSANDRA_BROADCAST_ADDRESS}
53 |
54 | if [ -n "${CASSANDRA_NAME:+1}" ]; then
55 | : ${CASSANDRA_SEEDS:="cassandra"}
56 | fi
57 | : ${CASSANDRA_SEEDS:="$CASSANDRA_BROADCAST_ADDRESS"}
58 |
59 | _sed-in-place "$CASSANDRA_CONFIG/cassandra.yaml" \
60 | -r 's/(- seeds:).*/\1 "'"$CASSANDRA_SEEDS"'"/'
61 |
62 | for yaml in \
63 | broadcast_address \
64 | broadcast_rpc_address \
65 | cluster_name \
66 | endpoint_snitch \
67 | listen_address \
68 | num_tokens \
69 | rpc_address \
70 | start_rpc \
71 | ; do
72 | var="CASSANDRA_${yaml^^}"
73 | val="${!var}"
74 | if [ "$val" ]; then
75 | _sed-in-place "$CASSANDRA_CONFIG/cassandra.yaml" \
76 | -r 's/^(# )?('"$yaml"':).*/\2 '"$val"'/'
77 | fi
78 | done
79 |
80 | for rackdc in dc rack; do
81 | var="CASSANDRA_${rackdc^^}"
82 | val="${!var}"
83 | if [ "$val" ]; then
84 | _sed-in-place "$CASSANDRA_CONFIG/cassandra-rackdc.properties" \
85 | -r 's/^('"$rackdc"'=).*/\1 '"$val"'/'
86 | fi
87 | done
88 | fi
89 |
90 | exec "$@"
--------------------------------------------------------------------------------
/discoveryx-server/src/main/scala/fusion/discoveryx/server/config/service/ConfigManagerServiceImpl.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.server.config.service
18 |
19 | import akka.actor.typed.scaladsl.AskPattern._
20 | import akka.actor.typed.{ ActorRef, ActorSystem }
21 | import akka.cluster.sharding.typed.ShardingEnvelope
22 | import akka.util.Timeout
23 | import com.typesafe.scalalogging.StrictLogging
24 | import fusion.discoveryx.server.config.ConfigManager
25 | import fusion.discoveryx.server.grpc.ConfigManagerService
26 | import fusion.discoveryx.server.namespace.NamespaceRef
27 | import fusion.discoveryx.server.namespace.NamespaceRef.{ ExistNamespace, NamespaceExists }
28 | import fusion.discoveryx.server.protocol.ConfigManagerCommand.Cmd
29 | import fusion.discoveryx.server.protocol._
30 | import helloscala.common.IntStatus
31 |
32 | import scala.concurrent.Future
33 | import scala.concurrent.duration._
34 |
35 | class ConfigManagerServiceImpl(namespaceRef: ActorRef[NamespaceRef.ExistNamespace])(implicit system: ActorSystem[_])
36 | extends ConfigManagerService
37 | with StrictLogging {
38 | private implicit val timeout: Timeout = 10.seconds
39 | private val configManager: ActorRef[ShardingEnvelope[ConfigManager.Command]] = ConfigManager.init(system)
40 |
41 | /**
42 | * #ListConfig
43 | * Query config list. Will not return config content.
44 | */
45 | override def listConfig(in: ListConfig): Future[ConfigResponse] = askConfig(in.namespace, Cmd.List(in))
46 |
47 | @inline private def askConfig(namespace: String, cmd: ConfigManagerCommand.Cmd): Future[ConfigResponse] =
48 | namespaceRef
49 | .ask[NamespaceExists](replyTo => ExistNamespace(namespace, replyTo))
50 | .flatMap {
51 | case NamespaceExists(true) =>
52 | configManager.ask[ConfigResponse](replyTo => ShardingEnvelope(namespace, ConfigManagerCommand(replyTo, cmd)))
53 | case _ =>
54 | Future.successful(ConfigResponse(IntStatus.BAD_REQUEST, s"Namespace [$namespace] not found."))
55 | }(system.executionContext)
56 | }
57 |
--------------------------------------------------------------------------------
/discoveryx-server/src/universal/conf/application.conf:
--------------------------------------------------------------------------------
1 | discoveryx {
2 | config-modules = [akka]
3 |
4 | akka {
5 | loglevel = INFO
6 | http.server.preview.enable-http2 = on
7 | actor.provider = cluster
8 | remote.artery.canonical.port = 49001
9 | cluster.seed-nodes = ["127.0.0.1:49001"]
10 | cluster.roles = [management, config, naming]
11 | }
12 |
13 | server {
14 | management {
15 | enable = true
16 | default-page = 1
17 | default-size = 20
18 | session-timeout = 2.hours
19 | journal-on-delete = on
20 | snapshot.number-of-events = 200
21 | snapshot.keep-n-snapshots = 2
22 | }
23 | config {
24 | enable = true
25 | default-page = 1
26 | default-size = 20
27 | journal-on-delete = on
28 | snapshot.number-of-events = 200
29 | snapshot.keep-n-snapshots = 2
30 | }
31 | naming {
32 | enable = true
33 | heartbeat-timeout = 30.seconds
34 | default-page = 1
35 | default-size = 20
36 | allow-replace-registration = true
37 | journal-on-delete = on
38 | snapshot.number-of-events = 200
39 | snapshot.keep-n-snapshots = 2
40 | }
41 | }
42 | }
43 |
44 | fusion.http.default {
45 | server {
46 | host = "0.0.0.0"
47 | port = 48000
48 | }
49 | }
50 |
51 | akka-persistence-jdbc {
52 | logicalDeletion.enable = false
53 | shared-databases {
54 | h2 {
55 | profile = "slick.jdbc.H2Profile$"
56 | db {
57 | url = "jdbc:h2:~/fusion-discoveryx/db/discoveryx;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;"
58 | user = devuser
59 | password = devPass.2019
60 | numThreads = 5
61 | maxConnections = 5
62 | minConnections = 1
63 | }
64 | }
65 | postgres {
66 | profile = "slick.jdbc.PostgresProfile$"
67 | db {
68 | url = "jdbc:postgresql://localhost:5432/fusion_discoveryx?reWriteBatchedInserts=true"
69 | user = "devuser"
70 | password = "devPass.2019"
71 | driver = "org.postgresql.Driver"
72 | numThreads = 5
73 | maxConnections = 5
74 | minConnections = 1
75 | }
76 | }
77 | }
78 | }
79 |
80 | jdbc-journal {
81 | use-shared-db = "h2"
82 | }
83 | jdbc-snapshot-store {
84 | use-shared-db = "h2"
85 | }
86 | jdbc-read-journal {
87 | use-shared-db = "h2"
88 | }
89 |
90 | akka.persistence {
91 | journal {
92 | plugin = "jdbc-journal"
93 | //auto-start-journals = ["jdbc-journal"]
94 | }
95 | snapshot-store {
96 | plugin = "jdbc-snapshot-store"
97 | //auto-start-snapshot-stores = ["jdbc-snapshot-store"]
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/web-console/src/stores/ConfigStore.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 配置管理
5 | * */
6 |
7 | import { action, observable } from 'mobx';
8 | import request from '../utils/request';
9 | import { PAGE_OBJECT } from '../utils/constants';
10 |
11 | export default class ConfigStore {
12 | /**
13 | * *************************** observable ***************************
14 | * */
15 |
16 | @observable
17 | configPage = PAGE_OBJECT;
18 |
19 | @observable
20 | config = {};
21 |
22 | /**
23 | * ****************************** ajax ******************************
24 | * */
25 |
26 | getConfigPage = async data => {
27 | const { listed } = await request({
28 | config: {
29 | method: 'POST',
30 | url: '/fusion/discoveryx/console/config/ListConfig',
31 | data,
32 | },
33 | });
34 | const configPage = {
35 | page: listed.page,
36 | size: listed.size,
37 | totalElements: listed.totalElements,
38 | data: listed.configs,
39 | };
40 | this.setConfigPage(configPage);
41 | return configPage;
42 | };
43 |
44 | getConfig = async data => {
45 | const { config } = await request({
46 | config: {
47 | method: 'POST',
48 | url: '/fusion/discoveryx/v1/config/GetConfig',
49 | data,
50 | },
51 | });
52 | this.setConfig(config);
53 | return config;
54 | };
55 |
56 | createConfig = data =>
57 | request({
58 | config: {
59 | method: 'POST',
60 | url: '/fusion/discoveryx/v1/config/PublishConfig',
61 | data,
62 | },
63 | success: { message: '新建成功' },
64 | error: { message: '新建失败' },
65 | });
66 |
67 | deleteConfig = data =>
68 | request({
69 | config: {
70 | method: 'POST',
71 | url: '/fusion/discoveryx/v1/config/RemoveConfig',
72 | data,
73 | },
74 | success: { message: '删除成功' },
75 | error: { message: '删除失败' },
76 | });
77 |
78 | /**
79 | * ***************************** action *****************************
80 | * */
81 |
82 | @action
83 | setConfigPage(data = PAGE_OBJECT) {
84 | this.configPage = data;
85 | }
86 |
87 | @action
88 | setConfig(data = {}) {
89 | this.config = data;
90 | }
91 |
92 | /**
93 | * **************************** computed ****************************
94 | * */
95 | // @computed
96 | // get computedData() {
97 | // if (this.msg.length > 0) {
98 | // return 'computed';
99 | // }
100 | // return [];
101 | // }
102 | }
103 |
--------------------------------------------------------------------------------
/discoveryx-client-play-ws/src/main/scala/fusion/discoveryx/client/play/javadsl/DiscoveryXWSClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 akka-fusion.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package fusion.discoveryx.client.play.javadsl;
18 |
19 | import akka.actor.typed.ActorSystem;
20 | import akka.stream.SystemMaterializer;
21 | import play.libs.ws.StandaloneWSClient;
22 | import play.libs.ws.WSClient;
23 | import play.libs.ws.ahc.AhcWSClient;
24 | import play.libs.ws.ahc.AhcWSClientConfigFactory;
25 | import play.libs.ws.ahc.StandaloneAhcWSClient;
26 | import play.shaded.ahc.org.asynchttpclient.AsyncHttpClient;
27 |
28 | public class DiscoveryXWSClient {
29 | // #standaloneWSClient
30 | public static DiscoveryXStandaloneWSClient standaloneWSClient(StandaloneWSClient client, ActorSystem> system) {
31 | return new DiscoveryXStandaloneWSClient(client, system);
32 | }
33 |
34 | public static DiscoveryXStandaloneWSClient standaloneWSClient(ActorSystem> system) {
35 | return standaloneWSClient(StandaloneAhcWSClient.create(
36 | AhcWSClientConfigFactory.forConfig(system.settings().config(), system.dynamicAccess().classLoader()),
37 | SystemMaterializer.get(system).materializer()), system);
38 | }
39 | // #standaloneWSClient
40 |
41 | // #wsClient
42 | public static DiscoveryXPlayWSClient wsClient(WSClient client, ActorSystem> system) {
43 | return new DiscoveryXPlayWSClient(client, system);
44 | }
45 |
46 | public static DiscoveryXPlayWSClient wsClient(AsyncHttpClient asyncHttpClient, ActorSystem> system) {
47 | return wsClient(new AhcWSClient(asyncHttpClient, SystemMaterializer.get(system).materializer()), system);
48 | }
49 |
50 | public static DiscoveryXPlayWSClient wsClient(ActorSystem> system) {
51 | return wsClient(
52 | AhcWSClient.create(
53 | AhcWSClientConfigFactory.forConfig(system.settings().config(), system.dynamicAccess().classLoader()),
54 | null,
55 | SystemMaterializer.get(system).materializer()),
56 | system);
57 | }
58 | // #wsClient
59 | }
60 |
--------------------------------------------------------------------------------
/discoveryx-server/src/main/resources/reference.conf:
--------------------------------------------------------------------------------
1 | discoveryx {
2 | config-modules = [akka]
3 |
4 | akka {
5 | http.server.preview.enable-http2 = on
6 | actor.provider = cluster
7 | cluster.roles = [management, config, naming]
8 | }
9 | server {
10 | management {
11 | enable = true
12 | default-page = 1
13 | default-size = 20
14 | session-timeout = 2.hours
15 | journal-on-delete = on
16 | snapshot.number-of-events = 200
17 | snapshot.keep-n-snapshots = 2
18 | }
19 | config {
20 | enable = true
21 | default-page = 1
22 | default-size = 20
23 | journal-on-delete = on
24 | snapshot.number-of-events = 200
25 | snapshot.keep-n-snapshots = 2
26 | }
27 | naming {
28 | enable = true
29 | heartbeat-timeout = 30.seconds
30 | default-page = 1
31 | default-size = 20
32 | allow-replace-registration = true
33 | journal-on-delete = on
34 | snapshot.number-of-events = 200
35 | snapshot.keep-n-snapshots = 2
36 | }
37 | }
38 | }
39 |
40 | akka.persistence {
41 | journal {
42 | plugin = "jdbc-journal"
43 | plugin = ${?JOURNAL_PLUIGN}
44 | // auto-start-journals = ["jdbc-journal"]
45 | }
46 | snapshot-store {
47 | plugin = "jdbc-snapshot-store"
48 | plugin = ${?SNAPSHOT_PLUGIN}
49 | // auto-start-snapshot-stores = ["jdbc-snapshot-store"]
50 | }
51 | }
52 |
53 | akka-persistence-jdbc {
54 | logicalDeletion.enable = false
55 | shared-databases {
56 | h2 {
57 | profile = "slick.jdbc.H2Profile$"
58 | db {
59 | url = "jdbc:h2:~/fusion-discoveryx/db/discoveryx;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;"
60 | user = devuser
61 | password = devPass.2019
62 | numThreads = 5
63 | maxConnections = 5
64 | minConnections = 1
65 | }
66 | }
67 | postgres {
68 | profile = "slick.jdbc.PostgresProfile$"
69 | db {
70 | url = "jdbc:postgresql://localhost:5432/fusion_discoveryx?reWriteBatchedInserts=true"
71 | user = "devuser"
72 | password = "devPass.2019"
73 | driver = "org.postgresql.Driver"
74 | numThreads = 5
75 | maxConnections = 5
76 | minConnections = 1
77 | }
78 | }
79 | mysql {
80 | profile = "slick.jdbc.MySQLProfile$"
81 | db {
82 | url = "jdbc:mysql://localhost:5432/fusion_discoveryx?useSSL=false&autoReconnect=true"
83 | user = "devuser"
84 | password = "devPass.2019"
85 | driver = "org.postgresql.Driver"
86 | numThreads = 5
87 | maxConnections = 5
88 | minConnections = 1
89 | }
90 | }
91 | }
92 | }
93 |
94 | cassandra-journal {
95 | support-deletes = on
96 | }
97 |
--------------------------------------------------------------------------------
/web-console/src/router/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Date Author Des
3 | *----------------------------------------------
4 | * 18-3-22 gongtiexin 配置路由
5 | * */
6 |
7 | import Loadable from '../components/Loadable';
8 | import {
9 | CONFIG_MANAGEMENT_CREATE,
10 | CONFIG_MANAGEMENT_DETAIL,
11 | CONFIG_MANAGEMENT_LIST,
12 | NAMESPACE_MANAGEMENT_LIST,
13 | SERVICE_MANAGEMENT_DETAIL,
14 | SERVICE_MANAGEMENT_LIST,
15 | USER_MANAGEMENT_LIST,
16 | } from './constants';
17 |
18 | const routes = [
19 | {
20 | path: CONFIG_MANAGEMENT_LIST,
21 | component: Loadable({
22 | loader: () =>
23 | import(
24 | /* webpackChunkName: "route-config-management-list" */ '../pages/config/management/List'
25 | ),
26 | }),
27 | },
28 | {
29 | path: CONFIG_MANAGEMENT_CREATE,
30 | component: Loadable({
31 | loader: () =>
32 | import(
33 | /* webpackChunkName: "route-config-management-create" */ '../pages/config/management/Create'
34 | ),
35 | }),
36 | },
37 | {
38 | path: CONFIG_MANAGEMENT_DETAIL,
39 | component: Loadable({
40 | loader: () =>
41 | import(
42 | /* webpackChunkName: "route-config-management-detail" */ '../pages/config/management/Detail'
43 | ),
44 | }),
45 | },
46 | {
47 | path: NAMESPACE_MANAGEMENT_LIST,
48 | component: Loadable({
49 | loader: () =>
50 | import(
51 | /* webpackChunkName: "route-namespace-management-list" */ '../pages/namespace/management/List'
52 | ),
53 | }),
54 | },
55 | {
56 | path: SERVICE_MANAGEMENT_LIST,
57 | component: Loadable({
58 | loader: () =>
59 | import(
60 | /* webpackChunkName: "route-service-management-list" */ '../pages/service/management/List'
61 | ),
62 | }),
63 | },
64 | {
65 | path: SERVICE_MANAGEMENT_DETAIL,
66 | component: Loadable({
67 | loader: () =>
68 | import(
69 | /* webpackChunkName: "route-service-management-detail" */ '../pages/service/management/Detail'
70 | ),
71 | }),
72 | },
73 | {
74 | path: USER_MANAGEMENT_LIST,
75 | component: Loadable({
76 | loader: () =>
77 | import(
78 | /* webpackChunkName: "route-user-management-list" */ '../pages/user/management/List'
79 | ),
80 | }),
81 | },
82 | ];
83 |
84 | const breadcrumbNameMap = {
85 | [CONFIG_MANAGEMENT_LIST]: '配置列表',
86 | [CONFIG_MANAGEMENT_CREATE]: '新建配置',
87 | [CONFIG_MANAGEMENT_DETAIL]: '配置详情',
88 | [NAMESPACE_MANAGEMENT_LIST]: '命名空间',
89 | [SERVICE_MANAGEMENT_LIST]: '服务列表',
90 | [SERVICE_MANAGEMENT_DETAIL]: '服务详情',
91 | [USER_MANAGEMENT_LIST]: '用户管理',
92 | };
93 |
94 | export { routes, breadcrumbNameMap };
95 |
--------------------------------------------------------------------------------