openvibers/openvibe.codes Commits
Limits page: Media's /limits.json joins Host's and Events' (namespaces and quotas, WS-G task 2); an hours unit
Changes
@@@ -417,6 +417,7 @@ ${table(['Rule', 'Value'], [// public: null until openvibe.host serves Host itself (WS-N task 10, Stage B step 2); read internally meanwhile.{ service: 'host', name: 'OpenVibe Host', internal: process.env.OV_HOST_INTERNAL_URL || 'http://127.0.0.1:4910', public: null },{ service: 'events', name: 'OpenVibe Events', internal: process.env.OV_EVENTS_INTERNAL_URL || 'http://127.0.0.1:4300', public: 'https://events.openvibe.network/limits.json' },++ { service: 'media', name: 'OpenVibe Media', internal: process.env.OV_MEDIA_INTERNAL_URL || 'http://127.0.0.1:4100', public: 'https://openvibe.media/limits.json' },];const limitsCache = new Map();async function limitsOf(src) {@@@ -442,6 +443,7 @@ ${table(['Rule', 'Value'], [if (unit === 'bytes') return bytes(Number(v));if (unit === 'per_minute') return `${n} a minute`;if (unit === 'per_day') return `${n} in 24 hours`;++ if (unit === 'hours') return `${n} hours`;if (unit === 'days') return `${n} days`;return n;}@@@ -25,6 +25,14 @@ const EVENTS = {],};++const MEDIA = {++ service: 'media', scope: 'per project tenant and environment',++ limits: [++ { id: 'storage_bytes', label: 'Stored bytes (every namespace of the tenant)', capability: 'media.object.upload', unit: 'bytes', production: 1073741824, sandbox: 104857600, exceeded: '413 media.quota.exceeded' },++ { id: 'unfinished_upload_hours', label: 'Hours an unfinished upload holds its quota', capability: 'media.object.upload', unit: 'hours', production: 72, sandbox: 72, exceeded: 'failed, bytes freed' },++ ],++};++function serve(body) {const s = http.createServer((req, res) => {if (!s.up) { res.statusCode = 503; return res.end('{}'); }@@@ -41,6 +49,8 @@ function serve(body) {const events = await serve(EVENTS);process.env.OV_HOST_INTERNAL_URL = `http://127.0.0.1:${host.address().port}`;process.env.OV_EVENTS_INTERNAL_URL = `http://127.0.0.1:${events.address().port}`;++ const media = await serve(MEDIA);++ process.env.OV_MEDIA_INTERNAL_URL = `http://127.0.0.1:${media.address().port}`;const { boot, check, done } = require('./helpers/boot');const t = await boot();@@@ -48,13 +58,14 @@ function serve(body) {const r = await t.get('/docs/limits');assert.strictEqual(r.status, 200, r.text.slice(0, 300));for (const s of ['1 GB', '100 MB', '50 in 24 hours', '120 a minute', '30 a minute', '7 days', 'quota.custom_domains', 'events.quota_exceeded',-- 'events.openvibe.network/limits.json', 'per project and environment (ADR-014)']) {++ 'events.openvibe.network/limits.json', 'openvibe.media/limits.json', '72 hours', 'media.quota.exceeded', 'per project and environment (ADR-014)']) {assert.ok(r.text.includes(s), `the page says ${s}`);}assert.match(r.text, /Custom domains<\/td><td[^>]*>[^<]*<a[^>]*><code>host\.site\.manage<\/code><\/a><\/td><td[^>]*>none<\/td>/, 'sandbox 0 reads "none"');assert.match(r.text, /Webhook subscriptions.*?<td[^>]*>5<\/td><td[^>]*>no limit<\/td>/s, 'production null reads "no limit"');assert.ok(!/\bfree\b/i.test(r.text.replace(/<[^>]+>/g, ' ')), 'no "free" copy');-- assert.ok(r.text.includes('Other capabilities') && r.text.includes('/docs/capabilities/media.object.upload'), 'owners without /limits.json are listed');++ assert.ok(r.text.includes('Other capabilities') && r.text.includes('/docs/capabilities/tools.tool.run'), 'owners without /limits.json are listed');++ assert.ok(!/Other capabilities[\s\S]*media\.object\.upload \(/.test(r.text), 'Media publishes its own now');assert.ok(!/Other capabilities[\s\S]*events\.app\.publish \(/.test(r.text), 'a covered owner is not listed again');assert.ok((await t.get('/docs')).text.includes('href="/docs/limits"'), 'the docs index links it');assert.ok((await t.get('/sitemap.xml')).text.includes('/docs/limits'), 'and the sitemap');@@@ -75,5 +86,6 @@ function serve(body) {await t.close();host.close();events.close();++ media.close();done();})().catch((err) => { console.error(err); process.exit(1); });
@@ -417,6 +417,7 @@ ${table(['Rule', 'Value'], [
@@ -417,6 +417,7 @@ ${table(['Rule', 'Value'], [
// public: null until openvibe.host serves Host itself (WS-N task 10, Stage B step 2); read internally meanwhile.
// public: null until openvibe.host serves Host itself (WS-N task 10, Stage B step 2); read internally meanwhile.
{ service: 'host', name: 'OpenVibe Host', internal: process.env.OV_HOST_INTERNAL_URL || 'http://127.0.0.1:4910', public: null },
{ service: 'host', name: 'OpenVibe Host', internal: process.env.OV_HOST_INTERNAL_URL || 'http://127.0.0.1:4910', public: null },
{ service: 'events', name: 'OpenVibe Events', internal: process.env.OV_EVENTS_INTERNAL_URL || 'http://127.0.0.1:4300', public: 'https://events.openvibe.network/limits.json' },
{ service: 'events', name: 'OpenVibe Events', internal: process.env.OV_EVENTS_INTERNAL_URL || 'http://127.0.0.1:4300', public: 'https://events.openvibe.network/limits.json' },
+ { service: 'media', name: 'OpenVibe Media', internal: process.env.OV_MEDIA_INTERNAL_URL || 'http://127.0.0.1:4100', public: 'https://openvibe.media/limits.json' },
];
];
const limitsCache = new Map();
const limitsCache = new Map();
async function limitsOf(src) {
async function limitsOf(src) {
@@ -442,6 +443,7 @@ ${table(['Rule', 'Value'], [
@@ -442,6 +443,7 @@ ${table(['Rule', 'Value'], [
if (unit === 'bytes') return bytes(Number(v));
if (unit === 'bytes') return bytes(Number(v));
if (unit === 'per_minute') return `${n} a minute`;
if (unit === 'per_minute') return `${n} a minute`;
if (unit === 'per_day') return `${n} in 24 hours`;
if (unit === 'per_day') return `${n} in 24 hours`;
+ if (unit === 'hours') return `${n} hours`;
if (unit === 'days') return `${n} days`;
if (unit === 'days') return `${n} days`;
return n;
return n;
}
}
@@ -25,6 +25,14 @@ const EVENTS = {
@@ -25,6 +25,14 @@ const EVENTS = {
],
],
};
};
+const MEDIA = {
+ service: 'media', scope: 'per project tenant and environment',
+ limits: [
+ { id: 'storage_bytes', label: 'Stored bytes (every namespace of the tenant)', capability: 'media.object.upload', unit: 'bytes', production: 1073741824, sandbox: 104857600, exceeded: '413 media.quota.exceeded' },
+ { id: 'unfinished_upload_hours', label: 'Hours an unfinished upload holds its quota', capability: 'media.object.upload', unit: 'hours', production: 72, sandbox: 72, exceeded: 'failed, bytes freed' },
+ ],
+};
+
function serve(body) {
function serve(body) {
const s = http.createServer((req, res) => {
const s = http.createServer((req, res) => {
if (!s.up) { res.statusCode = 503; return res.end('{}'); }
if (!s.up) { res.statusCode = 503; return res.end('{}'); }
@@ -41,6 +49,8 @@ function serve(body) {
@@ -41,6 +49,8 @@ function serve(body) {
const events = await serve(EVENTS);
const events = await serve(EVENTS);
process.env.OV_HOST_INTERNAL_URL = `http://127.0.0.1:${host.address().port}`;
process.env.OV_HOST_INTERNAL_URL = `http://127.0.0.1:${host.address().port}`;
process.env.OV_EVENTS_INTERNAL_URL = `http://127.0.0.1:${events.address().port}`;
process.env.OV_EVENTS_INTERNAL_URL = `http://127.0.0.1:${events.address().port}`;
+ const media = await serve(MEDIA);
+ process.env.OV_MEDIA_INTERNAL_URL = `http://127.0.0.1:${media.address().port}`;
const { boot, check, done } = require('./helpers/boot');
const { boot, check, done } = require('./helpers/boot');
const t = await boot();
const t = await boot();
@@ -48,13 +58,14 @@ function serve(body) {
@@ -48,13 +58,14 @@ function serve(body) {
const r = await t.get('/docs/limits');
const r = await t.get('/docs/limits');
assert.strictEqual(r.status, 200, r.text.slice(0, 300));
assert.strictEqual(r.status, 200, r.text.slice(0, 300));
for (const s of ['1 GB', '100 MB', '50 in 24 hours', '120 a minute', '30 a minute', '7 days', 'quota.custom_domains', 'events.quota_exceeded',
for (const s of ['1 GB', '100 MB', '50 in 24 hours', '120 a minute', '30 a minute', '7 days', 'quota.custom_domains', 'events.quota_exceeded',
- 'events.openvibe.network/limits.json', 'per project and environment (ADR-014)']) {
+ 'events.openvibe.network/limits.json', 'openvibe.media/limits.json', '72 hours', 'media.quota.exceeded', 'per project and environment (ADR-014)']) {
assert.ok(r.text.includes(s), `the page says ${s}`);
assert.ok(r.text.includes(s), `the page says ${s}`);
}
}
assert.match(r.text, /Custom domains<\/td><td[^>]*>[^<]*<a[^>]*><code>host\.site\.manage<\/code><\/a><\/td><td[^>]*>none<\/td>/, 'sandbox 0 reads "none"');
assert.match(r.text, /Custom domains<\/td><td[^>]*>[^<]*<a[^>]*><code>host\.site\.manage<\/code><\/a><\/td><td[^>]*>none<\/td>/, 'sandbox 0 reads "none"');
assert.match(r.text, /Webhook subscriptions.*?<td[^>]*>5<\/td><td[^>]*>no limit<\/td>/s, 'production null reads "no limit"');
assert.match(r.text, /Webhook subscriptions.*?<td[^>]*>5<\/td><td[^>]*>no limit<\/td>/s, 'production null reads "no limit"');
assert.ok(!/\bfree\b/i.test(r.text.replace(/<[^>]+>/g, ' ')), 'no "free" copy');
assert.ok(!/\bfree\b/i.test(r.text.replace(/<[^>]+>/g, ' ')), 'no "free" copy');
- assert.ok(r.text.includes('Other capabilities') && r.text.includes('/docs/capabilities/media.object.upload'), 'owners without /limits.json are listed');
+ assert.ok(r.text.includes('Other capabilities') && r.text.includes('/docs/capabilities/tools.tool.run'), 'owners without /limits.json are listed');
+ assert.ok(!/Other capabilities[\s\S]*media\.object\.upload \(/.test(r.text), 'Media publishes its own now');
assert.ok(!/Other capabilities[\s\S]*events\.app\.publish \(/.test(r.text), 'a covered owner is not listed again');
assert.ok(!/Other capabilities[\s\S]*events\.app\.publish \(/.test(r.text), 'a covered owner is not listed again');
assert.ok((await t.get('/docs')).text.includes('href="/docs/limits"'), 'the docs index links it');
assert.ok((await t.get('/docs')).text.includes('href="/docs/limits"'), 'the docs index links it');
assert.ok((await t.get('/sitemap.xml')).text.includes('/docs/limits'), 'and the sitemap');
assert.ok((await t.get('/sitemap.xml')).text.includes('/docs/limits'), 'and the sitemap');
@@ -75,5 +86,6 @@ function serve(body) {
@@ -75,5 +86,6 @@ function serve(body) {
await t.close();
await t.close();
host.close();
host.close();
events.close();
events.close();
+ media.close();
done();
done();
})().catch((err) => { console.error(err); process.exit(1); });
})().catch((err) => { console.error(err); process.exit(1); });