Skip to content

Commit

Permalink
Merge pull request #52 from AO-StreetArt/udpApi
Browse files Browse the repository at this point in the history
Udp api
  • Loading branch information
AO-StreetArt committed Mar 25, 2018
2 parents 5e76e7d + 95d6ffa commit e629155
Show file tree
Hide file tree
Showing 13 changed files with 298 additions and 20 deletions.
6 changes: 5 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ addons:
apt:
packages:
- nodejs
- python
- python-pip
services:
- docker
before_install:
Expand All @@ -27,6 +29,7 @@ before_install:
- docker logs --tail 50 document-db
- docker logs --tail 50 graph-db
- npm install newman --global;
- pip install requests
install:
- gradle assemble
script:
Expand All @@ -41,7 +44,7 @@ after_success:
# Build and push the convenience image used by the Docker Compose File
- cd $TRAVIS_BUILD_DIR && scripts/docker/build_config_docker_image.sh $TRAVIS_BRANCH
after_failure:
- docker logs --tail 150 crazyivan
- cd $TRAVIS_BUILD_DIR && docker logs --tail 150 crazyivan
- docker logs --tail 150 clyman
- cd $TRAVIS_BUILD_DIR && cat logs/testUtils.txt
- cat logs/testModel_obj.txt
Expand All @@ -63,6 +66,7 @@ after_failure:
- cat logs/testObjectQueryApi.txt
- cat logs/testObjectLockApi.txt
- cat logs/adrestia.log | grep ERROR
- cat logs/udpTest.log
notifications:
slack:
secure: AfMTl+Si4xHctYyrB8GaV5a5fJYEuX18Ow5/NRwpZuRoGfcFU/CkX/SKNHNMSpUyXdMDiTXuylnt3KtscwSTn2pJdfqlx91n5wuIcx7uO+Hv0pLsxKhHJ/3WLYVrPK9GKEVHbsKpR+gxw8Bu/HTGqLBL8k9TAjGl97m1h39k3ovIbAjxzKhSlUSVlxcdqmD18CEnD2szH1qSZ4IlsIraYJ0F7rZtr8mdAESPPU9Q9BAWSVNF2wQ40c3PPYZb6l/zaKEYN3BqHsBGEJHRzH+Aa+ZXtFfgtj6voqiigMVw3FTPl66jPaDx7TI8mJFFBWUGOOImrwNYliIiGyo/b+q3N4OYVWADHp1RaLQEZqwQzCqRfoqgIUCagDF5wjOP6hQCobBT61o2wDSE2xHT73yKnr03AHp7An0flD0+/SYl9J2OOIe9vLgluVUEPa/jyiApldpKoH+JH0ZhvdMhz40Eu3iV9XtBdl0emT9gSeY5cKu3LSuA1AHIaGQz4VpsEokF14ebVSbxKx6rYjaNOViM56vwpBOT0eS9lD/NNduu5OBcijoifpBc5oAAUuK1t4VuoXDtBMaMdoqcxExRcfuRK/H63pUgDt1RkXKRysvg68EJMPLZosCrBwit5jsVbyWn9svLH7D1Kew437rHccD6KXsFjUOrp2Vc+0ppuDAvSCk=
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ MAINTAINER Alex Barry
VOLUME /tmp
ADD target/adrestia-0.1.0.jar app.jar
ENV JAVA_OPTS=""
ENV SPRING_APPLICATION_JSON='{"server":{"port":"5885","ivan":{"retries":"3","timeout":"5000"},"zmq":{"redlist":{"duration":"10"},"greylist":{"duration":"10"},"blacklist":{"duration":"10"}}},"management":{"port":"5885","address":"127.0.0.1"},"spring":{"application":{"name":"Adrestia"},"profiles":{"active":"dev"},"cloud":{"consul":{"discovery":{"preferIpAddress":"false"}}}}}'
ENV SPRING_APPLICATION_JSON='{"server":{"port":"5885","ivan":{"retries":"3","timeout":"5000"},"zmq":{"redlist":{"duration":"10"},"greylist":{"duration":"10"},"blacklist":{"duration":"10"}}, "udp": {"port": "5886"}},"management":{"port":"5885","address":"127.0.0.1"},"spring":{"application":{"name":"Adrestia"},"profiles":{"active":"dev"},"cloud":{"consul":{"discovery":{"preferIpAddress":"false"}}}}}'
ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar
146 changes: 146 additions & 0 deletions scripts/py/testUdp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# The basic CLyman Flow performs a series of basic checks on the CLyman API
# It walks a single object through a full flow, step by step, and validates
# all of the fields on the object at each step of the way.

import logging
import sys
import json
import copy
import requests
import socket
import time

# Basic Config
aesel_addr = "http://127.0.0.1:5885"
udp_ip = "127.0.0.1"
udp_port = 5886
log_file = 'logs/udpTest.log'
log_level = logging.DEBUG

# Test Scene Data
test_scene_data = {
"key":"",
"name":"basicFlowName",
"latitude":124.0,
"longitude":122.0,
"distance":100.0,
"region":"basicFlowRegion",
"asset_ids":["basicAsset"],
"tags":["basicTag"]
}

# The transforms we will track throughout the flow
# These get calculated by hand, and validate the transformations applied
# Current implementation applies LHS Matrix multiplication of translation,
# then euler rotation, then scale, in that order.
# Final Result can be found using http://matrix.reshish.com/multCalculation.php
# Translation Matrix:
# For a translation <x, y, z>, the corresponding matrix is:
# [1.0, 0.0, 0.0, x.0,
# 0.0, 1.0, 0.0, y.0,
# 0.0, 0.0, 1.0, z.0,
# 0.0, 0.0, 0.0, 1.0]
# Rotation Matrix:
# For a rotation of theta degrees about the vector <x, y, z>, the rotation
# matrix can be found using https://www.andre-gaschler.com/rotationconverter/
# Scale Matrix:
# For a scale <x, y, z>, the corresponding matrix is:
# [x.0, 0.0, 0.0, 0.0,
# 0.0, y.0, 0.0, 0.0,
# 0.0, 0.0, z.0, 0.0,
# 0.0, 0.0, 0.0, 1.0]
test_transform = [1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0]

updated_test_transform = [2.0, 0.0, 0.0, 2.0,
0.0, 1.0806046, -1.682942, -0.6023374,
0.0, 1.682942, 1.0806046, 2.7635466,
0.0, 0.0, 0.0, 1.0]

# Object data represented through each piece of the flow
test_data = {
"key": "",
"name": "basicTestObject",
"type": "basicTestType",
"subtype": "basicTestSubtype",
"owner": "basicTestOwner",
"scene": "basicFlowName",
"translation": [0.0, 0.0, 0.0],
"euler_rotation": [0.0, 1.0, 0.0, 0.0],
"scale": [1.0, 1.0, 1.0],
"assets": ["basicTestAsset"]
}

updated_test_data = {
"key": "",
"name": "basicTestObject",
"type": "Mesh",
"subtype": "Cube",
"owner": "Alex",
"scene": "basicFlowName",
"translation": [1.0, 1.0, 1.0],
"euler_rotation": [1.0, 1.0, 0.0, 0.0],
"scale": [2.0, 2.0, 2.0],
"assets": ["anotherAsset"]
}

def execute_udp_flow(sock, udp_ip, udp_port, aesel_addr, test_data,
test_transform, updated_test_data, updated_test_transform):
# Send the UDP Message
sock.sendto(json.dumps(updated_test_data), (udp_ip, udp_port))
time.sleep(1)
# Validate that the update went through correctly
r = requests.get(aesel_addr + '/v1/scene/' + test_scene_data['name'] + '/object/' + updated_test_data['name'])
assert(r.status_code == requests.codes.ok)
parsed_json = r.json()
if parsed_json is not None:
for i in range(0,16):
logging.debug("Validating Transform element: %s" % i)
assert(parsed_json["transform"][i] - updated_test_transform[i] < 0.01)


# Execute the actual tests
def execute_main():
# Grab the global pieces of data
global test_data
global test_transform
global updated_test_data
global updated_test_transform
global log_file
global log_level
global udp_ip
global udp_port
global aesel_addr

logging.basicConfig(filename=log_file, level=log_level)

# Connect to UDP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
logging.debug("Connected to UDP Socket")

# Create a Scene and Object through the HTTP API
r = requests.post(aesel_addr + '/v1/scene/' + test_scene_data['name'], json=test_scene_data)
assert(r.status_code == requests.codes.ok)
response_json = r.json()
test_scene_data['key'] = response_json['key']
r = requests.post(aesel_addr + '/v1/scene/' + test_scene_data['name'] + "/object/" + test_data['name'], json=test_data)
assert(r.status_code == requests.codes.ok)
response_json = r.json()
test_data['key'] = response_json['key']
updated_test_data['key'] = response_json['key']

# Execute each test with a deep copy of the data, so that it stays
# independent through each test
execute_udp_flow(sock, udp_ip, udp_port, aesel_addr,
copy.deepcopy(test_data),
copy.deepcopy(test_transform),
copy.deepcopy(updated_test_data),
copy.deepcopy(updated_test_transform))

if __name__ == "__main__":
if len(sys.argv) > 1:
execute_main(sys.argv[1])
else:
execute_main()
4 changes: 2 additions & 2 deletions src/main/java/adrestia/Adrestia.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
import com.mongodb.MongoClient;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
Expand All @@ -38,7 +38,7 @@
*/
@EnableDiscoveryClient
@Configuration
@SpringBootApplication(exclude={SolrAutoConfiguration.class})
@SpringBootApplication(exclude = {SolrAutoConfiguration.class})
public class Adrestia extends AbstractMongoConfiguration {

// Hostname of Mongo Connection
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/adrestia/controller/obj3/ObjectController.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ public class ObjectController {
@Autowired
UtilityProviderInterface utils;

// UdpController, which exposes the UDP API
@Autowired
UdpController udpApi;

// Object Controller Logger
private static final Logger logger =
LogManager.getLogger("adrestia.ObjectController");
Expand Down
116 changes: 116 additions & 0 deletions src/main/java/adrestia/controller/obj3/UdpController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
Apache2 License Notice
Copyright 2017 Alex Barry
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package adrestia;

import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.charset.StandardCharsets;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* A Service which exposes Object Overwrites on a UDP port.
* Implements the Application Runner interface so that the port
* gets opened after config values and beans have been autowired.
*/
@Component
public class UdpController implements ApplicationRunner {
@Value("${server.udp.port}")
private int port;
private DatagramSocket socket;

// Object Controller Logger
private static final Logger logger =
LogManager.getLogger("adrestia.UdpController");

// DAO Object allowing access to object data
@Autowired
ObjectDao objData;

/**
* Start listening on the UDP Socket.
*/
@Override
public void run(ApplicationArguments args) throws Exception {
logger.info("Starting UDP API on port" + this.port);
// Define our runnable to execute on the background thread
int updPort = this.port;
Runnable r = new Runnable() {
@Override
public void run() {
try {
socket = new DatagramSocket(updPort);
} catch (Exception e) {
logger.error("Error opening UDP Socket: ", e);
return;
}
ObjectMapper mapper = new ObjectMapper();
while (true) {
byte[] buf = new byte[512];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
socket.receive(packet);
} catch (Exception e) {
logger.error("Error reading data from UDP Socket: ", e);
return;
}
String received
= new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
logger.info("Received UDP Request for Object Overwrite");
// Send the update
ObjectDocument inpObject;
try {
inpObject = mapper.readValue(received, ObjectDocument.class);
} catch (Exception e) {
logger.error("Error parsing data from UDP Socket: ", e);
return;
}
ObjectList clymanResponse = objData.overwrite(inpObject);
// If we have a successful response, then we pull the first value
if (clymanResponse.getNumRecords() <= 0
|| clymanResponse.getErrorCode() != 100) {
logger.debug("Failure Registered. Clyman Response Error Code and Length:");
logger.debug(clymanResponse.getNumRecords());
logger.debug(clymanResponse.getErrorCode());
}
}
}
};

// Start the thread to listen on the socket
new Thread(r).start();
}

/**
* Default empty UdpController constructor.
*/
public UdpController() {
super();
}
}
13 changes: 7 additions & 6 deletions src/main/java/adrestia/dao/zmq/ZmqSocketPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,13 @@ public ZmqSocketContainer getSocket(String connection, int serviceType) {
}

// Check if we have any sockets currently in use
for (int i = 0; i < usedSockets.size(); i++) {
if (usedSockets.get(i).getHostname().equals(connection)) {
makeNewSocket = false;
logger.debug("Identified Socket in use: " + usedSockets.get(i).getHostname());
}
}
// Pretty sure we still need a new socket here (multiple threads)
// for (int i = 0; i < usedSockets.size(); i++) {
// if (usedSockets.get(i).getHostname().equals(connection)) {
// makeNewSocket = false;
// logger.debug("Identified Socket in use: " + usedSockets.get(i).getHostname());
// }
// }

// Build a new socket
if (makeNewSocket) {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/adrestia/model/obj3/ObjectDocument.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class ObjectDocument {
private String owner;
private String scene;
private double[] translation = new double[0];
@JsonProperty("rotation_euler")
@JsonProperty("euler_rotation")
private double[] rotationEuler = new double[0];
private double[] scale = new double[0];
private String[] assets = new String[0];
Expand Down Expand Up @@ -146,7 +146,7 @@ public double[] getTranslation() {
* Returns value of rotationEuler.
* @return The current euler rotation of the object
*/
@JsonGetter("rotation_euler")
@JsonGetter("euler_rotation")
public double[] getRotationEuler() {
return this.rotationEuler;
}
Expand Down Expand Up @@ -244,7 +244,7 @@ public void setTranslation(double[] translation) {
* Sets new value of rotationEuler.
* @param rotationEuler The current rotation of the object
*/
@JsonSetter("rotation_euler")
@JsonSetter("euler_rotation")
public void setRotationEuler(double[] rotationEuler) {
this.rotationEuler = rotationEuler;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/adrestia/model/obj3/ObjectList.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public String generateTransformOverwrite() {
.concat(Double.toString(this.documents[i].getTranslation()[1]))
.concat(", ")
.concat(Double.toString(this.documents[i].getTranslation()[2]))
.concat("], \"rotation_euler\": [")
.concat("], \"euler_rotation\": [")
.concat(Double.toString(this.documents[i].getRotationEuler()[0]))
.concat(", ")
.concat(Double.toString(this.documents[i].getRotationEuler()[1]))
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ server.zmq.greylist.duration: 30
server.zmq.blacklist.duration: 300
server.mongo.host: localhost
server.mongo.port: 27017
server.udp.port: 5886
# Port for management exposures
management.port: 5885
# Address for management exposures
Expand Down

0 comments on commit e629155

Please sign in to comment.