Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
Takanori Takase committed Jun 13, 2020
0 parents commit fab4cd0
Show file tree
Hide file tree
Showing 20 changed files with 2,305 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# OS / Runtime
/**/.DS_Store
/**/Thumbs.db
/**/*.swp

# IDE (Eclipse)
.classpath
.project
.settings
bin

# IDE (Intellij IDEA)
*.iml
.idea
out

# Gradle
.gradle
build

# Travis CI
.ruby-version

# Application
/logs
25 changes: 25 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
language: java

jdk:
- openjdk11

notifications:
email:
- scm@after-sunrise.com

env:
global:
- JAVA_TOOL_OPTIONS=-Dhttps.protocols=TLSv1.2

deploy:
provider: releases
api_key:
secure: pMs3v0DuFSpWjPoq7gH/bdSW2brd//MpXJk5MM7x7xBZH6DGPSvwymcIyqlaz1OFX3X8tEpxQ2D/REtA+CUuaQzq0Xg1knmlWIwgMcMTiyzal0VC/2LLdiE1vP4lix9Z9qVGt45BkGcBdsykMbX58z2QWkbTBAUTqoUj8o8Mapn8bVJbUUCQV/mRSd8dWti1ep/NeKsnzRTu33FFdCtTmLZI0xgxKx6EPDBwrPRcgyE2SrUvj1BBB/Fp0vfZZWkr4+USwqwkK2RcQP3uxILMoDAFAPYhDC4qTvxeDWwPVI4QmY5+579RC/IQ3mDbz9/HAnuNgIUYk1kvlOK/xSQUz1XFaUemq9CqI3pI4JaxwIi+sT+S4V5yV1G8FVNqrJaSZ0Ctw4vnq/0wxp+RvSLxetT2eJJ8pcQENAMBVVDc32FBfB4E43dIAxg1uoxbkQ4tjiVrD/BM/s9MV0f+jb7uY8Zi1AmuYRjV18uaNWGVqKZrhmVsbs82fti90Kka0W8IqLoW79Qa1eFAyYMh4XDfCYzD4ITuby6h2NrN5L+oA8m200ceaa1KjHZ6GBIcquaolZLr7ABpoybxzyj91/sIzBZomiBTg2y95jEnEs46pT+RLPHgF7gmpLBwpPYZTFWFjekIFVwGi7UUqHLfXijZk9Y/5RK240WX+NdP880dboY=
file: build/libs/dukas-gprc-*.war
file_glob: true
skip_cleanup: true
overwrite: true
draft: true
on:
repo: after-the-sunrise/dukas-grpc
tags: true
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# dukas-grpc
[![Build Status][travis-icon]][travis-page]

**dukas-grpc** is a standalone server application for providing [gRPC][grpc-home] access to [Dukascopy][dukascopy-home]'s JForex trading platform.
The official [JForex SDK][dukascopy-wiki] allows the user to use JForex API by programming custom Java applications.
**dukas-grpc** server leverages this official SDK and provides gRPC access for the SDK.

* [gRPC][grpc-home] interface for request/response communication and publish/subscribe stream messaging.
* Optimized messaging performance over HTTP/2 or unix domain sockets.
* Automatic connection management with JForex platform. (cf: connect, throttled-reconnect, ...)

## Getting Started

### Trading Account

First of all, a valid [Dukascopy][dukascopy-home] trading account is required for the API access.
If you do not have one yet, a demo account can be created on the fly.

The IP address of the **dukas-grpc** server machine needs to be registered to the account.
This is mandatory, since API access from an unregistered IP address will need to provide a dynamic PIN code,
which is not ideal for automated server applications.
IP whitelisting can be done via "Summary > My Account > Security Settings > IP registration" after logging into the official website.

### Launching Server

* Java Runtime Environment 11 or later is required. (cf: `sudo dnf -y install java-11-openjdk`).
* Download the WAR archive from [releases][github-releases] page.
* Configure login credentials as either environment variables (`foo=bar java -jar ...`), or as system properties (`-Dfoo=bar`).
* List of available configuration keys and default values can be found in `com.after_sunrise.dukascopy.grpc.Config.java`.
* Use web-application container of your choice to deploy the war file, such as [jetty-runner].

After launching the application, search the log output for the following lines to confirm that the login credentials are configured correctly.

```text
yyyy-MM-dd HH:mm:ss.SSS|INFO |...|IClient connecting... (url=http://platform.dukas.../jforex.jnlp,..., user=DemoUser)
```

## Sample Client/Server Applications

* Create and configure a configuration file `./logs/dukas-test.properties` containing the login credentials.
* From an IDE, launch `com.after_sunrise.dukascopy.grpc.WebappServerTest#main` to launch the server application.
* From an IDE, launch `com.after_sunrise.dukascopy.grpc.WebappClientTest` methods to try out the requests and subscriptions.
* gRPC IDL file can be found at `./src/main/proto/dukascopy.proto`.

## Bulding from Source

JDK 11 or later is required. Make sure the `JAVA_HOME` environment variable is configured.
Then Clone the repository, and use gradle(w) to build the archives.

```shell script
$JAVA_HOME/bin/java -version

git clone git@github.com:after-the-sunrise/dukas-grpc.git

cd dukas-grpc && ./gradlew clean build
```

The archive is generated under `./build/libs/` directory.

[travis-page]:https://travis-ci.org/after-the-sunrise/dukas-grpc
[travis-icon]:https://travis-ci.org/after-the-sunrise/dukas-grpc.svg?branch=master
[github-releases]:https://github.com/after-the-sunrise/dukas-grpc/releases
[dukascopy-home]:https://www.dukascopy.com/
[dukascopy-wiki]:https://www.dukascopy.com/wiki/en/development
[grpc-home]:https://grpc.io/
[jetty-runner]:https://www.eclipse.org/jetty/documentation/current/runner.html
79 changes: 79 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
plugins {
id 'java'
id 'war'
id 'com.google.protobuf' version '0.8.12'
}

repositories {
mavenCentral()
maven {
url "https://www.dukascopy.com/client/jforexlib/publicrepo"
}
}

ext {
grpcVersion = '1.29.0'
}

dependencies {
compile "com.dukascopy.api:JForex-API:2.13.88"
compile("com.dukascopy.dds2:DDS2-jClient-JForex:3.6.14") {
exclude group: "org.slf4j", module: "slf4j-log4j12"
}
implementation "com.google.inject:guice:4.2.3"
implementation "com.google.inject.extensions:guice-servlet:4.2.3"
implementation "io.grpc:grpc-netty:$grpcVersion"
implementation "io.grpc:grpc-protobuf:$grpcVersion"
implementation "io.grpc:grpc-stub:$grpcVersion"
implementation "io.netty:netty-transport-native-epoll:4.1.50.Final:linux-x86_64"
implementation "io.netty:netty-transport-native-kqueue:4.1.50.Final:osx-x86_64"
compileOnly "org.apache.tomcat:tomcat-annotations-api:9.0.35" // necessary for Java 9+
compileOnly "jakarta.servlet:jakarta.servlet-api:4.0.3"
runtimeOnly "io.prometheus:simpleclient_servlet:0.9.0"
runtimeOnly "io.prometheus:simpleclient_logback:0.9.0"
runtimeOnly "ch.qos.logback:logback-classic:1.2.3"
testImplementation "org.eclipse.jetty:jetty-webapp:9.4.29.v20200521"
testImplementation "org.mockito:mockito-core:3.3.3"
testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.6.2"
}

configurations.all {
resolutionStrategy {
// JForex requires version 19.0 (Futures#dereference), while netty requires newer.
force 'com.google.guava:guava:23.6-jre' // 23.6-jre meets both requirements.
}
}

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.12.3"
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}

sourceSets {
main.java.srcDirs += "build/generated/source/proto/main/grpc"
main.java.srcDirs += "build/generated/source/proto/main/java"
}

group "com.after_sunrise.dukascopy"
version "0.0.1-SNAPSHOT"

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

test {
useJUnitPlatform()
}
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 5 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
183 changes: 183 additions & 0 deletions gradlew
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#!/usr/bin/env sh

#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
echo "$*"
}

die () {
echo
echo "$*"
echo
exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`

# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option

if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi

# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

exec "$JAVACMD" "$@"
Loading

0 comments on commit fab4cd0

Please sign in to comment.