Skip to content

Commit

Permalink
Add project with abstract class + 2 concrete implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
daneren2005 committed Feb 22, 2014
1 parent 5b17266 commit 563794b
Show file tree
Hide file tree
Showing 9 changed files with 568 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
gen/
.idea/
8 changes: 8 additions & 0 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="github.daneren2005.serverproxy">

<uses-sdk android:targetSdkVersion="19"
android:minSdkVersion="8" />

</manifest>
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
SocketProxy
ServerProxy
===========

ServerProxy is a Android library to provide easy to use classes to create a local server proxies. The following classes exist:

ServerProxy: abstract class which creates a socket and has methods to get a url to reference it.
-start: Start the proxy listening for requests
-stop: Stop the proxy listening for requests
-getPrivateAddress: Get a local url good for being passed internally to another application on the same device
-getPublicAddress: Get a url good for being passed to another device on the same LAN
FileProxy: Streams whichever file is referenced in the url. Can handle multiple concurrent streams
BufferProxy: Streams a file which is being concurrently downloaded. Takes a BufferProgress object to determine when the file is finished downloading. This is useful for serving a song to a MediaPlayer which is still being downloaded. Can only handle one at a time.
20 changes: 20 additions & 0 deletions ServerProxy.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
<configuration>
<option name="LIBRARY_PROJECT" value="true" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

11 changes: 11 additions & 0 deletions local.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Fri Feb 21 20:10:39 PST 2014
sdk.dir=C\:\\Program Files (x86)\\Android\\android-studio\\sdk
27 changes: 27 additions & 0 deletions src/github/daneren2005/serverproxy/BufferFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
This file is part of ServerProxy.
SocketProxy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson
*/

package github.daneren2005.serverproxy;

import java.io.File;

public interface BufferFile {
File getFile();
Long getContentLength();
long getEstimatedSize();
boolean isWorkDone();
void onStart();
void onStop();
}
76 changes: 76 additions & 0 deletions src/github/daneren2005/serverproxy/BufferProxy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
This file is part of ServerProxy.
SocketProxy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson
*/

package github.daneren2005.serverproxy;

import java.io.File;
import java.net.Socket;

import android.content.Context;

public class BufferProxy extends FileProxy {
private static final String TAG = BufferProxy.class.getSimpleName();
protected BufferFile progress;

public BufferProxy(Context context) {
super(context);
}

protected ProxyTask getTask(Socket client) {
return new BufferFileTask(client);
}

public void setBufferFile(BufferFile progress) {
this.progress = progress;
}

protected class BufferFileTask extends StreamFileTask {
public BufferFileTask(Socket client) {
super(client);
}

@Override
File getFile(String path) {
return progress.getFile();
}

@Override
Long getContentLength() {
Long contentLength = progress.getContentLength();
if(contentLength == null && progress.isWorkDone()) {
contentLength = file.length();
}
return contentLength;
}
@Override
long getFileSize() {
return progress.getEstimatedSize();
}

@Override
public void onStart() {
progress.onStart();
}
@Override
public void onStop() {
progress.onStop();
}

@Override
public boolean isWorkDone() {
return progress.isWorkDone() && cbSkip >= file.length();
}
}
}
197 changes: 197 additions & 0 deletions src/github/daneren2005/serverproxy/FileProxy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
This file is part of ServerProxy.
SocketProxy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson
*/

package github.daneren2005.serverproxy;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;

import android.content.Context;
import android.util.Log;

public class FileProxy extends ServerProxy {
private static final String TAG = FileProxy.class.getSimpleName();

public FileProxy(Context context) {
super(context);
}

protected ProxyTask getTask(Socket client) {
return new StreamFileTask(client);
}

protected class StreamFileTask extends ProxyTask {
File file;

public StreamFileTask(Socket client) {
super(client);
}

@Override
public boolean processRequest() {
if(!super.processRequest()) {
return false;
}

Log.i(TAG, "Processing request for file " + path);
file = getFile(path);
if (!file.exists()) {
Log.e(TAG, "File " + path + " does not exist");
return false;
}

// Make sure to not try to read past where the file is downloaded
if(cbSkip != 0 && cbSkip >= file.length()) {
return false;
}

return true;
}

File getFile(String path) {
return new File(path);
}

Long getContentLength() {
return file.length();
}
long getFileSize() {
return file.length();
}

@Override
public void run() {
Long contentLength = getContentLength();

// Create HTTP header
String headers;
if(cbSkip == 0) {
headers = "HTTP/1.0 200 OK\r\n";
} else {
headers = "HTTP/1.0 206 OK\r\n;";
headers += "Content-Range: bytes " + cbSkip + "-" + (file.length() - 1) + "/";
if(contentLength == null) {
headers += "*";
} else {
headers += contentLength;
}

Log.i(TAG, "Streaming starts from: " + cbSkip);
}
headers += "Content-Type: " + "application/octet-stream" + "\r\n";

long fileSize;
if(contentLength == null) {
fileSize = getFileSize();
} else {
fileSize = contentLength;
headers += "Content-Length: " + fileSize + "\r\n";
}
Log.i(TAG, "Streaming fileSize: " + fileSize);

headers += "Connection: close\r\n";
headers += "\r\n";
Log.d(TAG, headers);

long cbToSend = fileSize - cbSkip;
OutputStream output = null;
byte[] buff = new byte[64 * 1024];
try {
output = new BufferedOutputStream(client.getOutputStream(), 32*1024);
output.write(headers.getBytes());

// Make sure to have file lock
onStart();

// Loop as long as there's stuff to send
while (isRunning && !client.isClosed()) {

// See if there's more to send
int cbSentThisBatch = 0;
if (file.exists()) {
FileInputStream input = new FileInputStream(file);
input.skip(cbSkip);
int cbToSendThisBatch = input.available();
while (cbToSendThisBatch > 0) {
int cbToRead = Math.min(cbToSendThisBatch, buff.length);
int cbRead = input.read(buff, 0, cbToRead);
if (cbRead == -1) {
break;
}
cbToSendThisBatch -= cbRead;
cbToSend -= cbRead;
output.write(buff, 0, cbRead);
output.flush();
cbSkip += cbRead;
cbSentThisBatch += cbRead;
}
input.close();
}

// Done regardless of whether or not it thinks it is
if(isWorkDone()) {
break;
}

// If we did nothing this batch, block for a second
if (cbSentThisBatch == 0) {
Log.d(TAG, "Blocking until more data appears (" + cbToSend + ")");
Thread.sleep(1000);
}
}

// Release file lock, use of stream proxy means nothing else is using it
onStop();
}
catch (SocketException socketException) {
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");

// Release file lock, use of stream proxy means nothing else is using it
onStop();
}
catch (Exception e) {
Log.e(TAG, "Exception thrown from streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
}

// Cleanup
try {
if (output != null) {
output.close();
}
client.close();
}
catch (IOException e) {
Log.e(TAG, "IOException while cleaning up streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
}
}

public void onStart() {

}
public void onStop() {

}
public boolean isWorkDone() {
return cbSkip >= file.length();
}
}
}
Loading

0 comments on commit 563794b

Please sign in to comment.