175 lines
5.3 KiB
Java
175 lines
5.3 KiB
Java
package dev.peerat.framework;
|
|
|
|
import java.lang.reflect.Method;
|
|
import java.security.MessageDigest;
|
|
import java.util.List;
|
|
import java.util.regex.Matcher;
|
|
|
|
import dev.peerat.framework.utils.json.JsonMap;
|
|
|
|
public class RouteMapper<U extends User>{
|
|
|
|
private Router<U> router;
|
|
|
|
private RouteState[] states;
|
|
private int[] calls;
|
|
private int dif;
|
|
|
|
public RouteMapper(Router<U> router){
|
|
this.router = router;
|
|
this.states = new RouteState[0];
|
|
}
|
|
|
|
public void register(Object instance, Method method, Route route){
|
|
int length = states.length+1;
|
|
method.setAccessible(true);
|
|
this.states = addElement(states, new RouteState[length], new RouteState(instance, method, route));
|
|
if(this.calls != null) this.calls = new int[length];
|
|
}
|
|
|
|
public void activeReOrdering(){
|
|
this.calls = new int[states.length];
|
|
this.dif = 2;
|
|
}
|
|
|
|
public boolean exec(Context context, HttpReader reader, HttpWriter writer, List<RouteInterceptor> interceptors) throws Exception{
|
|
RouteState target = null;
|
|
Matcher matcher = null;
|
|
|
|
String path = context.getPath();
|
|
|
|
synchronized(states){
|
|
for(int i = 0; i < states.length; i++){
|
|
RouteState state = states[i];
|
|
matcher = state.match(path);
|
|
if(matcher != null){
|
|
if(state.isWebSocket()){
|
|
switchToWebSocket(reader, writer);
|
|
reader = new WebSocketReader(reader);
|
|
writer = new WebSocketWriter(writer);
|
|
if(state.needLogin()){
|
|
String token = reader.<JsonMap>readJson().get("token");
|
|
context.setUser(this.router.getUser(token));
|
|
}
|
|
}
|
|
if((!context.isLogged()) && state.needLogin()){
|
|
writer.response(401, router.getDefaultHeaders(context.getType()));
|
|
return true;
|
|
}
|
|
target = state;
|
|
order(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(target != null){
|
|
for(RouteInterceptor interceptor : interceptors){
|
|
if(!interceptor.intercept(matcher, context, reader, writer, target.getMethod())) return true;
|
|
}
|
|
target.getMethod().invoke(target.getInstance(), target.bindMethod(matcher, context, reader, writer));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void order(int index){
|
|
if(this.calls == null) return;
|
|
int call = this.calls[index]++;
|
|
if(call >= (Integer.MAX_VALUE-(dif+1))){
|
|
for(int i = 0; i < this.calls.length; i++) this.calls[i]/=dif;
|
|
dif++;
|
|
call = this.calls[index];
|
|
}
|
|
if(index < 1) return;
|
|
if(call > this.calls[index-1]){
|
|
switchElement(states, index, index-1);
|
|
|
|
this.calls[index] = this.calls[index-1];
|
|
this.calls[index-1] = call;
|
|
}
|
|
}
|
|
|
|
private <E> E[] addElement(E[] current, E[] growed, E element){
|
|
System.arraycopy(current, 0, growed, 0, current.length);
|
|
growed[current.length] = element;
|
|
return growed;
|
|
}
|
|
|
|
private <E> void switchElement(E[] array, int before, int after){
|
|
E tmp = array[before];
|
|
array[before] = array[after];
|
|
array[after] = tmp;
|
|
}
|
|
|
|
private void switchToWebSocket(HttpReader reader, HttpWriter writer) throws Exception{
|
|
String key = reader.getHeader("Sec-WebSocket-Key");
|
|
if (key == null) throw new IllegalArgumentException();
|
|
|
|
writer.write("HTTP/1.1 101 Switching Protocols\n");
|
|
writer.write("Connection: Upgrade\n");
|
|
writer.write("Upgrade: websocket\n");
|
|
writer.write("Sec-WebSocket-Accept: " + printBase64Binary(MessageDigest.getInstance("SHA-1")
|
|
.digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8"))) + "\n");
|
|
writer.write("\n");
|
|
writer.flush();
|
|
}
|
|
|
|
|
|
// From javax.xml.bind.DatatypeConverter
|
|
private String printBase64Binary(byte[] array){
|
|
char[] arrayOfChar = new char[(array.length + 2) / 3 * 4];
|
|
int i = _printBase64Binary(array, 0, array.length, arrayOfChar, 0);
|
|
assert i == arrayOfChar.length;
|
|
return new String(arrayOfChar);
|
|
}
|
|
|
|
private int _printBase64Binary(byte[] paramArrayOfbyte, int paramInt1, int paramInt2,
|
|
char[] paramArrayOfchar, int paramInt3){
|
|
int i = paramInt2;
|
|
int j;
|
|
for (j = paramInt1; i >= 3; j += 3){
|
|
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
|
|
paramArrayOfchar[paramInt3++] = encode(
|
|
(paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
|
|
paramArrayOfchar[paramInt3++] = encode(
|
|
(paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3);
|
|
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F);
|
|
i -= 3;
|
|
}
|
|
if (i == 1){
|
|
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
|
|
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4);
|
|
paramArrayOfchar[paramInt3++] = '=';
|
|
paramArrayOfchar[paramInt3++] = '=';
|
|
}
|
|
if (i == 2){
|
|
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
|
|
paramArrayOfchar[paramInt3++] = encode(
|
|
(paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
|
|
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2);
|
|
paramArrayOfchar[paramInt3++] = '=';
|
|
}
|
|
return paramInt3;
|
|
}
|
|
|
|
private char encode(int paramInt){
|
|
return encodeMap[paramInt & 0x3F];
|
|
}
|
|
|
|
private static final char[] encodeMap = initEncodeMap();
|
|
|
|
private static char[] initEncodeMap(){
|
|
char[] arrayOfChar = new char[64];
|
|
byte b;
|
|
for (b = 0; b < 26; b++)
|
|
arrayOfChar[b] = (char) (65 + b);
|
|
for (b = 26; b < 52; b++)
|
|
arrayOfChar[b] = (char) (97 + b - 26);
|
|
for (b = 52; b < 62; b++)
|
|
arrayOfChar[b] = (char) (48 + b - 52);
|
|
arrayOfChar[62] = '+';
|
|
arrayOfChar[63] = '/';
|
|
return arrayOfChar;
|
|
}
|
|
|
|
}
|