Compare commits

...

5 Commits

Author SHA1 Message Date
Deon George d6e23b9a90 Optimise queries for rendering the about page
Create Docker Image / Build Docker Image (x86_64) (push) Successful in 33s Details
Create Docker Image / Build Docker Image (arm64) (push) Successful in 1m38s Details
Create Docker Image / Final Docker Image Manifest (push) Successful in 10s Details
2024-04-13 22:41:58 +10:00
Deon George 2edc41b11e Support merging addresses when both src/dst addresses are in the seenby 2024-04-13 20:54:05 +10:00
Deon George 03ca4c10b1 Only add items to the queue when the queue is empty 2024-04-12 21:22:27 +10:00
Deon George 1923eb429f Change wording for Internet Address for a System 2024-04-12 20:06:58 +10:00
Deon George 1e08c2f6f7 Move Domain_Controller::NUMBER_MAX to Address::ADDRESS_FIELD_MAX 2024-04-12 15:29:11 +10:00
16 changed files with 101 additions and 39 deletions

View File

@ -1333,7 +1333,8 @@ final class Binkp extends BaseProtocol
&& (! $this->sessionGet(self::SE_NOFILES))
&& (! $this->send->fd))
{
$this->getFiles($this->node);
if (! $this->send->togo_count)
$this->getFiles($this->node);
// Open our next file to send
if ($this->send->togo_count && ! $this->send->fd) {

View File

@ -7,7 +7,6 @@ use Illuminate\Support\Str;
use App\Classes\Protocol as BaseProtocol;
use App\Classes\Sock\SocketClient;
use App\Http\Controllers\DomainController;
use App\Models\{Address,Domain,Mailer};
/**
@ -328,7 +327,7 @@ final class DNS extends BaseProtocol
{
$m = [];
return (preg_match('/^'.$prefix.'([0-9]+)+/',$label,$m) && ($m[1] <= DomainController::NUMBER_MAX))
return (preg_match('/^'.$prefix.'([0-9]+)+/',$label,$m) && ($m[1] <= Address::ADDRESS_FIELD_MAX))
? $m[1]
: NULL;
}

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Gate;
@ -10,8 +11,17 @@ use App\Models\{Address,Domain,Zone};
class DomainController extends Controller
{
// http://ftsc.org/docs/frl-1002.001
public const NUMBER_MAX = 0x7fff;
/**
* Daily stats as shown on the about page
*
* @param Domain $o
* @return Collection
*/
public function api_daily_stats(Request $request): Collection
{
$do = Domain::where('name',$request->name)->firstOrFail();
return $do->daily_area_stats();
}
/**
* Add or edit a domain

View File

@ -16,7 +16,7 @@ use Illuminate\Support\ViewErrorBag;
use App\Classes\FTN\Message;
use App\Http\Requests\{AddressMerge,AreafixRequest,SystemRegister};
use App\Jobs\AddressPoll;
use App\Models\{Address,Echoarea,Filearea,Netmail,Setup,System,Zone};
use App\Models\{Address,Echoarea,Echomail,Filearea,Netmail,Setup,System,Zone};
use App\Notifications\Netmails\AddressLink;
use App\Rules\{FidoInteger,TwoByteInteger};
@ -242,8 +242,8 @@ class SystemController extends Controller
'point_id' => [
'required',
function($attribute,$value,$fail) use ($request) {
if (! is_numeric($value) || $value > DomainController::NUMBER_MAX)
$fail(sprintf('Point numbers must be between 0 and %d',DomainController::NUMBER_MAX));
if (! is_numeric($value) || $value > Address::ADDRESS_FIELD_MAX)
$fail(sprintf('Point numbers must be between 0 and %d',Address::ADDRESS_FIELD_MAX));
// Check that the host doesnt already exist
$o = Address::where(function($query) use ($request,$value) {
@ -336,6 +336,24 @@ class SystemController extends Controller
if ($request->validated()) {
DB::beginTransaction();
// Find all the echomails that have both seenby's
$x = Echomail::select(['id'])
->join('echomail_seenby',['echomail_seenby.echomail_id'=>'echomails.id'])
->whereIn('address_id',[$request->src])
->distinct()
->with(['seenby:id'])
->get()
->filter(function($item) use ($request) {
return $item->seenby->contains($request->dst) && $item->seenby->contains($request->src);
});
// If the Echomail has both source and dest, delete the src
if ($x->count())
DB::table('echomail_seenby')
->where('address_id',$request->src)
->whereIn('echomail_id',$x->pluck('id'))
->delete();
// Find all echomail seenbys
$x = DB::update('update echomail_seenby set address_id=? where address_id=?',[$request->dst,$request->src]);

View File

@ -12,7 +12,6 @@ use Illuminate\Support\Facades\Log;
use App\Classes\FTN\{Message,Packet};
use App\Exceptions\InvalidFTNException;
use App\Http\Controllers\DomainController;
use App\Traits\ScopeActive;
class Address extends Model
@ -38,6 +37,9 @@ class Address extends Model
public const NODE_UNKNOWN = 1<<15; // Unknown
public const NODE_ALL = 0xFFF; // Mask to catch all nodes
// http://ftsc.org/docs/frl-1002.001
public const ADDRESS_FIELD_MAX = 0x7fff; // Maximum value for a field in the address
public static function boot()
{
parent::boot();
@ -968,10 +970,10 @@ class Address extends Model
// Check our numbers are correct.
foreach ([1,2,3] as $i)
if ((! is_numeric($matches[$i])) || ($matches[$i] > DomainController::NUMBER_MAX))
if ((! is_numeric($matches[$i])) || ($matches[$i] > self::ADDRESS_FIELD_MAX))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - zone, host, or node address invalid [%d]',$ftn,$matches[$i]));
if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > DomainController::NUMBER_MAX)))
if ((! empty($matches[4])) AND ((! is_numeric($matches[$i])) || ($matches[4] > self::ADDRESS_FIELD_MAX)))
throw new InvalidFTNException(sprintf('Invalid FTN: [%s] - point address invalid [%d]',$ftn,$matches[4]));
return [

View File

@ -139,10 +139,16 @@ class Domain extends Model
->get();
}
public function isManaged(): bool
{
return our_address()->pluck('zone.domain')->pluck('id')->contains($this->id);
}
/**
* Determine if this zone is managed by this host
*
* @return bool
* @deprecated use self::isManaged();
*/
public function managed(): bool
{

View File

@ -84,7 +84,6 @@ class User extends Authenticatable implements MustVerifyEmail
->get();
}
/**
* See if the user is already a member of the chosen network
*
@ -103,6 +102,7 @@ class User extends Authenticatable implements MustVerifyEmail
*/
public function isZC(): bool
{
$this->load(['systems.addresses']);
return $this->zc()->count() > 0;
}

View File

@ -4,13 +4,13 @@ namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use App\Http\Controllers\DomainController;
use App\Models\Address;
class FidoInteger implements Rule
{
/**
* Determine if the validation rule passes.
* This will check that a number used for zone, net, host is between 1 and DomainController::NUMBER_MAX.
* This will check that a number used for zone, net, host is between 1 and Address::ADDRESS_FIELD_MAX.
*
* @param string $attribute
* @param mixed $value
@ -18,7 +18,7 @@ class FidoInteger implements Rule
*/
public function passes($attribute,$value)
{
return (is_numeric($value) && ($value >= 0) && ($value < DomainController::NUMBER_MAX));
return (is_numeric($value) && ($value >= 0) && ($value < Address::ADDRESS_FIELD_MAX));
}
/**
@ -28,6 +28,6 @@ class FidoInteger implements Rule
*/
public function message()
{
return sprintf('The number must be between 0 and %d.',DomainController::NUMBER_MAX);
return sprintf('The number must be between 0 and %d.',Address::ADDRESS_FIELD_MAX);
}
}

View File

@ -4,13 +4,13 @@ namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use App\Http\Controllers\DomainController;
use App\Models\Address;
class TwoByteInteger implements Rule
{
/**
* Determine if the validation rule passes.
* This will check that a number used for zone, net, host is between 1 and DomainController::NUMBER_MAX.
* This will check that a number used for zone, net, host is between 1 and Address::ADDRESS_FIELD_MAX.
*
* @param string $attribute
* @param mixed $value
@ -18,7 +18,7 @@ class TwoByteInteger implements Rule
*/
public function passes($attribute,$value)
{
return (is_numeric($value) && ($value > 0) && ($value < DomainController::NUMBER_MAX));
return (is_numeric($value) && ($value > 0) && ($value < Address::ADDRESS_FIELD_MAX));
}
/**
@ -28,6 +28,6 @@ class TwoByteInteger implements Rule
*/
public function message()
{
return sprintf('The number must be between 1 and %d.',DomainController::NUMBER_MAX);
return sprintf('The number must be between 1 and %d.',Address::ADDRESS_FIELD_MAX);
}
}

View File

@ -4,13 +4,13 @@ namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use App\Http\Controllers\DomainController;
use App\Models\Address;
class TwoByteIntegerWithZero implements Rule
{
/**
* Determine if the validation rule passes.
* This will check that a number used for zone, net, host is between 1 and DomainController::NUMBER_MAX.
* This will check that a number used for zone, net, host is between 1 and Address::ADDRESS_FIELD_MAX.
*
* @param string $attribute
* @param mixed $value
@ -18,7 +18,7 @@ class TwoByteIntegerWithZero implements Rule
*/
public function passes($attribute,$value)
{
return (is_numeric($value) && ($value >= 0) && ($value < DomainController::NUMBER_MAX));
return (is_numeric($value) && ($value >= 0) && ($value < Address::ADDRESS_FIELD_MAX));
}
/**
@ -28,6 +28,6 @@ class TwoByteIntegerWithZero implements Rule
*/
public function message()
{
return sprintf('The number must be between 1 and %d.',DomainController::NUMBER_MAX);
return sprintf('The number must be between 1 and %d.',Address::ADDRESS_FIELD_MAX);
}
}

View File

@ -5,7 +5,6 @@ namespace App\Traits;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\DomainController;
use App\Models\{Address,System,Zone};
trait ParseAddresses
@ -37,13 +36,13 @@ trait ParseAddresses
// If domain should be flattened, look for node regardless of zone (within the list of zones for the domain)
$ao = ($zone->domain->flatten)
? Address::findZone($zone->domain,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,0)
: Address::findFTN(sprintf('%d:%d/%d@%s',$zone->zone_id,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$zone->domain->name));
? Address::findZone($zone->domain,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX,0)
: Address::findFTN(sprintf('%d:%d/%d@%s',$zone->zone_id,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX,$zone->domain->name));
switch ($type) {
case 'seenby':
if (! $ao)
$rogue->push(sprintf('%d:%d/%d',$zone->domain->flatten ? 0 : $zone->zone_id,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX));
$rogue->push(sprintf('%d:%d/%d',$zone->domain->flatten ? 0 : $zone->zone_id,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX));
else
$nodes->push($ao->id);
@ -51,7 +50,7 @@ trait ParseAddresses
case 'path':
if (! $ao) {
$ftn = sprintf('%d:%d/%d@%s',$zone->zone_id,$net&DomainController::NUMBER_MAX,$node&DomainController::NUMBER_MAX,$zone->domain->name);
$ftn = sprintf('%d:%d/%d@%s',$zone->zone_id,$net&Address::ADDRESS_FIELD_MAX,$node&Address::ADDRESS_FIELD_MAX,$zone->domain->name);
Log::info(sprintf('%s:- Creating address [%s] for path',self::LOGKEY,$ftn));
$ao = Address::createFTN($ftn,System::createUnknownSystem());

View File

@ -91,16 +91,26 @@ if (! function_exists('hexstr')) {
*/
function our_address(Domain $do=NULL,Address $ao=NULL): Collection|Address|NULL
{
$our = Setup::findOrFail(config('app.id'))->system->akas;
static $so = NULL;
static $our = NULL;
if (! $so)
$so = Setup::findOrFail(config('app.id'));
if (! $our) {
$so->load(['system.akas.zone.domain']);
$our = $so->system->akas;
}
$filter = $our;
if ($do)
$our = $our->filter(function($item) use ($do) { return $item->zone->domain_id === $do->id; })->sortBy('role');
$filter = $our->filter(function($item) use ($do) { return $item->zone->domain_id === $do->id; })->sortBy('role');
// If we are looking for a specific address, and there is only 1 result, return it, otherwise return what we have
if ($ao && config('fido.strict') && ($x=$our->filter(function($item) use ($ao) { return $item->role <= $ao->role; })->sortBy('role'))->count())
if ($ao && config('fido.strict') && ($x=$filter->filter(function($item) use ($ao) { return $item->role <= $ao->role; })->sortBy('role'))->count())
$our = $x;
return $ao ? $our->last() : $our;
return $ao ? $our->last() : ($do ? $filter : $our);
}
/**

View File

@ -125,7 +125,7 @@
@js('highcharts')
<script>
Highcharts.chart('network_traffic', {
var chart = Highcharts.chart('network_traffic', {
chart: {
type: 'spline',
zoomType: 'x',
@ -176,16 +176,30 @@
@foreach (\App\Models\Domain::active()
->when(((! $user) || (! $user->isAdmin())),function($query) { return $query->public()->active(); })
->orderBy('name')
->with(['echoareas'])->get() as $o)
->with(['echoareas'])
->get() as $o)
@if ($o->managed())
{
name: '{{ $o->name }}',
data: {!! $o->daily_area_stats() !!},
data: [],
dashStyle: 'ShortDot',
},
@endif
@endforeach
],
});
chart.series.forEach(function(item) {
$.ajax({
url: '/api/domain/daily',
type: 'GET',
dataType: 'json',
data : {name: item.name},
success: function(data) {
item.setData(data);
},
cache: false
});
});
</script>
@append

View File

@ -14,8 +14,9 @@
<dt>Explore Networks</dt>
@foreach (\App\Models\Domain::select(['id','name'])
->when(((! $user) || (! $user->isAdmin())),function($query) { return $query->public()->active(); })
->orderBy('name')->get() as $o)
@if ($o->managed())
->orderBy('name')
->get() as $o)
@if ($o->isManaged())
<dd><a href="{{ url('domain/view',['id'=>$o->id]) }}">{{ $o->name }}</a></dd>
@endif
@endforeach

View File

@ -134,7 +134,7 @@
<div class="row">
<!-- Address -->
<div class="col-5">
<label for="address" class="form-label">Internet Address</label>
<label for="address" class="form-label">BBS Internet Hostname</label>
<div class="input-group has-validation">
<span class="input-group-text"><i class="bi bi-globe"></i></span>
<input type="text" class="w-75 form-control @error('address') is-invalid @enderror" id="address" placeholder="FQDN" name="address" value="{{ old('address',$o->address) }}" @cannot($action,$o)readonly @endcannot>

View File

@ -14,3 +14,5 @@ use App\Http\Controllers\{DomainController,SystemController,ZoneController};
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::get('/domain/daily',[DomainController::class,'api_daily_stats']);