· 6 years ago · May 05, 2019, 06:10 PM
1package de.helight.fasciculus.server;
2
3import com.mongodb.async.client.MongoCollection;
4import de.helight.fasciculus.database.MongoConfig;
5import de.helight.fasciculus.database.PlayerEntity;
6import de.helight.fasciculus.packets.Packet;
7import de.helight.fasciculus.server.modules.ModuleLoader;
8import de.helight.fasciculus.universal.PacketRegistry;
9import de.helight.fasciculus.networking.client.ServerConnector;
10import de.helight.fasciculus.networking.handler.ConnectionHandler;
11import de.helight.fasciculus.packets.responses.UnsuccessfulLoginPacket;
12import io.jsonwebtoken.SignatureAlgorithm;
13import io.jsonwebtoken.security.Keys;
14import io.netty.buffer.Unpooled;
15import io.netty.channel.ChannelFutureListener;
16import io.netty.channel.ChannelHandlerContext;
17import lombok.Cleanup;
18import lombok.Getter;
19import lombok.SneakyThrows;
20import lombok.extern.flogger.Flogger;
21import me.helight.unilib.UniLib;
22import me.helight.unilib.concurrent.Delayed;
23import me.helight.unilib.configuration.ConfigFactory;
24import me.helight.unilib.database.DataSource;
25import me.helight.unilib.database.mongodb.MongoConnector;
26import me.helight.unilib.database.mongodb.MongoFactory;
27import me.helight.unilib.database.mongodb.MongoSource;
28
29import javax.crypto.SecretKey;
30import java.io.*;
31import java.util.Base64;
32import java.util.List;
33import java.util.Map;
34import java.util.concurrent.ConcurrentHashMap;
35import java.util.concurrent.CopyOnWriteArrayList;
36import java.util.concurrent.LinkedBlockingQueue;
37import java.util.logging.Level;
38
39@Getter
40@Flogger
41public class NetworkManager {
42
43 private List<String> allowedContexts = new CopyOnWriteArrayList<>();
44 private List<String> disconnectedContexts = new CopyOnWriteArrayList<>();
45
46 private Map<String, PacketWorker> workerMap = new ConcurrentHashMap<>();
47
48 private ServerConnector serverConnector;
49
50 private LinkedBlockingQueue<Packet> packetQueue = new LinkedBlockingQueue<>();
51
52 boolean isRunning = false;
53
54 private DataSource<PlayerEntity> playerCollection;
55
56 @Getter
57 private static NetworkManager instance;
58
59 @Getter
60 private ModuleLoader moduleLoader = new ModuleLoader();
61
62 public NetworkManager() {
63 instance = this;
64 isRunning = true;
65
66 MongoConnector mongoConnector = MongoFactory.dispenseMongoConnector(ConfigFactory.dispenseConfig(MongoConfig.class).read(), true);
67 playerCollection = new MongoSource<>(PlayerEntity.class, mongoConnector, "fasciculus_players");
68
69 serverConnector = new ServerConnector(25504);
70 serverConnector.addConnectionHandler(new ConnectionHandler() {
71 @Override
72 public void connect(ChannelHandlerContext context) {
73 disconnectedContexts.remove(id(context));
74 Delayed.delay(10000, () -> {
75 if (!allowedContexts.contains(id(context)) && !disconnectedContexts.contains(id(context))) {
76 UnsuccessfulLoginPacket p = new UnsuccessfulLoginPacket();
77 context.writeAndFlush(p);
78 context.close();
79 log.atInfo().log("Connection to %s has been evicted (NoCredentials)", context.channel().remoteAddress());
80 }
81 });
82 log.atInfo().log("Client (%s) connected", context.channel().remoteAddress());
83 }
84
85 @Override
86 public void disconnect(ChannelHandlerContext context) {
87 try {
88 disconnectedContexts.add(id(context));
89 workerMap.get(id(context)).stop();
90 workerMap.remove(id(context));
91 log.atInfo().log("Client (%s) disconnected", context.channel().remoteAddress());
92 } catch (Exception e) {
93
94 }
95 }
96 });
97 moduleLoader.loadModules();
98
99 }
100
101 @SneakyThrows
102 public boolean isTokenValid(String token) {
103 File file = new File("login.key");
104 @Cleanup FileReader fileReader = new FileReader(file);
105 @Cleanup BufferedReader bufferedReader = new BufferedReader(fileReader);
106 String hash = bufferedReader.readLine();
107 return SecurityHashing.equalsHash(token, hash);
108 }
109
110 @SneakyThrows
111 public static void createToken() {
112 SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS512);
113 String token = Base64.getEncoder().encodeToString(secretKey.getEncoded());
114 String hash = SecurityHashing.toHash(token);
115
116 File file = new File("login.key");
117 @Cleanup FileWriter fileWriter = new FileWriter(file);
118 @Cleanup PrintWriter printWriter = new PrintWriter(fileWriter);
119 printWriter.println(hash);
120
121 System.out.println("Login Token (Remember this token, it won't be shown again): " + token);
122 }
123
124 public void initServer() {
125 System.out.println("Register Packets");
126 PacketRegistry.init();
127 connect();
128
129 File file = new File("login.key");
130 if (!file.exists()) {
131 createToken();
132 }
133 }
134
135 public void connect() {
136 System.out.println("Starting Bootstrap");
137 UniLib.POOL.execute(serverConnector::connect);
138 }
139
140 public void disconnect() {
141 workerMap.forEach((key, value) -> {
142 ChannelHandlerContext ctx = value.getChannelHandlerContext();
143 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
144 ctx.close().addListener((ChannelFutureListener) future -> ctx.channel().parent().close());
145 });
146 workerMap.clear();
147 allowedContexts.clear();
148 disconnectedContexts.clear();
149 serverConnector.getChannelFuture().cancel(false);
150 }
151
152 public static String id(ChannelHandlerContext context) {
153 return context.channel().id().asLongText();
154 }
155}