mirror of
https://github.com/geometer/FBReaderJ.git
synced 2025-10-05 10:49:24 +02:00
more experiments with SynchroniserService
This commit is contained in:
parent
7d840b81af
commit
ce4ab7866c
5 changed files with 124 additions and 26 deletions
|
@ -345,7 +345,7 @@ public class ApiServerImplementation extends ApiInterface.Stub implements Api, A
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBookHash() {
|
public String getBookHash() {
|
||||||
final UID uid = BookUtil.createSHA256Uid(getReader().Model.Book.File);
|
final UID uid = BookUtil.createUid(getReader().Model.Book.File, "SHA-256");
|
||||||
return uid != null ? uid.Id : null;
|
return uid != null ? uid.Id : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,48 +19,146 @@
|
||||||
|
|
||||||
package org.geometerplus.android.fbreader.synchroniser;
|
package org.geometerplus.android.fbreader.synchroniser;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
|
import org.json.simple.JSONValue;
|
||||||
|
|
||||||
|
import org.geometerplus.zlibrary.core.network.*;
|
||||||
|
import org.geometerplus.fbreader.book.*;
|
||||||
import org.geometerplus.android.fbreader.libraryService.BookCollectionShadow;
|
import org.geometerplus.android.fbreader.libraryService.BookCollectionShadow;
|
||||||
|
|
||||||
public class SynchroniserService extends Service implements Runnable {
|
public class SynchroniserService extends Service implements IBookCollection.Listener, Runnable {
|
||||||
private final BookCollectionShadow myCollection = new BookCollectionShadow();
|
private final BookCollectionShadow myCollection = new BookCollectionShadow();
|
||||||
private volatile Thread mySynchronizationThread;
|
private volatile Thread mySynchronizationThread;
|
||||||
|
|
||||||
|
private final List<Book> myQueue = Collections.synchronizedList(new LinkedList<Book>());
|
||||||
|
private final Set<Book> myProcessed = new HashSet<Book>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
myCollection.bindToService(this, this);
|
myCollection.bindToService(this, this);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void addBook(Book book) {
|
||||||
public void run() {
|
if (!myProcessed.contains(book) && book.File.getPhysicalFile() != null) {
|
||||||
System.err.println("SYNCHRONIZER BINDED TO LIBRARY");
|
myQueue.add(book);
|
||||||
synchronized(this) {
|
|
||||||
if (mySynchronizationThread == null) {
|
|
||||||
mySynchronizationThread = new Thread() {
|
|
||||||
public void run() {
|
|
||||||
System.err.println("HELLO THREAD");
|
|
||||||
try {
|
|
||||||
mySynchronizationThread.sleep(5000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
}
|
|
||||||
System.err.println("BYE-BYE THREAD");
|
|
||||||
mySynchronizationThread = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mySynchronizationThread.setPriority(Thread.MIN_PRIORITY);
|
|
||||||
mySynchronizationThread.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void run() {
|
||||||
|
System.err.println("SYNCHRONIZER BINDED TO LIBRARY");
|
||||||
|
myCollection.addListener(this);
|
||||||
|
if (mySynchronizationThread == null) {
|
||||||
|
mySynchronizationThread = new Thread() {
|
||||||
|
public void run() {
|
||||||
|
System.err.println("HELLO THREAD");
|
||||||
|
for (BookQuery q = new BookQuery(new Filter.Empty(), 20);; q = q.next()) {
|
||||||
|
final List<Book> books = myCollection.books(q);
|
||||||
|
if (books.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (Book b : books) {
|
||||||
|
addBook(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!myQueue.isEmpty()) {
|
||||||
|
final Book book = myQueue.remove(0);
|
||||||
|
if (myProcessed.contains(book)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
myProcessed.add(book);
|
||||||
|
System.err.println("Processing " + book.getTitle() + " [" + book.File.getPath() + "]");
|
||||||
|
uploadBookToServer(book);
|
||||||
|
}
|
||||||
|
System.err.println("BYE-BYE THREAD");
|
||||||
|
mySynchronizationThread = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mySynchronizationThread.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
mySynchronizationThread.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toJSON(Object object) {
|
||||||
|
final StringWriter writer = new StringWriter();
|
||||||
|
try {
|
||||||
|
JSONValue.writeJSONString(object, writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("JSON serialization failed", e);
|
||||||
|
}
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static abstract class Request extends ZLNetworkRequest {
|
||||||
|
private final static String BASE_URL = "https://books.fbreader.org/app/";
|
||||||
|
|
||||||
|
Request(String app, Object data) {
|
||||||
|
super(BASE_URL + app, toJSON(data), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleStream(InputStream stream, int length) throws IOException, ZLNetworkException {
|
||||||
|
final BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||||
|
final StringBuilder buffer = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
buffer.append(line);
|
||||||
|
}
|
||||||
|
processResponse(JSONValue.parse(buffer.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final void perform() {
|
||||||
|
try {
|
||||||
|
ZLNetworkManager.Instance().perform(this);
|
||||||
|
} catch (ZLNetworkException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void processResponse(Object response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadBookToServer(Book book) {
|
||||||
|
final UID uid = BookUtil.createUid(book.File.getPhysicalFile(), "SHA-1");
|
||||||
|
if (uid == null) {
|
||||||
|
System.err.println("Failed: SHA-1 checksum not computed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.err.println("SHA-1: " + uid.Id);
|
||||||
|
new Request("books.by.hash", Collections.singletonMap("sha1", uid.Id)) {
|
||||||
|
public void processResponse(Object response) {
|
||||||
|
System.err.println("RESPONSE = " + response);
|
||||||
|
}
|
||||||
|
}.perform();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
myCollection.removeListener(this);
|
||||||
myCollection.unbind();
|
myCollection.unbind();
|
||||||
System.err.println("SYNCHRONIZER UNBINDED FROM LIBRARY");
|
System.err.println("SYNCHRONIZER UNBINDED FROM LIBRARY");
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBookEvent(BookEvent event, Book book) {
|
||||||
|
switch (event) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case Added:
|
||||||
|
addBook(book);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBuildEvent(IBookCollection.Status status) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,11 +78,11 @@ public abstract class BookUtil {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UID createSHA256Uid(ZLFile file) {
|
public static UID createUid(ZLFile file, String algorithm) {
|
||||||
InputStream stream = null;
|
InputStream stream = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final MessageDigest hash = MessageDigest.getInstance("SHA-256");
|
final MessageDigest hash = MessageDigest.getInstance(algorithm);
|
||||||
stream = file.getInputStream();
|
stream = file.getInputStream();
|
||||||
|
|
||||||
final byte[] buffer = new byte[2048];
|
final byte[] buffer = new byte[2048];
|
||||||
|
@ -98,7 +98,7 @@ public abstract class BookUtil {
|
||||||
for (byte b : hash.digest()) {
|
for (byte b : hash.digest()) {
|
||||||
f.format("%02X", b & 0xFF);
|
f.format("%02X", b & 0xFF);
|
||||||
}
|
}
|
||||||
return new UID("SHA-256", f.toString());
|
return new UID(algorithm, f.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return null;
|
return null;
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class NativeFormatPlugin extends FormatPlugin {
|
||||||
synchronized public void readUids(Book book) throws BookReadingException {
|
synchronized public void readUids(Book book) throws BookReadingException {
|
||||||
readUidsNative(book);
|
readUidsNative(book);
|
||||||
if (book.uids().isEmpty()) {
|
if (book.uids().isEmpty()) {
|
||||||
book.addUid(BookUtil.createSHA256Uid(book.File));
|
book.addUid(BookUtil.createUid(book.File, "SHA-256"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ public class MobipocketPlugin extends JavaFormatPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void readUids(Book book) throws BookReadingException {
|
public void readUids(Book book) throws BookReadingException {
|
||||||
if (book.uids().isEmpty()) {
|
if (book.uids().isEmpty()) {
|
||||||
book.addUid(BookUtil.createSHA256Uid(book.File));
|
book.addUid(BookUtil.createUid(book.File, "SHA-256"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue