From b3afe42f38ee57d517016210286f8231f3001247 Mon Sep 17 00:00:00 2001 From: Adrian Tiberius Date: Mon, 8 Jun 2015 14:51:03 +0200 Subject: [PATCH] Added jsonrpc server. --- .../ethereum/android_app/MainActivity.java | 277 ++++++++++-------- ethereumj-core-android/build.gradle | 122 ++++---- .../org/ethereum/android/EthereumManager.java | 110 +++---- .../android/jsonrpc/JsonRpcServer.java | 159 ++++++++++ .../android/jsonrpc/method/eth_coinbase.java | 29 ++ 5 files changed, 469 insertions(+), 228 deletions(-) create mode 100644 ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/JsonRpcServer.java create mode 100644 ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/method/eth_coinbase.java diff --git a/app/src/main/java/org/ethereum/android_app/MainActivity.java b/app/src/main/java/org/ethereum/android_app/MainActivity.java index 17b2a209..c2ad4924 100644 --- a/app/src/main/java/org/ethereum/android_app/MainActivity.java +++ b/app/src/main/java/org/ethereum/android_app/MainActivity.java @@ -1,118 +1,159 @@ -package org.ethereum.android_app; - -import android.content.Context; -import android.os.AsyncTask; -import android.support.v4.view.ViewPager; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.support.v7.widget.Toolbar; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; - -import org.ethereum.android.EthereumManager; - - -public class MainActivity extends ActionBarActivity { - - private static final String TAG = "MyActivity"; - private static Integer quit = 0; - - private Toolbar toolbar; - private ViewPager viewPager; - private SlidingTabLayout tabs; - private TabsPagerAdapter adapter; - - public EthereumManager ethereumManager = null; - - @Override - protected void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - toolbar = (Toolbar) findViewById(R.id.tool_bar); - setSupportActionBar(toolbar); - - ethereumManager = new EthereumManager(this); - - adapter = new TabsPagerAdapter(getSupportFragmentManager(), ethereumManager); - viewPager = (ViewPager) findViewById(R.id.pager); - viewPager.setAdapter(adapter);; - - tabs = (SlidingTabLayout) findViewById(R.id.tabs); - tabs.setDistributeEvenly(true); - tabs.setViewPager(viewPager); - - //StrictMode.enableDefaults(); - - new PostTask().execute(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - //return super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - Log.v(TAG, Integer.valueOf(id).toString()); - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - return true; - } - - return super.onOptionsItemSelected(item); - } - - // The definition of our task class - private class PostTask extends AsyncTask { - - - @Override - protected void onPreExecute() { - super.onPreExecute(); - } - - @Override - protected String doInBackground(Context... params) { - Log.v(TAG, "111"); - - Log.v(TAG, "222"); - ethereumManager.connect(); - Log.v(TAG, "333"); - while(true) { - - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - if (quit == 1) { - Log.v(TAG, "Ending background process."); - return "All Done!"; - } - - //publishProgress(1111); - } - } - - @Override - protected void onProgressUpdate(Integer... values) { - super.onProgressUpdate(values); - Log.v(TAG, values[0].toString()); - } - - @Override - protected void onPostExecute(String result) { - super.onPostExecute(result); - } - } -} +package org.ethereum.android_app; + +import android.content.Context; +import android.os.AsyncTask; +import android.support.v4.view.ViewPager; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.os.Build; + +import org.ethereum.android.EthereumManager; + + +public class MainActivity extends ActionBarActivity { + + private static final String TAG = "MyActivity"; + private static Integer quit = 0; + + private Toolbar toolbar; + private ViewPager viewPager; + private SlidingTabLayout tabs; + private TabsPagerAdapter adapter; + + public EthereumManager ethereumManager = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + toolbar = (Toolbar) findViewById(R.id.tool_bar); + setSupportActionBar(toolbar); + + ethereumManager = new EthereumManager(this); + + adapter = new TabsPagerAdapter(getSupportFragmentManager(), ethereumManager); + viewPager = (ViewPager) findViewById(R.id.pager); + viewPager.setAdapter(adapter);; + + tabs = (SlidingTabLayout) findViewById(R.id.tabs); + tabs.setDistributeEvenly(true); + tabs.setViewPager(viewPager); + + //StrictMode.enableDefaults(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + new PostTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + else + new PostTask().execute(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + new JsonRpcTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + else + new JsonRpcTask().execute(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + //return super.onCreateOptionsMenu(menu); + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + Log.v(TAG, Integer.valueOf(id).toString()); + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } + + // The definition of our task class + private class PostTask extends AsyncTask { + + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Context... params) { + Log.v(TAG, "111"); + + Log.v(TAG, "222"); + ethereumManager.connect(); + Log.v(TAG, "333"); + while(true) { + + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if (quit == 1) { + Log.v(TAG, "Ending background process."); + return "All Done!"; + } + + //publishProgress(1111); + } + } + + @Override + protected void onProgressUpdate(Integer... values) { + super.onProgressUpdate(values); + Log.v(TAG, values[0].toString()); + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + } + } + + + // The definition of our task class + private class JsonRpcTask extends AsyncTask { + + @Override + protected void onPreExecute() { + super.onPreExecute(); + } + + @Override + protected String doInBackground(Context... params) { + Log.v(TAG, "444"); + try { + ethereumManager.startJsonRpc(); + } catch (Exception e) { + } + Log.v(TAG, "555"); + return "done"; + } + + @Override + protected void onProgressUpdate(Integer... values) { + super.onProgressUpdate(values); + Log.v(TAG, values[0].toString()); + } + + @Override + protected void onPostExecute(String result) { + super.onPostExecute(result); + } + } +} diff --git a/ethereumj-core-android/build.gradle b/ethereumj-core-android/build.gradle index 86cd8034..c56d5e6e 100644 --- a/ethereumj-core-android/build.gradle +++ b/ethereumj-core-android/build.gradle @@ -1,60 +1,62 @@ -apply plugin: 'com.android.library' -apply plugin: 'com.neenbedankt.android-apt' - -buildscript { - repositories { - jcenter() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' - } -} - -repositories { - jcenter() - mavenCentral() -} - -android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" - - defaultConfig { - minSdkVersion 14 - targetSdkVersion 22 - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - -tasks.withType(JavaCompile){ - options.warnings = false -} - -dependencies { - apt 'com.google.dagger:dagger-compiler:2.0' - compile fileTree(dir: 'libs', include: ['*.jar']) - compile (project(':ethereumj-core')) { - exclude group: "org.apache.commons", module: "commons-pool2" - exclude group: "org.slf4j", module: "slf4j-log4j12" - exclude group: "org.hibernate", module: "hibernate-core" - exclude group: "org.hibernate", module: "hibernate-entitymanager" - exclude group: "redis.clients", module: "jedis" - exclude group: "org.antlr", module: "antlr4-runtime" - } - - //compile "com.google.dagger:dagger:2.1-SNAPSHOT" - compile "com.j256.ormlite:ormlite-android:4.48" - compile "org.glassfish:javax.annotation:10.0-b28" - compile "org.iq80.leveldb:leveldb:0.7" - compile 'org.slf4j:slf4j-android:1.7.12' - compile 'javax.persistence:persistence-api:1.0.2' -} +apply plugin: 'com.android.library' +apply plugin: 'com.neenbedankt.android-apt' + +buildscript { + repositories { + jcenter() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' + } +} + +repositories { + jcenter() + mavenCentral() +} + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +tasks.withType(JavaCompile){ + options.warnings = false +} + +dependencies { + apt 'com.google.dagger:dagger-compiler:2.0' + compile fileTree(dir: 'libs', include: ['*.jar']) + compile (project(':ethereumj-core')) { + exclude group: "org.apache.commons", module: "commons-pool2" + exclude group: "org.slf4j", module: "slf4j-log4j12" + exclude group: "org.hibernate", module: "hibernate-core" + exclude group: "org.hibernate", module: "hibernate-entitymanager" + exclude group: "redis.clients", module: "jedis" + exclude group: "org.antlr", module: "antlr4-runtime" + } + + //compile "com.google.dagger:dagger:2.1-SNAPSHOT" + compile "com.j256.ormlite:ormlite-android:4.48" + compile "org.glassfish:javax.annotation:10.0-b28" + compile "org.iq80.leveldb:leveldb:0.7" + compile 'org.slf4j:slf4j-android:1.7.12' + compile 'javax.persistence:persistence-api:1.0.2' + + compile group: 'com.thetransactioncompany', name: 'jsonrpc2-server', version: '1.11' +} diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java b/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java index 5256d55d..fbd655ac 100644 --- a/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/EthereumManager.java @@ -1,50 +1,60 @@ -package org.ethereum.android; - -import android.content.Context; - -import org.ethereum.android.di.modules.EthereumModule; -import org.ethereum.android.di.components.DaggerEthereumComponent; -import org.ethereum.config.SystemProperties; -import org.ethereum.facade.Ethereum; -import org.ethereum.listener.EthereumListenerAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class EthereumManager { - - private static final Logger logger = LoggerFactory.getLogger("manager"); - - public static Ethereum ethereum = null; - - - public EthereumManager(Context context) { - System.setProperty("sun.arch.data.model", "32"); - System.setProperty("leveldb.mmap", "false"); - ethereum = DaggerEthereumComponent.builder() - .ethereumModule(new EthereumModule(context)) - .build().ethereum(); - } - - public void start() { - - } - - public void connect() { - - ethereum.connect(SystemProperties.CONFIG.activePeerIP(), - SystemProperties.CONFIG.activePeerPort(), - SystemProperties.CONFIG.activePeerNodeid()); - //ethereum.getBlockchain(); - } - - public void startPeerDiscovery() { - - ethereum.startPeerDiscovery(); - } - - public void addListener(EthereumListenerAdapter listener) { - - ethereum.addListener(listener); - } - -} +package org.ethereum.android; + +import android.content.Context; + +import org.ethereum.android.di.modules.EthereumModule; +import org.ethereum.android.di.components.DaggerEthereumComponent; +import org.ethereum.config.SystemProperties; +import org.ethereum.facade.Ethereum; +import org.ethereum.listener.EthereumListenerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.ethereum.android.jsonrpc.JsonRpcServer; + +public class EthereumManager { + + private static final Logger logger = LoggerFactory.getLogger("manager"); + + public static Ethereum ethereum = null; + + private JsonRpcServer jsonRpcServer; + + + public EthereumManager(Context context) { + System.setProperty("sun.arch.data.model", "32"); + System.setProperty("leveldb.mmap", "false"); + ethereum = DaggerEthereumComponent.builder() + .ethereumModule(new EthereumModule(context)) + .build().ethereum(); + + jsonRpcServer = new JsonRpcServer(ethereum); + } + + public void start() { + + } + + public void connect() { + + ethereum.connect(SystemProperties.CONFIG.activePeerIP(), + SystemProperties.CONFIG.activePeerPort(), + SystemProperties.CONFIG.activePeerNodeid()); + //ethereum.getBlockchain(); + } + + public void startPeerDiscovery() { + + ethereum.startPeerDiscovery(); + } + + public void addListener(EthereumListenerAdapter listener) { + + ethereum.addListener(listener); + } + + public void startJsonRpc() throws Exception { + + jsonRpcServer.start(); + } + +} diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/JsonRpcServer.java b/ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/JsonRpcServer.java new file mode 100644 index 00000000..0c3cbceb --- /dev/null +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/JsonRpcServer.java @@ -0,0 +1,159 @@ +package org.ethereum.android.jsonrpc; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelOption; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.multipart.HttpPostStandardRequestDecoder; +import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; +import io.netty.handler.codec.http.HttpObject; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.buffer.ByteBuf; +import io.netty.util.CharsetUtil; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.channel.ChannelFuture; +import org.ethereum.facade.Ethereum; +import com.thetransactioncompany.jsonrpc2.*; +import com.thetransactioncompany.jsonrpc2.server.*; +import io.netty.handler.codec.http.HttpHeaders; +import static io.netty.handler.codec.http.HttpHeaders.Names.*; + +import org.ethereum.android.jsonrpc.method.*; + + +public final class JsonRpcServer { + + static final int PORT = 8545; + + private Ethereum ethereum; + private Dispatcher dispatcher; + + public JsonRpcServer(Ethereum ethereum) { + this.ethereum = ethereum; + + this.dispatcher = new Dispatcher(); + this.dispatcher.register(new eth_coinbase(this.ethereum)); + } + + public void start() throws Exception { + + EventLoopGroup bossGroup = new NioEventLoopGroup(1); + EventLoopGroup workerGroup = new NioEventLoopGroup(); + try { + ServerBootstrap b = new ServerBootstrap(); + b.option(ChannelOption.SO_BACKLOG, 1024); +// b.localAddress(InetAddress.getLocalHost(), PORT); + b.localAddress(PORT); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new JsonRpcServerInitializer()); + + Channel ch = b.bind().sync().channel(); + + ch.closeFuture().sync(); + } finally { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } + } + + class JsonRpcServerInitializer extends ChannelInitializer { + @Override + public void initChannel(SocketChannel ch) { + ChannelPipeline p = ch.pipeline(); + p.addLast(new HttpServerCodec()); + p.addLast(new JsonRpcServerHandler()); + } + } + + class JsonRpcServerHandler extends SimpleChannelInboundHandler { + + private HttpRequest request; + private final StringBuilder responseContent = new StringBuilder(); + private HttpPostStandardRequestDecoder decoder; + private String postData; + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (decoder != null) { + decoder.destroy(); + } + } + @Override + public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { + if (msg instanceof HttpRequest) { + HttpRequest req = this.request = (HttpRequest) msg; + if (!req.getUri().equals("/") || !request.getMethod().equals(HttpMethod.POST)) { + responseContent.append("Hi, how are you?!!"); + return; + } else { + decoder = new HttpPostStandardRequestDecoder(new DefaultHttpDataFactory(false), req); + postData = ""; + } + } + + if (decoder != null) { + if (msg instanceof HttpContent) { + HttpContent chunk = (HttpContent) msg; + decoder.offer(chunk); + postData += chunk.content().toString(0, chunk.content().capacity(), CharsetUtil.UTF_8); + + if (chunk instanceof LastHttpContent) { + JSONRPC2Request req = JSONRPC2Request.parse(postData); + JSONRPC2Response resp = dispatcher.process(req, null); + responseContent.append(resp); + writeResponse(ctx); + request = null; + decoder.destroy(); + decoder = null; + } + } + } else { + writeResponse(ctx); + } + } + + private void writeResponse(ChannelHandlerContext ctx) { + ByteBuf buf = Unpooled.copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8); + responseContent.setLength(0); + + boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION)) + || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) + && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION)); + FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf); + response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); + + if (!close) { + response.headers().set(CONTENT_LENGTH, buf.readableBytes()); + } + + ChannelFuture future = ctx.writeAndFlush(response); + if (close) { + future.addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } + } +} \ No newline at end of file diff --git a/ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/method/eth_coinbase.java b/ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/method/eth_coinbase.java new file mode 100644 index 00000000..d1cea209 --- /dev/null +++ b/ethereumj-core-android/src/main/java/org/ethereum/android/jsonrpc/method/eth_coinbase.java @@ -0,0 +1,29 @@ +package org.ethereum.android.jsonrpc.method; + +import com.thetransactioncompany.jsonrpc2.*; +import com.thetransactioncompany.jsonrpc2.server.*; +import org.ethereum.facade.Ethereum; + +public class eth_coinbase implements RequestHandler { + + private String name = ""; + private Ethereum ethereum; + + public eth_coinbase(Ethereum ethereum) { + this.ethereum = ethereum; + name = this.getClass().getSimpleName(); + } + + public String[] handledRequests() { + return new String[]{name}; + } + + public JSONRPC2Response process(JSONRPC2Request req, MessageContext ctx) { + if (req.getMethod().equals(name)) { + //TODO: place business logic here + return null; + } else { + return new JSONRPC2Response(JSONRPC2Error.METHOD_NOT_FOUND, req.getID()); + } + } +} \ No newline at end of file