toxiclibs 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 946268fb6e50b2556be590d1cf0b733f3915e31c98b19e436ec50bd872006a41
4
- data.tar.gz: '09522b131b7f1b8047dce50b62e39f8b7795383c028155e0d7236ef4baeb419c'
3
+ metadata.gz: ea1e1885aff507b0bb35cf61ddab9b086553d07b35be64e3b1673cbacc7846ce
4
+ data.tar.gz: dc1955313145c89dafbe4ace7b55d15af37f0d6fafee423a3a700e423ed14fca
5
5
  SHA512:
6
- metadata.gz: c86c4b5dd436f79bed4d9ba21ca7c2f14e822e13a7eeeabdab677b0b93f67ce8d4b3da915632a9cafa29fddb0720be53f5c19ff253bbcbce55b6ca9b4b0bc94f
7
- data.tar.gz: 13a197bc603117f7a863b2d32d658aae44d23080f5b4cd1fddd490706ec66739c91ad57efa87020f00546ff55431423482376b658fff905eac713913b9533152
6
+ metadata.gz: 466378a7a6896aad508c6de8928253695fa891aca794a90906e9481021195f556cd42363a79f50bf33e4d9c7dd4e65ff4ab7d4dd48f4a54acd8696abaae76a84
7
+ data.tar.gz: c1b115629d788cc547cc37fedeb07406c9f55d572f4553bc842bc7b07aa00cbf5b17a961fd523463924adca4e593273248bb9f072e8cc3c3d2de3a50058cb27e
data/.mvn/extensions.xml CHANGED
@@ -3,6 +3,6 @@
3
3
  <extension>
4
4
  <groupId>io.takari.polyglot</groupId>
5
5
  <artifactId>polyglot-ruby</artifactId>
6
- <version>0.4.0</version>
6
+ <version>0.4.6</version>
7
7
  </extension>
8
8
  </extensions>
data/CHANGELOG.md CHANGED
@@ -1,3 +1,5 @@
1
+ **v2.1.0** Add module-info.
2
+
1
3
  **v2.0.0** Bump to target minimum of jdk11 thus removing JAXB annotations (possibly esoteric and underused anyway).
2
4
 
3
5
  **v1.0.1** Bump processing to 3.4, support toxiclibs Voronoi etc
data/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  gem install toxiclibs
9
9
  ```
10
10
 
11
- ### NB: Use version 0.4 for ruby-processing, and 1.0.0+ for propane and JRubyArt
11
+ ### NB: Use version 0.4 for ruby-processing, and 2.1.0+ for propane, PiCrate and JRubyArt
12
12
 
13
13
  NB: Build is only failing because current version of processing is not available at maven central.
14
14
  This gem provides Karsten Schmidts (aka toxi, @postspectacular) toxiclibs jars for JRubyArt. To compile the gem follow the instructions for [JRubyArt][]. Most parts of toxiclibs API is exposed in the latest version, (but only a few examples are included) in principle it should be possible to make all available!!! For this demonstration I have used up to date source code for version 21, since [toxis final release][] has not yet been released (although [Dan Shiffman][] has released a version for processing-3.0+). There are reported to be number of outstanding bugs with toxiclibs, if they affect you report it [here][] (or better fix them yourself and submit a pull request).
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ end
18
18
 
19
19
  desc 'Build gem'
20
20
  task :gem do
21
- sh "gem build toxiclibs.gemspec"
21
+ sh "jgem build toxiclibs.gemspec"
22
22
  end
23
23
 
24
24
  desc 'Compile'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  # wrapper to give version a meaningful name
3
3
  module Toxiclibs
4
- VERSION = '2.0.0'.freeze
4
+ VERSION = '2.1.0'.freeze
5
5
  end
data/lib/toxiclibs.jar CHANGED
Binary file
data/pom.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  project 'toxiclibs' do
2
2
 
3
3
  model_version '4.0.0'
4
- id 'ruby-processing:toxiclibs:2.0.0'
4
+ id 'ruby-processing:toxiclibs:2.1.0'
5
5
  packaging 'jar'
6
6
 
7
7
  description 'toxiclibs-library for JRubyArt'
@@ -22,21 +22,17 @@ project 'toxiclibs' do
22
22
  'polyglot.dump.pom' => 'pom.xml',
23
23
  'project.build.sourceEncoding' => 'UTF-8',
24
24
  'target.release' => '11',
25
- 'polyglot.dump.pom' => 'pom.xml'
25
+ 'polyglot.dump.pom' => 'pom.xml',
26
+ 'maven.deploy.skip' => 'true'
26
27
  )
27
28
 
28
- jar 'org.processing:core:3.3.7'
29
+ jar 'org.processing:core:4.0.0'
29
30
 
30
31
  overrides do
31
32
  plugin( :compiler, '3.8.1',
32
33
  'release' => '11' )
33
34
  plugin :javadoc, '2.10.4'
34
- plugin(
35
- :jar, '3.2.0',
36
- 'archive' => {
37
- 'manifestFile' => 'MANIFEST.MF'
38
- }
39
- )
35
+ plugin :jar, '3.2.0'
40
36
  plugin :jdeps, '3.1.2' do
41
37
  execute_goals 'jdkinternals', 'test-jdkinternals'
42
38
  end
data/pom.xml CHANGED
@@ -2,7 +2,7 @@
2
2
  <!--
3
3
 
4
4
 
5
- DO NOT MODIFIY - GENERATED CODE
5
+ DO NOT MODIFY - GENERATED CODE
6
6
 
7
7
 
8
8
  -->
@@ -11,7 +11,7 @@ DO NOT MODIFIY - GENERATED CODE
11
11
  <modelVersion>4.0.0</modelVersion>
12
12
  <groupId>ruby-processing</groupId>
13
13
  <artifactId>toxiclibs</artifactId>
14
- <version>2.0.0</version>
14
+ <version>2.1.0</version>
15
15
  <name>toxiclibs</name>
16
16
  <description>toxiclibs-library for JRubyArt</description>
17
17
  <developers>
@@ -34,6 +34,7 @@ DO NOT MODIFIY - GENERATED CODE
34
34
  <url>https://github.com/ruby-processing/toxiclibs/issues</url>
35
35
  </issueManagement>
36
36
  <properties>
37
+ <maven.deploy.skip>true</maven.deploy.skip>
37
38
  <polyglot.dump.pom>pom.xml</polyglot.dump.pom>
38
39
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
39
40
  <source.directory>src</source.directory>
@@ -43,7 +44,7 @@ DO NOT MODIFIY - GENERATED CODE
43
44
  <dependency>
44
45
  <groupId>org.processing</groupId>
45
46
  <artifactId>core</artifactId>
46
- <version>3.3.7</version>
47
+ <version>4.0.0</version>
47
48
  </dependency>
48
49
  </dependencies>
49
50
  <build>
@@ -66,11 +67,6 @@ DO NOT MODIFIY - GENERATED CODE
66
67
  <plugin>
67
68
  <artifactId>maven-jar-plugin</artifactId>
68
69
  <version>3.2.0</version>
69
- <configuration>
70
- <archive>
71
- <manifestFile>MANIFEST.MF</manifestFile>
72
- </archive>
73
- </configuration>
74
70
  </plugin>
75
71
  <plugin>
76
72
  <artifactId>maven-jdeps-plugin</artifactId>
@@ -0,0 +1,22 @@
1
+ module toxiclibs{
2
+ exports toxi.color;
3
+ exports toxi.data.csv;
4
+ exports toxi.data.feeds;
5
+ exports toxi.geom;
6
+ exports toxi.image.util;
7
+ exports toxi.music.scale;
8
+ exports toxi.newmesh;
9
+ exports toxi.physics2d;
10
+ exports toxi.physics3d;
11
+ exports toxi.processing;
12
+ exports toxi.sim.automata;
13
+ exports toxi.sim.dla;
14
+ exports toxi.sim.erosion;
15
+ exports toxi.sim.fluids;
16
+ exports toxi.sim.grayscott;
17
+ exports toxi.util;
18
+ exports toxi.volume;
19
+ requires org.processing.core;
20
+ requires java.desktop;
21
+ requires java.logging;
22
+ }
@@ -0,0 +1,10 @@
1
+ /*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+
7
+ module ToxiclibsTest {
8
+ requires org.processing.core;
9
+ requires toxiclibs;
10
+ }
@@ -1,4 +1,4 @@
1
-
1
+ package toxi;
2
2
  import processing.core.*;
3
3
 
4
4
  import toxi.geom.*;
@@ -56,7 +56,7 @@ public class BooleanShapes extends PApplet {
56
56
  }
57
57
 
58
58
  static public void main(String[] passedArgs) {
59
- String[] appletArgs = new String[]{"BooleanShapes"};
59
+ String[] appletArgs = new String[]{"toxi.BooleanShapes"};
60
60
  if (passedArgs != null) {
61
61
  PApplet.main(concat(appletArgs, passedArgs));
62
62
  } else {
metadata CHANGED
@@ -1,18 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toxiclibs
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karsten Schmidt
8
8
  - Martin Prout
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-05-03 00:00:00.000000000 Z
12
+ date: 2021-09-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
16
  requirements:
18
17
  - - "~>"
@@ -21,8 +20,9 @@ dependencies:
21
20
  - - ">="
22
21
  - !ruby/object:Gem::Version
23
22
  version: 12.3.0
24
- type: :development
23
+ name: rake
25
24
  prerelease: false
25
+ type: :development
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - "~>"
@@ -31,8 +31,8 @@ dependencies:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 12.3.0
34
- description: " Toxiclibs java libraries wrapped in a rubygem. Compiled and tested
35
- with JRubyArt-2.4 and processing-3.4\n"
34
+ description: " Toxiclibs java libraries wrapped in a rubygem. Compiled and tested\
35
+ \ with JRubyArt-2.4 and processing-3.4\n"
36
36
  email: mamba2928@yahoo.co.uk
37
37
  executables: []
38
38
  extensions: []
@@ -86,16 +86,7 @@ files:
86
86
  - lib/toxiclibs/version.rb
87
87
  - pom.rb
88
88
  - pom.xml
89
- - src/com/toxi/net/ClientListener.java
90
- - src/com/toxi/net/ServerListener.java
91
- - src/com/toxi/net/ServerListenerAdapter.java
92
- - src/com/toxi/net/ServerState.java
93
- - src/com/toxi/net/UDPConnection.java
94
- - src/com/toxi/net/UDPSyncClient.java
95
- - src/com/toxi/net/UDPSyncServer.java
96
- - src/com/toxi/nio/UDPClient.java
97
- - src/com/toxi/nio/UDPClientState.java
98
- - src/com/toxi/nio/UDPServer.java
89
+ - src/main/java/module-info.java
99
90
  - src/main/java/toxi/color/AccessCriteria.java
100
91
  - src/main/java/toxi/color/AlphaAccessor.java
101
92
  - src/main/java/toxi/color/CMYKAccessor.java
@@ -435,14 +426,15 @@ files:
435
426
  - src/main/java/toxi/volume/VolumetricHashMap.java
436
427
  - src/main/java/toxi/volume/VolumetricSpace.java
437
428
  - src/main/java/toxi/volume/VolumetricSpaceArray.java
438
- - src/test/java/BooleanShapes.java
429
+ - src/test/java/module-info.java
430
+ - src/test/java/toxi/BooleanShapes.java
439
431
  - toxiclibs.gemspec
440
432
  homepage: http://ruby-processing.github.io/toxicgem/
441
433
  licenses:
442
434
  - MIT
443
435
  - LGPL-3.0
444
436
  metadata: {}
445
- post_install_message:
437
+ post_install_message:
446
438
  rdoc_options: []
447
439
  require_paths:
448
440
  - lib
@@ -457,8 +449,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
457
449
  - !ruby/object:Gem::Version
458
450
  version: '0'
459
451
  requirements: []
460
- rubygems_version: 3.1.2
461
- signing_key:
452
+ rubygems_version: 3.2.14
453
+ signing_key:
462
454
  specification_version: 4
463
455
  summary: Updated and extended toxiclibs libraries for JRubyArt and propane
464
456
  test_files: []
@@ -1,41 +0,0 @@
1
- package com.toxi.net;
2
-
3
- /**
4
- *
5
- * @author tux
6
- */
7
- public interface ClientListener {
8
- /**
9
- * Callback to trigger an update of the server managed process. This might
10
- * be called several times in a row if the client has fallen behind in time.
11
- * There should be NO rendering related tasks being called from this
12
- * callback.
13
- */
14
- public void triggerUpdate();
15
-
16
- /**
17
- * Callback to trigger the rendering of a new frame. This method will ALWAYS
18
- * be called after {{@link #triggerUpdate()} and should be purely focused on
19
- * drawing/rendering specific tasks, but no CPU intensive model updates.
20
- */
21
- public void triggerFrame();
22
-
23
- /**
24
- * Callback to confirm client has successfully connected
25
- */
26
- public void notifyConnected();
27
-
28
- /**
29
- * Callback to notify client has disconnected from the server.
30
- */
31
- public void notifyDisconnected();
32
-
33
- /**
34
- * Callback to give the client a chance to react to the encountered
35
- * exception.
36
- *
37
- * @param e
38
- * the exception which caused the callback
39
- */
40
- public void handleError(Exception e);
41
- }
@@ -1,70 +0,0 @@
1
- package com.toxi.net;
2
-
3
- import java.net.DatagramPacket;
4
-
5
- /**
6
- *
7
- * @author tux
8
- */
9
- public interface ServerListener {
10
-
11
- /**
12
- * Notifies listener immediately after the server socket has been created.
13
- */
14
- public void serverStarted();
15
-
16
- /**
17
- * Notifies the listener server is shutting down.
18
- */
19
- public void serverShutdown();
20
-
21
- /**
22
- * Gives listener a chance to react to any fatal server errors.
23
- *
24
- * @param e
25
- */
26
- public void serverError(Exception e);
27
-
28
- /**
29
- * Notifies the listener of a new server state. The state info itself is
30
- * attached.
31
- *
32
- * @param s
33
- */
34
- public void serverStateChanged(ServerState s);
35
-
36
- /**
37
- * Notifies listener of a new client connection. Details are attached.
38
- *
39
- * @param conn
40
- */
41
- public void clientConnected(UDPConnection conn);
42
-
43
- /**
44
- * Notifies listener a client has disconnected. Connection details are
45
- * attached.
46
- *
47
- * @param conn
48
- */
49
- public void clientDisconnected(UDPConnection conn);
50
-
51
- /**
52
- * Notifies and forwards received client data to the listener for further
53
- * analysis.
54
- *
55
- * @param conn
56
- * client connection details
57
- * @param receivePacket
58
- * data sent by the client
59
- */
60
- public void clientUpdated(UDPConnection conn, DatagramPacket receivePacket);
61
-
62
- /**
63
- * Gives the listener a chance to add extra data to the payload packet
64
- * distributed to each client.
65
- *
66
- * @return additional data, or null if none required
67
- */
68
- public byte[] getSyncPayload();
69
-
70
- }
@@ -1,47 +0,0 @@
1
- /**
2
- *
3
- */
4
- package com.toxi.net;
5
-
6
- import java.net.DatagramPacket;
7
-
8
- /**
9
- * @author toxi
10
- *
11
- */
12
- public class ServerListenerAdapter implements ServerListener {
13
-
14
- @Override
15
- public void clientConnected(UDPConnection conn) {
16
-
17
- }
18
-
19
- @Override
20
- public void clientDisconnected(UDPConnection conn) {
21
- }
22
-
23
- @Override
24
- public void clientUpdated(UDPConnection conn, DatagramPacket receivePacket) {
25
- }
26
-
27
- @Override
28
- public byte[] getSyncPayload() {
29
- return new byte[0];
30
- }
31
-
32
- @Override
33
- public void serverError(Exception e) {
34
- }
35
-
36
- @Override
37
- public void serverShutdown() {
38
- }
39
-
40
- @Override
41
- public void serverStarted() {
42
- }
43
-
44
- @Override
45
- public void serverStateChanged(ServerState s) {
46
- }
47
- }
@@ -1,18 +0,0 @@
1
- package com.toxi.net;
2
-
3
- /**
4
- *
5
- * @author tux
6
- */
7
- public enum ServerState {
8
-
9
- /**
10
- *
11
- */
12
- WAITING_FOR_CLIENTS,
13
-
14
- /**
15
- *
16
- */
17
- SYNCHING
18
- }
@@ -1,66 +0,0 @@
1
- package com.toxi.net;
2
-
3
- import java.io.*;
4
- import java.net.*;
5
-
6
- /**
7
- * @author Karsten Schmidt <info@postspectacular.com>
8
- */
9
-
10
- class UDPConnection {
11
-
12
- /**
13
- * Default time-to-live duration
14
- */
15
- static int TTL = 10000;
16
-
17
- protected InetAddress ip;
18
- protected int port;
19
-
20
- protected long lastUpdate;
21
-
22
- UDPConnection(InetAddress ip, int port) {
23
- this.ip = ip;
24
- this.port = port;
25
- lastUpdate = System.currentTimeMillis();
26
- }
27
-
28
- public boolean isAlive() {
29
- return System.currentTimeMillis() - lastUpdate < TTL;
30
- }
31
-
32
- public void update() {
33
- lastUpdate = System.currentTimeMillis();
34
- }
35
-
36
- public void send(DatagramSocket socket, byte[] data) throws IOException {
37
- DatagramPacket sendPacket = new DatagramPacket(data, data.length, ip,
38
- port);
39
- socket.send(sendPacket);
40
- }
41
-
42
- public InetAddress getIP() {
43
- return ip;
44
- }
45
-
46
- public int getPort() {
47
- return port;
48
- }
49
-
50
- public long getLastUpdate() {
51
- return lastUpdate;
52
- }
53
-
54
- @Override
55
- public String toString() {
56
- return UDPConnection.buildHash(ip, port);
57
- }
58
-
59
- static final void setTTL(int ttl) {
60
- TTL = ttl;
61
- }
62
-
63
- public static final String buildHash(InetAddress ip, int port) {
64
- return ip.getHostAddress() + ":" + port;
65
- }
66
- }
@@ -1,81 +0,0 @@
1
- package com.toxi.net;
2
-
3
- import java.io.IOException;
4
- import java.net.*;
5
- import java.util.logging.Level;
6
- import java.util.logging.Logger;
7
-
8
- class UDPSyncClient extends Thread {
9
- private ClientListener listener;
10
-
11
- protected String serverName;
12
- protected int port;
13
- protected int clientID;
14
- protected int ttl;
15
-
16
- private int frameCount;
17
- protected long lastUpdate;
18
-
19
- private static final Logger logger = Logger.getLogger(UDPSyncClient.class
20
- .getName());
21
-
22
- UDPSyncClient(String serverName, int port, int clientID, int ttl) {
23
- this.serverName = serverName;
24
- this.port = port;
25
- this.clientID = clientID;
26
- this.ttl = ttl;
27
- }
28
-
29
- @Override
30
- public void run() {
31
- DatagramSocket clientSocket = null;
32
- lastUpdate = System.currentTimeMillis();
33
- try {
34
- clientSocket = new DatagramSocket();
35
- InetAddress ip = InetAddress.getByName(serverName);
36
- byte[] sendData = new byte[] { 1 };
37
- byte[] receiveData = new byte[8];
38
- // do initial sign on by sending a message to the server
39
- DatagramPacket sendPacket = new DatagramPacket(sendData,
40
- sendData.length, ip, port);
41
- clientSocket.send(sendPacket);
42
- while (true) {
43
- DatagramPacket receivePacket = new DatagramPacket(receiveData,
44
- receiveData.length);
45
- clientSocket.receive(receivePacket);
46
- String payload = new String(receivePacket.getData(), 0,
47
- receivePacket.getLength());
48
- if (logger != null)
49
- logger.finest(payload);
50
- int newFrameCount = Integer.parseInt(payload);
51
- if (newFrameCount > 0) {
52
- while (frameCount < newFrameCount) {
53
- if (listener != null)
54
- listener.triggerUpdate();
55
- frameCount++;
56
- }
57
- }
58
- if (listener != null)
59
- listener.triggerFrame();
60
- long now = System.currentTimeMillis();
61
- if (now - lastUpdate > ttl) {
62
- sendPacket = new DatagramPacket(sendData, sendData.length,
63
- ip, port);
64
- clientSocket.send(sendPacket);
65
- lastUpdate = now;
66
- if (logger != null)
67
- logger.log(Level.FINER, "TTL updated on: {0}", lastUpdate);
68
- }
69
- }
70
- } catch (IOException | NumberFormatException ex) {
71
- logger.log(Level.SEVERE, null, ex);
72
- } finally {
73
- if (clientSocket != null)
74
- clientSocket.close();
75
- }
76
- }
77
-
78
- public void setListener(ClientListener l) {
79
- listener = l;
80
- }
81
- }
@@ -1,450 +0,0 @@
1
- package com.toxi.net;
2
-
3
- import java.io.FileInputStream;
4
- import java.io.FileNotFoundException;
5
- import java.io.IOException;
6
- import java.net.DatagramPacket;
7
- import java.net.DatagramSocket;
8
- import java.net.InetAddress;
9
- import java.net.SocketTimeoutException;
10
- import java.util.HashMap;
11
- import java.util.Iterator;
12
- import java.util.logging.ConsoleHandler;
13
- import java.util.logging.Level;
14
- import java.util.logging.Logger;
15
-
16
- import org.kohsuke.args4j.CmdLineException;
17
- import org.kohsuke.args4j.CmdLineParser;
18
- import org.kohsuke.args4j.Option;
19
-
20
- import toxi.util.datatypes.TypedProperties;
21
-
22
- /**
23
- * <p>
24
- * An <a href="http://mostpixelsever.com">MPE</a> inspired synch server for
25
- * networked multi-screen applications. All communication is realised via UDP.
26
- * Clients are not requested to acknowledge every single packet received, but
27
- * need to send a heart beat in a regular (configurable) interval. The server
28
- * discards any data received from clients, so it doesn't matter what is being
29
- * sent back. A single byte will suffice.
30
- * </p>
31
- *
32
- * <p>
33
- * The server can be configured via CLI arguments and/or Java property files and
34
- * can be connected to an existing logger. When run on from the commandline a
35
- * console logger is automatically added.
36
- * </p>
37
- *
38
- * @author Karsten Schmidt <info@postspectacular.com>
39
- */
40
- public class UDPSyncServer {
41
-
42
- private static final int DEFAULT_RECEIVE_PACKET_SIZE = 32;
43
-
44
- private static final int DEFAULT_NUM_CLIENTS = 1;
45
-
46
- private static final int DEFAULT_FRAMERATE = 30;
47
-
48
- private static final int DEFAULT_PORT = 9002;
49
-
50
- private static final int DEFAULT_RECEIVE_TIMEOUT = 1;
51
-
52
- private ServerState state;
53
-
54
- DatagramSocket socket;
55
- HashMap<String, UDPConnection> connections = new HashMap<>();
56
-
57
- /**
58
- *
59
- */
60
- @Option(name = "-port", aliases = "-p", usage = "server socket port number")
61
- protected int port = DEFAULT_PORT;
62
-
63
- @Option(name = "-config", aliases = "-c", usage = "path to configuration file", metaVar = "PATH")
64
- private String configFile;
65
- private TypedProperties config;
66
-
67
- @Option(name = "-packetsize", aliases = "-s", usage = "receive packet size")
68
- private int receivePacketSize = DEFAULT_RECEIVE_PACKET_SIZE;
69
- private byte[] receiveData;
70
-
71
- /**
72
- *
73
- */
74
- @Option(name = "-rectimeout", aliases = "-rt", usage = "receive timeout (in ms), minimum 1ms")
75
- protected int receiveTimeOut = DEFAULT_RECEIVE_TIMEOUT;
76
-
77
- /**
78
- *
79
- */
80
- @Option(name = "-ttl", usage = "client time-to-live, max. time interval after which clients expire")
81
- protected int connectionTimeOut = UDPConnection.TTL;
82
-
83
- /**
84
- *
85
- */
86
- @Option(name = "-numclients", aliases = "-num", usage = "number of clients")
87
- protected int numClients = DEFAULT_NUM_CLIENTS;
88
-
89
- /**
90
- *
91
- */
92
- @Option(name = "-framerate", aliases = "-fps", usage = "target framerate")
93
- protected int frameRate = DEFAULT_FRAMERATE;
94
-
95
- /**
96
- *
97
- */
98
- protected int frameDuration;
99
-
100
- /**
101
- *
102
- */
103
- protected int frameCount;
104
-
105
- private static Logger LOGGER;
106
-
107
- /**
108
- * Optional server event listener
109
- */
110
- protected ServerListener listener;
111
-
112
- /**
113
- *
114
- */
115
- public UDPSyncServer() {
116
- config = new TypedProperties();
117
- setMaxReceivePacketSize(DEFAULT_RECEIVE_PACKET_SIZE);
118
- }
119
-
120
- /**
121
- *
122
- * @param args
123
- */
124
- public static void main(String args[]) {
125
- new UDPSyncServer().execute(args);
126
- }
127
-
128
- /**
129
- * Main entry point for CLI.
130
- *
131
- * @param args
132
- * command line arguments
133
- */
134
- public void execute(String[] args) {
135
- CmdLineParser parser = new CmdLineParser(this);
136
- parser.setUsageWidth(80);
137
- try {
138
- parser.parseArgument(args);
139
- } catch (CmdLineException e) {
140
- System.err.println(e.getMessage());
141
- System.err.println("java UDPSyncServer [options]");
142
- parser.printUsage(System.err);
143
- System.err.println();
144
- return;
145
- }
146
-
147
- try {
148
- if (configFile != null)
149
- config.load(new FileInputStream(configFile));
150
- LOGGER = Logger.getLogger("com.postspectacular");
151
- LOGGER.addHandler(new ConsoleHandler());
152
- LOGGER.setLevel(Level.CONFIG);
153
- configure(config);
154
- run();
155
- } catch (FileNotFoundException e) {
156
- System.err.println("cannot find config file @ " + args[0]);
157
- } catch (IOException e) {
158
- System.err.println("cannot read config file @ " + args[0]);
159
- }
160
- }
161
-
162
- /**
163
- * Configures the server with settings using the passed-in properties.
164
- *
165
- * @param config
166
- */
167
- public void configure(TypedProperties config) {
168
- this.config = config;
169
- port = config.getInt("server.port", port);
170
- setMaxReceivePacketSize(config.getInt("udp.packetsize",
171
- receivePacketSize));
172
- numClients = config.getInt("server.numclients", numClients);
173
- frameRate = config.getInt("server.framerate", frameRate);
174
- frameDuration = 1000 / frameRate;
175
- connectionTimeOut = config.getInt("udp.ttl", connectionTimeOut);
176
- UDPConnection.setTTL(connectionTimeOut);
177
- receiveTimeOut = config.getInt("udp.receivetimeout", receiveTimeOut);
178
- if (LOGGER != null) {
179
- LOGGER.log(Level.INFO, "configured server... port:{0} clients:{1} fps:{2} ttl:{3} rto:{4}", new Object[]{port, numClients, frameRate, connectionTimeOut, receiveTimeOut});
180
- }
181
- setState(ServerState.WAITING_FOR_CLIENTS);
182
- }
183
-
184
- /**
185
- * Main server loop/state machine. Creates socket and handles syncing of
186
- * connected clients.
187
- */
188
- public void run() {
189
- try {
190
- socket = new DatagramSocket(port);
191
- if (LOGGER != null)
192
- LOGGER.log(Level.INFO, "creating socket @ port {0}", port);
193
- if (listener != null) {
194
- listener.serverStarted();
195
- }
196
- while (true) {
197
- switch (state) {
198
-
199
- case WAITING_FOR_CLIENTS:
200
- if (LOGGER != null)
201
- LOGGER.info("Server running, waiting for connections...");
202
- // disable timeout, i.e socket will block indefinitely
203
- // until
204
- // a packet is received
205
- socket.setSoTimeout(0);
206
- while (connections.size() < numClients) {
207
- receiveAndAddConnection();
208
- }
209
- // all connected, start syncing...
210
- setState(ServerState.SYNCHING);
211
- break;
212
-
213
- case SYNCHING:
214
- socket.setSoTimeout(receiveTimeOut);
215
- if (connections.size() > 0) {
216
- doHeartBeat();
217
- byte[] payload = getSyncPayload();
218
- Iterator<UDPConnection> iter = connections.values()
219
- .iterator();
220
- // Uses nanoTime for better precision / more stable
221
- // framerate, but unavailable on OSX!!!
222
- long beginSynch = System.nanoTime();
223
- while (iter.hasNext()) {
224
- UDPConnection conn = iter.next();
225
- if (!conn.isAlive()) {
226
- iter.remove();
227
- if (LOGGER != null)
228
- LOGGER.log(Level.WARNING, "{0} disconnected", conn);
229
- if (listener != null)
230
- listener.clientDisconnected(conn);
231
- }
232
- conn.send(socket, payload);
233
- }
234
- int returnCount = 0;
235
- while (returnCount < numClients
236
- && returnCount < connections.size() + 1) {
237
- try {
238
- DatagramPacket receivePacket = new DatagramPacket(
239
- receiveData, receiveData.length);
240
- socket.receive(receivePacket);
241
- InetAddress ip = receivePacket.getAddress();
242
- int portDP = receivePacket.getPort();
243
- String connID = UDPConnection.buildHash(ip,
244
- portDP);
245
- UDPConnection conn = connections
246
- .get(connID);
247
- if (conn != null) {
248
- conn.update();
249
- returnCount++;
250
- } else {
251
- // renewed connection
252
- conn = new UDPConnection(ip, portDP);
253
- conn.send(socket, getSyncPayload());
254
- connections.put(connID, conn);
255
- if (LOGGER != null)
256
- LOGGER.log(Level.FINE, "re-adding connection: {0}", conn);
257
- }
258
- if (listener != null)
259
- listener.clientUpdated(conn,
260
- receivePacket);
261
- } catch (SocketTimeoutException e) {
262
- // no further packets available
263
- break;
264
- }
265
- }
266
- long endSynch = System.nanoTime();
267
- long delta = (endSynch - beginSynch) / 1000000;
268
- if (delta < frameDuration) {
269
- int sleep = frameDuration - (int) delta;
270
- if (LOGGER != null)
271
- LOGGER.log(Level.FINEST, "sleeping: {0}", sleep);
272
- Thread.sleep(sleep);
273
- }
274
- } else {
275
- if (LOGGER != null)
276
- LOGGER.info("all clients disconnected");
277
- setState(ServerState.WAITING_FOR_CLIENTS);
278
- }
279
- }
280
- }
281
- } catch (IOException | InterruptedException e) {
282
- handleException(e);
283
- } finally {
284
- if (LOGGER != null)
285
- LOGGER.info("server shutting down...");
286
- if (socket != null)
287
- socket.close();
288
- }
289
- }
290
-
291
- /**
292
- * Attempts to receive data sent from clients to confirm they're still
293
- * connected. The timeout for this action is set to 1ms by default, so
294
- * currently not more than 25 machines can be reliably connected & synched
295
- * at 25fps.
296
- *
297
- * If a connection times out it's removed from the list of active clients.
298
- * On the other hand if a new connection hash is found we know a client has
299
- * reconnected and will be added back to the pool.
300
- */
301
- protected void receiveAndAddConnection() {
302
- try {
303
- DatagramPacket receivePacket = new DatagramPacket(receiveData,
304
- receiveData.length);
305
- if (LOGGER != null)
306
- LOGGER.log(Level.INFO, "waiting for {0} more clients to reconnect...", (numClients - connections.size()));
307
- socket.receive(receivePacket);
308
- InetAddress ip = receivePacket.getAddress();
309
- int portDP = receivePacket.getPort();
310
- String connID = UDPConnection.buildHash(ip, portDP);
311
- if (connections.get(connID) == null) {
312
- if (connections.isEmpty()) {
313
- frameCount = 0;
314
- if (LOGGER != null)
315
- LOGGER.info("resetting frame count");
316
- }
317
- UDPConnection conn = new UDPConnection(ip, portDP);
318
- connections.put(connID, conn);
319
- conn.send(socket, getSyncPayload());
320
- if (LOGGER != null)
321
- LOGGER.log(Level.FINE, "added new connection: {0}", conn);
322
- if (listener != null) {
323
- listener.clientConnected(conn);
324
- }
325
- }
326
- } catch (SocketTimeoutException e) {
327
- } catch (IOException e) {
328
- handleException(e);
329
- }
330
- }
331
-
332
- private void handleException(Exception e) {
333
- if (listener != null)
334
- listener.serverError(e);
335
- if (LOGGER != null)
336
- LOGGER.log(Level.SEVERE, "Server error", e);
337
- else
338
- e.printStackTrace();
339
- }
340
-
341
- /**
342
- * Updates the internal state of the heartbeat info sent out later.
343
- */
344
- protected void doHeartBeat() {
345
- frameCount++;
346
- }
347
-
348
- /**
349
- * Collects and formats payload data sent via UDP to all clients. By default
350
- * only the current frame number is sent. If more data is required you can
351
- * either overwrite this method or append data via an attached
352
- * {@link ServerListener}.
353
- *
354
- * @return payload data as byte array
355
- */
356
- protected byte[] getSyncPayload() {
357
- StringBuilder sb = new StringBuilder();
358
- sb.append(frameCount);
359
- byte[] defaultPayload = sb.toString().getBytes();
360
- if (listener != null) {
361
- byte[] userPayload = listener.getSyncPayload();
362
- if (userPayload != null) {
363
- byte[] combinedPayload = new byte[defaultPayload.length
364
- + userPayload.length];
365
- System.arraycopy(defaultPayload, 0, combinedPayload, 0,
366
- defaultPayload.length);
367
- System.arraycopy(userPayload, 0, combinedPayload,
368
- defaultPayload.length, userPayload.length);
369
- return combinedPayload;
370
- }
371
- }
372
- return defaultPayload;
373
- }
374
-
375
- /**
376
- * Triggers and logs a new server state. If present, this will also notify
377
- * the {@link ServerListener}.
378
- *
379
- * @param s
380
- * new server state
381
- */
382
- private void setState(ServerState s) {
383
- state = s;
384
- if (LOGGER != null)
385
- LOGGER.log(Level.CONFIG, "new server state: {0}", state);
386
- if (listener != null)
387
- listener.serverStateChanged(s);
388
- }
389
-
390
- /**
391
- * @return Maximum size of UDP packets the server is able to receive
392
- */
393
- public int getMaxPacketSize() {
394
- return receiveData.length;
395
- }
396
-
397
- /**
398
- * Sets the max. size of UDP packets the server is able to receive
399
- *
400
- * @param size
401
- */
402
- public final void setMaxReceivePacketSize(int size) {
403
- receivePacketSize = size;
404
- if (receiveData == null) {
405
- receiveData = new byte[size];
406
- } else if (receiveData.length != size) {
407
- synchronized (receiveData) {
408
- receiveData = new byte[size];
409
- }
410
- }
411
- }
412
-
413
- /**
414
- * @return configured number of clients the server is expecting and
415
- * initially waiting for to connect before any syncing begins.
416
- */
417
- public int getNumClients() {
418
- return numClients;
419
- }
420
-
421
- /**
422
- * Sets the number of clients the server is expecting and initially waiting
423
- * for to connect before any syncing begins.
424
- *
425
- * @param numClients
426
- */
427
- public void setNumClients(int numClients) {
428
- this.numClients = numClients;
429
- }
430
-
431
- /**
432
- * Attaches a logger to the server.
433
- *
434
- * @param logger
435
- */
436
- public void setLogger(Logger logger) {
437
- UDPSyncServer.LOGGER = logger;
438
- }
439
-
440
- /**
441
- * Attaches an event listener to the server.
442
- *
443
- * @param listener
444
- */
445
- public void setListener(ServerListener listener) {
446
- this.listener = listener;
447
- if (LOGGER != null)
448
- LOGGER.log(Level.INFO, "new server listener: {0}", listener);
449
- }
450
- }
@@ -1,121 +0,0 @@
1
- package com.toxi.nio;
2
-
3
- import java.net.*;
4
- import java.io.*;
5
- import java.nio.*;
6
- import java.nio.channels.*;
7
- import java.nio.channels.spi.SelectorProvider;
8
- import java.util.*;
9
- import java.util.logging.Level;
10
- import java.util.logging.Logger;
11
-
12
- /**
13
- *
14
- * @author tux
15
- */
16
- public class UDPClient {
17
-
18
- /**
19
- *
20
- */
21
- public final static int DEFAULT_PORT = 9876;
22
-
23
- int port = DEFAULT_PORT;
24
- SocketAddress remote;
25
- DatagramChannel channel;
26
- Selector selector;
27
- ByteBuffer buffer1;
28
- ByteBuffer buffer2;
29
-
30
- int clientID;
31
-
32
- /**
33
- *
34
- * @param clientID
35
- */
36
- public UDPClient(int clientID) {
37
- this.clientID = clientID;
38
- System.out.println("new client ID: " + clientID);
39
- try {
40
- remote = new InetSocketAddress("192.168.1.64", port);
41
- channel = DatagramChannel.open();
42
- channel.configureBlocking(false);
43
- channel.connect(remote);
44
- selector = SelectorProvider.provider().openSelector();
45
- channel.register(selector, SelectionKey.OP_READ
46
- | SelectionKey.OP_WRITE);
47
- buffer1 = ByteBuffer.allocate(4);
48
- buffer2 = ByteBuffer.allocate(4);
49
- } catch (IOException ex) {
50
- System.err.println(ex);
51
- }
52
- }
53
-
54
- /**
55
- *
56
- * @param command
57
- */
58
- public void send(int command) {
59
- try {
60
- selector.select(clientID);
61
- Set readyKeys = selector.selectedKeys();
62
- Iterator iterator = readyKeys.iterator();
63
- if (iterator.hasNext()) {
64
- SelectionKey key = (SelectionKey) iterator.next();
65
- iterator.remove();
66
- if (key.isWritable()) {
67
- buffer1.clear();
68
- buffer1.putInt(command);
69
- buffer1.flip();
70
- channel.write(buffer1);
71
- }
72
- }
73
- } catch (IOException ex) {
74
- System.err.println(ex);
75
- }
76
- }
77
-
78
- /**
79
- *
80
- * @return
81
- */
82
- public int receive() {
83
- int r = 0;
84
- try {
85
- selector.select(clientID);
86
- Set readyKeys2 = selector.selectedKeys();
87
- Iterator iterator2 = readyKeys2.iterator();
88
- if (iterator2.hasNext()) {
89
- SelectionKey key2 = (SelectionKey) iterator2.next();
90
- iterator2.remove();
91
- if (key2.isReadable()) {
92
- buffer2.clear();
93
- channel.read(buffer2);
94
- buffer2.flip();
95
- int command = buffer2.getInt();
96
- r = command;
97
- }
98
- }
99
- } catch (IOException ex) {
100
- System.err.println(ex);
101
- }
102
- return r;
103
- }
104
-
105
- /**
106
- *
107
- * @param args
108
- */
109
- public static void main(String[] args) {
110
- UDPClient client = new UDPClient(Integer.parseInt(args[0]));
111
- client.send(1);
112
- while (true) {
113
- System.out.println(client.receive());
114
- try {
115
- Thread.sleep(33);
116
- } catch (InterruptedException ex) {
117
- Logger.getLogger(UDPClient.class.getName()).log(Level.SEVERE, null, ex);
118
- }
119
- }
120
- }
121
- }
@@ -1,32 +0,0 @@
1
- package com.toxi.nio;
2
-
3
- import java.net.SocketAddress;
4
-
5
- /**
6
- *
7
- * @author tux
8
- */
9
- public class UDPClientState {
10
- SocketAddress addr;
11
- boolean isReady;
12
- long lastUpdate;
13
-
14
- /**
15
- *
16
- * @param a
17
- */
18
- public UDPClientState(SocketAddress a) {
19
- addr = a;
20
- isReady = true;
21
- lastUpdate = System.currentTimeMillis();
22
- System.out.println("new client: " + addr);
23
- }
24
-
25
- /**
26
- *
27
- * @return
28
- */
29
- public SocketAddress getAddress() {
30
- return addr;
31
- }
32
- }
@@ -1,129 +0,0 @@
1
- package com.toxi.nio;
2
-
3
- import java.net.*;
4
- import java.io.*;
5
- import java.nio.*;
6
- import java.nio.channels.*;
7
- import java.util.ArrayList;
8
- import java.util.Iterator;
9
-
10
- /**
11
- *
12
- * @author tux
13
- */
14
- public class UDPServer extends Thread {
15
-
16
- /**
17
- *
18
- */
19
- public final static int DEFAULT_PORT = 9876;
20
-
21
- /**
22
- *
23
- */
24
- public final static int MAX_PACKET_SIZE = 32;
25
-
26
- private int port;
27
- private int packetSize;
28
- private int numClients;
29
-
30
- ArrayList<UDPClientState> clients;
31
- private int frameCount = 0;
32
- private int frameDuration;
33
-
34
- /**
35
- *
36
- * @param args
37
- */
38
- public static void main(String[] args) {
39
- new UDPServer(1, 25).start();
40
- try {
41
- while (true) {
42
- Thread.sleep(1000);
43
- // System.out.println("running.");
44
- }
45
- } catch (InterruptedException e) {
46
- e.printStackTrace();
47
- }
48
- }
49
-
50
- /**
51
- *
52
- * @param numClients
53
- * @param fps
54
- */
55
- public UDPServer(int numClients, int fps) {
56
- this(DEFAULT_PORT, numClients, MAX_PACKET_SIZE, fps);
57
- }
58
-
59
- /**
60
- *
61
- * @param port
62
- * @param numClients
63
- * @param maxPacketSize
64
- * @param fps
65
- */
66
- public UDPServer(int port, int numClients, int maxPacketSize, int fps) {
67
- this.port = port;
68
- this.numClients = numClients;
69
- this.packetSize = maxPacketSize;
70
- frameDuration = 1000 / fps;
71
- clients = new ArrayList<UDPClientState>();
72
- }
73
-
74
- /**
75
- *
76
- */
77
- public void run() {
78
- DatagramChannel channel = null;
79
- DatagramSocket socket = null;
80
- ByteBuffer buffer = null;
81
- try {
82
- channel = DatagramChannel.open();
83
- socket = channel.socket();
84
- SocketAddress address = new InetSocketAddress(
85
- InetAddress.getLocalHost(), port);
86
- socket.bind(address);
87
- buffer = ByteBuffer.allocateDirect(packetSize);
88
- System.out.println("Server running: " + address);
89
- System.out.println("Heartbeat interval: " + frameDuration);
90
- System.out.println("waiting for clients...");
91
-
92
- // get the addresses-initialisation phase
93
- while (clients.size() < numClients) {
94
- clients.add(new UDPClientState(channel.receive(buffer)));
95
- buffer.flip();
96
- buffer.clear();
97
- }
98
- // server now knows the clients
99
-
100
- // MAIN LOOP-server is working for the clients
101
- while (true) {
102
- long beginSynch = System.currentTimeMillis();
103
- buffer.clear();
104
- buffer.putInt(frameCount++);
105
- buffer.flip();
106
- Iterator<UDPClientState> iter = clients.iterator();
107
- while (iter.hasNext()) {
108
- channel.send(buffer, iter.next().getAddress());
109
- }
110
- long endSynch = System.currentTimeMillis();
111
- if (endSynch - beginSynch < frameDuration) {
112
- int sleep = frameDuration - (int) (endSynch - beginSynch);
113
- // System.out.println("sleeping: " + sleep);
114
- Thread.sleep(sleep);
115
- } else {
116
- Thread.sleep(2);
117
- }
118
- }
119
- } catch (Exception ex) {
120
- System.err.println(ex);
121
- } finally {
122
- if (socket != null)
123
- socket.close();
124
- if (buffer != null)
125
- buffer = null;
126
- System.out.println("server shutdown.");
127
- }
128
- }
129
- }