mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-13 03:30:29 +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.ILuaContext;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.core.apis.http.CheckUrl;
|
||||
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.*;
|
||||
import dan200.computercraft.core.apis.http.request.HttpRequest;
|
||||
import dan200.computercraft.core.apis.http.websocket.Websocket;
|
||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||
@ -33,9 +30,9 @@ public class HTTPAPI implements ILuaAPI
|
||||
{
|
||||
private final IAPIEnvironment m_apiEnvironment;
|
||||
|
||||
private final ResourceQueue<CheckUrl> checkUrls = new ResourceQueue<>();
|
||||
private final ResourceQueue<HttpRequest> requests = new ResourceQueue<>( () -> ComputerCraft.httpMaxRequests );
|
||||
private final ResourceQueue<Websocket> websockets = new ResourceQueue<>( () -> ComputerCraft.httpMaxWebsockets );
|
||||
private final ResourceGroup<CheckUrl> checkUrls = new ResourceGroup<>();
|
||||
private final ResourceGroup<HttpRequest> requests = new ResourceQueue<>( () -> ComputerCraft.httpMaxRequests );
|
||||
private final ResourceGroup<Websocket> websockets = new ResourceGroup<>( () -> ComputerCraft.httpMaxWebsockets );
|
||||
|
||||
public HTTPAPI( IAPIEnvironment environment )
|
||||
{
|
||||
@ -189,7 +186,10 @@ public class HTTPAPI implements ILuaAPI
|
||||
try
|
||||
{
|
||||
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 };
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public class CheckUrl extends Resource<CheckUrl>
|
||||
private final String address;
|
||||
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 );
|
||||
this.environment = environment;
|
||||
|
@ -24,9 +24,9 @@ import java.util.function.Consumer;
|
||||
public abstract class Resource<T extends Resource<T>> implements Closeable
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -93,10 +93,10 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
|
||||
tryClose();
|
||||
}
|
||||
|
||||
public void queue( Consumer<T> task )
|
||||
public boolean queue( Consumer<T> task )
|
||||
{
|
||||
@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 )
|
||||
|
@ -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;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.IntSupplier;
|
||||
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<>();
|
||||
|
||||
public ResourceQueue( IntSupplier limit )
|
||||
{
|
||||
this.limit = limit;
|
||||
super( limit );
|
||||
}
|
||||
|
||||
public ResourceQueue()
|
||||
{
|
||||
this.limit = ZERO;
|
||||
}
|
||||
|
||||
public void startup()
|
||||
{
|
||||
active = true;
|
||||
}
|
||||
|
||||
public synchronized void shutdown()
|
||||
{
|
||||
active = false;
|
||||
|
||||
super.shutdown();
|
||||
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( () -> {
|
||||
setup.run();
|
||||
return resource;
|
||||
} );
|
||||
}
|
||||
if( !active ) return false;
|
||||
|
||||
public synchronized void queue( Supplier<T> resource )
|
||||
{
|
||||
Resource.cleanup();
|
||||
if( !active ) return;
|
||||
|
||||
int limit = this.limit.getAsInt();
|
||||
if( limit <= 0 || resources.size() < limit )
|
||||
{
|
||||
resources.add( resource.get() );
|
||||
}
|
||||
else
|
||||
{
|
||||
pending.add( resource );
|
||||
}
|
||||
if( !super.queue( resource ) ) pending.add( resource );
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void release( T resource )
|
||||
{
|
||||
if( !active ) return;
|
||||
super.release( resource );
|
||||
|
||||
resources.remove( resource );
|
||||
if( !active ) return;
|
||||
|
||||
int limit = this.limit.getAsInt();
|
||||
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.NetworkUtils;
|
||||
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 io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
@ -64,7 +64,7 @@ public class HttpRequest extends Resource<HttpRequest>
|
||||
|
||||
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 );
|
||||
this.environment = environment;
|
||||
|
@ -27,7 +27,7 @@ public class HttpResponseHandle implements ILuaObject
|
||||
private final String responseStatus;
|
||||
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.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.NetworkUtils;
|
||||
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 io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
@ -57,7 +57,7 @@ public class Websocket extends Resource<Websocket>
|
||||
private final String address;
|
||||
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 );
|
||||
this.environment = environment;
|
||||
|
Loading…
Reference in New Issue
Block a user