/*
* Neiro Technology 2011-2014
*/
package psconsole;
import java.awt.EventQueue;
import java.net.*;
import java.io.*;
import java.util.*;
import textsockets.*;
import psconsole.UserItemRenderer.UserItemValue;
/**
* Серверная логика Pending Script Console
* @author deathNC
*/
public class ServerConsole {
public ServerConsole(int port, MainForm form) throws IOException {
this.form = form;
server = new ServerSocket(port);
connections = new ArrayList<>();
isStopped = false;
pkgCount = 0;
startThreads();
}
/**
* Поиск сокета, связанного с торговым счётом accID
* @param accID Account ID (номер торгового счёта)
* @return null, если терминала с указанным accID нет в списке
*/
public Terminal get(long accID) {
synchronized (connections) {
for (Terminal conn : connections)
if (accID == conn.accID) return conn;
}
return null;
}
/**
* Запускает поток обнаружения новых клиентов
*/
private void startThreads() {
// -- ожидание новых подключений
Thread clientSearching = new Thread(new Runnable() {
@Override
public void run() {
while (!isStopped) {
try {
Socket s = server.accept();
if (s != null) {
Terminal terminal = new Terminal(s);
synchronized (ServerConsole.this.connections) {
connections.add(terminal);
}
debug("searcher: client connected");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
clientSearching.start();
Thread orderHistorySender = new Thread(new Runnable() {
@Override
public void run() {
while (!isStopped) {
try {
Thread.sleep(10000);
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
List<Terminal> list = form.server.getConnectionsList();
for (Terminal t : list) {
UserItemValue item = form.getUser(t.getID());
if (item == null) continue;
PSPackage pkg = new PSPackage();
pkg.set("cmd", "historyID");
OrderList.OrderItem order = item.history.getLastByID();
pkg.set("id", Long.toString(order != null ? order.id : -1));
t.sendPackage(pkg);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
orderHistorySender.setDaemon(true);
orderHistorySender.start();
}
/**
* Завершение работы сервера
*/
public synchronized void stop() {
isStopped = true;
}
/**
* Возвращает список всех соединений
* @return ArrayList. Пустой лист, если соединение нет (not null)
*/
public List<Terminal> getConnectionsList() {
synchronized (connections) {
List<Terminal> list = new ArrayList<>(connections.size() + 4);
for (Terminal t : connections)
list.add(t);
return list;
}
}
public void packageCounter() {
synchronized (this) {
++pkgCount;
}
try {
final long cnt = pkgCount;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
form.lblPkgCounter.setText("package count: " + pkgCount);
}
});
} catch (Exception e) {
}
}
private final List<Terminal> connections;
private volatile boolean isStopped;
private final ServerSocket server;
private volatile long pkgCount;
private final MainForm form;
public class Terminal extends PSSocket {
public Terminal(Socket client) {
super(client);
accID = -1;
}
@Override
public void onPackage(PSPackage pkg) {
String cmd = pkg.get("cmd");
ServerConsole.this.packageCounter();
if (cmd == null || cmd.isEmpty()) return;
//<editor-fold desc=" stop ">
else if ("stop".equals(cmd)) {
this.stop();
System.out.println("отключение клиента");
}
//</editor-fold>
//<editor-fold desc=" Инициализация ">
else if ("init".equals(cmd)) {
accID = Integer.parseInt(pkg.get("accID"));
//debug("init clien: " + accID);
StringTokenizer st = new StringTokenizer(pkg.get("prm"), "=,");
double b = 0.0;
double p = 0.0;
String currency = null;
// -- разбор параметров
while (st.hasMoreTokens()) {
String nm = st.nextToken();
if (!st.hasMoreTokens()) break;
String vl = st.nextToken();
if ("b".equalsIgnoreCase(nm))
b = Double.parseDouble(vl);
else if ("p".equalsIgnoreCase(nm))
p = Double.parseDouble(vl);
else if ("currency".equalsIgnoreCase(nm))
currency = vl.toUpperCase();
}
// -- синхронно сообщаем форме, что подключился терминал
final PSPackage ans = new PSPackage();
ans.set("cmd", "init");
final PSPackage _pkg = pkg;
final double bal = b, prof = p;
final String crnc = currency;
try {
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
boolean flag = false;
UserItemValue user = form.getUser(accID);
if (user == null) {
user = new UserItemValue(accID);
flag = true;
}
user.terminalAddress = _pkg.get("executableAddress");
user.balance = bal;
user.profit = prof;
user.terminalConnected = true;
user.currency = crnc;
if (flag) {
form.addUser(user);
form.saveUserList();
}
ans.set("symbols", form.symbolList.getSymbolList());
OrderList.OrderItem order = user.history.getLastByID();
if (order != null)
ans.set("lastHistOrderID", Long.toString(order.id));
else ans.set("lastHistOrderID", Long.toString(-1));
}
});
// -- отправка ответа
sendPackage(ans);
} catch (Exception e) {
e.printStackTrace();
}
}
//</editor-fold>
//<editor-fold desc=" Обновление информации ">
else if ("data-update".equals(cmd)) {
final double b = Double.parseDouble(pkg.get("balance"));
final double p = Double.parseDouble(pkg.get("profit"));
String sbuf = pkg.get("time");
final long tm = (sbuf == null ? 0L : Integer.parseInt(sbuf) * 1000L);
// -- вытаскиваем ордера
String str = pkg.get("orders");
PSPackage orderspkg = null;
if (str != null) {
orderspkg = new PSPackage();
if (!orderspkg.unpack(new StringBuilder(str)))
orderspkg = null;
}
final PSPackage _opkg = orderspkg;
// -- обновление информации о символах
final String symbolData = pkg.get("symbols");
try {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
UserItemValue item = form.getUser(accID);
if (item == null) return;
// получение списока ордеров в аккаунте
if (_opkg != null) {
item.orders.refreshOrders(_opkg, true);
}
// обновление серверного времени
if (tm != 0L)
form.setCurrentTime(tm);
// обновление данных аккаунта
boolean flag =
Math.abs(item.balance - b) > 1d ||
Math.abs(item.profit - p) > 1d;
item.balance = b;
item.profit = p;
if (flag) form.lstUsers.repaint();
// -- обновление MarketInfo
if (symbolData != null)
form.symbolList.refreshSymbolData(symbolData);
// обновление панелей
List<UserItemValue> uList = form.getSelectedUsers();
if (uList.contains(item))
form.onUserSelected(uList, form.paneCurrent);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
//</editor-fold>
//<editor-fold desc=" История ордеров ">
else if ("orders-history".equals(cmd)) {
try {
final PSPackage _pkg = pkg;
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
UserItemValue user = form.getUser(accID);
if (user != null) {
user.history.refreshOrders(_pkg, false);
user.saveOrdersHistory();
}
// обновление панелей
List<UserItemValue> uList = form.getSelectedUsers();
if (uList.contains(user))
form.onUserSelected(uList, form.paneCurrent);
}
});
} catch (Exception e) {
}
}
//</editor-fold>
//<editor-fold desc=" log ">
else if ("log".equals(cmd)) {
try {
//System.out.println(" >> LOG >> " + pkg.get("text"));
final String logText = pkg.get("text");
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
form.txtLogText.append("\n" + logText + "\n");
}
});
} catch (Exception e) {
}
}
//</editor-fold>
else { debug("cmd: " + cmd); }
}
@Override
public void onClosed(Socket socket) {
try {
synchronized (ServerConsole.this.connections) {
connections.remove(this);
System.out.println("count connections: " + connections.size());
}
if (accID != 0) {
synchronized (form) {
UserItemValue item = form.getUser(accID);
if (item != null) {
item.terminalConnected = false;
form.lstUsers.repaint();
}
}
}
if (!socket.isClosed()) socket.close();
} catch (IOException error) {
error.printStackTrace();
}
}
/**
* Возвращает ID аккаунта, который в данный момент связан с соединением
* @return int
*/
public long getID() {
return accID;
}
public volatile long accID;
}
public void debug(Object x) {
System.out.println(x);
}
// <editor-fold desc=" баловство ">
private static String generateID() {
Random rand = new Random();
return Long.toHexString(System.currentTimeMillis()) + Integer.toHexString(rand.nextInt(16));
}
private static double f_x(int index) {
return Math.sqrt(index);
}
private static double calc_N(int i, int stepCount) {
if (i >= stepCount) return f_x(i);
else return f_x(i) + ( 1 / calc_N(i + 1, stepCount) );
}
public static String getCurrencyStr(double value) {
long x = (long)(value * 100);
long m = x % 100;
String dr;
if (m < 1) dr = "";
else if (m % 10 == 0) dr = "." + (m / 10);
else dr = "." + (m >= 10 ? Long.toString(m) : "0" + m);
StringBuilder s = new StringBuilder(Long.toString(x / 100));
StringBuilder n = new StringBuilder();
while (s.length() > 0) {
if (n.length() > 0) n.insert(0, ' ');
int i = s.length() - 3;
if (i < 0) i = 0;
n.insert(0, s.substring(i, s.length()));
s.delete(i, s.length());
}
return n.toString() + dr;
}
public static String doubleToStr(double value, int digits) {
double mult = digits > 0 ? Math.pow(10, digits) : 1d;
long x = (long)(value * mult);
String s = Long.toString(x);
StringBuilder sb = new StringBuilder();
if (digits > 0) {
sb.append('.');
sb.append(s.substring(s.length() - digits, s.length()));
s = s.substring(0, s.length() - digits);
}
sb.insert(0, s);
return sb.toString();
}
public static void main(String[] args) throws Exception {
byte[] b = "+79234326358".getBytes();
for (int i = 0; i < b.length; ++i)
System.out.print(Byte.toString(b[i]));
}
// </editor-fold>
}