mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-19 05:32:55 +00:00
A couple of minor changes to HTTP limiting
- We now error if there are too many websockets, instead of queuing them up. As these have a more explicit "lifetime", it could be confusing if http.websocket just blocks indefinitely. - Fix a CCME when cleaning up resources.
This commit is contained in:
parent
932f8a44fc
commit
8dd084ac5c
@ -10,10 +10,7 @@ import dan200.computercraft.ComputerCraft;
|
|||||||
import dan200.computercraft.api.lua.ILuaAPI;
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.apis.http.CheckUrl;
|
import dan200.computercraft.core.apis.http.*;
|
||||||
import dan200.computercraft.core.apis.http.HTTPRequestException;
|
|
||||||
import dan200.computercraft.core.apis.http.Resource;
|
|
||||||
import dan200.computercraft.core.apis.http.ResourceQueue;
|
|
||||||
import dan200.computercraft.core.apis.http.request.HttpRequest;
|
import dan200.computercraft.core.apis.http.request.HttpRequest;
|
||||||
import dan200.computercraft.core.apis.http.websocket.Websocket;
|
import dan200.computercraft.core.apis.http.websocket.Websocket;
|
||||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||||
@ -33,9 +30,9 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
private final IAPIEnvironment m_apiEnvironment;
|
private final IAPIEnvironment m_apiEnvironment;
|
||||||
|
|
||||||
private final ResourceQueue<CheckUrl> checkUrls = new ResourceQueue<>();
|
private final ResourceGroup<CheckUrl> checkUrls = new ResourceGroup<>();
|
||||||
private final ResourceQueue<HttpRequest> requests = new ResourceQueue<>( () -> ComputerCraft.httpMaxRequests );
|
private final ResourceGroup<HttpRequest> requests = new ResourceQueue<>( () -> ComputerCraft.httpMaxRequests );
|
||||||
private final ResourceQueue<Websocket> websockets = new ResourceQueue<>( () -> ComputerCraft.httpMaxWebsockets );
|
private final ResourceGroup<Websocket> websockets = new ResourceGroup<>( () -> ComputerCraft.httpMaxWebsockets );
|
||||||
|
|
||||||
public HTTPAPI( IAPIEnvironment environment )
|
public HTTPAPI( IAPIEnvironment environment )
|
||||||
{
|
{
|
||||||
@ -189,7 +186,10 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
URI uri = Websocket.checkUri( address );
|
URI uri = Websocket.checkUri( address );
|
||||||
new Websocket( websockets, m_apiEnvironment, uri, address, headers ).queue( Websocket::connect );
|
if( !new Websocket( websockets, m_apiEnvironment, uri, address, headers ).queue( Websocket::connect ) )
|
||||||
|
{
|
||||||
|
throw new LuaException( "Too many websockets already open" );
|
||||||
|
}
|
||||||
|
|
||||||
return new Object[] { true };
|
return new Object[] { true };
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public class CheckUrl extends Resource<CheckUrl>
|
|||||||
private final String address;
|
private final String address;
|
||||||
private final String host;
|
private final String host;
|
||||||
|
|
||||||
public CheckUrl( ResourceQueue<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri )
|
public CheckUrl( ResourceGroup<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri )
|
||||||
{
|
{
|
||||||
super( limiter );
|
super( limiter );
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
|
@ -24,9 +24,9 @@ import java.util.function.Consumer;
|
|||||||
public abstract class Resource<T extends Resource<T>> implements Closeable
|
public abstract class Resource<T extends Resource<T>> implements Closeable
|
||||||
{
|
{
|
||||||
private final AtomicBoolean closed = new AtomicBoolean( false );
|
private final AtomicBoolean closed = new AtomicBoolean( false );
|
||||||
private final ResourceQueue<T> limiter;
|
private final ResourceGroup<T> limiter;
|
||||||
|
|
||||||
protected Resource( ResourceQueue<T> limiter )
|
protected Resource( ResourceGroup<T> limiter )
|
||||||
{
|
{
|
||||||
this.limiter = limiter;
|
this.limiter = limiter;
|
||||||
}
|
}
|
||||||
@ -93,10 +93,10 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
|
|||||||
tryClose();
|
tryClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queue( Consumer<T> task )
|
public boolean queue( Consumer<T> task )
|
||||||
{
|
{
|
||||||
@SuppressWarnings( "unchecked" ) T thisT = (T) this;
|
@SuppressWarnings( "unchecked" ) T thisT = (T) this;
|
||||||
limiter.queue( thisT, () -> task.accept( thisT ) );
|
return limiter.queue( thisT, () -> task.accept( thisT ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static <T extends Closeable> T closeCloseable( T closeable )
|
protected static <T extends Closeable> T closeCloseable( T closeable )
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dan200.computercraft.core.apis.http;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.IntSupplier;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of {@link Resource}s, with an upper bound on capacity.
|
||||||
|
*/
|
||||||
|
public class ResourceGroup<T extends Resource<T>>
|
||||||
|
{
|
||||||
|
private static final IntSupplier ZERO = () -> 0;
|
||||||
|
|
||||||
|
final IntSupplier limit;
|
||||||
|
|
||||||
|
boolean active = false;
|
||||||
|
|
||||||
|
final Set<T> resources = Collections.newSetFromMap( new ConcurrentHashMap<>() );
|
||||||
|
|
||||||
|
public ResourceGroup( IntSupplier limit )
|
||||||
|
{
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceGroup()
|
||||||
|
{
|
||||||
|
this.limit = ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startup()
|
||||||
|
{
|
||||||
|
active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void shutdown()
|
||||||
|
{
|
||||||
|
active = false;
|
||||||
|
|
||||||
|
for( T resource : resources ) resource.close();
|
||||||
|
resources.clear();
|
||||||
|
|
||||||
|
Resource.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public final boolean queue( T resource, Runnable setup )
|
||||||
|
{
|
||||||
|
return queue( () -> {
|
||||||
|
setup.run();
|
||||||
|
return resource;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean queue( Supplier<T> resource )
|
||||||
|
{
|
||||||
|
Resource.cleanup();
|
||||||
|
if( !active ) return false;
|
||||||
|
|
||||||
|
int limit = this.limit.getAsInt();
|
||||||
|
if( limit <= 0 || resources.size() < limit )
|
||||||
|
{
|
||||||
|
resources.add( resource.get() );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void release( T resource )
|
||||||
|
{
|
||||||
|
resources.remove( resource );
|
||||||
|
}
|
||||||
|
}
|
@ -7,80 +7,44 @@
|
|||||||
package dan200.computercraft.core.apis.http;
|
package dan200.computercraft.core.apis.http;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.IntSupplier;
|
import java.util.function.IntSupplier;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A queue for {@link Resource}s, with built-in rate-limiting.
|
* A {@link ResourceGroup} which will queue items when the group at capacity.
|
||||||
*/
|
*/
|
||||||
public class ResourceQueue<T extends Resource<T>>
|
public class ResourceQueue<T extends Resource<T>> extends ResourceGroup<T>
|
||||||
{
|
{
|
||||||
private static final IntSupplier ZERO = () -> 0;
|
|
||||||
|
|
||||||
private final IntSupplier limit;
|
|
||||||
|
|
||||||
private boolean active = false;
|
|
||||||
|
|
||||||
private final Set<T> resources = new HashSet<>();
|
|
||||||
private final ArrayDeque<Supplier<T>> pending = new ArrayDeque<>();
|
private final ArrayDeque<Supplier<T>> pending = new ArrayDeque<>();
|
||||||
|
|
||||||
public ResourceQueue( IntSupplier limit )
|
public ResourceQueue( IntSupplier limit )
|
||||||
{
|
{
|
||||||
this.limit = limit;
|
super( limit );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceQueue()
|
public ResourceQueue()
|
||||||
{
|
{
|
||||||
this.limit = ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startup()
|
|
||||||
{
|
|
||||||
active = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void shutdown()
|
public synchronized void shutdown()
|
||||||
{
|
{
|
||||||
active = false;
|
super.shutdown();
|
||||||
|
|
||||||
pending.clear();
|
pending.clear();
|
||||||
for( T resource : resources ) resource.close();
|
|
||||||
resources.clear();
|
|
||||||
|
|
||||||
Resource.cleanup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void queue( T resource, Runnable setup )
|
public synchronized boolean queue( Supplier<T> resource )
|
||||||
{
|
{
|
||||||
queue( () -> {
|
if( !active ) return false;
|
||||||
setup.run();
|
|
||||||
return resource;
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void queue( Supplier<T> resource )
|
if( !super.queue( resource ) ) pending.add( resource );
|
||||||
{
|
return true;
|
||||||
Resource.cleanup();
|
|
||||||
if( !active ) return;
|
|
||||||
|
|
||||||
int limit = this.limit.getAsInt();
|
|
||||||
if( limit <= 0 || resources.size() < limit )
|
|
||||||
{
|
|
||||||
resources.add( resource.get() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pending.add( resource );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void release( T resource )
|
public synchronized void release( T resource )
|
||||||
{
|
{
|
||||||
if( !active ) return;
|
super.release( resource );
|
||||||
|
|
||||||
resources.remove( resource );
|
if( !active ) return;
|
||||||
|
|
||||||
int limit = this.limit.getAsInt();
|
int limit = this.limit.getAsInt();
|
||||||
if( limit <= 0 || resources.size() < limit )
|
if( limit <= 0 || resources.size() < limit )
|
||||||
|
@ -12,7 +12,7 @@ import dan200.computercraft.core.apis.IAPIEnvironment;
|
|||||||
import dan200.computercraft.core.apis.http.HTTPRequestException;
|
import dan200.computercraft.core.apis.http.HTTPRequestException;
|
||||||
import dan200.computercraft.core.apis.http.NetworkUtils;
|
import dan200.computercraft.core.apis.http.NetworkUtils;
|
||||||
import dan200.computercraft.core.apis.http.Resource;
|
import dan200.computercraft.core.apis.http.Resource;
|
||||||
import dan200.computercraft.core.apis.http.ResourceQueue;
|
import dan200.computercraft.core.apis.http.ResourceGroup;
|
||||||
import dan200.computercraft.core.tracking.TrackingField;
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
@ -64,7 +64,7 @@ public class HttpRequest extends Resource<HttpRequest>
|
|||||||
|
|
||||||
final AtomicInteger redirects;
|
final AtomicInteger redirects;
|
||||||
|
|
||||||
public HttpRequest( ResourceQueue<HttpRequest> limiter, IAPIEnvironment environment, String address, String postText, HttpHeaders headers, boolean binary, boolean followRedirects )
|
public HttpRequest( ResourceGroup<HttpRequest> limiter, IAPIEnvironment environment, String address, String postText, HttpHeaders headers, boolean binary, boolean followRedirects )
|
||||||
{
|
{
|
||||||
super( limiter );
|
super( limiter );
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
|
@ -27,7 +27,7 @@ public class HttpResponseHandle implements ILuaObject
|
|||||||
private final String responseStatus;
|
private final String responseStatus;
|
||||||
private final Map<String, String> responseHeaders;
|
private final Map<String, String> responseHeaders;
|
||||||
|
|
||||||
public HttpResponseHandle(@Nonnull ILuaObject reader, int responseCode, String responseStatus, @Nonnull Map<String, String> responseHeaders)
|
public HttpResponseHandle( @Nonnull ILuaObject reader, int responseCode, String responseStatus, @Nonnull Map<String, String> responseHeaders )
|
||||||
{
|
{
|
||||||
this.reader = reader;
|
this.reader = reader;
|
||||||
this.responseCode = responseCode;
|
this.responseCode = responseCode;
|
||||||
|
@ -12,7 +12,7 @@ import dan200.computercraft.core.apis.IAPIEnvironment;
|
|||||||
import dan200.computercraft.core.apis.http.HTTPRequestException;
|
import dan200.computercraft.core.apis.http.HTTPRequestException;
|
||||||
import dan200.computercraft.core.apis.http.NetworkUtils;
|
import dan200.computercraft.core.apis.http.NetworkUtils;
|
||||||
import dan200.computercraft.core.apis.http.Resource;
|
import dan200.computercraft.core.apis.http.Resource;
|
||||||
import dan200.computercraft.core.apis.http.ResourceQueue;
|
import dan200.computercraft.core.apis.http.ResourceGroup;
|
||||||
import dan200.computercraft.shared.util.IoUtil;
|
import dan200.computercraft.shared.util.IoUtil;
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
@ -57,7 +57,7 @@ public class Websocket extends Resource<Websocket>
|
|||||||
private final String address;
|
private final String address;
|
||||||
private final HttpHeaders headers;
|
private final HttpHeaders headers;
|
||||||
|
|
||||||
public Websocket( ResourceQueue<Websocket> limiter, IAPIEnvironment environment, URI uri, String address, HttpHeaders headers )
|
public Websocket( ResourceGroup<Websocket> limiter, IAPIEnvironment environment, URI uri, String address, HttpHeaders headers )
|
||||||
{
|
{
|
||||||
super( limiter );
|
super( limiter );
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
|
Loading…
Reference in New Issue
Block a user