This commit is contained in:
j3d1 2023-05-31 20:43:14 +02:00
parent 7e8f984ee2
commit a1fd49c5d1
11 changed files with 406 additions and 214 deletions

View file

@ -6,14 +6,50 @@ class ServerSet {
if (!unreachable_neighbors || typeof unreachable_neighbors.queryUnreachable !== 'function' || typeof unreachable_neighbors.unreachable !== 'function') {
throw new Error('no unreachable_neighbors')
}
this.servers = servers;
this.servers = [... new Set(servers)] // deduplicate
this.unreachable_neighbors = unreachable_neighbors;
}
add(server) {
console.log('adding server', server)
if (!server || typeof server !== 'string') {
throw new Error('server must be a string')
}
if (server in this.servers) {
console.log('server already in set', server)
return
}
this.servers.push(server);
}
async get(auth, target) {
if (!auth || typeof auth.buildAuthHeader !== 'function') {
throw new Error('no auth')
}
for (const server of this.servers) {
try {
if (this.unreachable_neighbors.queryUnreachable(server)) {
continue
}
const url = "http://" + server + target // TODO https
return await fetch(url, {
method: 'GET',
headers: {
...auth.buildAuthHeader(url)
},
credentials: 'omit'
}).catch(err => {
console.error('get from server failed', server, err)
this.unreachable_neighbors.unreachable(server)
}
).then(response => response.json())
} catch (e) {
console.error('get from server failed', server, e)
}
}
throw new Error('all servers failed')
}
async post(auth, target, data) {
if (!auth || typeof auth.buildAuthHeader !== 'function') {
throw new Error('no auth')
@ -32,7 +68,10 @@ class ServerSet {
},
credentials: 'omit',
body: JSON.stringify(data)
}).catch(err => this.unreachable_neighbors.unreachable(server)
}).catch(err => {
console.error('post to server failed', server, err)
this.unreachable_neighbors.unreachable(server)
}
).then(response => response.json())
} catch (e) {
console.error('post to server failed', server, e)
@ -59,7 +98,10 @@ class ServerSet {
},
credentials: 'omit',
body: JSON.stringify(data)
}).catch(err => this.unreachable_neighbors.unreachable(server)
}).catch(err => {
console.error('patch to server failed', server, err)
this.unreachable_neighbors.unreachable(server)
}
).then(response => response.json())
} catch (e) {
console.error('patch to server failed', server, e)
@ -68,56 +110,6 @@ class ServerSet {
throw new Error('all servers failed')
}
async get(auth, target) {
if (!auth || typeof auth.buildAuthHeader !== 'function') {
throw new Error('no auth')
}
for (const server of this.servers) {
try {
if (this.unreachable_neighbors.queryUnreachable(server)) {
continue
}
const url = "http://" + server + target // TODO https
return await fetch(url, {
method: 'GET',
headers: {
...auth.buildAuthHeader(url)
},
credentials: 'omit'
}).catch(err => this.unreachable_neighbors.unreachable(server)
).then(response => response.json())
} catch (e) {
console.error('get from server failed', server, e)
}
}
throw new Error('all servers failed')
}
async delete(auth, target) {
if (!auth || typeof auth.buildAuthHeader !== 'function') {
throw new Error('no auth')
}
for (const server of this.servers) {
try {
if (this.unreachable_neighbors.queryUnreachable(server)) {
continue
}
const url = "http://" + server + target // TODO https
return await fetch(url, {
method: 'DELETE',
headers: {
...auth.buildAuthHeader(url)
},
credentials: 'omit'
}).catch(err => this.unreachable_neighbors.unreachable(server)
).then(response => response.json())
} catch (e) {
console.error('delete from server failed', server, e)
}
}
throw new Error('all servers failed')
}
async put(auth, target, data) {
if (!auth || typeof auth.buildAuthHeader !== 'function') {
throw new Error('no auth')
@ -136,7 +128,10 @@ class ServerSet {
},
credentials: 'omit',
body: JSON.stringify(data)
}).catch(err => this.unreachable_neighbors.unreachable(server)
}).catch(err => {
console.error('put to server failed', server, err)
this.unreachable_neighbors.unreachable(server)
}
).then(response => response.json())
} catch (e) {
console.error('put to server failed', server, e)
@ -144,8 +139,107 @@ class ServerSet {
}
throw new Error('all servers failed')
}
async delete(auth, target) {
if (!auth || typeof auth.buildAuthHeader !== 'function') {
throw new Error('no auth')
}
for (const server of this.servers) {
try {
if (this.unreachable_neighbors.queryUnreachable(server)) {
continue
}
const url = "http://" + server + target // TODO https
return await fetch(url, {
method: 'DELETE',
headers: {
...auth.buildAuthHeader(url)
},
credentials: 'omit'
}).catch(err => {
console.error('delete from server failed', server, err)
this.unreachable_neighbors.unreachable(server)
}
)
} catch (e) {
console.error('delete from server failed', server, e)
}
}
throw new Error('all servers failed')
}
}
class ServerSetUnion {
constructor(serverSets) {
if (!serverSets || !Array.isArray(serverSets)) {
throw new Error('no serverSets')
}
this.serverSets = serverSets;
}
add(serverset) {
if (!serverset || !(serverset instanceof ServerSet)) {
throw new Error('no serverset')
}
if (this.serverSets.find(s => serverset.servers.every(s2 => s.servers.includes(s2)))) {
console.warn('serverset already in union', serverset)
return
}
this.serverSets.push(serverset)
}
async post(auth, target, data) {
try {
return await this.serverSets.reduce(async (acc, serverset) => {
return await serverset.post(auth, target, data)
}, Promise.resolve())
} catch (e) {
throw new Error('all servers failed')
}
}
async patch(auth, target, data) {
try {
return await this.serverSets.reduce(async (acc, serverset) => {
return await serverset.patch(auth, target, data)
}, Promise.resolve())
} catch (e) {
throw new Error('all servers failed')
}
}
async get(auth, target) {
try {
return await this.serverSets.reduce(async (acc, serverset) => {
return await serverset.get(auth, target)
}, Promise.resolve())
} catch (e) {
throw new Error('all servers failed')
}
}
async delete(auth, target) {
try {
return await this.serverSets.reduce(async (acc, serverset) => {
return await serverset.delete(auth, target)
}, Promise.resolve())
} catch (e) {
throw new Error('all servers failed')
}
}
async put(auth, target, data) {
try {
return await this.serverSets.reduce(async (acc, serverset) => {
return await serverset.put(auth, target, data)
}, Promise.resolve())
} catch (e) {
throw new Error('all servers failed')
}
}
}
class authMethod {
constructor(method, auth) {
this.method = method;
@ -167,7 +261,6 @@ function createSignAuth(username, signKey) {
return new authMethod(({signKey, username}, {url, data}) => {
const json = JSON.stringify(data)
const signature = nacl.crypto_sign_detached(nacl.encode_utf8(url + (data ? json : "")), signKey)
console.log('sign', nacl.to_hex(signature), url, json)
return {'Authorization': 'Signature ' + username + ':' + nacl.to_hex(signature)}
}, context)
}
@ -188,6 +281,6 @@ function createNullAuth() {
}, {})
}
export {ServerSet, createSignAuth, createTokenAuth, createNullAuth};
export {ServerSet, ServerSetUnion, createSignAuth, createTokenAuth, createNullAuth};