WIP
parent
53a9f198b5
commit
9a4f448a47
|
@ -0,0 +1,188 @@
|
|||
using System;
|
||||
using ln.application;
|
||||
using ln.application.service;
|
||||
using System.Threading;
|
||||
using ln.types.odb.ng;
|
||||
using ln.types;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ln.json;
|
||||
using ln.types.odb.ng.storage.session;
|
||||
namespace ln.provider
|
||||
{
|
||||
public class IPPoolService : ApplicationServiceBase
|
||||
{
|
||||
CoreService CoreService { get; set; }
|
||||
ProviderApplication Application => (ProviderApplication)base.CurrentApplicationInterface;
|
||||
|
||||
RPC rpc;
|
||||
|
||||
SessionStorageContainer mapperSession;
|
||||
Mapper mapper;
|
||||
|
||||
IPAllocation v6Root;
|
||||
IPAllocation v4Root;
|
||||
|
||||
public IPPoolService()
|
||||
:base("IPPoolService")
|
||||
{
|
||||
DependOnService<CoreService>();
|
||||
|
||||
rpc = new RPC(this);
|
||||
}
|
||||
|
||||
public override void ServiceMain(IApplicationInterface applicationInterface)
|
||||
{
|
||||
CoreService = Dependency<CoreService>();
|
||||
|
||||
using (mapperSession = new SessionStorageContainer(CoreService.CoreStorageContainer))
|
||||
{
|
||||
mapper = new Mapper(mapperSession);
|
||||
|
||||
mapper.EnsureIndex<IPAllocation>("CIDR");
|
||||
mapper.EnsureIndex<IPAllocation>("Pool");
|
||||
|
||||
Application.RPCContainer.Add("ippool", rpc);
|
||||
|
||||
v6Root = mapper.Load<IPAllocation>(Query.Equals<IPAllocation>("CIDR",IPv6.ANY)).FirstOrDefault();
|
||||
v4Root = mapper.Load<IPAllocation>(Query.Equals<IPAllocation>("CIDR", IPv6.V4Space)).FirstOrDefault();
|
||||
|
||||
if (v6Root == null)
|
||||
{
|
||||
v6Root = new IPAllocation(IPv6.ANY, "Global IPv6 Space", null);
|
||||
mapper.Save(v6Root);
|
||||
}
|
||||
|
||||
if (v4Root == null)
|
||||
{
|
||||
v4Root = new IPAllocation(IPv6.V4Space, "Global IPv4 Space", v6Root.CIDR);
|
||||
mapper.Save(v4Root);
|
||||
}
|
||||
|
||||
Ready();
|
||||
|
||||
while (!StopRequested)
|
||||
{
|
||||
lock (Thread.CurrentThread)
|
||||
{
|
||||
Monitor.Wait(Thread.CurrentThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapper = null;
|
||||
|
||||
Application.RPCContainer.Remove("ippool");
|
||||
CoreService = null;
|
||||
}
|
||||
|
||||
public IPAllocation[] GetAllocations()
|
||||
{
|
||||
return mapper.Load<IPAllocation>().ToArray();
|
||||
}
|
||||
public IPAllocation GetAllocation(IPv6 cidr)
|
||||
{
|
||||
return mapper.Load<IPAllocation>(Query.Equals<IPAllocation>("CIDR", cidr)).FirstOrDefault();
|
||||
}
|
||||
|
||||
public IPAllocation[] GetPoolAllocations(IPv6 pool)
|
||||
{
|
||||
return mapper.Load<IPAllocation>(Query.Equals<IPAllocation>("Pool", pool)).ToArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public IPAllocation AllocateAny(IPv6 zone,int width,string usage)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public IPAllocation AllocateCIDR(IPv6 zone,IPv6 cidr,string usage,bool splitZones)
|
||||
{
|
||||
IPAllocation pool = GetAllocation(zone);
|
||||
if (pool == null)
|
||||
throw new KeyNotFoundException();
|
||||
|
||||
if (!pool.CIDR.Contains(cidr))
|
||||
throw new ArgumentException(String.Format("{0} doesn't contain {1}", pool.CIDR.ToCIDR(), cidr.ToCIDR()));
|
||||
|
||||
if (splitZones)
|
||||
{
|
||||
IPAllocation allocation = pool;
|
||||
while (!allocation.CIDR.Equals(cidr))
|
||||
{
|
||||
foreach (IPv6 splitCIDR in allocation.CIDR.Split(1))
|
||||
{
|
||||
if (splitCIDR.Contains(cidr))
|
||||
{
|
||||
IPAllocation split = GetAllocation(splitCIDR);
|
||||
if (split == null)
|
||||
{
|
||||
split = new IPAllocation(splitCIDR,allocation.CIDR);
|
||||
mapper.Save(split);
|
||||
allocation = split;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return allocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
IPAllocation allocation = GetAllocation(cidr);
|
||||
if (allocation != null)
|
||||
throw new Exception("Allocation already present");
|
||||
|
||||
allocation = new IPAllocation(cidr, cidr.ToCIDR(), pool.CIDR);
|
||||
allocation.AllocatedTo = usage;
|
||||
|
||||
mapper.Save(allocation);
|
||||
|
||||
return allocation;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class RPC
|
||||
{
|
||||
IPPoolService poolService;
|
||||
|
||||
public RPC(IPPoolService poolService)
|
||||
{
|
||||
this.poolService = poolService;
|
||||
}
|
||||
|
||||
public IPAllocation[] GetAllocations() => poolService.GetAllocations();
|
||||
public IPAllocation GetAllocation(IPv6 cidr) => poolService.GetAllocation(cidr);
|
||||
public IPAllocation[] GetPoolAllocations(IPv6 pool) => poolService.GetPoolAllocations(pool);
|
||||
|
||||
public IPAllocation AllocateAny(IPv6 zone, int width, string usage) => poolService.AllocateAny(zone, width, usage);
|
||||
public IPAllocation AllocateCIDR(IPv6 zone, IPv6 cidr, string usage, bool splitZones) => poolService.AllocateCIDR(zone, cidr, usage,splitZones);
|
||||
|
||||
}
|
||||
|
||||
public class IPAllocation
|
||||
{
|
||||
public IPv6 CIDR { get; }
|
||||
public string Name { get; set; } = String.Empty;
|
||||
|
||||
public string AllocatedTo { get; set; } = String.Empty;
|
||||
|
||||
public IPv6 Pool { get; }
|
||||
|
||||
private IPAllocation(){}
|
||||
public IPAllocation(IPv6 cidr): this(cidr, cidr.ToCIDR(), IPv6.ANY) { }
|
||||
public IPAllocation(IPv6 cidr, IPv6 pool) : this(cidr, cidr.ToCIDR(), pool) { }
|
||||
public IPAllocation(IPv6 cidr,String name,IPv6 pool)
|
||||
{
|
||||
Pool = pool;
|
||||
CIDR = cidr;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -10,6 +10,8 @@ using ln.types.odb.ng.storage;
|
|||
using System.Security.Cryptography;
|
||||
using System.Linq;
|
||||
using ln.types;
|
||||
using ln.types.odb.ng.storage.session;
|
||||
using ln.types.odb.ng.storage.fs;
|
||||
namespace ln.provider
|
||||
{
|
||||
public class ProviderApplication : Application
|
||||
|
@ -28,12 +30,10 @@ namespace ln.provider
|
|||
if (Directory.Exists("../../www"))
|
||||
WWWPath = "../../www";
|
||||
|
||||
ServiceDefinition coreRPCService = new ServiceDefinition("ln.provider.CoreService");
|
||||
coreRPCService.AutoStart = true;
|
||||
ServiceDefinition coreRPCService = ServiceDefinition.From<CoreService>(true);
|
||||
ServiceContainer.Add(coreRPCService);
|
||||
|
||||
ServiceContainer.Add(
|
||||
coreRPCService
|
||||
);
|
||||
ServiceContainer.Add(ServiceDefinition.From<IPPoolService>(true));
|
||||
}
|
||||
|
||||
public override void PrepareStart()
|
||||
|
@ -66,7 +66,7 @@ namespace ln.provider
|
|||
public ProviderApplication Application => (ProviderApplication)base.CurrentApplicationInterface;
|
||||
|
||||
public IStorageContainer CoreStorageContainer { get; private set; }
|
||||
public Session CoreStorageSession { get; private set; }
|
||||
public SessionStorageContainer CoreStorageSession { get; private set; }
|
||||
public Mapper CoreStorageMapper { get; private set; }
|
||||
|
||||
public CoreService()
|
||||
|
@ -79,7 +79,7 @@ namespace ln.provider
|
|||
CoreStorageContainer = new FSStorageContainer("/var/cache/ln.provider");
|
||||
CoreStorageContainer.Open();
|
||||
|
||||
CoreStorageSession = new Session(CoreStorageContainer);
|
||||
CoreStorageSession = new SessionStorageContainer(CoreStorageContainer);
|
||||
CoreStorageMapper = new Mapper(CoreStorageSession);
|
||||
|
||||
CoreStorageMapper.EnsureIndex<AuthenticatedUser>("ID");
|
||||
|
@ -90,6 +90,8 @@ namespace ln.provider
|
|||
Application.HttpServer.DefaultApplication = Application.WWWApplication;
|
||||
Application.RPCContainer.Add("core",new RPC(Application));
|
||||
|
||||
Ready();
|
||||
|
||||
while (!StopRequested)
|
||||
{
|
||||
lock (this)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ProviderApplication.cs" />
|
||||
<Compile Include="IPPoolService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ln.types\ln.types.csproj">
|
||||
|
@ -78,6 +79,11 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="www\style.css" />
|
||||
<None Include="www\ln.provider.js" />
|
||||
<None Include="www\page.layout.css" />
|
||||
<None Include="www\ln.provider.pool.js" />
|
||||
<None Include="www\ln.provider.pool.html" />
|
||||
<None Include="www\ln.provider.components.js" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -2,38 +2,68 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ln.provider</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script type="text/javascript" src="vue.js"></script>
|
||||
<script type="text/javascript" src="ln.application.js"></script>
|
||||
<title>ln.provider Web Interface</title>
|
||||
|
||||
<link href="/style.css" rel="stylesheet" />
|
||||
<link href="/page.layout.css" rel="stylesheet" />
|
||||
<link href="/tables.layout.css" rel="stylesheet" />
|
||||
|
||||
<script type="text/javascript" src="/vue.js"></script>
|
||||
<script type="text/javascript" src="/vue-router.js"></script>
|
||||
<script type="text/javascript" src="/ln.tools.js"></script>
|
||||
<script type="text/javascript" src="/ln.application.js"></script>
|
||||
|
||||
<script type="text/javascript" src="ln.provider.components.js"></script>
|
||||
<script type="text/javascript" src="ln.provider.js"></script>
|
||||
<script type="text/javascript" src="ln.provider.pool.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
LN();
|
||||
</script>
|
||||
<div id="body">
|
||||
<div id="header">
|
||||
<div class="logo">
|
||||
<div style="background-color: #2a7fff; color: white;">ln.</div><div style="background-color: white;">provider</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="app">
|
||||
|
||||
<h1>{{ serverString }}</h1>
|
||||
<div id="navbar">
|
||||
<router-link
|
||||
v-for="route in LNProvider.routes"
|
||||
v-if="route.label"
|
||||
v-bind:to="route.path"
|
||||
>{{ route.label }}</router-link>
|
||||
</div>
|
||||
|
||||
<div id="page">
|
||||
<router-view
|
||||
v-bind="{ LNP: LNP }"
|
||||
></router-view>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="flex row">
|
||||
<div id="ServerString" class="silver">{{ LNP.serverString }}</div>
|
||||
<div class="grow"></div>
|
||||
<div id="ServerTime" class="" style="margin-right: 12px;">{{ LNP.serverTime }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var providerCore = {
|
||||
serverString: "",
|
||||
}
|
||||
var LNP = new LNProvider();
|
||||
|
||||
LN().rpc("core","GetServerString",[],function(result,error){
|
||||
document.title = result;
|
||||
providerCore.serverString = result;
|
||||
LNP
|
||||
.initialize()
|
||||
.then(function(){
|
||||
const router = new VueRouter({
|
||||
routes: LNProvider.routes,
|
||||
});
|
||||
new Vue({
|
||||
el: "#body",
|
||||
data: {
|
||||
LNP,
|
||||
},
|
||||
router,
|
||||
}).$mount("#body");
|
||||
});
|
||||
|
||||
var app = new Vue({
|
||||
el: "#app",
|
||||
data: providerCore,
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,336 +0,0 @@
|
|||
var LN = (function(){
|
||||
var appInterface;
|
||||
|
||||
var defaultOptions = {
|
||||
url: null,
|
||||
|
||||
};
|
||||
|
||||
class LNInterface {
|
||||
constructor(opt){
|
||||
var self = this;
|
||||
|
||||
this.options = {}
|
||||
Object.assign(this.options,opt);
|
||||
|
||||
if (this.options.url == null)
|
||||
this.options.url = this.constructURL();
|
||||
|
||||
|
||||
this.rpcCallbacks = [];
|
||||
this.rpcNextID = 1;
|
||||
|
||||
this.websocket = new WebSocket(this.options.url);
|
||||
this.websocket.onerror = function(e){
|
||||
alert("WebSocket caught error: " + e.date);
|
||||
}
|
||||
this.websocket.onmessage = function(e){
|
||||
var j = JSON.parse(e.data);
|
||||
if (j.state){
|
||||
updateState(j.state);
|
||||
} else if (j.id)
|
||||
{
|
||||
for (var n=0;n<self.rpcCallbacks.length;n++)
|
||||
{
|
||||
if (self.rpcCallbacks[n].id == j.id)
|
||||
{
|
||||
if (j.error)
|
||||
{
|
||||
console.log("RPCResult with error received: " + JSON.stringify(j.error));
|
||||
}
|
||||
self.rpcCallbacks[n].cbfn(j.result,j.error);
|
||||
self.rpcCallbacks.splice(n,1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rpc(module,method,parameters,cbfn){
|
||||
|
||||
var rpcCall = {
|
||||
module: module,
|
||||
method: method,
|
||||
parameters: parameters,
|
||||
id: this.rpcNextID++,
|
||||
};
|
||||
|
||||
if (this.websocket.readyState != 1)
|
||||
{
|
||||
setTimeout(function(){
|
||||
LN().rpc(module,method,parameters,cbfn);
|
||||
},250);
|
||||
} else {
|
||||
this.rpcCallbacks.push( { id: rpcCall.id, cbfn: cbfn } );
|
||||
this.websocket.send(
|
||||
JSON.stringify(rpcCall)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
constructURL(){
|
||||
var pageURI = window.location;
|
||||
|
||||
var scheme = pageURI.scheme == "https" ? "wss:" : "ws:";
|
||||
var host = pageURI.host;
|
||||
|
||||
return scheme + "//" + host + "/socket";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
return function(options){
|
||||
if (!appInterface)
|
||||
appInterface = new LNInterface(options);
|
||||
return appInterface;
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Object.values = function(o) {
|
||||
var values = [];
|
||||
for(var property in o) {
|
||||
values.push(o[property]);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
function encodeID( t )
|
||||
{
|
||||
return ("" + t).replace( /[\.\/]/g, "_");
|
||||
}
|
||||
|
||||
var lagDetector = null;
|
||||
|
||||
function updateState(state)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (lagDetector)
|
||||
clearTimeout(lagDetector);
|
||||
|
||||
$("#ServerTime").text("ServerTime: " + moment(state.currentTime).format());
|
||||
|
||||
lagDetector = setTimeout(function(){
|
||||
$("#ServerTime").text("Server lag detected");
|
||||
}, 2000);
|
||||
|
||||
} catch (e)
|
||||
{
|
||||
$("#ServerTime").text("Server state unexpected!");
|
||||
}
|
||||
}
|
||||
|
||||
function SKYAPI(baseurl){
|
||||
|
||||
this.baseurl = baseurl;
|
||||
this.refresh = []
|
||||
|
||||
this.websocket = new WebSocket("ws://localhost:8080/socket");
|
||||
this.websocket.onerror = function(e){
|
||||
alert("WebSocket Error: " + e);
|
||||
}
|
||||
this.websocket.onmessage = function(e){
|
||||
var j = JSON.parse(e.data);
|
||||
if (j.state){
|
||||
updateState(j.state);
|
||||
}
|
||||
}
|
||||
|
||||
this.setBaseURL = function(url){ this.baseurl = url; }
|
||||
this.addRefresh = function( rh, seconds = null ){ this.refresh.push( { interval: seconds ? seconds : 5, refresh: rh } ); }
|
||||
|
||||
this.get = function(page, json, handler = null){ return this.__request("GET", page, json, handler); }
|
||||
this.post = function(page, json, handler = null){ return this.__request("POST", page, json, handler); }
|
||||
this.put = function(page, json, handler = null){ return this.__request("PUT", page, json, handler); }
|
||||
|
||||
this.__request = function(method, page, json, handler = null){
|
||||
if (page[0] == '/')
|
||||
page = page.substr(1);
|
||||
|
||||
var x = new XMLHttpRequest();
|
||||
if (handler != null)
|
||||
{
|
||||
x.onload = function(){
|
||||
var responseText = x.responseText;
|
||||
if (json && !content)
|
||||
handler( JSON.parse( responseText ) );
|
||||
else
|
||||
handler( responseText );
|
||||
}
|
||||
}
|
||||
x.open(method, this.baseurl + page);
|
||||
|
||||
if (json)
|
||||
x.send(JSON.stringify(json));
|
||||
else
|
||||
x.send();
|
||||
}
|
||||
|
||||
this.getJson = function(page, handler){
|
||||
var j = function(t){
|
||||
handler(JSON.parse(t));
|
||||
};
|
||||
return this.get( page, null, j );
|
||||
}
|
||||
|
||||
this.call = function(endpoint,method,parameters = [], receiver = null){
|
||||
var x = new XMLHttpRequest();
|
||||
|
||||
x.open("POST", this.baseurl + endpoint, (receiver != null));
|
||||
x.setRequestHeader("content-type","application/json");
|
||||
|
||||
if (receiver)
|
||||
{
|
||||
x.onload = function(){ var r = JSON.parse(this.responseText).Result; receiver(r); }
|
||||
x.onerror = function(){ receiver(false); }
|
||||
}
|
||||
|
||||
var methodCall = {
|
||||
"MethodName": method,
|
||||
"Parameters": parameters
|
||||
}
|
||||
|
||||
x.send(JSON.stringify(methodCall));
|
||||
|
||||
if (!receiver)
|
||||
{
|
||||
var result = JSON.parse(x.responseText);
|
||||
if (result.Exception != null)
|
||||
throw result.Exception;
|
||||
|
||||
return result.Result;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
this.loadPage = function (page) {
|
||||
if (page[0] == '/')
|
||||
page = page.substr(1);
|
||||
|
||||
var x = new XMLHttpRequest();
|
||||
|
||||
x.open("GET", this.baseurl + page);
|
||||
x.setRequestHeader("x-template-unframed","unframed");
|
||||
x.onload = function()
|
||||
{
|
||||
$("#content").empty();
|
||||
$("#content").append(this.responseText);
|
||||
history.pushState(null, page, skyapi().baseurl + page);
|
||||
}
|
||||
|
||||
this.refresh = []
|
||||
|
||||
x.send();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.fireOnLoad = function(element){
|
||||
if (element.onload != null)
|
||||
{
|
||||
element.onload();
|
||||
}
|
||||
|
||||
for (var n=0;n<element.children.length;n++)
|
||||
this.fireOnLoad(element.children[n]);
|
||||
}
|
||||
|
||||
this.__refresh_index = 0;
|
||||
this.UIRefresh = function(){
|
||||
|
||||
this.__refresh_index++;
|
||||
|
||||
for (var n=0;n<this.refresh.length;n++)
|
||||
{
|
||||
var r = this.refresh[n];
|
||||
if ((this.__refresh_index % r.interval)==0)
|
||||
r.refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setInterval( function(){ skyapi().UIRefresh(); }, 1000 );
|
||||
}
|
||||
|
||||
function showStatistics(stats)
|
||||
{
|
||||
try
|
||||
{
|
||||
$("#ServerTime").text("ServerTime: " + stats.ServerTime);
|
||||
|
||||
$("#indHttpServer").attr("state",stats.States.HttpServer);
|
||||
$("#indManager").attr("state",stats.States.Manager);
|
||||
$("#indCrawler").attr("state",stats.States.Crawler);
|
||||
$("#indChecks").attr("state",stats.States.Checks);
|
||||
$("#indDispatcher").attr("state",stats.States.Dispatcher);
|
||||
|
||||
$("#indHttpServer").attr("title",stats.States.HttpServer);
|
||||
$("#indManager").attr("title",stats.States.Manager);
|
||||
$("#indCrawler").attr("title",stats.States.Crawler);
|
||||
$("#indChecks").attr("title",stats.States.Checks);
|
||||
$("#indDispatcher").attr("title",stats.States.Dispatcher);
|
||||
|
||||
} catch (e)
|
||||
{
|
||||
$("#ServerTime").text("Server unreachable");
|
||||
|
||||
$("#indHttpServer").attr("state",3);
|
||||
$("#indManager").attr("state",0);
|
||||
$("#indCrawler").attr("state",0);
|
||||
$("#indChecks").attr("state",0);
|
||||
$("#indDispatcher").attr("state",0);
|
||||
|
||||
$("#indHttpServer").attr("title","UNKNOWN");
|
||||
$("#indManager").attr("title","UNKNOWN");
|
||||
$("#indCrawler").attr("title","UNKNOWN");
|
||||
$("#indChecks").attr("title","UNKNOWN");
|
||||
$("#indDispatcher").attr("title","UNKNOWN");
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatistics()
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = skyapi().call("api/management","GetStatistics",[],showStatistics);
|
||||
} catch (e)
|
||||
{
|
||||
showStatistics(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var __skyapi = new SKYAPI("/");
|
||||
|
||||
function skyapi()
|
||||
{
|
||||
return __skyapi;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function ScaleSI(value)
|
||||
{
|
||||
if (value > 1000000000)
|
||||
return ((value / 1000000000) | 0) + "G";
|
||||
if (value > 1000000)
|
||||
return ((value / 1000000) | 0) + "M";
|
||||
if (value > 1000)
|
||||
return ((value / 1000) | 0) + "k";
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
Vue.component('toggle-pane',{
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
label: String,
|
||||
class: String,
|
||||
},
|
||||
data: function(){
|
||||
return {
|
||||
};
|
||||
},
|
||||
template: `
|
||||
<div class="toggle-pane">
|
||||
<button
|
||||
@click="visible = !visible"
|
||||
>{{ label }}</button>
|
||||
<div
|
||||
v-if="visible"
|
||||
><slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
|
@ -0,0 +1,92 @@
|
|||
var LNProvider = (function(){
|
||||
|
||||
class LNProvider
|
||||
{
|
||||
constructor(options){
|
||||
let self = this;
|
||||
|
||||
this.serverString = "N/A";
|
||||
this.serverTime = "N/A";
|
||||
|
||||
this.lagDetector = null;
|
||||
|
||||
this.IPAllocations = [];
|
||||
|
||||
LN().option("wsError",(e)=>self.wsError(e));
|
||||
LN().option("wsClose",(e)=>self.wsClose(e));
|
||||
LN().option("wsUpdate",(e)=>self.wsUpdate(e));
|
||||
|
||||
LN().connect();
|
||||
}
|
||||
|
||||
initialize(){
|
||||
return Promise.all(LNProvider.initializers);
|
||||
}
|
||||
|
||||
loadIPAllocations(){
|
||||
let self = this;
|
||||
console.log("loadIPAllocations()");
|
||||
LN().rpc("ippool","GetAllocations",[],function(r,e){
|
||||
self.IPAllocations = r;
|
||||
console.log("IPA: " + JSON.stringify(r));
|
||||
});
|
||||
}
|
||||
|
||||
allocate(type,cidr,maskWidth,zone,usage,splitZone){
|
||||
let self = this;
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
|
||||
} else if (type == 1)
|
||||
{
|
||||
LN().rpc("ippool","AllocateCIDR",[zone,cidr,usage,splitZone],function(r,e){
|
||||
if (e){
|
||||
alert("Error: \n" + JSON.stringify(e));
|
||||
} else {
|
||||
self.IPAllocations.push(r);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wsUpdate(state)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.lagDetector)
|
||||
clearTimeout(this.lagDetector);
|
||||
|
||||
this.serverTime = moment(state.currentTime).format();
|
||||
|
||||
this.lagDetector = setTimeout(function(){
|
||||
this.serverTime = "Server lag detected";
|
||||
}, 2000);
|
||||
|
||||
} catch (e)
|
||||
{
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
wsError(e){
|
||||
this.serverTime = "WebSocket: Error: " + JSON.stringify(e);
|
||||
}
|
||||
wsClose(e){
|
||||
this.serverTime = "WebSocket: Connection lost";
|
||||
setTimeout(function(){
|
||||
LN().connect();
|
||||
}, 2500 );
|
||||
}
|
||||
}
|
||||
|
||||
LNProvider.routes = [];
|
||||
LNProvider.initializers = [];
|
||||
|
||||
|
||||
return LNProvider;
|
||||
})();
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<div>
|
||||
<h1>IP Pools</h1>
|
||||
<toggle-pane
|
||||
label="Allokationsparameter..."
|
||||
:visible="true"
|
||||
>
|
||||
<div class="flex row">
|
||||
<span>
|
||||
<label for="allocFree">Freie Allokation</label>
|
||||
<input type="radio" id="allocFree" v-model="allocationType" value="0"><br>
|
||||
<label for="allocCIDR">CIDR Allokation</label>
|
||||
<input type="radio" id="allocCIDR" v-model="allocationType" value="1"><br>
|
||||
</span>
|
||||
<fieldset
|
||||
v-if="allocationType == 0"
|
||||
>
|
||||
<div>
|
||||
<span>Maskenlänge:</span>
|
||||
<span><input type="number" min="1" max="127" v-model="subnetWidth"></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Netzbreite:</span>
|
||||
<span><input type="number" min="1" max="127" v-model="allocationWidth"></span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset
|
||||
v-if="allocationType == 1"
|
||||
>
|
||||
<div>
|
||||
<span>Zielnetz:</span>
|
||||
<span><input type="text" v-model="targetCIDR"></span>
|
||||
</div>
|
||||
<div>
|
||||
<label for="independentAllocation">Unabhängige Allokation</label>
|
||||
<input type="checkbox" id="independentAllocation" v-model="independentAllocation">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset
|
||||
>
|
||||
<div>
|
||||
<span>Verwendung:</span>
|
||||
<span><input type="text" v-model="allocationUsage"></span>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</toggle-pane>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Aktionen</td>
|
||||
<td>CIDR</td>
|
||||
<td>Name</td>
|
||||
<td>Pool</td>
|
||||
<td>Verwendungsnachweis</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="ipa in IPAllocations"
|
||||
>
|
||||
<td>
|
||||
<button
|
||||
@click="LNP.allocate(allocationType,targetCIDR,subnetWidth,ipa.CIDR,allocationUsage,!independentAllocation);"
|
||||
>+</button>
|
||||
</td>
|
||||
<td>{{ ipa.CIDR }}</td>
|
||||
<td>{{ ipa.Name }}</td>
|
||||
<td>{{ ipa.Pool }}</td>
|
||||
<td>{{ ipa.AllocatedTo }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,45 @@
|
|||
LNProvider.initializers.push(
|
||||
new Promise((resolve,reject)=>{
|
||||
LN()
|
||||
.load("/ln.provider.pool.html")
|
||||
.then((template)=>{
|
||||
LNProvider.routes.push(
|
||||
{
|
||||
path: "/ippool",
|
||||
label: "IP Pool",
|
||||
component: {
|
||||
props: {
|
||||
LNP: Object,
|
||||
},
|
||||
template: template,
|
||||
data: function(){
|
||||
return {
|
||||
allocationWidth: 64,
|
||||
targetCIDR: "",
|
||||
independentAllocation: false,
|
||||
allocationType: 0,
|
||||
allocationUsage: "",
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
IPAllocations: ()=>LNP.IPAllocations,
|
||||
subnetWidth: {
|
||||
get: function(){
|
||||
return 128 - this.allocationWidth;
|
||||
},
|
||||
set: function(v){
|
||||
this.allocationWidth = 128 - v;
|
||||
},
|
||||
},
|
||||
},
|
||||
beforeRouteEnter: function(to,from,next){
|
||||
LNP.loadIPAllocations();
|
||||
next();
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
);
|
|
@ -0,0 +1,145 @@
|
|||
|
||||
html {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
body {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
div#body {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#header {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
|
||||
border-bottom: 1px solid black;
|
||||
background-color: #bad6ff;
|
||||
padding: 4px;
|
||||
|
||||
}
|
||||
|
||||
#header > div {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
#navbar {
|
||||
padding: 8px;
|
||||
|
||||
border-bottom: 1px solid black;
|
||||
|
||||
font-size: 16px;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
#navbar > a {
|
||||
display: inline-block;
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
|
||||
}
|
||||
#navbar > a.router-link-active {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#page {
|
||||
padding: 16px;
|
||||
|
||||
flex-grow: 1;
|
||||
|
||||
overflow-y: scroll;
|
||||
}
|
||||
#page::after {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#footer {
|
||||
height: 20px;
|
||||
padding: 6px;
|
||||
padding-left: 24px;
|
||||
background-color: #bad6ff;
|
||||
border-top: 1px solid black;
|
||||
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.p {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.DISABLED {
|
||||
color: #D0D0D0;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
|
||||
border: none;
|
||||
}
|
||||
fieldset > div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
width: 100%;
|
||||
margin: 4px;
|
||||
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
fieldset > div > * {
|
||||
flex-grow: 0;
|
||||
}
|
||||
fieldset > div > *:first-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
||||
.toggle-pane {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.toggle-pane > div {
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
input {
|
||||
height: 16px;
|
||||
|
||||
border: 1px solid #bad6ff;
|
||||
border-radius: 3px;
|
||||
|
||||
padding: 4px;
|
||||
}
|
|
@ -25,3 +25,32 @@ div.app {
|
|||
|
||||
|
||||
|
||||
.logo {
|
||||
display: inline-block;
|
||||
border: 1px solid black;
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.logo > div {
|
||||
display: inline-block;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex.row {
|
||||
flex-direction: row;
|
||||
}
|
||||
.flex.column {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex > * {
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table tr {
|
||||
|
||||
}
|
||||
|
||||
table td {
|
||||
padding: 4px;
|
||||
border-bottom: 1px solid #D0D0D0;
|
||||
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table > thead {
|
||||
font-style: italic;
|
||||
background-color: #bad6ff;
|
||||
transition: background-color 1000ms;
|
||||
}
|
||||
|
||||
table > thead tr {
|
||||
|
||||
}
|
||||
|
||||
table > thead td {
|
||||
}
|
||||
|
||||
table > tbody tr {
|
||||
|
||||
}
|
||||
|
||||
table > tbody td {
|
||||
|
||||
}
|
||||
|
||||
table > tfoot tr {
|
||||
|
||||
}
|
||||
|
||||
table > tfoot td {
|
||||
|
||||
}
|
||||
|
||||
table > tbody > tr:hover > td {
|
||||
border-top: 2px solid black;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
Loading…
Reference in New Issue