relayConnectionsBySessionId = Maps.newConcurrentMap();
69 |
70 | private RelaySessionConnection openConnection(String deviceId) throws Exception {
71 | RelayClient relayClient = new RelayClient(configuration);
72 | SessionInvitation sessionInvitation = relayClient.getSessionInvitation(relayServerAddress, deviceId);
73 | RelayConnection relayConnection = relayClient.openConnectionSessionMode(sessionInvitation);
74 | final RelaySessionConnection relaySessionConnection = new RelaySessionConnection(relayConnection);
75 | relayConnectionsBySessionId.put(relaySessionConnection.getSessionId(), relaySessionConnection);
76 | relaySessionConnection.getEventBus().register(new Object() {
77 | @Subscribe
78 | public void handleConnectionClosedEvent(ConnectionClosedEvent event) {
79 | relayConnectionsBySessionId.remove(relaySessionConnection.getSessionId());
80 | }
81 | });
82 | relaySessionConnection.connect();
83 | return relaySessionConnection;
84 | }
85 |
86 | public void start(int port) throws Exception {
87 | server = new Server(port);
88 | // if (soapSsl) {
89 | // SslContextFactory sslContextFactory = new SslContextFactory();
90 | // sslContextFactory.setKeyStorePath(Main.class.getResource("/keystore.jks").toExternalForm());
91 | // sslContextFactory.setKeyStorePassword("cjstorepass");
92 | // sslContextFactory.setKeyManagerPassword("cjrestkeypass");
93 | // SslSocketConnector connector = new SslSocketConnector(sslContextFactory);
94 | // connector.setPort(serverPort);
95 | // server.setConnectors(new Connector[]{connector});
96 | // } else {
97 | // SocketConnector connector = new SocketConnector();
98 | // connector.setPort(port);
99 | // server.setConnectors(new Connector[]{connector});
100 | // }
101 |
102 | server.setHandler(new AbstractHandler() {
103 |
104 | @Override
105 | public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
106 | logger.trace("handling requenst");
107 | HttpRelayProtos.HttpRelayServerMessage serverMessage;
108 | try {
109 | HttpRelayProtos.HttpRelayPeerMessage peerMessage = HttpRelayProtos.HttpRelayPeerMessage.parseFrom(request.getInputStream());
110 | logger.debug("handle peer message type = {} session id = {} sequence = {}", peerMessage.getMessageType(), peerMessage.getSessionId(), peerMessage.getSequence());
111 | serverMessage = handleMessage(peerMessage);
112 | } catch (Exception ex) {
113 | logger.error("error", ex);
114 | serverMessage = HttpRelayProtos.HttpRelayServerMessage.newBuilder()
115 | .setMessageType(HttpRelayProtos.HttpRelayServerMessageType.ERROR)
116 | .setData(ByteString.copyFromUtf8("error : " + ex.toString()))
117 | .build();
118 | }
119 | logger.debug("send server response message type = {} session id = {} sequence = {}", serverMessage.getMessageType(), serverMessage.getSessionId(), serverMessage.getSequence());
120 | try {
121 | serverMessage.writeTo(response.getOutputStream());
122 | response.getOutputStream().flush();
123 | } catch (Exception ex) {
124 | logger.error("error", ex);
125 | }
126 | }
127 | });
128 | server.start();
129 | logger.info("http relay server READY on port {}", port);
130 | }
131 |
132 | private HttpRelayProtos.HttpRelayServerMessage handleMessage(HttpRelayProtos.HttpRelayPeerMessage message) throws Exception {
133 | switch (message.getMessageType()) {
134 | case CONNECT: {
135 | String deviceId = message.getDeviceId();
136 | checkNotNull(emptyToNull(deviceId));
137 | RelaySessionConnection connection = openConnection(deviceId);
138 | return HttpRelayProtos.HttpRelayServerMessage.newBuilder()
139 | .setMessageType(HttpRelayProtos.HttpRelayServerMessageType.PEER_CONNECTED)
140 | .setSessionId(connection.getSessionId())
141 | .setIsServerSocket(connection.isServerSocket())
142 | .build();
143 | }
144 | case PEER_CLOSING: {
145 | RelaySessionConnection connection = requireConnectionBySessionId(message.getSessionId());
146 | connection.close();
147 | return HttpRelayProtos.HttpRelayServerMessage.newBuilder()
148 | .setMessageType(HttpRelayProtos.HttpRelayServerMessageType.SERVER_CLOSING)
149 | .build();
150 | }
151 | case PEER_TO_RELAY: {
152 | RelaySessionConnection connection = requireConnectionBySessionId(message.getSessionId());
153 | connection.sendData(message);
154 | return HttpRelayProtos.HttpRelayServerMessage.newBuilder()
155 | .setMessageType(HttpRelayProtos.HttpRelayServerMessageType.DATA_ACCEPTED)
156 | .build();
157 | }
158 | case WAIT_FOR_DATA: {
159 | RelaySessionConnection connection = requireConnectionBySessionId(message.getSessionId());
160 | HttpRelayProtos.HttpRelayServerMessage response = connection.waitForDataAndGet(MAX_WAIT_FOR_DATA_SECS * 1000);
161 | return response;
162 | }
163 | }
164 | throw new IllegalArgumentException("unsupported message type = " + message.getMessageType());
165 | }
166 |
167 | private RelaySessionConnection requireConnectionBySessionId(String sessionId) {
168 | checkNotNull(Strings.emptyToNull(sessionId));
169 | RelaySessionConnection connection = relayConnectionsBySessionId.get(sessionId);
170 | checkNotNull(connection, "connection not found for sessionId = %s", sessionId);
171 | return connection;
172 | }
173 |
174 | public void join() throws InterruptedException {
175 | server.join();
176 | }
177 |
178 | @Override
179 | public void close() {
180 | try {
181 | server.stop();
182 | } catch (Exception ex) {
183 | logger.warn("error stopping server", ex);
184 | }
185 | IOUtils.closeQuietly(configuration);
186 | }
187 |
188 | }
189 |
--------------------------------------------------------------------------------
/a-sync-http-relay/src/main/java/it/anyplace/sync/httprelay/server/RelaySessionConnection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Davide Imbriaco
3 | *
4 | * This Java file is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the License for the specific language governing permissions and
12 | * limitations under the License.
13 | */
14 | package it.anyplace.sync.httprelay.server;
15 |
16 | import static com.google.common.base.Objects.equal;
17 | import com.google.common.eventbus.EventBus;
18 | import java.io.Closeable;
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.io.OutputStream;
22 | import java.net.Socket;
23 | import java.util.UUID;
24 | import java.util.concurrent.ExecutorService;
25 | import java.util.concurrent.Executors;
26 | import java.util.concurrent.TimeUnit;
27 | import org.apache.commons.io.IOUtils;
28 | import org.slf4j.Logger;
29 | import org.slf4j.LoggerFactory;
30 | import com.google.protobuf.ByteString;
31 | import it.anyplace.sync.httprelay.protos.HttpRelayProtos;
32 | import it.anyplace.sync.httprelay.protos.HttpRelayProtos.HttpRelayPeerMessage;
33 | import it.anyplace.sync.httprelay.protos.HttpRelayProtos.HttpRelayServerMessage;
34 | import java.io.File;
35 | import java.io.FileOutputStream;
36 | import org.apache.commons.io.FileUtils;
37 | import static com.google.common.base.Preconditions.checkArgument;
38 | import it.anyplace.sync.core.interfaces.RelayConnection;
39 |
40 | /**
41 | *
42 | * @author aleph
43 | */
44 | public class RelaySessionConnection implements Closeable {
45 |
46 | private final Logger logger = LoggerFactory.getLogger(getClass());
47 | private final String sessionId;
48 | private final EventBus eventBus = new EventBus();
49 | private Socket socket;
50 | private InputStream inputStream;
51 | private OutputStream outputStream;
52 | private long peerToRelaySequence = 0, relayToPeerSequence = 0;
53 | private final ExecutorService readerExecutorService = Executors.newSingleThreadExecutor(), processorService = Executors.newSingleThreadExecutor();
54 | private File tempFile;
55 | private final RelayConnection relayConnection;
56 |
57 | public RelaySessionConnection(RelayConnection relayConnection) {
58 | this.relayConnection = relayConnection;
59 | this.sessionId = UUID.randomUUID().toString();
60 | }
61 |
62 | public long getPeerToRelaySequence() {
63 | return peerToRelaySequence;
64 | }
65 |
66 | public long getRelayToPeerSequence() {
67 | return relayToPeerSequence;
68 | }
69 |
70 | public void sendData(HttpRelayPeerMessage message) throws IOException {
71 | synchronized (outputStream) {
72 | checkArgument(equal(message.getMessageType(), HttpRelayProtos.HttpRelayPeerMessageType.PEER_TO_RELAY));
73 | checkArgument(equal(message.getSessionId(), sessionId));
74 | checkArgument(message.getSequence() == peerToRelaySequence + 1);
75 | if (message.getData() != null && !message.getData().isEmpty()) {
76 | try {
77 | logger.debug("sending {} bytes of data from peer to relay", message.getData().size());
78 | message.getData().writeTo(outputStream);
79 | peerToRelaySequence = message.getSequence();
80 | } catch (IOException ex) {
81 | close();
82 | throw ex;
83 | }
84 | }
85 | }
86 | }
87 |
88 | private File getTempFile() {
89 | synchronized (inputStream) {
90 | if (tempFile == null) {
91 | tempFile = createTempFile();
92 | }
93 | return tempFile;
94 | }
95 | }
96 |
97 | private File createTempFile() {
98 | try {
99 | File file = File.createTempFile("http-relay-" + sessionId, null);
100 | file.deleteOnExit();
101 | return file;
102 | } catch (IOException ex) {
103 | throw new RuntimeException(ex);
104 | }
105 | }
106 |
107 | private byte[] popTempFile() {
108 | try {
109 | File newFile;
110 | synchronized (inputStream) {
111 | if (!hasData()) {
112 | return new byte[0];
113 | }
114 | newFile = createTempFile();
115 | getTempFile().renameTo(newFile);
116 | tempFile = null;
117 | }
118 | byte[] data = FileUtils.readFileToByteArray(newFile);
119 | FileUtils.deleteQuietly(newFile);
120 | logger.debug("returning {} bytes of data from relay to peer", data.length);
121 | return data;
122 | } catch (IOException ex) {
123 | throw new RuntimeException(ex);
124 | }
125 | }
126 |
127 | public HttpRelayServerMessage getData() {
128 | checkArgument(!isClosed());
129 | byte[] data = popTempFile();
130 | return HttpRelayServerMessage.newBuilder()
131 | .setData(ByteString.copyFrom(data))
132 | .setMessageType(HttpRelayProtos.HttpRelayServerMessageType.RELAY_TO_PEER)
133 | .setSequence(++relayToPeerSequence)
134 | .build();
135 | }
136 |
137 | private boolean isClosed = false;
138 |
139 | public boolean isClosed() {
140 | return isClosed;
141 | }
142 |
143 | public boolean hasData() {
144 | synchronized (inputStream) {
145 | return getTempFile().exists() && getTempFile().length() > 0;
146 | }
147 | }
148 |
149 | public HttpRelayServerMessage waitForDataAndGet(long timeout) {
150 | synchronized (inputStream) {
151 | if (!isClosed() && !hasData()) {
152 | try {
153 | inputStream.wait(timeout);
154 | } catch (InterruptedException ex) {
155 | }
156 | }
157 | }
158 | if (isClosed()) {
159 | return HttpRelayServerMessage.newBuilder().setMessageType(HttpRelayProtos.HttpRelayServerMessageType.SERVER_CLOSING).build();
160 | } else {
161 | return getData();
162 | }
163 | }
164 |
165 | public void connect() throws IOException {
166 | socket = relayConnection.getSocket();
167 | inputStream = socket.getInputStream();
168 | outputStream = socket.getOutputStream();
169 | readerExecutorService.submit(new Runnable() {
170 |
171 | private final byte[] buffer = new byte[1024 * 10]; //10k
172 |
173 | @Override
174 | public void run() {
175 | while (!Thread.interrupted() && !isClosed()) {
176 | try {
177 | int count = inputStream.read(buffer);
178 | if (count < 0) {
179 | closeBg();
180 | return;
181 | }
182 | if (count == 0) {
183 | continue;
184 | }
185 | logger.info("received {} bytes from relay for session {}", count, sessionId);
186 | synchronized (inputStream) {
187 | try (OutputStream out = new FileOutputStream(getTempFile(), true)) {
188 | out.write(buffer, 0, count);
189 | }
190 | inputStream.notifyAll();
191 | }
192 | processorService.submit(new Runnable() {
193 | @Override
194 | public void run() {
195 | eventBus.post(DataReceivedEvent.INSTANCE);
196 | }
197 | });
198 | } catch (IOException ex) {
199 | if (isClosed()) {
200 | return;
201 | }
202 | logger.error("error reading data", ex);
203 | closeBg();
204 | return;
205 | }
206 | }
207 | }
208 |
209 | private void closeBg() {
210 |
211 | new Thread() {
212 | @Override
213 | public void run() {
214 | close();
215 | }
216 | }.start();
217 | }
218 | });
219 | }
220 |
221 | public String getSessionId() {
222 | return sessionId;
223 | }
224 |
225 | public EventBus getEventBus() {
226 | return eventBus;
227 | }
228 |
229 | @Override
230 | public void close() {
231 | if (!isClosed()) {
232 | isClosed = true;
233 | logger.info("closing connection for session = {}", sessionId);
234 | readerExecutorService.shutdown();
235 | processorService.shutdown();
236 | if (inputStream != null) {
237 | IOUtils.closeQuietly(inputStream);
238 | synchronized (inputStream) {
239 | inputStream.notifyAll();
240 | }
241 | inputStream = null;
242 | }
243 | if (outputStream != null) {
244 | IOUtils.closeQuietly(outputStream);
245 | outputStream = null;
246 | }
247 | if (socket != null) {
248 | IOUtils.closeQuietly(socket);
249 | socket = null;
250 | }
251 | try {
252 | readerExecutorService.awaitTermination(2, TimeUnit.SECONDS);
253 | } catch (InterruptedException ex) {
254 | }
255 | try {
256 | processorService.awaitTermination(2, TimeUnit.SECONDS);
257 | } catch (InterruptedException ex) {
258 | }
259 | eventBus.post(ConnectionClosedEvent.INSTANCE);
260 | }
261 | }
262 |
263 | public boolean isServerSocket() {
264 | return relayConnection.isServerSocket();
265 | }
266 |
267 | public enum DataReceivedEvent {
268 | INSTANCE;
269 | }
270 |
271 | public enum ConnectionClosedEvent {
272 | INSTANCE;
273 | }
274 |
275 | }
276 |
--------------------------------------------------------------------------------
/a-sync-http-relay/src/main/resources/httpRelayProtos.proto:
--------------------------------------------------------------------------------
1 | package it.anyplace.sync.httprelay.protos;
2 |
3 | message HttpRelayPeerMessage{
4 | optional HttpRelayPeerMessageType message_type = 1;
5 | optional string session_id = 2;
6 | optional string device_id = 3;
7 | optional int64 sequence = 4;
8 | optional bytes data = 5;
9 | }
10 |
11 | message HttpRelayServerMessage{
12 | optional HttpRelayServerMessageType message_type = 1;
13 | optional string session_id = 2;
14 | optional bool is_server_socket = 3;
15 | optional int64 sequence = 4;
16 | optional bytes data = 5;
17 | }
18 |
19 | enum HttpRelayPeerMessageType {
20 | CONNECT = 0;
21 | PEER_TO_RELAY = 1;
22 | WAIT_FOR_DATA = 2;
23 | PEER_CLOSING = 3;
24 | }
25 |
26 | enum HttpRelayServerMessageType {
27 | PEER_CONNECTED = 0;
28 | DATA_ACCEPTED = 1;
29 | RELAY_TO_PEER = 2;
30 | SERVER_CLOSING = 3;
31 | ERROR = 4;
32 | }
33 |
--------------------------------------------------------------------------------
/a-sync-parent/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | it.anyplace.sync
5 | a-sync-parent
6 | 1.3
7 | pom
8 | a-sync-parent
9 | a-sync-parent
10 | https://github.com/davide-imbriaco/a-sync
11 |
12 |
13 | UTF-8
14 | 1.7
15 | 1.7
16 |
17 |
18 |
19 |
20 | Mozilla Public License Version 2.0
21 | http://mozilla.org/MPL/2.0/
22 | repo
23 |
24 |
25 |
26 |
27 | scm:git:https://github.com/davide-imbriaco/a-sync.git
28 | scm:git:git@github.com:davide-imbriaco/a-sync.git
29 | https://github.com/davide-imbriaco/a-sync
30 |
31 |
32 |
33 |
34 | davide.imbriaco
35 | Davide Imbriaco
36 | davide.imbriaco@gmail.com
37 | anyplace.it
38 | http://anyplace.it
39 |
40 | owner
41 | developer
42 |
43 | Europe/Rome
44 |
45 |
46 |
47 |
48 |
49 | org.apache.commons
50 | commons-lang3
51 | 3.4
52 |
53 |
54 | commons-io
55 | commons-io
56 | 2.4
57 |
58 |
59 | org.slf4j
60 | slf4j-api
61 | 1.7.13
62 |
63 |
64 | ch.qos.logback
65 | logback-classic
66 | 1.1.3
67 |
68 |
69 | commons-cli
70 | commons-cli
71 | 1.3.1
72 |
73 |
74 | com.google.code.gson
75 | gson
76 | 2.5
77 |
78 |
79 | com.google.guava
80 | guava
81 | 19.0
82 |
83 |
84 | com.google.code.findbugs
85 | jsr305
86 | 3.0.0
87 |
88 |
89 | commons-beanutils
90 | commons-beanutils
91 | 1.9.2
92 |
93 |
94 | org.apache.httpcomponents
95 | httpclient
96 | 4.3.5
97 |
98 |
99 | com.google.protobuf
100 | protobuf-java
101 | 2.6.1
102 |
103 |
104 | org.bouncycastle
105 | bcmail-jdk15on
106 | 1.55
107 |
108 |
109 | org.bouncycastle
110 | bcpkix-jdk15on
111 | 1.55
112 |
113 |
114 | net.jpountz.lz4
115 | lz4
116 | 1.3.0
117 |
118 |
119 | org.mortbay.jetty.alpn
120 | alpn-boot
121 | 7.1.3.v20150130
122 | provided
123 |
124 |
125 |
126 |
127 |
128 |
129 | org.apache.maven.plugins
130 | maven-jar-plugin
131 | 3.0.2
132 |
133 |
134 |
135 | true
136 | true
137 |
138 |
139 |
140 |
141 |
142 | org.apache.maven.plugins
143 | maven-source-plugin
144 | 3.0.1
145 |
146 |
147 | attach-sources
148 |
149 | jar
150 |
151 |
152 |
153 |
154 |
155 | org.apache.maven.plugins
156 | maven-javadoc-plugin
157 | 2.10.4
158 |
159 |
160 | attach-javadocs
161 |
162 | jar
163 |
164 |
165 |
166 |
167 |
168 | org.apache.maven.plugins
169 | maven-gpg-plugin
170 | 1.6
171 |
172 |
173 | sign-artifacts
174 | verify
175 |
176 | sign
177 |
178 |
179 |
180 |
181 |
182 | org.sonatype.plugins
183 | nexus-staging-maven-plugin
184 | 1.6.7
185 | true
186 |
187 | ossrh
188 | https://oss.sonatype.org/
189 | true
190 |
191 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/a-sync-relay/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | it.anyplace.sync
6 | a-sync-parent
7 | 1.3
8 | ../a-sync-parent
9 |
10 | a-sync-relay
11 | jar
12 |
13 |
14 | ${project.groupId}
15 | a-sync-core
16 | ${project.version}
17 |
18 |
19 |
--------------------------------------------------------------------------------
/a-sync-relay/src/main/java/it/anyplace/sync/client/protocol/rp/beans/SessionInvitation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Davide Imbriaco
3 | *
4 | * This Java file is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the License for the specific language governing permissions and
12 | * limitations under the License.
13 | */
14 | package it.anyplace.sync.client.protocol.rp.beans;
15 |
16 | import static com.google.common.base.Preconditions.checkNotNull;
17 | import com.google.common.base.Strings;
18 | import java.net.InetAddress;
19 | import java.net.InetSocketAddress;
20 |
21 | /**
22 | *
23 | * @author aleph
24 | */
25 | public class SessionInvitation {
26 |
27 | private final String from, key;
28 | private final InetAddress address;
29 | private final int port;
30 | private final boolean isServerSocket;
31 |
32 | private SessionInvitation(String from, String key, InetAddress address, int port, boolean isServerSocket) {
33 | checkNotNull(Strings.emptyToNull(from));
34 | checkNotNull(Strings.emptyToNull(key));
35 | checkNotNull(address);
36 | this.from = from;
37 | this.key = key;
38 | this.address = address;
39 | this.port = port;
40 | this.isServerSocket = isServerSocket;
41 | }
42 |
43 | public String getFrom() {
44 | return from;
45 | }
46 |
47 | public String getKey() {
48 | return key;
49 | }
50 |
51 | public InetAddress getAddress() {
52 | return address;
53 | }
54 |
55 | public int getPort() {
56 | return port;
57 | }
58 |
59 | public boolean isServerSocket() {
60 | return isServerSocket;
61 | }
62 |
63 | public static Builder newBuilder() {
64 | return new Builder();
65 | }
66 |
67 | public InetSocketAddress getSocketAddress() {
68 | return new InetSocketAddress(getAddress(), getPort());
69 | }
70 |
71 | public static class Builder {
72 |
73 | private String from, key;
74 | private InetAddress address;
75 | private int port;
76 | private boolean isServerSocket;
77 |
78 | private Builder() {
79 |
80 | }
81 |
82 | public String getFrom() {
83 | return from;
84 | }
85 |
86 | public String getKey() {
87 | return key;
88 | }
89 |
90 | public InetAddress getAddress() {
91 | return address;
92 | }
93 |
94 | public int getPort() {
95 | return port;
96 | }
97 |
98 | public boolean isServerSocket() {
99 | return isServerSocket;
100 | }
101 |
102 | public Builder setFrom(String from) {
103 | this.from = from;
104 | return this;
105 | }
106 |
107 | public Builder setKey(String key) {
108 | this.key = key;
109 | return this;
110 | }
111 |
112 | public Builder setAddress(InetAddress address) {
113 | this.address = address;
114 | return this;
115 | }
116 |
117 | public Builder setPort(int port) {
118 | this.port = port;
119 | return this;
120 | }
121 |
122 | public Builder setServerSocket(boolean isServerSocket) {
123 | this.isServerSocket = isServerSocket;
124 | return this;
125 | }
126 |
127 | public SessionInvitation build() {
128 | return new SessionInvitation(from, key, address, port, isServerSocket);
129 | }
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/a-sync-repository/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | it.anyplace.sync
6 | a-sync-parent
7 | 1.3
8 | ../a-sync-parent
9 |
10 | a-sync-repository
11 | jar
12 |
13 |
14 | ${project.groupId}
15 | a-sync-core
16 | ${project.version}
17 |
18 |
19 | com.h2database
20 | h2
21 | 1.4.193
22 |
23 |
24 | com.zaxxer
25 | HikariCP-java7
26 | 2.4.9
27 |
28 |
29 |
--------------------------------------------------------------------------------
/a-sync-repository/src/main/resources/indexSerializationProtos.proto:
--------------------------------------------------------------------------------
1 | package it.anyplace.sync.core.repo.protos;
2 |
3 | message Index {
4 | optional int64 version = 1;
5 | optional int64 sequence = 2;
6 | optional int64 last_update = 5;
7 | repeated PeerIndexInfo peers = 3;
8 | repeated FileInfo files = 4;
9 | repeated FolderInfo folders = 6;
10 | }
11 |
12 | message PeerIndexInfo {
13 | optional string device_id = 3;
14 | optional string folder = 4;
15 | optional uint64 id = 1;
16 | optional int64 sequence = 2;
17 | }
18 |
19 | message FileInfo {
20 | optional string folder = 12;
21 | optional string name = 1;
22 | optional FileInfoType type = 2;
23 | optional int64 size = 3;
24 | optional uint32 permissions = 4;
25 | optional int64 modified_s = 5;
26 | optional int32 modified_ns = 11;
27 | optional bool deleted = 6;
28 | optional bool invalid = 7;
29 | optional bool no_permissions = 8;
30 | optional Vector version = 9;
31 | optional int64 sequence = 10;
32 | repeated BlockInfo Blocks = 16;
33 | }
34 |
35 | message FolderInfo {
36 | optional string folder = 1;
37 | optional string label = 2;
38 | }
39 |
40 | enum FileInfoType {
41 | FILE = 0;
42 | DIRECTORY = 1;
43 | SYMLINK_FILE = 2;
44 | SYMLINK_DIRECTORY = 3;
45 | SYMLINK_UNKNOWN = 4;
46 | }
47 |
48 | message Blocks {
49 | repeated BlockInfo blocks = 1;
50 | }
51 |
52 | message BlockInfo {
53 | optional int64 offset = 1;
54 | optional int32 size = 2;
55 | optional bytes hash = 3;
56 | }
57 |
58 | message Vector {
59 | repeated Counter counters = 1;
60 | }
61 |
62 | message Counter {
63 | optional uint64 id = 1;
64 | optional uint64 value = 2;
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/a-sync-webclient/nbactions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | run
5 |
6 | jar
7 |
8 |
9 | process-classes
10 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec
11 |
12 |
13 | -classpath %classpath it.anyplace.sync.webclient.Main
14 | java
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/a-sync-webclient/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | it.anyplace.sync
6 | a-sync-parent
7 | 1.3
8 | ../a-sync-parent
9 |
10 | a-sync-webclient
11 | jar
12 |
13 |
14 |
15 | ${project.groupId}
16 | a-sync-client
17 | ${project.version}
18 |
19 |
20 | org.eclipse.jetty
21 | jetty-http
22 | 8.1.22.v20160922
23 |
24 |
25 |
26 |
27 |
28 |
29 | maven-compiler-plugin
30 | 3.6.0
31 |
32 | 1.7
33 | 1.7
34 |
35 |
36 |
37 | org.apache.maven.plugins
38 | maven-shade-plugin
39 | 2.4.1
40 |
41 |
42 |
43 |
44 | package
45 |
46 | shade
47 |
48 |
49 |
50 |
51 | it.anyplace.sync.webclient.Main
52 |
53 |
54 |
55 |
56 | *:*
57 |
58 | META-INF/*.SF
59 | META-INF/*.DSA
60 | META-INF/*.RSA
61 |
62 |
63 |
64 | true
65 | executable
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/java/it/anyplace/sync/webclient/HttpService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this template, choose Tools | Templates
3 | * and open the template in the editor.
4 | */
5 | package it.anyplace.sync.webclient;
6 |
7 | import it.anyplace.sync.client.SyncthingClient;
8 | import it.anyplace.sync.core.configuration.ConfigurationService;
9 | import java.io.Closeable;
10 | import java.io.IOException;
11 | import java.util.logging.Level;
12 | import javax.servlet.ServletException;
13 | import javax.servlet.http.HttpServletRequest;
14 | import javax.servlet.http.HttpServletResponse;
15 | import org.apache.commons.io.IOUtils;
16 | import org.eclipse.jetty.server.Request;
17 | import org.eclipse.jetty.server.Server;
18 | import org.eclipse.jetty.server.handler.AbstractHandler;
19 | import org.eclipse.jetty.server.handler.ContextHandler;
20 | import org.eclipse.jetty.server.handler.HandlerList;
21 | import org.eclipse.jetty.server.handler.ResourceHandler;
22 | import org.eclipse.jetty.util.resource.Resource;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | public class HttpService implements Closeable {
27 |
28 | private final Logger logger = LoggerFactory.getLogger(getClass());
29 |
30 | private final ConfigurationService configuration;
31 | private final SyncthingClient syncthingClient;
32 | private final static int PORT = 8385;
33 | private final Server server;
34 |
35 | public HttpService(ConfigurationService configuration) {
36 | this.configuration = configuration;
37 | this.syncthingClient = new SyncthingClient(configuration);
38 | this.server = new Server(PORT);
39 |
40 | HandlerList handlerList = new HandlerList();
41 | {
42 | ContextHandler contextHandler = new ContextHandler("/api");
43 | contextHandler.setHandler(new AbstractHandler() {
44 | @Override
45 | public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
46 | logger.info("ws!!");
47 |
48 | new Thread() {
49 | @Override
50 | public void run() {
51 | try {
52 | Thread.sleep(200);
53 | } catch (InterruptedException ex) {
54 | }
55 | close();
56 | }
57 | }.start();
58 |
59 | response.setContentType("application/json");
60 | response.getWriter().write("{success:true}");
61 | }
62 | });
63 | handlerList.addHandler(contextHandler);
64 | }
65 | {
66 | ResourceHandler resourceHandler = new ResourceHandler();
67 | resourceHandler.setBaseResource(Resource.newClassPathResource("/web"));
68 | ContextHandler contextHandler = new ContextHandler("/web");
69 | contextHandler.setHandler(resourceHandler);
70 | handlerList.addHandler(contextHandler);
71 | }
72 | server.setHandler(handlerList);
73 | }
74 |
75 | @Override
76 | public void close() {
77 | try {
78 | if (server.isRunning()) {
79 | server.stop();
80 | }
81 | } catch (Exception ex) {
82 | logger.error("error stopping jetty server", ex);
83 | }
84 | IOUtils.closeQuietly(syncthingClient);
85 | }
86 |
87 | public void start() throws Exception {
88 | logger.info("starting jetty server");
89 | server.start();
90 | }
91 |
92 | public void join() throws Exception {
93 | server.join();
94 | }
95 |
96 | public int getPort() {
97 | return PORT;
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/java/it/anyplace/sync/webclient/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Davide Imbriaco
3 | *
4 | * This Java file is subject to the terms of the Mozilla Public
5 | * License, v. 2.0. If a copy of the MPL was not distributed with this
6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 | *
8 | * Unless required by applicable law or agreed to in writing, software
9 | * distributed under the License is distributed on an "AS IS" BASIS,
10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 | * See the License for the specific language governing permissions and
12 | * limitations under the License.
13 | */
14 | package it.anyplace.sync.webclient;
15 |
16 | import it.anyplace.sync.core.configuration.ConfigurationService;
17 | import it.anyplace.sync.core.security.KeystoreHandler;
18 | import java.awt.Desktop;
19 | import java.io.File;
20 | import java.net.URI;
21 | import org.apache.commons.cli.CommandLine;
22 | import org.apache.commons.cli.CommandLineParser;
23 | import org.apache.commons.cli.DefaultParser;
24 | import org.apache.commons.cli.HelpFormatter;
25 | import org.apache.commons.cli.Options;
26 | import org.apache.commons.io.FileUtils;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 |
30 | /**
31 | *
32 | * @author aleph
33 | */
34 | public class Main {
35 |
36 | private final static Logger logger = LoggerFactory.getLogger(Main.class);
37 |
38 | public static void main(String[] args) throws Exception {
39 | Options options = new Options();
40 | options.addOption("C", "set-config", true, "set config file for s-client");
41 | options.addOption("h", "help", false, "print help");
42 | CommandLineParser parser = new DefaultParser();
43 | CommandLine cmd = parser.parse(options, args);
44 |
45 | if (cmd.hasOption("h")) {
46 | HelpFormatter formatter = new HelpFormatter();
47 | formatter.printHelp("s-client", options);
48 | return;
49 | }
50 |
51 | File configFile = cmd.hasOption("C") ? new File(cmd.getOptionValue("C")) : new File(System.getProperty("user.home"), ".s-client.properties");
52 | logger.info("using config file = {}", configFile);
53 | try (ConfigurationService configuration = ConfigurationService.newLoader().loadFrom(configFile)) {
54 | FileUtils.cleanDirectory(configuration.getTemp());
55 | KeystoreHandler.newLoader().loadAndStore(configuration);
56 | logger.debug("{}", configuration.getStorageInfo().dumpAvailableSpace());
57 | try (HttpService httpService = new HttpService(configuration)) {
58 | httpService.start();
59 | if(Desktop.isDesktopSupported()){
60 | Desktop.getDesktop().browse(URI.create("http://localhost:"+httpService.getPort()+"/web/webclient.html"));
61 | }
62 | httpService.join();
63 | }
64 | }
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_444444_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davide-imbriaco/a-sync/59f28e55940d868505860c82e4f7776c6c0fb9bd/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_444444_256x240.png
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_555555_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davide-imbriaco/a-sync/59f28e55940d868505860c82e4f7776c6c0fb9bd/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_555555_256x240.png
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_777620_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davide-imbriaco/a-sync/59f28e55940d868505860c82e4f7776c6c0fb9bd/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_777620_256x240.png
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_777777_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davide-imbriaco/a-sync/59f28e55940d868505860c82e4f7776c6c0fb9bd/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_777777_256x240.png
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_cc0000_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davide-imbriaco/a-sync/59f28e55940d868505860c82e4f7776c6c0fb9bd/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_cc0000_256x240.png
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davide-imbriaco/a-sync/59f28e55940d868505860c82e4f7776c6c0fb9bd/a-sync-webclient/src/main/resources/web/lib/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/webclient.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | a-sync-client
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | loading...
16 |
17 |
hello
18 |
19 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/webclient.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 |
3 | $('#wc_loading').hide();
4 | $('#wc_mainContent').show();
5 |
6 | $('#wc_exit').on('click', function () {
7 | $.get('/api/exit');
8 | });
9 |
10 | });
11 |
--------------------------------------------------------------------------------
/a-sync-webclient/src/main/resources/web/webclient.less:
--------------------------------------------------------------------------------
1 |
2 | /* global stuff */
3 |
4 | html, body{
5 | margin: 0;
6 | padding: 0;
7 | height: 100%;
8 | }
9 | * {
10 | box-sizing: border-box;
11 | }
12 |
--------------------------------------------------------------------------------
/docs/http_relay_protocol.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davide-imbriaco/a-sync/59f28e55940d868505860c82e4f7776c6c0fb9bd/docs/http_relay_protocol.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | it.anyplace.sync
5 | a-sync
6 | 1.3
7 | pom
8 |
9 |
10 | a-sync-parent
11 | a-sync-core
12 | a-sync-relay
13 | a-sync-http-relay
14 | a-sync-bep
15 | a-sync-client
16 | a-sync-http-relay-server
17 | a-sync-repository
18 | a-sync-discovery
19 | a-sync-webclient
20 |
21 |
22 |
23 |
24 |
25 | maven-deploy-plugin
26 |
27 | true
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------