support doip-cluster

This commit is contained in:
CaiHQ 2023-04-24 18:57:40 +08:00
parent 3f4d154d2b
commit 94f1b6dc7d
7 changed files with 197 additions and 43 deletions

View File

@ -40,17 +40,17 @@ dependencies {
implementation 'io.grpc:grpc-all:1.43.1'
implementation 'org.apache.velocity:velocity-engine-core:2.3'
implementation 'com.nimbusds:nimbus-jose-jwt:9.10'
implementation 'org.bdware.doip:doip-sdk:1.3.9'
implementation 'org.bdware.doip:doip-audit-tool:1.2.2'
implementation 'org.bdware.doip:bdosclient:0.0.2'
implementation 'org.bdware.doip:doip-sdk:1.4.2'
implementation 'org.bdware.doip:doip-audit-tool:1.2.6'
implementation 'org.bdware.doip:bdosclient:0.0.3'
implementation fileTree(dir: 'lib', include: '*.jar')
testImplementation 'junit:junit:4.13.2'
implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final-linux-aarch_64-fedora'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
// implementation 'io.netty:netty-tcnative-boringssl-static:2.0.59.Final'
}
compileJava {

View File

@ -15,6 +15,7 @@ import io.netty.util.TimerTask;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.sc.ContractManager;
import org.bdware.sc.ContractMeta;
import org.bdware.sc.YJSPacker;
import org.bdware.sc.bean.Contract;
import org.bdware.sc.bean.ContractExecType;
@ -135,10 +136,11 @@ public class FileActions {
request.protocolVersion(),
OK,
Unpooled.wrappedBuffer(
"{\"status\":\"false\",\"data\":\"Missing argument!\"}"
"{\"status\":\"false\",\"data\":\"Missing argument, please check: path, fileName, isPrivate, order, count, pubKey, sign!\"}"
.getBytes()));
ChannelFuture f = ctx.write(fullResponse);
ChannelFuture f = addCrossOriginHeaderAndWrite(ctx, fullResponse);
f.addListener(ChannelFutureListener.CLOSE);
return;
}
@ -236,7 +238,7 @@ public class FileActions {
"{\"status\":\"false\",\"data\":\"Permission denied!\"}"
.getBytes()));
ChannelFuture f = ctx.write(fullResponse);
ChannelFuture f = addCrossOriginHeaderAndWrite(ctx, fullResponse);
f.addListener(ChannelFutureListener.CLOSE);
return;
}
@ -249,16 +251,47 @@ public class FileActions {
new HttpPostRequestDecoder(new DefaultHttpDataFactory(true), request);
httpDecoder.setDiscardThreshold(0);
File dir;
boolean isPrivate =
transformedParam.containsKey("isPrivate")
&& Boolean.parseBoolean(transformedParam.get("isPrivate"));
// TODO verify signature and
if (isPrivate) {
String pub = "/" + transformedParam.get("pubKey");
dir = new File(GlobalConf.instance.projectDir + "/private" + pub, dirName);
if (transformedParam.containsKey("contractID")) {
String contractID = transformedParam.get("contractID");
ContractMeta meta = CMActions.manager.statusRecorder.getContractMeta(contractID);
if (meta == null) {
DefaultFullHttpResponse fullResponse =
new DefaultFullHttpResponse(
request.protocolVersion(),
OK,
Unpooled.wrappedBuffer(
"{\"status\":\"false\",\"data\":\"no such contract!\"}"
.getBytes()));
ChannelFuture f = addCrossOriginHeaderAndWrite(ctx, fullResponse);
f.addListener(ChannelFutureListener.CLOSE);
return;
}
if (!meta.contract.getOwner().equals(pubkey)) {
DefaultFullHttpResponse fullResponse =
new DefaultFullHttpResponse(
request.protocolVersion(),
OK,
Unpooled.wrappedBuffer(
"{\"status\":\"false\",\"data\":\"not owner!\"}"
.getBytes()));
ChannelFuture f = addCrossOriginHeaderAndWrite(ctx, fullResponse);
f.addListener(ChannelFutureListener.CLOSE);
return;
}
dir = new File(GlobalConf.instance.getDBPath(), meta.getName());
dir = new File(dir, dirName);
if (!dir.exists()) dir.mkdirs();
} else {
dir = new File(GlobalConf.instance.publicDir, dirName);
boolean isPrivate =
transformedParam.containsKey("isPrivate")
&& Boolean.parseBoolean(transformedParam.get("isPrivate"));
// TODO verify signature and
if (isPrivate) {
String pub = "/" + transformedParam.get("pubKey");
dir = new File(GlobalConf.instance.projectDir + "/private" + pub, dirName);
} else {
dir = new File(GlobalConf.instance.publicDir, dirName);
}
}
if (!dir.isDirectory()) {
dir = dir.getParentFile();
@ -273,7 +306,7 @@ public class FileActions {
"{\"status\":\"false\",\"data\":\"FileName illegal!\"}"
.getBytes()));
ChannelFuture f = ctx.write(fullResponse);
ChannelFuture f = addCrossOriginHeaderAndWrite(ctx, fullResponse);
f.addListener(ChannelFutureListener.CLOSE);
return;
}
@ -309,7 +342,9 @@ public class FileActions {
boolean isDebug =
transformedParam.containsKey("isDebug")
&& Boolean.parseBoolean(transformedParam.get("isDebug"));
String doi = unzipIfYpk(target, dir, isDebug);
String doi = null;
if (target.getParentFile().getParentFile().equals(new File(GlobalConf.instance.privateDir)))
doi = unzipIfYpk(target, dir, isDebug);
if (null != doi) {
retStr = retStr.replaceFirst("null", doi);
}
@ -317,11 +352,16 @@ public class FileActions {
DefaultFullHttpResponse fullResponse =
new DefaultFullHttpResponse(
request.protocolVersion(), OK, Unpooled.wrappedBuffer(retStr.getBytes()));
fullResponse.headers().add("Access-Control-Allow-Origin", "*");
ChannelFuture f = ctx.write(fullResponse);
ChannelFuture f = addCrossOriginHeaderAndWrite(ctx, fullResponse);
f.addListener(ChannelFutureListener.CLOSE);
}
private static ChannelFuture addCrossOriginHeaderAndWrite(ChannelHandlerContext ctx, DefaultFullHttpResponse fullResponse) {
fullResponse.headers().add("Access-Control-Allow-Origin", "*");
fullResponse.headers().add("Access-Control-Allow-Methods", "*");
return ctx.write(fullResponse);
}
public static String geneRandomID() {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();

View File

@ -126,7 +126,7 @@ public class BCOManager {
}
private File getYpkFile(YPKInfo ypkInfo) {
File f = new File(bcodir, ypkInfo.ypkName);
File f = new File(bcodir, ypkInfo.pkgName);
if (ypkInfo.version != null)
f = new File(f, ypkInfo.version);
f = new File(f, ypkInfo.md5 + ".ypk");

View File

@ -104,7 +104,7 @@ public class ContractRepositoryHandler extends RepositoryHandlerBase implements
c.setType(ContractExecType.valueOf(digitalObject.attributes.get("contractExecType").getAsString()));
else c.setType(ContractExecType.Sole);
if (digitalObject.attributes.has("shardingId"))
c.setType(ContractExecType.valueOf(digitalObject.attributes.get("shardingId").getAsString()));
c.setShardingId(Integer.valueOf(digitalObject.attributes.get("shardingId").getAsString()));
else c.setShardingId(-1);
c.setScript(path);
c.setOwner(doipMessage.credential.getSigner());

View File

@ -19,19 +19,20 @@ import org.bdware.server.GlobalConf;
import org.bdware.server.action.CMActions;
import org.zz.gmhelper.SM2KeyPair;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class ContractRepositoryMain {
private static final Logger LOGGER = LogManager.getLogger(ContractRepositoryMain.class);
static AuditDoipServer currentServer;
static LocalDoipFrowarder forwarder;
static final String repoType = "BDRepo";
public static void start() {
try {
LOGGER.info("DOIPServer, start" + new Gson().toJson(GlobalConf.instance.doaConf));
String url = GlobalConf.instance.doaConf.doipAddress;
forwarder = new LocalDoipFrowarder();
if (url == null || GlobalConf.instance.doaConf.repoDoid.isEmpty()) {
LOGGER.warn("missing args, failed to start! url:" + url + " doid:" + GlobalConf.instance.doaConf.repoDoid);
return;
@ -60,22 +61,22 @@ public class ContractRepositoryMain {
String id = message.header.parameters.id;
id = id.replaceAll(".*/", "");
ContractMeta meta = CMActions.manager.statusRecorder.getContractMeta(id);
builder.addAttributes("port", meta.contract.getDoipPort());
DoipMessage ret;
if (message.credential != null && message.credential.getSigner() != null) {
if (signer.verifyMessage(message)) {
ret = builder.create();
} else {
DoipMessageFactory.DoipMessageBuilder builder2 = new DoipMessageFactory.DoipMessageBuilder();
DoipMessageFactory.DoipMessageBuilder resp = builder2.createResponse(DoipResponseCode.UnAuth_Client, message);
resp.setBody("verify failed".getBytes(StandardCharsets.UTF_8));
ret = resp.create();
}
signer.signMessage(ret);
} else {
if (enableDelegate(meta)) {
LOGGER.info("delegate:" + message.requestID);
//if port is near cmhttp server port
builder.addAttributes("port", meta.contract.getDoipPort());
DoipMessage ret;
ret = builder.create();
if (message.credential != null && message.credential.getSigner() != null) {
signer.signMessage(ret);
}
return ret;
} else {
LOGGER.info("forward:" + message.requestID);
return forwarder.forward(meta, message);
}
return ret;
}
@Override
@ -97,4 +98,10 @@ public class ContractRepositoryMain {
LOGGER.warn("load doip config exception!");
}
}
private static boolean enableDelegate(ContractMeta meta) {
int port = meta.contract.getDoipPort();
int delta = Integer.valueOf(GlobalConf.instance.ipPort.split(":")[1]) - port;
return Math.abs(delta) < 200;
}
}

View File

@ -0,0 +1,58 @@
package org.bdware.server.doip;
import org.bdware.doip.codec.doipMessage.DoipMessage;
import org.bdware.doip.codec.doipMessage.DoipMessageFactory;
import org.bdware.doip.codec.doipMessage.DoipResponseCode;
import org.bdware.doip.endpoint.client.ClientConfig;
import org.bdware.doip.endpoint.client.DoipClientImpl;
import org.bdware.doip.endpoint.client.DoipMessageCallback;
import org.bdware.sc.ContractMeta;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;
public class LocalDoipFrowarder {
Map<Integer, DoipClientImpl> connections;
public LocalDoipFrowarder() {
connections = new HashMap<>();
}
public DoipMessage forward(ContractMeta meta, DoipMessage message) {
DoipClientImpl connection;
try {
if (connections.containsKey(meta.contract.getDoipPort())) {
connection = connections.get(meta.contract.getDoipPort());
} else {
connection = new DoipClientImpl();
connection.connect(ClientConfig.fromUrl("tcp://127.0.0.1:" + meta.contract.getDoipPort()));
connections.put(meta.contract.getDoipPort(), connection);
}
if (!connection.isConnected()) connection.reconnect();
DoipMessage[] result = new DoipMessage[1];
connection.sendRawMessage(message, new DoipMessageCallback() {
@Override
public void onResult(DoipMessage msg) {
synchronized (result) {
result[0] = msg;
result.notify();
}
}
});
synchronized (result) {
if (result[0] == null)
result.wait(30000L);
}
return result[0];
} catch (Exception e) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(bo));
DoipMessageFactory.DoipMessageBuilder builder = new DoipMessageFactory.DoipMessageBuilder();
builder.createResponse(DoipResponseCode.UnKnownError, message);
builder.setBody(bo.toByteArray());
return builder.create();
}
}
}

View File

@ -87,7 +87,11 @@ public class DOIPOverHttpHandler {
sendListContractProcess(arg, ctx);
return;
case Retrieve:
sendAssets(arg, ctx);
if (arg.has("__public") && arg.get("__public").getAsBoolean()) {
sendPublicFiles(arg, ctx);
} else {
sendAssets(arg, ctx);
}
return;
case RetrieveYPK:
sendYpk(arg, ctx, request);
@ -163,6 +167,45 @@ public class DOIPOverHttpHandler {
return;
}
private void sendPublicFiles(JsonObject arg, ChannelHandlerContext ctx) throws Exception {
ContractMeta meta =
CMActions.manager.statusRecorder.getContractMeta(
arg.get("contractID").getAsString());
if (meta == null) {
HttpFileHandleAdapter.sendError(ctx, HttpResponseStatus.NOT_FOUND);
return;
}
String path = arg.get("argument").getAsString();
File dir = new File("./ContractDB", meta.getName());
File toSend = new File(dir, path);
FileInputStream fin;
try {
if (!toSend.exists() || toSend.isDirectory()) {
HttpFileHandleAdapter.sendError(ctx, HttpResponseStatus.NOT_FOUND);
return;
} else
fin = new FileInputStream(toSend);
} catch (Exception e) {
HttpFileHandleAdapter.sendError(ctx, HttpResponseStatus.NOT_FOUND);
return;
}
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.OK);
HttpFileHandleAdapter.appendContentType(path, response.headers());
ctx.write(response);
ChannelFuture future = ctx.writeAndFlush(new ChunkedStream(fin));
future.addListener(
new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> arg0) throws Exception {
ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
fin.close();
}
});
// 写入文件尾部
future.addListener(ChannelFutureListener.CLOSE);
return;
}
private void sendAssets(JsonObject arg, ChannelHandlerContext ctx) throws Exception {
ContractMeta meta =
CMActions.manager.statusRecorder.getContractMeta(
@ -225,7 +268,6 @@ public class DOIPOverHttpHandler {
}
private void injectExtraArgs(JsonObject transformedParam, String fulluri) {
String[] data = fulluri.split("/");
String contractIDOrName = data[2];
String uris[] = URLDecoder.decode(fulluri).split("\\?");
@ -253,7 +295,8 @@ public class DOIPOverHttpHandler {
transformedParam.addProperty("contractID", data[2].replaceAll("\\?.*$", ""));
if (data.length > 3) {
String assetPath = data[3];
if (assetPath.equals("assets")) {
transformedParam.remove("__public");
if (assetPath.equals("assets") && !fulluri.contains("..")) {
transformedParam.addProperty("operation", Operations.Retrieve.val);
int index = data[0].length() + data[1].length() + data[2].length() + 2;
String path = fulluri.substring(index);
@ -261,6 +304,12 @@ public class DOIPOverHttpHandler {
if (path.equals("/assets/"))
path += "index.html";
transformedParam.addProperty("argument", path);
} else if (assetPath.equals("public") && !fulluri.contains("..")) {
transformedParam.addProperty("operation", Operations.Retrieve.val);
int index = data[0].length() + data[1].length() + data[2].length() + 2;
String path = fulluri.substring(index);
transformedParam.addProperty("argument", path);
transformedParam.addProperty("__public", true);
}
if (assetPath.startsWith("ypk?")) {
transformedParam.addProperty("operation", Operations.RetrieveYPK.val);