mirror of
https://github.com/telemt/telemt.git
synced 2026-09-17 15:58:31 +03:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 935b5a3527 | |||
| 4ca7418442 | |||
| 464bc180e1 | |||
| 8b0ee9bf3d | |||
| 24c4cefc74 | |||
| 97c046757a | |||
| 4e3d560a88 | |||
| 9908e04e04 |
Generated
+1
-1
@@ -2780,7 +2780,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "telemt"
|
name = "telemt"
|
||||||
version = "3.5.6"
|
version = "3.5.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "telemt"
|
name = "telemt"
|
||||||
version = "3.5.6"
|
version = "3.5.7"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.88"
|
rust-version = "1.88"
|
||||||
|
|
||||||
|
|||||||
+30
-10
@@ -1,12 +1,32 @@
|
|||||||
# LICENSING
|
# Licensing
|
||||||
## Licenses for Versions
|
|
||||||
| Version ≥ | Version ≤ | License |
|
|
||||||
|-----------|-----------|---------------|
|
|
||||||
| 1.0 | 3.3.17 | NO LICNESE |
|
|
||||||
| 3.3.18 | 3.4.0 | TELEMT PL 3 |
|
|
||||||
|
|
||||||
### License Types
|
Telemt is currently distributed under the **TELEMT Public License**
|
||||||
- **NO LICENSE** = ***ALL RIGHT RESERVED***
|
|
||||||
- **TELEMT PL** - special Telemt Public License based on Apache License 2 principles
|
|
||||||
|
|
||||||
## [Telemt Public License 3](https://github.com/telemt/telemt/blob/main/LICENSE)
|
For the complete and legally binding license terms, see [`LICENSE`](./LICENSE).
|
||||||
|
|
||||||
|
The license file accompanying a particular release is authoritative for that release. A future release may use a different version of the TELEMT Public License or another license without changing the licensing terms of previously released versions.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Under the TELEMT Public License, you may generally:
|
||||||
|
|
||||||
|
* use and reproduce the Software;
|
||||||
|
* modify it and create derivative works;
|
||||||
|
* publish and redistribute source or binary copies;
|
||||||
|
* sublicense the Software;
|
||||||
|
* sell copies or products containing the Software.
|
||||||
|
|
||||||
|
The license includes several conditions and limitations, including:
|
||||||
|
|
||||||
|
* copyright notices, attribution notices, and the license text must be preserved when redistributing Telemt-derived code;
|
||||||
|
* modified versions must be clearly identified as modified and include a brief description of the changes;
|
||||||
|
* modified or redistributed versions must not be presented as official Telemt releases;
|
||||||
|
* the license does not grant rights to Telemt trademarks, logos, or branding;
|
||||||
|
* contributors provide a patent license for patent claims necessarily infringed by their contributions, subject to defensive termination provisions;
|
||||||
|
* contributions submitted for inclusion in Telemt are licensed under the same license unless explicitly stated otherwise;
|
||||||
|
* operators of publicly accessible services using Telemt are encouraged to provide attribution;
|
||||||
|
* providing corresponding source code and build instructions with binary distributions is encouraged, but not required.
|
||||||
|
|
||||||
|
The Software is provided **WITHOUT ANY KIND OF WARRANTY**, as described in [`LICENSE`](./LICENSE).
|
||||||
|
|
||||||
|
This document is only a summary intended to make Telemt's licensing easier to understand. If anything in this document conflicts with the applicable [`LICENSE`](./LICENSE), the license text controls.
|
||||||
|
|||||||
+2
-2
@@ -447,9 +447,9 @@ check_port_availability() {
|
|||||||
port_info=""
|
port_info=""
|
||||||
|
|
||||||
if command -v ss >/dev/null 2>&1; then
|
if command -v ss >/dev/null 2>&1; then
|
||||||
port_info=$($SUDO ss -tulnp 2>/dev/null | grep -E ":${SERVER_PORT}([[:space:]]|$)" || true)
|
port_info=$($SUDO ss -tlnp 2>/dev/null | grep -E ":${SERVER_PORT}([[:space:]]|$)" || true)
|
||||||
elif command -v netstat >/dev/null 2>&1; then
|
elif command -v netstat >/dev/null 2>&1; then
|
||||||
port_info=$($SUDO netstat -tulnp 2>/dev/null | grep -E ":${SERVER_PORT}([[:space:]]|$)" || true)
|
port_info=$($SUDO netstat -tlnp 2>/dev/null | grep -E ":${SERVER_PORT}([[:space:]]|$)" || true)
|
||||||
elif command -v lsof >/dev/null 2>&1; then
|
elif command -v lsof >/dev/null 2>&1; then
|
||||||
port_info=$($SUDO lsof -i :${SERVER_PORT} 2>/dev/null | grep LISTEN || true)
|
port_info=$($SUDO lsof -i :${SERVER_PORT} 2>/dev/null | grep LISTEN || true)
|
||||||
else
|
else
|
||||||
|
|||||||
+10
-16
@@ -23,13 +23,7 @@ const pending=[],upPending=[],recoveryPending=[],lanes=new Map(),closedLanes=new
|
|||||||
const canonicalFailures=['timeout','network','upgrade','http','protocol'];
|
const canonicalFailures=['timeout','network','upgrade','http','protocol'];
|
||||||
const failure=(reason,message)=>Object.assign(new Error(message||reason),{telemtReason:reason});
|
const failure=(reason,message)=>Object.assign(new Error(message||reason),{telemtReason:reason});
|
||||||
const failureReason=(error,fallback)=>error&&canonicalFailures.includes(error.telemtReason)?error.telemtReason:fallback;
|
const failureReason=(error,fallback)=>error&&canonicalFailures.includes(error.telemtReason)?error.telemtReason:fallback;
|
||||||
const status=(state,phase,reason,deadlineMs)=>{
|
const status=state=>{if(port&&!closed)port.postMessage({t:'status',state})};
|
||||||
if(!port||closed)return;
|
|
||||||
const currentPhase=phase||(state==='connected'?'committed':state==='reconnecting'?'retrying':state==='failed'?'terminal':createStarted?'negotiating':'starting');
|
|
||||||
let currentDeadline=deadlineMs;
|
|
||||||
if(currentDeadline===undefined)currentDeadline=negotiationStartedAt?Math.max(0,negotiationStartedAt+negotiatedFinalDeadline*1000-Date.now()):0;
|
|
||||||
port.postMessage({t:'status',state,phase:currentPhase,reason:reason||'',deadline_ms:Math.max(0,Math.ceil(currentDeadline))});
|
|
||||||
};
|
|
||||||
const socketURL=()=>relayOrigin.replace(/^https:/,'wss:')+'/api/v1/ws';
|
const socketURL=()=>relayOrigin.replace(/^https:/,'wss:')+'/api/v1/ws';
|
||||||
const requestClient=requestSupport.create({
|
const requestClient=requestSupport.create({
|
||||||
origin:()=>relayOrigin,closed:()=>closed,retryMs:()=>bridgeRetryMs,longPollMs:()=>longPollMs,requestMs:()=>bridgeRequestMs,
|
origin:()=>relayOrigin,closed:()=>closed,retryMs:()=>bridgeRetryMs,longPollMs:()=>longPollMs,requestMs:()=>bridgeRequestMs,
|
||||||
@@ -48,7 +42,7 @@ function settleBatch(lease){if(!buffers.settleBatch(lease))return false;detachLe
|
|||||||
function cancelBatch(lease){if(!lease||lease.settled)return;buffers.cancelBatch(lease);detachLease(lease)}
|
function cancelBatch(lease){if(!lease||lease.settled)return;buffers.cancelBatch(lease);detachLease(lease)}
|
||||||
const attemptHeaders=(attempt,failure)=>negotiationEnabled?Object.assign({'X-Carrier-Capabilities':carrierCapabilities,'X-Carrier-Attempt':String(attempt)},failure?{'X-Carrier-Failure':failure}:{}):{};
|
const attemptHeaders=(attempt,failure)=>negotiationEnabled?Object.assign({'X-Carrier-Capabilities':carrierCapabilities,'X-Carrier-Attempt':String(attempt)},failure?{'X-Carrier-Failure':failure}:{}):{};
|
||||||
function finishOldRecovery(){
|
function finishOldRecovery(){
|
||||||
recoveryReplaced=false;resetScheduler();status('connected','committed','',0);
|
recoveryReplaced=false;resetScheduler();status('connected');
|
||||||
while(recoveryPending.length&&!closed){const data=recoveryPending.shift();release(data.byteLength,1,null);queueCarrier(data)}
|
while(recoveryPending.length&&!closed){const data=recoveryPending.shift();release(data.byteLength,1,null);queueCarrier(data)}
|
||||||
}
|
}
|
||||||
function rejectRecoveryCommit(error){
|
function rejectRecoveryCommit(error){
|
||||||
@@ -110,13 +104,13 @@ function sampleScheduler(){
|
|||||||
}
|
}
|
||||||
function observeResumeTrigger(){
|
function observeResumeTrigger(){
|
||||||
const gap=Math.max(schedulerGapPending,schedulerGap());schedulerGapPending=0;if(!carrierCommitted||closed)return;
|
const gap=Math.max(schedulerGapPending,schedulerGap());schedulerGapPending=0;if(!carrierCommitted||closed)return;
|
||||||
if(gap>=2*longPollMs)status('reconnecting','retrying','',bridgeRecoveryMs);
|
if(gap>=2*longPollMs)status('reconnecting');
|
||||||
if(gap>=reconnectGraceMs&&!recoveryController.active())recoveryController.recover('timeout',null);
|
if(gap>=reconnectGraceMs&&!recoveryController.active())recoveryController.recover('timeout',null);
|
||||||
}
|
}
|
||||||
function fail(reason){
|
function fail(reason){
|
||||||
if(closed)return;reason=reason||'protocol';if(canonicalFailures.includes(reason))terminalFailure=reason;
|
if(closed)return;reason=reason||'protocol';if(canonicalFailures.includes(reason))terminalFailure=reason;
|
||||||
rejectRecoveryCommit(failure(reason));
|
rejectRecoveryCommit(failure(reason));
|
||||||
status('failed','terminal',reason,0);if(port)port.postMessage({t:'close'});close(true);
|
status('failed');if(port)port.postMessage({t:'close'});close(true);
|
||||||
}
|
}
|
||||||
function knownCarrier(value){return value==='https'||value==='https-lanes'||value==='websocket'||value==='websocket-lanes'}
|
function knownCarrier(value){return value==='https'||value==='https-lanes'||value==='websocket'||value==='websocket-lanes'}
|
||||||
function sessionEcho(response,expectedAttempt,states,exactAttempt){
|
function sessionEcho(response,expectedAttempt,states,exactAttempt){
|
||||||
@@ -184,7 +178,7 @@ async function resolveAttempt(reason,epoch,snapshot){
|
|||||||
if(!token||cursor!=='0'||(snapshot.selected&&echo.selected!==snapshot.selected))throw new Error('changed carrier replay');
|
if(!token||cursor!=='0'||(snapshot.selected&&echo.selected!==snapshot.selected))throw new Error('changed carrier replay');
|
||||||
const welcome=response.body;if(closed||epoch!==attemptEpoch)return;
|
const welcome=response.body;if(closed||epoch!==attemptEpoch)return;
|
||||||
cleanupToken=token;
|
cleanupToken=token;
|
||||||
if(!welcomeSent){welcomeSent=true;port.postMessage(welcome,[welcome]);status('connecting','provisional','',Math.max(0,negotiationStartedAt+negotiatedFinalDeadline*1000-Date.now()))}
|
if(!welcomeSent){welcomeSent=true;port.postMessage(welcome,[welcome]);status('connecting')}
|
||||||
if(echo.state!=='provisional'){switching=false;fail('protocol');return}
|
if(echo.state!=='provisional'){switching=false;fail('protocol');return}
|
||||||
advanceConfirmed(reason,epoch);
|
advanceConfirmed(reason,epoch);
|
||||||
}catch(error){if(!closed&&epoch===attemptEpoch){switching=false;fail(failureReason(error,'protocol'))}}
|
}catch(error){if(!closed&&epoch===attemptEpoch){switching=false;fail(failureReason(error,'protocol'))}}
|
||||||
@@ -222,7 +216,7 @@ async function createSession(epoch){
|
|||||||
if(!token||cursor!=='0'){advanceCarrier('protocol',epoch);return}
|
if(!token||cursor!=='0'){advanceCarrier('protocol',epoch);return}
|
||||||
const welcome=response.body;if(closed||epoch!==attemptEpoch)return;
|
const welcome=response.body;if(closed||epoch!==attemptEpoch)return;
|
||||||
carrier=selected;sessionToken=token;cleanupToken=token;downCursor=cursor;
|
carrier=selected;sessionToken=token;cleanupToken=token;downCursor=cursor;
|
||||||
if(!welcomeSent){welcomeSent=true;port.postMessage(welcome,[welcome]);status('connecting','provisional','',Math.max(0,negotiationStartedAt+negotiatedFinalDeadline*1000-Date.now()))}
|
if(!welcomeSent){welcomeSent=true;port.postMessage(welcome,[welcome]);status('connecting')}
|
||||||
if(carrier==='websocket')openCandidateSocket(null,null,epoch);
|
if(carrier==='websocket')openCandidateSocket(null,null,epoch);
|
||||||
maybeStartCandidate();
|
maybeStartCandidate();
|
||||||
}catch(error){if(closed||epoch!==attemptEpoch)return;advanceCarrier(failureReason(error,'network'),epoch)}
|
}catch(error){if(closed||epoch!==attemptEpoch)return;advanceCarrier(failureReason(error,'network'),epoch)}
|
||||||
@@ -245,7 +239,7 @@ function commitCarrier(probe,epoch){
|
|||||||
carrierCommitted=true;candidateRunning=false;if(carrierTimer)clearTimeout(carrierTimer);carrierTimer=null;
|
carrierCommitted=true;candidateRunning=false;if(carrierTimer)clearTimeout(carrierTimer);carrierTimer=null;
|
||||||
resetScheduler();
|
resetScheduler();
|
||||||
attemptController=null;currentAttempt=null;
|
attemptController=null;currentAttempt=null;
|
||||||
status('connected','committed','',0);
|
status('connected');
|
||||||
if(carrier==='https')poll();
|
if(carrier==='https')poll();
|
||||||
else if(carrier==='https-lanes'){const lane=lanes.get(probe.id);if(lane&&!lane.polling)pollLane(lane)}
|
else if(carrier==='https-lanes'){const lane=lanes.get(probe.id);if(lane&&!lane.polling)pollLane(lane)}
|
||||||
while(pending.length&&!closed){const data=pending.shift();release(data.byteLength,1,null);queueCarrier(data)}
|
while(pending.length&&!closed){const data=pending.shift();release(data.byteLength,1,null);queueCarrier(data)}
|
||||||
@@ -504,13 +498,13 @@ function activatePort(nextPort){
|
|||||||
else if(!carrierCommitted){if(!reserve(data,null)){fail('capacity');return}pending.push(data);maybeStartCandidate()}
|
else if(!carrierCommitted){if(!reserve(data,null)){fail('capacity');return}pending.push(data);maybeStartCandidate()}
|
||||||
else queueCarrier(data);
|
else queueCarrier(data);
|
||||||
}
|
}
|
||||||
}else if(message.data&&message.data.t==='close'){status('failed','terminal','closed',0);close(true)}
|
}else if(message.data&&message.data.t==='close'){status('failed');close(true)}
|
||||||
};
|
};
|
||||||
port.start();status('connecting','starting','',bridgeRequestMs);helloTimer=setTimeout(()=>fail('timeout'),bridgeRequestMs);
|
port.start();status('connecting');helloTimer=setTimeout(()=>fail('timeout'),bridgeRequestMs);
|
||||||
}
|
}
|
||||||
recoveryController=recoverySupport.create({
|
recoveryController=recoverySupport.create({
|
||||||
budgetMs:()=>bridgeRecoveryMs,requestMs:()=>bridgeRequestMs,url:()=>relayOrigin+recoveryPath,token:()=>cleanupToken||sessionToken,
|
budgetMs:()=>bridgeRecoveryMs,requestMs:()=>bridgeRequestMs,url:()=>relayOrigin+recoveryPath,token:()=>cleanupToken||sessionToken,
|
||||||
read:(response,limit,exact,signal)=>responseBody.read(response,limit,exact,signal),cancel:responseBody.cancel,status:remaining=>status('reconnecting','retrying','',remaining),
|
read:(response,limit,exact,signal)=>responseBody.read(response,limit,exact,signal),cancel:responseBody.cancel,status:()=>status('reconnecting'),
|
||||||
restored:finishOldRecovery,replace:replaceCarrier,replaceable:error=>failureReason(error,'network')!=='protocol',
|
restored:finishOldRecovery,replace:replaceCarrier,replaceable:error=>failureReason(error,'network')!=='protocol',
|
||||||
reason:(error,fallback)=>failureReason(error,fallback),terminal:reason=>fail(recoveryController.remaining()<=0?'timeout':reason)
|
reason:(error,fallback)=>failureReason(error,fallback),terminal:reason=>fail(recoveryController.remaining()<=0?'timeout':reason)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -177,3 +177,16 @@ fn ambiguous_commit_is_resolved_before_carrier_advance() {
|
|||||||
.contains("addEventListener('pagehide',()=>fail('navigation')")
|
.contains("addEventListener('pagehide',()=>fail('navigation')")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rendered_page_preserves_exact_v1_status_control_envelope() {
|
||||||
|
let page = render_page("HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", 4);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
page.body
|
||||||
|
.matches("port.postMessage({t:'status',state})")
|
||||||
|
.count(),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert!(!page.body.contains("port.postMessage({t:'status',state,"));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user