cp/src/main/java/org/bdware/sc/boundry/JavaScriptEntry.java
2021-09-29 17:55:13 +08:00

743 lines
29 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package org.bdware.sc.boundry;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.sc.ContractProcess;
import org.bdware.sc.bean.ContractRequest;
import org.bdware.sc.boundry.utils.SQLUtil;
import org.bdware.sc.conn.ResultCallback;
import org.bdware.sc.conn.SocketGet;
import org.bdware.sc.engine.DesktopEngine;
import org.bdware.sc.engine.SyncMechUtil;
import org.bdware.sc.event.REvent;
import org.bdware.sc.http.ApiGate;
import org.bdware.sc.syncMech.SyncType;
import org.bdware.sc.util.HashUtil;
import org.bdware.sc.util.JsonUtil;
import org.zz.gmhelper.SM2KeyPair;
import wrp.jdk.nashorn.api.scripting.NashornScriptEngine;
import wrp.jdk.nashorn.internal.objects.Global;
import wrp.jdk.nashorn.internal.runtime.PropertyMap;
import wrp.jdk.nashorn.internal.runtime.ScriptFunction;
import wrp.jdk.nashorn.internal.runtime.ScriptObject;
import wrp.jdk.nashorn.internal.scripts.JO;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.security.Security;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.bdware.sc.event.REvent.REventType.*;
public class JavaScriptEntry {
// private static final HostnameVerifier DO_NOT_VERIFY = (hostname, session) -> true;
public static final Map<String, ScriptFunction> topic_handlers = new HashMap<>();
private static final Logger LOGGER = LogManager.getLogger(JavaScriptEntry.class);
public static NashornScriptEngine currentEngine;
public static SyncMechUtil currentSyncUtil;
// public static int contractManagerPort;
public static Random random;
public static long invokeID;
public static String doi;
public static String authInfoPersistDOI;
public static SocketGet get; // public static CloseableHttpClient httpClient = getHttpClient();
public static int numOfCopies;
public static boolean isDebug;
public static List<REvent> msgList;
public static int shadingId;
// private static SM2KeyPair keyPair = new SM2().generateKeyPair(); // TODO 本地服务器的,39上运行39的
// public static String privKey;
// public static String pubKey;
private static SM2KeyPair keyPair;
public static void setSM2KeyPair(String pubKey, String privKey) {
keyPair =
new SM2KeyPair(
SM2KeyPair.publicKeyStr2ECPoint(pubKey), new BigInteger(privKey, 16));
}
public static SM2KeyPair getKeyPair() {
return keyPair;
}
public static Global getEngineGlobal() {
return currentEngine.getNashornGlobal();
}
public static String byteArrayHash(byte[] hash) {
return HashUtil.hashByteArray(hash);
}
public static Connection getMysqlConnection(String url, String usrName, String pwd) {
return SQLUtil.getConnection("jdbc:mysql://" + url, usrName, pwd);
}
public static String example(String arg) {
LOGGER.debug("called: " + arg);
return arg + 1;
}
// public static MongoClient connectMongoDb(String url, int port, String dbName, String usrName,
// String pwd) {
// return getMongoDBConnection(url, port, dbName, usrName, pwd);
// }
//
// public static MongoClient getMongoDBConnection(String url, int port, String dbName, String
// usrName, String pwd) {
// return MongoDBUtil.connect(url, port, dbName, usrName, pwd);
// }
public static String bytes2Str(byte[] bytes) {
return new String(bytes);
}
public static Object connectNeo4j(String url, String usrName, String pwd) {
try {
if (url.startsWith("jdbc:neo4j")) {
Connection con;
con = DriverManager.getConnection(url, usrName, pwd);
return con;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static long currentTimeMillis() {
return System.currentTimeMillis();
}
public static Lock createLock() {
return new ReentrantLock();
}
public static String asyncTest(String str, ScriptFunction fun) {
LOGGER.debug(str);
DesktopEngine.applyWithGlobal(fun, currentEngine.getNashornGlobal(), str);
return "success";
}
// public static String http(String baseUrl, String method, Map<String, String> header,
// Map<String, String> argMap,
// List<String> reservedList) {
// return HttpUtil.request(baseUrl, method, header, argMap, reservedList);
// }
public static byte[] inputStreamToBytes(InputStream in) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] buff = new byte[4 * 1024 * 1024];
try {
for (int count; (count = in.read(buff)) > 0; ) {
bo.write(buff, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
}
return bo.toByteArray();
}
// private static String list2Str(List<String> reservedList) {
// return JsonUtil.toJson(reservedList);
// }
//
// private static String map2Str(Map<String, Object> map) {
// return JsonUtil.toJson(map);
// }
// private static CloseableHttpClient getHttpClient(String url) {
// try {
// SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
//
// @Override
// public boolean isTrusted(java.security.cert.X509Certificate[] arg0, String arg1)
// throws java.security.cert.CertificateException {
// return true;
// }
// }).build();
//
// SSLConnectionSocketFactory sslSf = new SSLConnectionSocketFactory(sslcontext, null, null,
// new NoopHostnameVerifier());
// int tle = 10;
// if (url.contains("data.tj.gov.cn"))
// tle = 3;
// return HttpClients.custom().setSSLSocketFactory(sslSf)
// .setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
// @Override
// public long getKeepAliveDuration(HttpResponse arg0, HttpContext arg1) {
// return 0;
// }
// }).setConnectionTimeToLive(tle, TimeUnit.SECONDS).build();
//
// } catch (Exception e) {
// e.printStackTrace();
// }
// return null;
// }
public static InputStream httpAsInputStream(String url) {
try {
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
return conn.getInputStream();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// public static String httpPost(String str) {
// System.out.println("JavaSScriptEntry httpPost:" + str);
// PostRequest req = new PostRequest();
// req = JsonUtil.fromJson(str, PostRequest.class);
// // System.out.println("url========>" + req.url);
// // System.out.println("data=======>" + req.data);
//
// Result r = new Result();
// try {
// URL url = new URL(req.url);//
// HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// connection.setDoOutput(true);
// connection.setDoInput(true);
// connection.setUseCaches(false);
// connection.setInstanceFollowRedirects(true);
// connection.setRequestMethod("POST"); // 璁剧疆璇锋眰鏂瑰紡
// connection.setRequestProperty("Accept", "application/json"); // 璁剧疆鎺ユ敹鏁版嵁鐨勬牸寮<E789B8>
// connection.setRequestProperty("Content-Type", "application/json"); // 璁剧疆鍙戦<E98D99>佹暟鎹殑鏍煎紡
// connection.connect();
// OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); //
// utf-8缂栫爜
// out.append(req.data);
// out.flush();
// out.close();
//
// r.resposeCode = connection.getResponseCode();
// InputStream input = connection.getInputStream();
//
// Scanner sc = new Scanner(input);
// StringBuilder sb = new StringBuilder();
// for (; sc.hasNextLine();) {
// sb.append(sc.nextLine()).append("\n");
// }
// sc.close();
// r.response = sb.toString();
// return JsonUtil.toJson(r);
// } catch (Throwable e) {
// r.resposeCode = 505;
// // ByteArrayOutputStream bo = new ByteArrayOutputStream();
// // e.printStackTrace(new PrintStream(bo));
// r.response = e.getMessage();
// return JsonUtil.toJson(r);
// }
// }
public static void executeFunction(ScriptFunction callback, Object arg) {
DesktopEngine.applyWithGlobal(callback, currentEngine.getNashornGlobal(), arg);
}
public static ApiGate createAPIGate(String ip) {
return new ApiGate(ip);
}
public static ApiGate createAPIGate(String ip, String port) {
return new ApiGate(ip, Integer.parseInt(port));
}
public static String executeContractWithSig(
String contractID, String action, String arg, String pubkey, String sig) {
try {
ContractRequest app = new ContractRequest();
app.setContractID(contractID).setAction(action).setArg(arg);
app.setPublicKey(pubkey);
app.setSignature(sig);
app.fromContract = keyPair.getPublicKeyStr();
if (!app.verifySignature()) {
return "{\"status\":\"Exception\",\"data\":\"invalid signature\"}";
}
app.setRequesterDOI(doi);
app.setFromDebug(isDebug);
if (numOfCopies > 1) {
// The caller is special.
app.setRequestID(
app.getPublicKey().hashCode()
+ "_"
+ numOfCopies
+ "_"
+ (invokeID++)
+ "_"
+ random.nextInt()
+ "_mul");
} else {
app.setRequestID(
app.getPublicKey().hashCode()
+ "_"
+ (invokeID++)
+ "_"
+ random.nextInt());
}
return get.syncGet("dd", "executeContract", JsonUtil.toJson(app));
} catch (Exception e) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(bo));
return bo.toString();
}
}
public static String executeContract(String contractID, String action, String arg) {
if (currentSyncUtil.engine.recovering) {
String str =
currentSyncUtil.transRecoverUtil.curRecoverRecord.getExecuteResult(
invokeID + "");
String[] strs = str.split("<seperate>");
String flag1 = strs[0];
String flag = strs[1];
String res = strs[2];
if (flag1.equals("1")) {
invokeID++;
}
if (flag.equals("1")) {
random.nextInt();
}
return res;
}
long formerInvokeID = invokeID;
int flag1 = 0; // 标志invokeID++操作是否进行过
int flag = 0; // 标志random是否取下一个
try {
ContractRequest app = new ContractRequest();
app.setContractID(contractID).setAction(action).setArg(arg);
app.doSignature(keyPair);
app.setRequesterDOI(doi);
app.setFromDebug(isDebug);
if (numOfCopies > 1) {
app.setRequestID(
String.format(
"%d_%d_%d_%d_mul",
keyPair.getPublicKeyStr().hashCode(),
numOfCopies,
(invokeID++),
random.nextInt()));
// The caller is special.
flag = 1;
flag1 = 1;
LOGGER.warn("invoke contractExecution! " + JsonUtil.toJson(app));
} else {
app.setRequestID(
String.format(
"%d_%d_%d",
keyPair.getPublicKeyStr().hashCode(),
(invokeID++),
random.nextInt()));
flag = 1;
flag1 = 1;
}
return executeContract(formerInvokeID, flag1, flag, app);
} catch (Exception e) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(bo));
String result = bo.toString();
if (currentSyncUtil.startFlag
&& currentSyncUtil.currType == SyncType.Trans
&& !currentSyncUtil.engine.recovering) {
currentSyncUtil.transRecordUtil.recordExecutes(
formerInvokeID + "", flag1 + "<seperate>" + flag + "<seperate>" + result);
}
return result;
}
}
private static String executeContract(long formerInvokeID, int flag1, int flag, ContractRequest app) {
String result = get.syncGet("dd", "executeContract", JsonUtil.toJson(app));
if (currentSyncUtil.startFlag
&& currentSyncUtil.currType == SyncType.Trans
&& !currentSyncUtil.engine.recovering) {
currentSyncUtil.transRecordUtil.recordExecutes(
formerInvokeID + "",
flag1 + "<seperate>" + flag + "<seperate>" + result);
}
return result;
}
public static void executeContractAsyncWithoutSig(
String contractID, String action, String arg, final ScriptFunction cb) {
try {
ContractRequest app = new ContractRequest();
app.setContractID(contractID).setAction(action).setArg(arg);
app.setRequestID((invokeID++) + "_" + random.nextInt());
get.asyncGet(
"dd",
"executeContract",
JsonUtil.toJson(app),
new ResultCallback() {
@Override
public void onResult(String str) {
if (null != cb) {
DesktopEngine.applyWithGlobal(
cb, currentEngine.getNashornGlobal(), str);
}
}
});
} catch (Exception e) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(bo));
}
}
/* public static String executeContract(String contractID, String action, String arg) {
//redo,use record data
if(currentSyncUtil.transRecoverUtil != null && currentSyncUtil.transRecoverUtil.recovering){
String k = TransRecordUtil.produceExecuteIdentifier(contractID,action,arg);
return currentSyncUtil.transRecoverUtil.curRecoverRecord.getExecuteResult(k);
}
try {
ContractRequest app = new ContractRequest();
app.setContractID(contractID).setAction(action).setArg(arg);
//app.doSignature(keyPair.getPrivateKey().toString(16));
app.doSignature(keyPair);
String result = get.syncGet("dd", "executeContract", JsonUtil.toJson(app));
if(currentSyncUtil.startFlag && currentSyncUtil.currType == SyncType.Trans){
String k = currentSyncUtil.transRecordUtil.produceExecuteIdentifier(contractID,action,arg);
currentSyncUtil.transRecordUtil.recordExecutes(k,result);
}
return result;
} catch (Exception e) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(bo));
String result = bo.toString();
if(currentSyncUtil.startFlag && currentSyncUtil.currType == SyncType.Trans){
String k = TransRecordUtil.produceExecuteIdentifier(contractID,action,arg);
currentSyncUtil.transRecordUtil.recordExecutes(k,result);
}
return result;
}
}*/
// public static String queryContractIdByDOI(String contractDOI) throws Exception {
// DigitalObject contractDO;
// DoipClient doipClient =
// DoipClient.createByRepoUrlAndMsgFmt(
// DOIPMainServer.repoUrl, DoipMessageFormat.PACKET.getName());
// DoMessage response = doipClient.retrieve(contractDOI, null, null);
// if (response.parameters.response == DoResponse.Success) {
// contractDO = DigitalObject.parse(response.body);
// } else {
// response = DOAClient.getGlobalInstance().retrieve(contractDOI, null, null);
// contractDO = DigitalObject.parse(response.body);
// }
// ContractInstanceDO contractInstanceDO =
// (ContractInstanceDO)
// ContractManager.toObject(contractDO.elements.get(0).getData());
// return contractInstanceDO.id;
// }
// public static String executeContractByDOI(String contractDOI, String action, String arg) {
// try {
// String contractID = queryContractIdByDOI(contractDOI);
// return executeContract(contractID, action, arg);
// } catch (Exception e) {
// ByteArrayOutputStream bo = new ByteArrayOutputStream();
// e.printStackTrace(new PrintStream(bo));
// return bo.toString();
// }
// }
//
// public static String getAuthInfo() {
// try {
// DigitalObject contractDO;
// DoipClient doipClient =
// DoipClient.createByRepoUrlAndMsgFmt(
// DOIPMainServer.repoUrl, DoipMessageFormat.PACKET.getName());
// DoMessage response = doipClient.retrieve(authInfoPersistDOI, null, null);
// if (response.parameters.response != DoResponse.Success) {
// response = DOAClient.getGlobalInstance().retrieve(authInfoPersistDOI, null,
// null);
// }
// contractDO = DigitalObject.parse(response.body);
// return new String(contractDO.elements.get(0).getData());
// } catch (Exception e) {
// ByteArrayOutputStream bo = new ByteArrayOutputStream();
// e.printStackTrace(new PrintStream(bo));
// return "Failed: " + bo.toString();
// }
// }
//
// public static String setAuthInfo(String authInfo) {
// try {
//
// DigitalObject contractDO = new DigitalObject(authInfoPersistDOI, DoType.Json);
// Element e = new Element("authInfo", "JsonString");
// e.setData(authInfo.getBytes());
// contractDO.addElements(e);
//
// DoipClient doipClient =
// DoipClient.createByRepoUrlAndMsgFmt(
// DOIPMainServer.repoUrl, DoipMessageFormat.PACKET.getName());
// DoMessage response = doipClient.update(contractDO);
// if (response.parameters.response != DoResponse.Success) {
// DoHandleRecord dohr =
// DOAClient.getGlobalInstance().resolveDO(authInfoPersistDOI);
// if (dohr == null) {
// return "Failed: Can not resolve authInfoPersistDOI: " +
// authInfoPersistDOI;
// }
// ServiceHandleRecord repoHandleRecord =
// DOAClient.getGlobalInstance().resolveDOIPService(dohr.repository);
// doipClient =
// DoipClient.createByRepoUrlAndMsgFmt(
// repoHandleRecord.getListenerInfos().get(0).url,
// DoipMessageFormat.PACKET.getName());
// response = doipClient.update(contractDO);
// if (response.parameters.response != DoResponse.Success) {
// return "Failed: Can not update authInfoPersistDOI: " + authInfoPersistDOI;
// }
// }
// return "Succeeded";
// } catch (Exception e) {
// ByteArrayOutputStream bo = new ByteArrayOutputStream();
// e.printStackTrace(new PrintStream(bo));
// return "Failed: " + bo.toString();
// }
// }
public static String executeContractAsync(
String contractID, String action, String arg, final ScriptFunction cb) {
try {
ContractRequest app = new ContractRequest();
app.setContractID(contractID).setAction(action).setArg(arg);
app.doSignature(keyPair);
app.setRequestID((invokeID++) + "_" + random());
app.setRequesterDOI(doi);
get.asyncGet(
"dd",
"executeContract",
JsonUtil.toJson(app),
new ResultCallback() {
@Override
public void onResult(String str) {
if (cb != null) {
DesktopEngine.applyWithGlobal(
cb, currentEngine.getNashornGlobal(), str, arg);
}
}
});
return "success";
} catch (Exception e) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(bo));
return bo.toString();
}
}
/**
* publish an event with semantic AT_LEAST_ONCE
*
* @param topic the topic
* @param content the content
* @author Kaidong Wu
*/
public static void pubEvent(String topic, String content) {
pubEventConstraint(topic, content, null);
}
/**
* publish an event with some semantic
*
* @param topic the topic
* @param content the content
* @param constraint the constraint, AT_LEAST_ONCE, AT_MOST_ONCE, and ONLY_ONCE
* @author Kaidong Wu
*/
public static void pubEventConstraint(String topic, String content, String constraint) {
String reqID =
String.format(
"%d_%d_%d_%s_pe",
keyPair.getPublicKeyStr().hashCode(), numOfCopies, invokeID, random());
REvent msg = new REvent(topic, PUBLISH, content, reqID);
if (null != constraint) {
msg.setSemantics(REvent.REventSemantics.valueOf(constraint));
}
msgList.add(msg);
}
/**
* subscribe a topic
*
* @param topic event topic
* @param fun related handler function
* @author Kaidong Wu
*/
public static void subscribe(String topic, ScriptFunction fun) {
subscribe(topic, fun, false);
if (topic_handlers.containsKey(topic)) {
ContractProcess.instance.unSubscribe(topic_handlers.get(topic).getName());
}
topic_handlers.put(topic, fun);
}
private static void subscribe(String topic, ScriptFunction fun, boolean fromPreSub) {
String reqID =
String.format(
"%d_%d_%d_%s_se",
keyPair.getPublicKeyStr().hashCode(), numOfCopies, invokeID, random());
REvent msg =
new REvent(
topic,
SUBSCRIBE,
String.format(
"{\"subscriber\":\"%s\",\"handler\":\"%s\"}",
ContractProcess.instance.getContractName(), fun.getName()),
reqID);
if (fromPreSub) {
msg.setSemantics(REvent.REventSemantics.ONLY_ONCE);
}
msgList.add(msg);
ContractProcess.instance.subscribe(fun.getName());
}
public static void unsubscribe(String topic) {
String reqID =
String.format(
"%d_%d_%d_%s_us",
keyPair.getPublicKeyStr().hashCode(), numOfCopies, invokeID, random());
String content;
if (null == topic) {
content = "{\"subscriber\":\"" + ContractProcess.instance.getContractName() + "\"}";
topic_handlers.forEach((k, c) -> {
topic_handlers.remove(k);
ContractProcess.instance.unSubscribe(c.getName());
});
} else {
String handler = topic_handlers.get(topic).getName();
content =
String.format(
"{\"subscriber\":\"%s\",\"handler\":\"%s\"}",
ContractProcess.instance.getContractName(), handler);
topic_handlers.remove(topic);
ContractProcess.instance.unSubscribe(handler);
}
REvent msg =
new REvent(
topic,
UNSUBSCRIBE,
content,
reqID);
msgList.add(msg);
}
/**
* pre-sub in ONLY_ONCE
*
* @param topic the topic
* @param content the content
* @author Kaidong Wu
*/
public static void preSub(String topic, String content) {
String newTopic = topic + "|" + content + "|" + ContractProcess.instance.getContractName();
subscribe(newTopic, topic_handlers.get(topic), true);
String reqID =
String.format(
"%d_%d_%d_%s_pse",
keyPair.getPublicKeyStr().hashCode(), numOfCopies, (invokeID++), random());
REvent msg = new REvent(topic, REvent.REventType.PRESUB, newTopic, reqID);
msg.setSemantics(REvent.REventSemantics.ONLY_ONCE);
msgList.add(msg);
}
/**
* @return a random value with string format
* @author Kaidong Wu
*/
public static String random() {
String seed = String.valueOf(null == random ? System.currentTimeMillis() : random.nextInt());
return HashUtil.sha3(seed);
}
public static String getContractInfo(String topic) {
return null;
// TODO
}
public static String sendEmail(String json) {
try {
final JsonObject jo = JsonParser.parseString(json).getAsJsonObject();
Properties props = new Properties();
props.setProperty("mail.debug", "false");
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.smtp.host", jo.get("host").getAsString());
props.setProperty("mail.smtp.port", jo.get("port").getAsString());
props.setProperty("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", "true");
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.socketFactory.port", jo.get("port").getAsString());
Session session =
Session.getDefaultInstance(
props,
new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(
jo.get("from").getAsString(),
jo.get("pwd").getAsString()); // 发件人邮件用户名、密码
}
});
// 创建邮件对象
Message msg = new MimeMessage(session);
msg.setSubject(jo.get("subject").getAsString());
msg.setText(jo.get("content").getAsString());
msg.setFrom(new InternetAddress(jo.get("from").getAsString()));
msg.addRecipient(
Message.RecipientType.TO, new InternetAddress(jo.get("to").getAsString()));
Transport.send(msg);
} catch (Exception e) {
e.printStackTrace();
return "failed";
}
return "success";
}
public static ScriptObject getCaller(int i) {
JO ret = new JO(PropertyMap.newMap());
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
if (stacktrace.length > i + 2) {
ret.put("name", stacktrace[i + 2].getMethodName(), false);
ret.put("file", stacktrace[i + 2].getFileName(), false);
}
return ret;
}
public static class Result {
public int responseCode;
public String response;
}
static class PostRequest {
String url;
String data;
}
}